Лаборатория Параллельных информационных технологий НИВЦ МГУ
Опубликован: 22.04.2008 | Доступ: свободный | Студентов: 1177 / 413 | Оценка: 4.30 / 4.19 | Длительность: 08:05:00
Специальности: Программист
Лекция 7:

Пересылка разнотипных данных

< Лекция 6 || Лекция 7: 123

Создание нового типа данных 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
< Лекция 6 || Лекция 7: 123