next up previous contents
Next: Корректное использование адресов Up: Производные типы данных Previous: Объявление и удаление объектов   Contents

Использование универсальных типов данных в коммуникации

Дескрипторы производных типов данных могут быть переданы в коммуникационный вызов, где бы ни потребовался аргумент типа данных. Вызов вида MPI_SEND (buf, count, datatype , ...), где count > 1, интерпретируется как если бы вызов был передан новому типу данных, который является конкатенацией некоторого числа копий типа данных. Поэтому MPI_SEND (buf, count, datatype, dest, tag, comm) эквивалентен:

MPI_TYPE_CONTIGUOUS(count, datatype, newtype) MPI_TYPE_COMMIT(newtype) MPI_SEND(buf, 1, newtype, dest, tag, comm).

Аналогичное утверждение применимо ко всем коммуникационным функциям, которые имеют аргументы count и datatype.

Предположим, что выполнена операция передачи MPI_SEND(buf, count, datatype, dest,
tag, comm)
, где тип задается картой:

{(type0, disp0),...,(typen-1, dispn-1)},

и экстентом extent. (Пустые элементы ``псевдотипа'' MPI_UB и MPI_LB не указаны в карте типа, но они влияют на значение extent). Операция передачи посылает $ n \times count$ элементов, где элемент $ i \times n + j$ находится в ячейке с адресом addr$_{i,j}$= buf + extent $\times $ i + disp$_{j}$ и имеет тип type$_{j}$, for i = 0 ,..., count-1 and j = 0 ,..., n-1. Эти элементы не обязаны быть ни смежными, ни различными; их порядок может быть произвольным.

Переменная, хранимая по адресу addr$_{i,j}$ в вызывающей подпрограмме должна иметь тип, соответствующий type$_{j}$, где типовое соответствие определяется как в разделе 3.3.1. Посланное сообщение содержит n $\times $ count элементов, где элемент i $\times $ n +j имеет тип type$_{j}$.

Аналогично предположим, что выполнена операция приема MPI_RECV (buf, count, datatype, source, tag, comm, status), где тип данных имеет карту

{(type0, disp0) ,...,(typen-1, dispn-1) },

с экстентом extent. (Опять пустые элементы ``псевдотипа'' не указываются в списке карты, но они влияют на значение extent). Эта операция принимает n $\times $ countэлементов, где элемент i $\times $ n + j есть в ячейке buf + extent $\times $ i + disp$_{j}$ и имеет тип type$_{j}$. Если входящее сообщение состоит из k элементов, тогда мы обязаны иметь k<=n$\times $count; элемент i $\times $ n + j должен иметь тип, соответствующий type$_{j}$.

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

Пример 3.28 Этот пример показывает, что типовое соответствие определяется в терминах базисного типа, из которого состоит производный тип.

... CALL MPI_TYPE_CONTIGUOUS(2, MPI_REAL, type2, ...) CALL MPI_TYPE_CONTIGUOUS(4, MPI_REAL, type4, ...) CALL MPI_TYPE_CONTIGUOUS(2, type2, type22, ...) ... CALL MPI_SEND(a, 4, MPI_REAL, ...) CALL MPI_SEND(a, 2, type2, ...) CALL MPI_SEND(a, 1, type22, ...) CALL MPI_SEND(a, 1, type4, ...) ... CALL MPI_RECV(a, 4, MPI_REAL, ...) CALL MPI_RECV(a, 2, type2, ...) CALL MPI_RECV(a, 1, type22, ...) CALL MPI_RECV(a, 1, type4, ...)

Каждая из этих передач соответствует любой операции приема.

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

Предположим, что выполнена операция MPI_RECV (buf, count, datatype, dest, tag, comm, status), где тип данных таков

