У меня есть следующая структура.
typedef struct
{
int *Ai;
double *Ax;
int nz;
}column;
Я хочу передать эту структуру с помощью MPI_Send
и MPI_Receive
. Как создать MPI_Datatype
для этой структуры?
У меня есть следующая структура.
typedef struct
{
int *Ai;
double *Ax;
int nz;
}column;
Я хочу передать эту структуру с помощью MPI_Send
и MPI_Receive
. Как создать MPI_Datatype
для этой структуры?
MPI предназначен для работы с массивами структур, а не со структурами массивов.
MPI_Hindexed
, который предлагал @suszterpatt, - ужасный взлом. Он позволит вам отправлять только один элемент типа структуры и только элемент, который использовался для определения типа данных MPI. Для других переменных одного и того же типа структуры в большинстве случаев гарантируется, что вычисленные смещения будут ошибочными. Кроме того, типы Hindexed используют один и тот же тип данных MPI для всех элементов и, таким образом, не позволяют отправлять как ints, так и double.
Мудрое дело - превратить вашу программу в использование массивов структур:
typedef struct
{
int i;
double z;
} point;
typedef struct
{
point *A;
int nz;
} column;
Теперь вы можете создать структурированный тип MPI point_type
и использовать его для отправки nz
элементов этого типа, давая column.A
в качестве адреса буфера:
int lens[3];
MPI_Aint base, disps[2];
MPI_Datatype oldtypes[2], point_struct, point_type;
MPI_Get_address(&point, disps);
MPI_Get_address(&point.z, disps+1);
base = disps[0];
lens[0] = 1; disps[0] = MPI_Aint_diff(disps[0], base); oldtypes[0] = MPI_INT;
lens[1] = 1; disps[1] = MPI_Aint_diff(disps[1], base); oldtypes[1] = MPI_DOUBLE;
MPI_Type_create_struct(2, lens, disps, oldtypes, &point_struct);
MPI_Type_create_resized(point_struct, 0, sizeof(point), &point_type);
MPI_Type_commit(&point_type);
MPI_Send(column.A, column.nz, point_type, ...);
Сначала создается тип данных MPI point_struct
, который описывает компоновку элементов структуры, но не учитывает какие-либо дополнения в конце и, следовательно, не может использоваться для надежной отправки массива таких структур. Следовательно, второй тип данных point_type
с правильной степенью создается с помощью MPI_Type_create_resized
.
На стороне приемника вы заглянете в сообщение с помощью MPI_Probe
, извлеките количество элементов с помощью MPI_Get_count
с типом point_type
(который идет прямо в поле nz
), выделите A
и используйте его в MPI_Recv
для получения элементов nz
:
MPI_Status status;
MPI_Probe(source, tag, comm, &status);
MPI_Get_count(&status, point_type, &column.nz);
if (nz == MPI_UNDEFINED)
... non-integral message was received, do something
column.A = (point *)malloc(column.nz*sizeof(point));
MPI_Recv(column.A, column.nz, point_type, source, tag, comm, MPI_STATUS_IGNORE);
Если это изменение кода невозможно, вы все равно можете пройти промежуточный шаг преобразования своей структуры перед отправкой, процесс, обычно называемый (un-) маршалинг. В вашем случае сделайте что-то вроде этого (я предполагаю, что вы храните количество элементов массива в Ai
и Ax
в поле nz
):
point *temp = (point *)malloc(nz*sizeof(point));
for (int i = 0; i < column.nz; i++)
{
temp[i].i = column.Ai[i];
temp[i].z = column.Az[i];
}
MPI_Send(temp, nz, point_type, ...);
free(temp);
На стороне приемника вы должны сделать противоположное: выделить достаточно большой буфер, который может удерживать структуру, получать сообщение в ней и затем делать противоположное преобразование.
И снова вам не нужно передавать фактическое значение nz
, так как его можно легко извлечь из длины сообщения, используя MPI_Get_count
.
Отправка указателей на другую машину бессмысленна (каламбур не предназначен). Из-за виртуальной адресации указатель, вероятно, укажет на недопустимое расположение памяти на принимающем компьютере, и даже если нет, вы фактически не отправили данные, на которые он указывал.
Однако при правильном использовании типов данных MPI_Address()
и MPI_Hindexed
можно описать макет памяти ваших данных (я предполагаю, что ваши указатели указывают на динамические массивы). Например. если Ai
указывает на 3 int
s, а Ax
указывает на 5 double
s, вам понадобится тип Hindexed
с 3-мя блоками: 3 MPI_INT
s, 5 MPI_DOUBLE
s и 1 MPI_INT
, с смещениями, полученными с помощью MPI_Address()
.
Не забудьте переопределить и подтвердить тип данных, если вы измените количество отправленных элементов или полностью перераспределите массивы. И если вы отправляете несколько структур, вам придется определять и фиксировать этот тип данных для каждого из них, так как ваш тип данных MPI специфичен для одного конкретного экземпляра этих структур.
Также имейте в виду, что вам нужно будет сделать подобную сложную распаковку на принимающей стороне, если вы хотите воссоздать исходную структуру.
"Мудрое дело - превратить вашу программу в использование массивов структур"
Часто это концептуально также лучше.
Я хотел бы указать еще один механизм: использование MPI_Pack и MPI_Unpack. Например, с исходной структурой вы можете упаковать первое целое число, а затем упаковать два массива. Приемник распакует целое число, а затем узнает, сколько других вещей нужно распаковать.
Это также хорошее решение, если ваш объект недоступен напрямую, но доступен только через итератор или около того.