Mpfr_t в пользовательских структурах MPI

Я работаю над преобразованием своей программы для использования произвольной точности и поэтому начал использовать MPFR. У меня была собственная структура MPI, содержащая мои данные в исходном коде. Теперь, когда я преобразовал свои данные в mpfr_t, я не знаю, как создать эту структуру в MPI.

typedef struct job_s {
    int f;
    mpfr_t l,t,r,b;
} jobs;

MPI_Datatype MPI_JOBS_TYPE;
MPI_Type_create_struct(
    5,
    (int []) {1, sizeof(mpfr_t), sizeof(mpfr_t), sizeof(mpfr_t), sizeof(mpfr_t)},
    (MPI_Datatype []) {offsetof(jobs,f), offsetof(jobs,l), offsetof(jobs,t), offsetof(jobs,r), offsetof(jobs, b)},
    (MPI_Datatype []) {MPI_INT, MPI_BYTE, MPI_BYTE, MPI_BYTE, MPI_BYTE},
    &MPI_JOBS_TYPE
);

MPI_Type_commit(&MPI_JOBS_TYPE);

Эта структура затем отправляется позже с помощью

jobs send;
/* set the objects of the struct to whatever using MPFR */
MPI_Send(&send, 1, MPI_JOBS_TYPE, reqRank, 0, MPI_COMM_WORLD);

Я не уверен, куда идти дальше. Я понимаю, что это очень неправильно, поскольку MPI не может определить размер структуры, поскольку я еще даже не установил точность (это вообще так работает?). Буду признателен за любую помощь! Спасибо.

Обновлено: Я так близко, но что-то все еще не так с экспортом, отправкой, получением или импортом переменных mpfr_t. Я успешно могу упаковать f, отправить, получить и распаковать!

char * mpfr_buf;
size_t mpfr_buf_size;
char buf [3000];
pos = 0;
MPI_Pack(&f, 1, MPI_INT, buf, 3000, &pos, MPI_COMM_WORLD);

stream = open_memstream(&mpfr_buf, &mpfr_buf_size);
for(i = 0; i < 4; ++i)
    mpfr_fpif_export(stream, bounds[i]);
MPI_Pack(stream, 3000-sizeof(int), MPI_BYTE, buf, 3000, &pos, MPI_COMM_WORLD);

print_bounds(bounds, "s");

MPI_Send(buf, pos, MPI_PACKED, reqRank, 0, MPI_COMM_WORLD);

fclose(stream);
f += 1;

и на принимающей стороне

pos = 0;
char buf [3000];
MPI_Recv(buf, 3000, MPI_PACKED, PARENT, 0, MPI_COMM_WORLD, &status);
int msgSize = 0;
MPI_Get_count(&status, MPI_BYTE, &msgSize);
printf("msg size %d\n", msgSize);
MPI_Unpack(buf, 3000, &pos, &f, 1, MPI_INT, MPI_COMM_WORLD);
printf("Worker %d recived frame %d\n", rank, f);

char streambuf [3000];
MPI_Unpack(buf, 3000, &pos, streambuf, msgSize - pos, MPI_BYTE, MPI_COMM_WORLD);
stream = fmemopen(streambuf, 3000, "r");
for(i = 0; i < 4; ++i){
    mpfr_fpif_import(bounds[i], stream);
}
fclose(stream);

Я получаю мусор для первых трех импортируемых файлов, а для последнего я SIGBART с ошибкой get_str.c:157: MPFR assertion failed: size_s1 >= m. Еще раз любая помощь приветствуется! Спасибо.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

К сожалению, передавать числа MPFR не так просто, как типы данных MPI, не нарушая при этом исходную или двоичную совместимость. Проблема в том, что mpfr_t — это структура с элементом типа указатель, поэтому вы не можете просто сериализовать ее как чистую последовательность байтов. Вам необходимо зарегистрировать тип данных MPI, соответствующий внутренней структуре MPFR, и использовать его при определении типа данных MPI для вашей собственной структуры.

Но вы не можете создать только один тип MPI, соответствующий любому экземпляру mpfr_t. MPI не поддерживает погоню за указателем, и, учитывая, что элемент указателя в mpfr_t может указывать на местоположения с произвольным и, скорее всего, различным смещением в каждом экземпляре (создание структурированного типа MPI работает со смещениями от адреса буфера), вам необходимо создать отдельный тип данных MPI для каждой переменной типа mpfr_t. Это возможно, но очень далеко от оптимального, потому что:

  • вы нарушаете правило инкапсуляции данных, заглядывая внутрь mpfr_t
  • ваш код станет непереносимым для гибридных архитектур
  • это большая работа и ее действительно сложно отладить

Портативное решение — использовать функции MPFR для Ввода и вывода, и, в частности, две экспериментальные функции, которые читают и записывают экземпляры MPFR из и в потоки C FILE. Что вам нужно сделать, так это создать поток памяти с помощью open_memstream и использовать mpfr_fpif_export для записи в него переносимых представлений l, t, r и b, а затем упаковать полученные байты в буфер MPI с помощью MPI_Pack. Вам также придется вручную упаковать f. На стороне получателя распакуйте f с помощью MPI_Unpack, затем распакуйте массив байтов и откройте его как поток памяти с помощью fmemopen в режиме чтения, затем используйте mpfr_fpif_import, чтобы прочитать из него четыре значения. Поскольку представления могут иметь разный размер, вам следует использовать MPI_Probe на стороне получателя, чтобы сначала получить фактический размер сообщения, а затем выделить достаточно большой буфер для MPI_Recv.

Если экспериментальный характер экспорта и импорта FPIF вас как-то сбивает с толку, используйте строковый ввод/вывод.

Я попробую! Спасибо.

Lucian Chauvin 27.06.2024 15:51

Я обновил свой пост, указав, что он довольно близок к этому, но все еще не уверен, что происходит не так.

Lucian Chauvin 28.06.2024 16:30

@LucianChauvin, вы распаковываете 1 байт сообщения вместо всего сериализованного потока. Используйте MPI_Get_count(&status, MPI_BYTE, &msgSize), чтобы узнать размер сообщения. msgSize - pos (после первой распаковки) — размер упакованного массива байт, который станет потоком вашей памяти.

Hristo Iliev 28.06.2024 17:41

Обратите внимание, что MPI_Pack не кодирует информацию о типе или размере в сообщении, и вы должны указать правильный размер распаковки MPI_Unpack.

Hristo Iliev 28.06.2024 17:48

Хорошо. У меня все заработало, спасибо за помощь. Сейчас это происходит довольно медленно, но пусть будет так.

Lucian Chauvin 28.06.2024 23:51

@LucianChauvin, у тебя есть идеи, что делает его медленным? Такие инструменты, как Score-P, могут оказаться полезными.

Hristo Iliev 01.07.2024 15:17

@Hristo_Ilieve Я пришел к выводу, что изменение скорости не имеет ничего общего с тем, что мы здесь сделали. Спасибо за помощь.

Lucian Chauvin 04.07.2024 18:10

Другие вопросы по теме