{(type0, disp0) ,...,(typen-1, dispn-1).

Принятое сообщение не обязано ни заполнять весь буфер, ни заполнять число ячеек, которое кратно n. Может быть принято любое число k базисных элементов, где 0 $ \le $ k $ \le $ count $ \bullet $ n. Количество полученных базисных элементов может быть получено из статуса с помощью функции MPI_GET_ELEMENTS.

Синтаксис функции MPI_GET_ELEMENTS представлен ниже.

MPI_GET_ELEMENTS(status, datatype, count)

IN status возвращает статус операции приема (статус)
IN datatype тип данных операции приема (дескриптор)
OUT count число принятых базисных элементов (целое)

int MPI_Get_elements(MPI_Status *status, MPI_Datatype datatype, int *count) MPI_GET_ELEMENTS(STATUS, DATATYPE, COUNT, IERROR) INTEGER STATUS(MPI_STATUS_SIZE), DATATYPE, COUNT, IERROR int MPI::Status::Get_elements(const MPI::Datatype& datatype) const

Ранее определенная функция MPI_GET_COUNT (раздел 3.2.5) имеет различное поведение. Она возвращает количество полученных ``элементов верхнего уровня'', то есть количество ``копий'' типа данных. В предыдущем примере MPI_GET_COUNT может возвратить любое целое число k, где 0 $ \le $ k $ \le $ count $ \bullet $n. Если MPI_GET_COUNT возвращает k, тогда число принятых базисных элементов (и значение, возвращенное MPI_GET_ELEMENTS) есть n $\times $ k. Если число полученных базисных элементов не кратно n, то есть операция приема не получила общее число ``копий'' datatype, то MPI_GET_COUNT возвращает значение MPI_UNDEFINED.

Пример 3.29 Использование MPI_GET_COUNT и MPI_GET_ELEMENT

... CALL MPI_TYPE_CONTIGUOUS(2, MPI_REAL, Type2, ierr) CALL MPI_TYPE_COMMIT(Type2, ierr) ... CALL MPI_COMM_RANK(comm, rank, ierr) IF(rank.EQ.0) THEN CALL MPI_SEND(a, 2, MPI_REAL, 1, 0, comm, ierr) CALL MPI_SEND(a, 3, MPI_REAL, 1, 0, comm, ierr) ELSE CALL MPI_RECV(a, 2, Type2, 0, 0, comm, stat, ierr) CALL MPI_GET_COUNT(stat, Type2, i, ierr) ! возвращает i=1 CALL MPI_GET_ELEMENTS(stat, Type2, i, ierr) ! возвращает i=2 CALL MPI_RECV(a, 2, Type2, 0, 0, comm, stat, ierr) CALL MPI_GET_COUNT(stat,Type2,i,ierr) ! возвращает ! i=MPI_UNDEFINED CALL MPI_GET_ELEMENTS(stat, Type2, i, ierr) ! возвращает i=3 END IF

Функция MPI_GET_ELEMENTS также может использоваться после операции probe, чтобы найти число элементов в опробованном сообщении. Заметим, что две функции MPI_GET_COUNT и MPI_GET_ELEMENTS возвращают то же самое значение, когда они используются с базисным типом данных.

Объяснение: Расширение, данное в определении MPI_GET_COUNT, представляется естественным: хотелось бы, чтобы эта функция возвращала значение аргумента count, когда приемный буфер полон. Иногда datatype представляет базисную единицу данных, которую желательно передать, например, запись в массиве записей (структур). Хотелось бы обладать возможностью выяснять, как много компонентов было получено, без забот о разделении числа элементов в каждом компоненте. Однако в другом случае тип данных используется для определения комплексного размещения данных в приемной памяти и не представляет базисную единицу данных для передачи. В таких случаях необходимо использовать функцию MPI_GET_ELEMENTS. []

Совет пользователям: Определение MPI требует, чтобы прием не изменял памяти вне элементов, определенных в качестве составляющих буфера. В частности, определение говорит, что заполненное пространство в структуре не может модифицироваться, когда такая структура скопирована из одного процесса в другой. Это ограничивало бы очевидную оптимизацию копирования структуры вместе с заполнением как один непрерывный блок. Реализация MPI свободна делать такую оптимизацию, если она не воздействует на результат вычислений. Пользователь может ``создать'' эту оптимизацию явным включением заполнения как части сообщения.[]


next up previous contents
Next: Корректное использование адресов Up: Производные типы данных Previous: Объявление и удаление объектов   Contents
Alex Otwagin 2002-12-10