Программирование для многопроцессорных систем в стандарте MPI - Шпаковский Г.И., Серикова Н.В.. Программирование для многопроцессорных систем в стандарте MPI -. Организация вычислений в многопроцессорных системах
Скачать 1.61 Mb.
|
MPI_TEST_CANCELLED (status, flag) IN status статус (Status) OUT flag (логический тип ) int MPI_Test_cancelled(MPI_Status *status, int *flag) MPI_TEST_CANCELLED(STATUS, FLAG, IERROR) LOGICAL FLAG INTEGER STATUS(MPI_STATUS_SIZE), IERROR bool MPI::Status::Is_cancelled () const Функция MPI_TEST_CANCELLED возвращает flag = true , если обмен, связанный со статусным объектом, был отменен успешно. В таком случае все другие поля статуса (такие как count или tag ) не оп- ределены. В противном случае возвращается flag = false 3.9. СОВМЕЩЕННЫЕ ПРИЕМ И ПЕРЕДАЧА СООБЩЕНИЙ Операция send–receive комбинирует в одном обращении посылку сообщения одному получателю и прием сообщения от другого отпра- вителя. Получателем и отправителем может быть тот же самый про- цесс. Эта операция весьма полезна для выполнения сдвига по цепи 82 процессов. Если для такого сдвига были использованы блокирующие приемы и передачи, тогда нужно корректно упорядочить эти приемы и передачи так, чтобы предупредить циклические зависимости, кото- рые могут привести к дедлоку. MPI_SENDRECV выполняет операции блокируемой передачи и приема. Передача и прием используют тот же самый коммуникатор, но, возможно, различные тэги. Буфера отправителя и получателя должны быть разделены и могут иметь различную длину и типы дан- ных. Сообщение, посланное операцией send–receive , может быть по- лучено обычной операцией приема или опробовано операцией probe , send–receive может также получать сообщения, посланные обычной операцией передачи. MPI_SENDRECV(sendbuf, sendcount, sendtype, dest, sendtag, recvbuf, recvcount, recvtype, source, recvtag, comm, status) IN sendbuf начальный адрес буфера отправителя (альтернатива) IN sendcount число элементов в буфере отправителя (целое) IN sendtype тип элементов в буфере отправителя (дескриптор) IN dest номер процесса-получателя (целое) IN sendtag тэг процесса-отправителя (целое) OUT recvbuf начальный адрес приемного буфера (альтернатива) IN recvcount число элементов в приемном буфере (целое) IN recvtype тип элементов в приемном буфере (дескриптор) IN source номер процесса-отправителя (целое) IN recvtag тэг процесса-получателя (целое) IN comm коммуникатор (дескриптор) OUT status статус (статус) int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, MPI_Datatype recvtag, MPI_Comm comm, MPI_Status *status) MPI_SENDRECV(SENDBUF, SENDCOUNT, SENDTYPE, DEST, SENDTAG, RECVBUF, RECVCOUNT, RECVTYPE, SOURCE, RECVTAG, COMM, STATUS, IERROR) INTEGER SENDCOUNT, SENDTYPE, DEST, SENDTAG, RECVCOUNT, RECVTYPE, SOURCE, RECVTAG, COMM, STATUS(MPI_STATUS_SIZE), IERROR void MPI::Comm::Sendrecv(const void *sendbuf, int sendcount, const MPI::Datatype& sendtype, int dest, int sendtag, void *recvbuf, int recvcount, const MPI::Datatype& recvtype, int source, int recvtag, MPI::Status& status) const 83 MPI_SENDRECV_REPLACE выполняет блокируемые передачи и приемы. Тот же самый буфер используется для отправки и получе- ния, так что посланное сообщение замещается полученным. MPI_SENDRECV_REPLACE (buf, count, datatype, dest, sendtag, source, recvtag, comm, status) INOUT buf начальный адрес буфера отправителя и получателя (альтернатива) IN count число элементов в буфере отправителя и получателя (целое) IN datatype тип элементов в буфере отправителя и получателя (дескриптор) IN dest номер процесса-получателя (целое) IN sendtag тэг процесса-отправителя (целое) IN source номер процесса-отправителя (целое) IN recvtag тэг процесса-получателя (целое) IN comm коммуникатор (дескриптор) OUT status статус (статус) int MPI_Sendrecv_replace(void* buf,int count, MPI_Datatype datatype, int dest, int sendtag, int source, int recvtag, MPI_Comm comm, MPI_Status *status) MPI_SENDRECV_REPLACE(BUF, COUNT, DATATYPE, DEST, SENDTAG, SOURCE, RECVTAG, COMM, STATUS, IERROR) INTEGER COUNT, DATATYPE, DEST, SENDTAG, SOURCE, RECVTAG, COMM, STATUS(MPI_STATUS_SIZE), IERROR void MPI::Comm::Sendrecv_replace (void* buf, int count, const MPI::Datatype& datatype, int dest, int sendtag, int source, int recvtag, MPI::Status& status) const Семантика операции send–receive похожа на запуск двух конкури- рующих потоков, один выполняет передачу, другой – прием, с после- дующим объединением этих потоков. Во многих случаях удобно опи- сать "фиктивный" отправитель или получатель для коммуникаций. Это упрощает код, который необходим для работы с границами, на- пример, в случае нециклического сдвига, выполненного по вызову send–receive . Когда в вызове нужны аргументы отправителя или по- лучателя, вместо номера может быть использовано специальное зна- чение MPI_PROC_NULL. Обмен с процессом, который имеет значе- ние MPI_PROC_NULL, не дает результата. Передача в процесс с MPI_PROC_NULL успешна и заканчивается сразу, как только воз- можно. Прием от процесса с MPI_PROC_NULL успешен и заканчи- вается сразу, как только возможно без изменения буфера приема. Ко- гда выполняется прием с source = MPI_PROC_NULL , тогда статус возвращает source = MPI_PROC_NULL, tag = MPI_ANY_TAG и count = 0 84 3.10. ПРОИЗВОДНЫЕ ТИПЫ ДАННЫХ До сих пор все парные обмены использовали только непрерывные буфера, содержащие последовательности элементов одного типа. Час- то необходимо передавать сообщения, которые содержат значения различных типов или посылать несмежные данные. Одно из решений состоит в том, чтобы упаковать несмежные данные в смежный буфер на стороне отправителя и распаковать обратно на приемной стороне. Это неэффективно, поскольку требуется дополнительная операция копирования память–память на обеих сторонах. MPI обеспечивает ме- ханизм для описания общих буферов для несмежных коммуникаций, в которых используются производные типы данных, образуемые конст- рукторами, описанными в этом разделе. Универсальный тип данных есть скрытый объект, который опи- сывается двумя составляющими: последовательностью базисных ти- пов и последовательностью целых (байтовых) смещений. Не требуется, чтобы смещения были положительными, различны- ми или возрастающего порядка. Порядок объектов не обязан совпа- дать с их порядком в памяти, и объект может появляться более чем один раз. Последовательность указанных выше пар называется картой ти- па . Последовательность базисных типов данных (смещения игнори- руются) есть сигнатура типа. Можно использовать дескриптор обще- го типа данных как аргумент в операциях передачи или приема вместо аргумента базисного типа данных. Операция MPI_SEND ( buf, 1, datatype,...) будет использовать бу- фер посылки, определенный базовым адресом buf и общим типом данных, связанным с datatype ; она будет генерировать сообщение с сигнатурой типа, определенной аргументом datatype. Базисные типы данных, представленные в 3.2.2, – частные случаи универсального типа и являются предопределенными (например, MPI_INT есть предопределенный указатель на тип данных с одним элементом типа int и смещением равным нулю). Экстент ( extent) типа данных определяется как пространство, от первого байта до последнего байта, занятое элементами этого типа данных, округленное вверх с учетом требований выравнивания дан- ных. 85 3.10.1. Конструкторы типа данных Простейшим типом конструктора типа данных является конструк- тор MPI_TYPE_CONTIGUOUS , который позволяет копировать тип данных в смежные области. MPI_TYPE_CONTIGUOUS (count, oldtype, newtype) IN count число повторений (неотрицательное целое) IN oldtype старый тип данных (дескриптор) OUT newtype новый тип данных (дескриптор) int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype) MPI_TYPE_CONTIGUOUS(COUNT, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, OLDTYPE, NEWTYPE, IERROR MPI::Datatype MPI::Datatype::Create_contiguous (int count) const Новый тип newtype есть тип, полученный конкатенацией (сцепле- нием) count копий старого типа oldtype Функция MPI_TYPE_VECTOR является универсальным конст- руктором, который позволяет реплицировать типы данных в области, которые состоят из блоков равного объема. Каждый блок получается как конкатенация некоторого количества копий старого типа. Про- странство между блоками кратно размеру old datatype MPI_TYPE_VECTOR ( count, blocklength, stride, oldtype, newtype) IN count число блоков (неотрицательное целое) IN blocklength число элементов в каждом блоке (неотрицательное целое) IN stride число элементов между началами каждого блока (целое) IN oldtype старый тип данных (дескриптор) OUT newtype новый тип данных (дескриптор) int MPI_Type_vector(int count, int blocklength, int stride,MPI_Datatype oldtype, MPI_Datatype *newtype) MPI_TYPE_VECTOR(COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR MPI::Datatype MPI::Datatype::Create_vector (int count, int blocklength, int stride) const 86 Функция MPI_TYPE_HVECTOR идентична за исключением то- го, что страйд задается в байтах, а не в элементах. ( H соответствует слову heterogeneous – неоднородный.) MPI_TYPE_HVECTOR ( count, blocklength, stride, oldtype, newtype) IN count число блоков (неотрицательное целое) IN blocklength число элементов в каждом блоке (неотрицательное целое) IN stride число байтов между началом каждого блока (целое) IN oldtype старый тип данных (дескриптор) OUT newtype новый тип данных (дескриптор) int MPI_Type_hvector(int count, int blocklength, MPI_Aint stride, MPI_Datatype oldtype, MPI_Datatype *newtype) MPI_TYPE_HVECTOR(COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, BLOCKLENGTH, STRIDE, OLDTYPE, NEWTYPE, IERROR MPI::Datatype MPI::Datatype::Create_hvector (int count, int blocklength, MPI::Aint stride) const Функция MPI_TYPE_INDEXED позволяет реплицировать старый тип old datatype в последовательность блоков (каждый блок есть кон- катенация old datatype ), где каждый блок может содержать различное число копий и иметь различное смещение. Все смещения блоков кратны длине старого блока oldtype MPI_TYPE_INDEXED(count, array_of_blocklengths, array_of_displacements, oldtype, newtype) IN count число блоков IN array_of_blocklengths число элементов в каждом блоке (массив неотри- цательных целых) IN array_of_displacements смещение для каждого блока (массив целых) IN oldtype старый тип данных (дескриптор) OUT newtype новый тип данных (дескриптор) int MPI_Type_indexed(int count, int *array_of_blocklengths, int *array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype) MPI_TYPE_INDEXED(COUNT, ARRAY_OF_BLOCKLENGTHS, ARRAY_OF_DISPLACEMENTS, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*), ARRAY_OF_DISPLACEMENTS(*), OLDTYPE, NEWTYPE, IERROR MPI::Datatype MPI::Datatype::Create_indexed(int count, const int array_of_blocklengths[], const int array_of_displacements[]) const 87 Функция MPI_TYPE_HINDEXED идентична. MPI_TYPE_HINDEXED (count, array_of_blocklengths, array_of_displacements, oldtype, newtype) IN count число блоков (неотрицательное целое) IN array_of_blocklengths число элементов в каждом блоке (массив неотри- цательных целых) IN array_of_displacements смещение каждого блока в байтах (массив целых) IN oldtype старый тип данных (дескриптор) OUT newtype новый тип данных (дескриптор) int MPI_Type_hindexed(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype) MPI_TYPE_HINDEXED(COUNT, ARRAY_OF_BLOCKLENGTHS, ARRAY_OF_DISPLACEMENTS, OLDTYPE, NEWTYPE, IERROR) INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*), ARRAY_OF_DISPLACEMENTS(*), OLDTYPE, NEWTYPE, IERROR Смещения блоков в массиве array_of_displacements задаются в байтах, а не в кратностях ширины старого типа oldtype MPI_TYPE_STRUCT является общим типом конструктора. Он отличается от предыдущего тем, что позволяет каждому блоку состо- ять из репликаций различного типа. MPI_TYPE_STRUCT (count, array_of_blocklengths, array_of_displacements, array_of_types, newtype) IN count число блоков (целое) IN array_of_blocklength число элементов в каждом блоке (массив целых) IN array_of_displacements смещение каждого блока в байтах (массив целых) IN array_of_types тип элементов в каждом блоке (массив дескрипто- ров объектов типов данных) OUT newtype новый тип данных (дескриптор) int MPI_Type_struct(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements, MPI_Datatype *array_of_types, MPI_Datatype *newtype) MPI_TYPE_STRUCT(COUNT, ARRAY_OF_BLOCKLENGTHS, ARRAY_OF_DISPLACEMENTS, ARRAY_OF_TYPES, NEWTYPE, IERROR) INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*), ARRAY_OF_DISPLACEMENTS(*), ARRAY_OF_TYPES(*), NEWTYPE, IERROR 88 Обращение к MPI_TYPE_HINDEXED (count, B, D, oldtype, new- type) эквивалентно обращению к MPI_TYPE_STRUCT (count, B, D, T, newtype), где каждый вход T равен oldtype. 3.10.2. Адресные функции и функции экстентов Смещения в универсальном типе данных задаются относительно начального буферного адреса. Этот начальный адрес “нуль” отмечает- ся константой MPI_BOTTOM . Поэтому тип данных может описывать абсолютный адрес элементов в коммуникационном буфере, в этом случае аргумент buf получает значение MPI_BOTTOM Адрес ячейки памяти может быть найден путем использования функции MPI_ADDRESS MPI_ADDRESS (location, address) IN location ячейка в памяти (альтернатива) OUT address адрес ячейки (целое) int MPI_Address(void* location, MPI_Aint *address) MPI_ADDRESS(LOCATION, ADDRESS, IERROR) INTEGER ADDRESS, IERROR Функция MPI_ADDRESS возвращает байтовый адрес ячейки. Пример 3.17. Использование MPI_ADDRESS для массива. REAL A(100,100) INTEGER I1, I2, DIFF CALL MPI_ADDRESS(A(1,1), I1, IERROR) CALL MPI_ADDRESS(A(10,10), I2, IERROR) DIFF = I2 – I1 ! значение DIFF есть 909*sizeofreal; значение I1 и I2 зависят от реализации. Функция MPI_TYPE_EXTENT возвращает экстент типа данных. MPI_TYPE_EXTENT(datatype, extent) IN datatype тип данных (дескриптор) OUT extent экстент типа данных (целое) int MPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent) MPI_TYPE_EXTENT(DATATYPE, EXTENT, IERROR) INTEGER DATATYPE, EXTENT, IERROR 89 Функция MPI_TYPE_SIZE возвращает общий размер в байтах элементов в сигнатуре типа, связанной с datatype , то есть общий раз- мер данных в сообщении, которое было бы создано с этим типом дан- ных. Элементы, которые появляются несколько раз в типе данных, подсчитываются с учетом их кратности. MPI_TYPE_SIZE (datatype, size) IN datatype тип данных (дескриптор) OUT size размер типа данных (целое) int MPI_Type_size (MPI_Datatype datatype, int *size) MPI_TYPE_SIZE(DATATYPE, SIZE, IERROR) INTEGER DATATYPE, SIZE, IERROR int MPI::Datatype::Get_size ( ) const 3.10.3. Маркеры нижней и верхней границ Часто удобно явно указать нижнюю и верхнюю границы карты типа. Это позволяет определить тип данных, который имеет «дыры» в начале или конце, или тип с элементами, которые идут выше верхней или ниже нижней границы. Пользователь может явно описать грани- цы типа данных, которые соответствуют этим структурам. Чтобы дос- тичь этого, вводятся два дополнительных «псевдо-типа данных»: MPI_LB и MPI_UB , – которые могут быть использованы соответст- венно для маркировки нижней и верхней границ типа данных. Эти псевдотипы не занимают места ( экстент ( MPI_LB ) = экстент ( MPI_UB ) = 0). Они не меняют size или count типа данных и не влия- ют на содержание сообщения, созданного с этим типом данных. Они влияют на определение экстента типа данных и, следовательно, влия- ют на результат репликации этого типа данных конструктором типа данных. Две функции могут быть использованы для нахождения нижней и верхней границ типа данных. MPI_TYPE_LB( datatype, displacement) IN datatype тип данных (дескриптор) OUT displacement смещение нижней границы от исходной в байтах (целое) int MPI_Type_lb(MPI_Datatype datatype, MPI_Aint* displacement) 90 MPI_TYPE_LB( DATATYPE, DISPLACEMENT, IERROR) INTEGER DATATYPE, DISPLACEMENT, IERROR MPI_TYPE_UB( datatype, displacement) IN datatype тип данных (дескриптор) OUT displacement смещение верхней границы от исходной в байтах (целое) int MPI_Type_ub(MPI_Datatype datatype, MPI_Aint* displacement) MPI_TYPE_UB( DATATYPE, DISPLACEMENT, IERROR) INTEGER DATATYPE, DISPLACEMENT, IERROR |