Пересылка разнотипных данных
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLEN элементов базового типа данных TYPE. Следующий блок начинается через STRIDE байт после начала предыдущего блока.
MPI_TYPE_INDEXED(COUNT, BLOCKLENS, DISPLS, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLENS (I) элементов базового типа данных. I-й блок начинается через DISPLS (i) элементов базового типа данных с начала буфера посылки. Полученный тип данных можно считать обобщением векторного типа.
В следующем примере задается тип данных newtype для описания нижнетреугольной матрицы типа double precision (при этом учитывается, что в языке Фортран массивы хранятся по столбцам).
do i = 1, n blocklens (i) = n-i + 1 displs(i) = n*(i-1)+i-1 end do call MPI_TYPE_INDEXED(n, blocklens, displs, MPI_DOUBLE_PRECISION, newtype, ierr) MPI_TYPE_HINDEXED(COUNT, BLOCKLENS, DISPLS, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLENS (I) элементов базового типа данных. I-й блок начинается через DISPLS (I) байт с начала буфера посылки.
MPI_TYPE_STRUCT(COUNT, BLOCKLENS, DISPLS, TYPES, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPES(*), NEWTYPE, IERR
Создание структурного типа данных NEWTYPE из COUNT блоков по BLOCKLENS (i) элементов типа TYPES (I) . I-й блок начинается через DISPLS (I) байт с начала буфера посылки.
В следующем примере создается новый тип данных newtype, который после регистрации может быть использован для пересылки как единого целого пяти элементов данных, которые можно представить следующим образом (тип элемента данных, количество байт от начала буфера посылки):
{(MPI_DOUBLE_PRECISION, 0), (MPI_DOUBLE_PRECISION, 8), (MPI_DOUBLE_PRECISION, 16), (MPI_CHARACTER, 24), (MPI_CHARACTER, 25)} blocklens(1) = 3 blocklens(2) = 2 types(1) = MPI_DOUBLE_PRECISION types(2) = MPI_CHARACTER displs(1) = 0 displs(2) = 24 call MPI_TYPE_STRUCT(2, blocklens, displs, types, & newtype, ierr) MPI_TYPE_COMMIT(DATATYPE, IERR) INTEGER DATATYPE, IERR
Регистрация созданного производного типа данных DATATYPE. После регистрации этот тип данных можно использовать в операциях обмена наравне с предопределенными типами данных. Предопределенные типы данных регистрировать не нужно.
MPI_TYPE_FREE(DATATYPE, IERR) INTEGER DATATYPE, IERR
Аннулирование производного типа данных DATATYPE. Параметр DATATYPE устанавливается в значение MPI_DATATYPE_NULL. Гарантируется, что любой начатый обмен, использующий данные аннулируемого типа, будет нормально завершен. При этом производные от DATATYPE типы данных остаются и могут использоваться дальше. Предопределенные типы данных не могут быть аннулированы.
MPI_TYPE_SIZE(DATATYPE, SIZE, IERR) INTEGER DATATYPE, SIZE, IERR
Определение размера SIZE типа данных DATATYPE в байтах (объема памяти, занимаемого одним элементом данного типа).
MPI_ADDRESS(LOCATION, ADDRESS, IERR) <type> LOCATION(*) INTEGER ADDRESS, IERR
Определение абсолютного байт-адреса ADDRESS размещения массива LOCATION в оперативной памяти компьютера. Адрес отсчитывается от базового адреса, значение которого содержится в системной константе MPI_BOTTOM. Процедура позволяет определять абсолютные адреса объектов как в языке Фортран, так и в Си, хотя в Си для этого предусмотрены иные средства. В языке Си параметр ADDRESS имеет тип MPi_Aint.
В следующем примере описывается новый тип данных newtype, который после регистрации используется для пересылки как единого целого двух элементов данных типов double precision и character (1). В качестве адреса буфера посылки используется базовый адрес MPI_BOTTOM, а для определения смещений элементов данных datl и dat2 используются вызовы процедуры MPI_ADDRESS. Перед пересылкой новый тип регистрируется при помощи вызова процедуры MPI_TYPE_COMMIT. Заметим, что пересылается один элемент данных производного типа, хотя он и состоит из двух разнотипных элементов.
blocklens(1) = 1 blocklens(2) = 1 types(1) = MPI_DOUBLE_PRECISION types(2) = MPI_CHARACTER call MPI_ADDRESS(dat1, address(1), ierr) displs(1) = address(1) call MPI_ADDRESS(dat2, address(2), ierr) displs(2) = address(2) call MPI_TYPE_STRUCT(2, blocklens, displs, types, & newtype, ierr) call MPI_TYPE_COMMIT(newtype, ierr) call MPI_SEND(MPI_BOTTOM, 1, newtype, dest, tag, & MPI_COMM_WORLD, ierr) MPI_TYPE_LB(DATATYPE, DISPL, IERR) INTEGER DATATYPE, DISPL, IERR
Определение смещения DISPL В байтах нижней границы элемента типа данных DATATYPE от начала буфера данных.
MPI_TYPE_UB(DATATYPE, DISPL, IERR) INTEGER DATATYPE, DISPL, IERR
Определение смещения DISPL В байтах верхней границы элемента типа данных DATATYPE от начала буфера данных.
MPI_TYPE_EXTENT(DATATYPE, EXTENT, IERR) INTEGER DATATYPE, EXTENT, IERR
Определение диапазона EXTENT (разницы между верхней и нижней границами элемента данного типа) типа данных DATATYPE В байтах.
В следующем примере производный тип данных используется для перестановки столбцов матрицы в обратном порядке. Тип данных matr_rev, создаваемый процедурой MPI_TYPE_VECTOR, описывает локальную часть матрицы данного процесса в переставленными в обратном порядке столбцами. После регистрации этот тип данных может использоваться при пересылке. Программа работает правильно, если размер матрицы N делится нацело на число процессов приложения.
program example19 include 'mpif.h' integer ierr, rank, size, N, nl parameter (N = 8) double precision a(N, N), b(N, N) call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) nl = (N-1)/size+1 call work (a, b, N, nl, size, rank) call MPI_FINALIZE(ierr) end subroutine work(a, b, n, nl, size, rank) include 'mpif.h' integer ierr, rank, size, n, nl, ii, matr_rev double precision a(n, nl), b(n, nl) integer i, j, status(MPI_STATUS_SIZE) do j = 1, nl do i = 1, n b(i,j) = 0.d0 ii = j+rank*nl a(i,j) = 100*ii+i enddo enddo call MPI_TYPE_VECTOR(nl, n, -n, MPI_DOUBLE_PRECISION, & matr_rev, ierr) call MPI_TYPE_COMMIT(matr_rev, ierr) call MPI_SENDRECV(a(1, nl), 1, MATR_REV, size-rank-1, 1, & b, nl*n, MPI_DOUBLE_PRECISION, & size-rank-1, 1, MPI_COMM_WORLD, & status, ierr) do j = 1, nl do i = 1, n print *, 'process ', rank, ': ', & j+rank*nl, ' ', i, a(i,j), ' ', b(i,j) enddo enddo end