MPI, C, производные типы, структура векторов?

Мне нужно создать тип, производный от MPI, для представления класса в моей программе. Класс довольно простой, но большой (около 75 элементов данных**). Все элементы данных представляют собой одиночные значения, одномерные или двумерные массивы. Вот пример:

class RestartData {
  int dsr;
  double firea2sorgn;
  int ifwoody[NUM_PFT];
  double rootfrac[MAX_ROT_LAY][NUM_PFT];
  ....
  ....
}

Я думаю, что использование MPI_Type_struct уместно. (например, http://www.open-mpi.org/doc/v1.5/man3/MPI_Type_struct.3.php)

И я более или менее следую примеру в этом вопросе: сериализация структуры в C и передавать через MPI, но я не знаю, как обращаться с 2D-массивами. Могу ли я создать MPI_Type_struct, содержащий несколько MPI_Type_vector? Мне не удалось найти пример создания MPI_Type_struct, содержащего 2D-массивы. Я на правильном пути?

Заранее спасибо.


** Я думаю, что понимаю возможные проблемы с передачей одного большого сообщения, но в этом случае сообщение передается нечасто и в естественной точке синхронизации (ведомые отправляют данные обратно мастеру, когда они закончили обрабатывать числа)


person tbc    schedule 24.09.2013    source источник


Ответы (2)


Производные типы в MPI могут свободно создаваться из других производных типов, а затем использоваться для дальнейшего создания других производных типов.

2D-массивы, если они непрерывны в памяти, как в вашем случае, не сильно отличаются от 1D-массивов. Что касается элемента rootfrac, вы можете либо создать непрерывный тип данных с MAX_ROOT_LAY * NUM_PFT элементами типа MPI_DOUBLE, либо создать непрерывный тип данных (назовем его t_dbl_pft) с NUM_PFT элементами типа MPI_DOUBLE, а затем использовать его для создания другого непрерывного типа данных с MAX_ROOT_LAY элементов типа t_dbl_pft. Другой вариант — вообще не создавать тип данных, поскольку конструктор структурированного типа MPI берет отдельную длину блока (т. е. количество элементов) для каждого элемента структуры.

Например, следующий тип описывает элементы данных, которые вы показали:

#include <cstddef> // for offsetof

MPI_Type t_1d;
MPI_Type_contiguous(NUM_PFT, MPI_DOUBLE, &t_1d);
// No need to commit - this type is not used for communication

MPI_Type t_restart;
int counts[4] = { 1, 1, NUM_PFT, MAX_ROT_LAY };
MPI_Type types[4] = { MPI_INT, MPI_DOUBLE, MPI_INT, t_1d };
MPI_Aint displs[4] = {
   offsetof(RestartData, dsr),
   offsetof(RestartData, firea2sorgn),
   offsetof(RestartData, ifwoody),
   offsetof(RestartData, rootfrac),
};
MPI_Type_create_struct(4, counts, displs, types, &t_restart);
MPI_Type_commit(&t_restart);

// The 1D type is no longer needed
MPI_Type_free(&t_1d);

Обратите внимание, что вам нужно либо создать тип данных MPI внутри функции-члена RestartData, либо объявить подпрограмму, в которой создается тип, как friend для класса, чтобы он мог получить доступ к закрытым и защищенным элементам данных. Также обратите внимание, что offsetof работает только с классами POD (обычные старые данные), например. никаких причудливых конструкторов и членов таких типов, как std::string.

person Hristo Iliev    schedule 25.09.2013
comment
+1: я с Христо в этом вопросе, предпочитая строгую типизацию (ну, насколько это возможно для C++MPI), а не слабую типизацию (это все байты или символы), как это было предложено @ Ответ Адама. - person High Performance Mark; 25.09.2013
comment
Для любопытства (и полноты), как бы вы справились с членом, не относящимся к типу POD? - person tbc; 25.09.2013
comment
Обычно используются MPI_Pack и MPI_Unpack для реализации переносимой ручной (де-)сериализации в промежуточный буфер, который впоследствии отправляется/получается с использованием типа данных MPI_PACKED. - person Hristo Iliev; 26.09.2013
comment
обновление - оказалось довольно легко заставить прототип работать, используя первый пример Христо: создать непрерывный тип данных с элементами MAX_ROOT_LAY * NUM_PFT типа MPI_DOUBLE.... Кажется отличным для некоторого начального тестирования, но кажется, что это может быть утомительно поддерживать ? - person tbc; 01.10.2013

Самый простой способ — просто рассматривать весь объект как большой буфер:

MPI_Datatype datatype;

MPI_Type_contiguous(sizeof(RestartData), MPI_BYTE, &datatype);
MPI_Type_commit(&datatype);

Я не вижу смысла рассказывать MPI о внутренней структуре вашего класса.

В качестве альтернативы двумерный массив представляет собой массив одномерных массивов. Итак (я полагаю), вы могли бы использовать один вызов MPI_Type_contiguous для каждого измерения массива для создания типа данных массива.

person Adam    schedule 24.09.2013
comment
Хм, это определенно выглядит как простой способ начать. Я попробую это и посмотрю, что произойдет. Спасибо. - person tbc; 25.09.2013
comment
Это ужасный ответ. Зачем тогда использовать MPI? Он мог просто использовать 0MQ или даже сокеты для передачи сообщений. - person Hristo Iliev; 25.09.2013
comment
@HristoIliev, что можно получить от указания структуры? - person Adam; 25.09.2013
comment
MPI — это переносимость исходного кода. Например, программу можно запустить в гетерогенном кластере со смешанными 32/64-разрядными узлами или смешанными узлами с прямым/обратным порядком байтов. Также MPI разрешено выполнять преобразования на MPI_CHAR, и вместо этого следует использовать MPI_BYTE, если преобразование должно быть подавлено. - person Hristo Iliev; 25.09.2013
comment
Переносимость исходного кода между разными системами, а не внутри одной системы. Я даже не могу понять, как запустить работу с разными двоичными файлами на разных узлах. Если один и тот же двоичный файл обрабатывает память по-разному на разных узлах, возникают более серьезные проблемы. Хорошая мысль о MPI_BYTE. - person Adam; 25.09.2013
comment
Единственное преимущество, которое я вижу в типе данных, отличном от MPI_BYTE[], заключается в использовании встроенных функций агрегирования для типов POD. т.е. MPI_Reduce. В любом случае они не будут работать с пользовательскими типами данных. Все остальные вроде посылов, трансляций, разброса/сборки и т.д., практически все равно работают только на буферах. Какая разница, MPI_DOUBLE или MPI_BYTE[sizeof(double)]? - person Adam; 25.09.2013
comment
Гетерогенные архитектуры более распространены, чем вы думаете, например. Платы Intel Xeon Phi поддерживают передачу сообщений MPI между своими хост-системами. В этом случае структурированные типы облегчают передачу данных с различным выравниванием элементов (и преобразованием представления данных, где это необходимо). - person Hristo Iliev; 25.09.2013