next up previous contents
Next: Другие конструкторы производных типов Up: Группировка данных для пересылки Previous: Параметр count   Contents

Производные типы и MPI_Type_struct

Может показаться, что другим вариантом могло бы стать хранение a, b, n в структуре с тремя членами - два числа с плавающей точкой и целое - и попытка использовать аргумент datatype в функции MPI_Bcast(). Трудность здесь состоит в том, что тип datatype является одним из MPI_Datatype(), которые не являются пользовательскими типами, как структуры в C. Если определить тип:

typedef struct {

  float a;

  float b;

  int n;

} INDATA_TYPE

а затем переменную
INDATA_TYPE indata
то при вызове
MPI_Bcast(&indata, 1, INDATA_TYPE, 0, MPI_COMM_WORLD)
произойдет ошибка. Проблема состоит в том, что MPI является библиотекой готовых функций. При этом функции MPI не ориентированы на применение пользовательских типов данных, определенных в программе.

MPI обеспечивает частичное решение этой проблемы, разрешая пользователю во время выполнения создавать собственные типы данных MPI. Чтобы построить тип данных для MPI, необходимо определить расположение данных в типе: тип элементов и их относительные местоположения в памяти. Такой тип называют производным типом данных. Ниже приведена функция, которая будет строить производный тип, соответствующий INDATA_TYPE:

void Build_derived_type(INDATA_TYPE* indata,

     MPI-Datatype* message_type_ptr)

{

  int block_lengths[3];

  MPI_Aint displacements[3];

  MPI_Aint addresses[4];

  MPI_Datatype typelist[3];

 

  /* Создает производный тип данных, содержащий

  * два элемента float и один int */

  /* Сначала нужно определить типы элементов */

  typelist[0] = MPI_FLOAT;

  typelist[1] = MPI_FLOAT;

  typelist[2] = MPI_INT;

 

  /* Определить количество элементов каждого типа */

  block_lengths[0] = block_lengths[1] =

     block_lengths[2] = 1;

  

  /* Вычислить смещения элементов 

  * относительно indata */

  MPI_Address(indata, &addresses[0]);

  MPI_Address(&(indata->a), &addresses[1]);

  MPI_Address(&(indata->b), &addresses[2]);

  MPI_Address(&(indata->n), &addresses[3]);

  displacements[0] = addresses[1] - addresses[0];

  displacements[1] = addresses[2] - addresses[0];

  displacements[2] = addresses[3] - addresses[0];

 

  /* Создать производный тип */

  MPI_Type_struct(3, block_lengths, displacements,

     typelist, Message_type_ptr);

 

  /* Зарегистрировать его для использования */

  MPI_Type_commit(message_type_ptr);

} /* Build_derived_type */

Первые три оператора определяют тип элементов производного типа, а следующие определяют число элементов каждого типа. Следующие четыре оператора вычисляют адреса трех членов indata, а еще три оператора используют вычисленные адреса, чтобы определить смещения этих трех членов относительно адреса первого, которому дают смещение 0. При наличии этой информации MPI становятся известны типы, размеры, и относительные местоположения элементов переменной, имеющей тип INDATA_TYPE, после чего можно создать производный тип данных, который соответствует типу в языке C. Это выполняется с помощью вызовов функций MPI_Type_struct() и MPI_Type_commit().

Новый тип данных MPI можно использовать в любых коммуникационных функциях MPI. Чтобы использовать его, необходимо применять стартовый адрес переменной типа INDATA_TYPE в качестве первого аргумента, а производный тип данных - в качестве аргумента datatype. При этом функция Get_data() в примере принимает вид.

void Get_data3(INDATA_TYPE* indata, int my_rank) {

  MPI_Datatype message_type; /* Аргументы для */

  int root = 0; /* MPI_Bcast */

  int count = 1;

  if (my_rank == 0) {

    printf(''Введите a, b, and n\n'');

    scanf(''%f %f %d'', &(indata->a),

         &(indata->b), &(indata->n));

  }

  Build_derived_type(indata, &message_type);

  MPI_Bcast(indata, count, message_type, root,

  MPI_COMM_WORLD);

} /* Get_data3 */

Отметим, что тип элементов массива смещений MPI_Aint не является int. Это специальный тип MPI, позволяющий предоставлять адреса, большие по размеру, чем int.

Производные типы данных строятся с помощью функции
MPI_Type_struct(). Синтаксис этой функции таков:

int MPI_Type_Struct(int count,

  int* array_of_block_lengths,

  MPI_Aint* array_of_displacements,

  MPI_Datatype* array_of_types,

  MPI_Datatype* newtype)

Аргумент count определяет число элементов в производном типе. Он также задает размер трех массивов: массива длин блоков
array_of_block_lengths, массива смещений в данном типе
array_of_displacements, и массива типов array_of_types. Массив
array_of_block_lengths содержит число вхождений для каждого элемента типа. Так, если элемент типа - непрерывный массив m элементов, то соответствующий элемент в array_of_block_lengths равен m. Массив array_of_displacements содержит смещение каждого элемента от начала сообщения, а массив array_of_types содержит типы данных MPI_datatype для каждого элемента. Аргумент newtype возвращает указатель на тип данных MPI, созданный вызовом MPI_Type_struct.

Следует также отметить, что newtype и элементы массива
array_of_types все имеют тип MPI_Datatype. Поэтому функцию
MPI_Type_struct() можно вызывать рекурсивно для построения более сложных производных типов данных.


next up previous contents
Next: Другие конструкторы производных типов Up: Группировка данных для пересылки Previous: Параметр count   Contents
2004-06-22