2016-09-29 3 views
1

Существует динамически выделяется структура:MPI производного типа данные для динамически выделенных структур с динамически выделяемым членом

TYPE Struct  
    INTEGER :: N 
    REAL*8 :: A 
    REAL*8,ALLOCATABLE :: B(:) 
END TYPE Struct 

и имеет динамически выделенный memeber: B (:)

При попытке использовать MPI_TYPE_CREATE_STRUCT для создания производного типа данных для такого Struct, бывает, что разные CPU создают непоследовательные производные типы данных. Это связано с тем, что Struct% B (:) может находиться в разных ячейках памяти относительно первого члена Struct% N на разных ЦП.

Тогда MPI_SEND (STRUCT, ...) не получится ...

Итак, как может такая проблема быть решена, если я действительно хочу, чтобы отправить эту структуру с помощью MPI производного типа данных?

Или такой тип производного типа запрещен?

+0

Очень странно, как вы написали весь этот вопрос, и нигде вы не указали Fortran, язык, который вы используете. Хорошо, я пометил это для вас. –

+0

Вы видели http://stackoverflow.com/questions/2258759/passing-variable-length-structures-between-mpi-processes и http://stackoverflow.com/questions/4273253/variable-sized-message-in- mpi? –

+0

Извините за флаг ... Я видел эти ссылки всего лишь минуту назад, они не решают проблему, с которой я столкнулся, что я имею в виду: использовать REAL * 8 :: B (2) вместо allocatable один в порядке и без проблем! Проблема показывает, когда я использую REAL * 8, ALLOCATABLE :: B (:) @JohnZwinck –

ответ

3

Чтобы отправить один элемент этой структуры, просто proceed as usual путем создания структурированного типа данных с использованием MPI_TYPE_CREATE_STRUCT. В зависимости от того, как куча и стек программы расположены друг относительно друга, смещение B(1) относительно N может стать огромным положительным или отрицательным числом, но это не проблема на большинстве платформ Unix, а число должен соответствовать диапазону INTEGER(KIND=MPI_ADDRESS_KIND).

Важно: Отдельные экземпляры структуры будут скорее всего имеют разные смещения B относительно N, поэтому тип данных MPI может быть использован только для отправки конкретной записи, которая была использована для получения зачетов во время строительства тип данных.

Когда я пытаюсь использовать MPI_TYPE_CREATE_STRUCT создать производный тип данных для такого Struct, случается, что диффере процессоры создают несовместимые производные типы данных. Это связано с тем, что Struct% B (:) может находиться в разных ячейках памяти относительно первого элемента Struct% N на разных ЦП.

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

Чтобы отправить несколько элементов, все становится немного сложнее. Существует два решения:

Используйте MPI_PACK для сериализации данных со стороны отправителя и MPI_UNPACK для десериализации его на стороне приемника. Поскольку для упаковки и распаковки требуется дополнительное пространство для буфера, это удваивает требования к памяти программы.

или

Создайте отдельную структуру MPI тип данных для каждой записи, а затем создать структуру типа данных, который сочетает в себе все записи.Вот пример того, как отправить массив из двух таких структур, один с 10 элементов в B и один с 20:

TYPE(Struct) :: Structs(2) 

ALLOCATE(Structs(1)%B(10)) 
ALLOCATE(Structs(2)%B(20)) 

! (1) Create a separate structure datatype for each record 
DO i=1,2 
    CALL MPI_GET_ADDRESS(Structs(i)%N, POS_(1), IError) 
    CALL MPI_GET_ADDRESS(Structs(i)%A, POS_(2), IError) 
    CALL MPI_GET_ADDRESS(Structs(i)%B(1), POS_(3), IError) 
    Offsets = POS_ - POS_(1) 

    Types(1) = MPI_INTEGER 
    Types(2) = MPI_REAL8 
    Types(3) = MPI_REAL8 

    Blocks(1) = 1 
    Blocks(2) = 1 
    Blocks(3) = i * 10 

    CALL MPI_TYPE_CREATE_STRUCT(3, Blocks, Offsets, Types, Elem_Type(i), IError) 
END DO 

! (2) Create a structure of structures that describes the whole array 
CALL MPI_GET_ADDRESS(Structs(1)%N, POS_(1), IError) 
CALL MPI_GET_ADDRESS(Structs(2)%N, POS_(2), IError) 
Offsets = POS_ - POS_(1) 

Types(1) = Elem_Type(1) 
Types(2) = Elem_Type(2) 

Blocks(1) = 1 
Blocks(2) = 1 

CALL MPI_TYPE_CREATE_STRUCT(2, Blocks, Offsets, Types, TwoElem_Type, IError) 
CALL MPI_TYPE_COMMIT(TwoElem_Type, IError) 

! (2.1) Free the intermediate datatypes 
DO i=1,2 
    CALL MPI_TYPE_FREE(Elem_Type(i), IError) 
END DO 

! (3) Send the array 
CALL MPI_SEND(Structs(1)%N, 1, TwoElem_Type, ...) 

Обратите внимание, что хотя строительство MPI типов данных является относительно дешевой операцией, вы не должны использовать описанную выше процедуру для отправки, например, 1000000 экземпляров структурированного типа. Кроме того, дескрипторы типа MPI живут в памяти, управляемой библиотекой, и важно своевременное освобождение типов данных, которые больше не нужны.

+0

Я понял! Я действительно многому научился от этого! ~^_^~ –

+0

Что делать, если количество структур в массиве сильно варьируется? Каждый раз нам нужно было бы определить новый тип данных, такой как «TwoElem_Type», «MillionElem_Type» и т. Д. – Shibli

+0

Да, к сожалению, MPI был разработан для работы в основном с «линейными» типами, т.е. типами, которые последовательно хранятся в памяти после некоторых повторяющихся шаблон. Типы ветвления, где данные хранятся по всей памяти и передаются через указатели, напрямую не поддерживаются, и каждый должен взломать их. Тем не менее, для очень больших объектов данных построение типа данных намного дешевле, чем отправка данных по сети, поэтому это не должно быть большой проблемой. –

Смежные вопросы