2016-09-29 47 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會創建不一致的派生數據類型。 這是因爲在不同的CPU上,Struct%B(:)可能位於相對於第一個構件StructN的不同內存位置。

然後MPI_SEND(結構,...)是不會得逞的......

那麼,怎麼會這樣的問題可以解決,如果我真的想用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

通過創建使用MPI_TYPE_CREATE_STRUCT的結構化數據類型發送結構的一個元件,簡單地proceed as usual。根據程序堆和程序堆相互之間的位置關係,B(1)相對於N的偏移量最終可能是一個巨大的正數或負數,但這在大多數Unix平臺上都沒有問題,數字應該在INTEGER(KIND=MPI_ADDRESS_KIND)的範圍內。

重要:結構的不同實例將最有可能B相對的不同偏移N,因此只能用於發送這是用於在施工過程中獲得的偏移量的特定記錄的MPI數據類型數據類型。

當我嘗試使用MPI_TYPE_CREATE_STRUCT爲這樣的Struct創建派生數據類型時,碰巧不同的CPU會創建不一致的派生數據類型。這是因爲在不同的CPU上,Struct%B(:)可能位於與第一個元素Struct%N不同的內存位置。

這是一個非問題。通信操作兩邊的MPI數據類型只能是一致的,這意味着它們應該由相同序列中相同的基本數據類型組成。 每個元素的偏移量是無關緊要的。換句話說,只要發送方和接收方在調用MPI_TYPE_CREATE_STRUCT時指定了相同類型和數量的數據元素,程序就會正常工作。

要發送多個元素,事情會變得有點複雜。有兩種解決方案:

使用MPI_PACK來串行化發送端數據和MPI_UNPACK以在接收端對其進行反序列化。由於打包和解包需要額外的緩衝空間,這使得程序的內存需求增加了一倍。

創建爲每個記錄單獨的MPI結構數據類型,然後創建一個結合了所有記錄的數據類型結構。下面是如何發送兩個這樣的結構的陣列,一個在B 10元和一個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被設計爲主要用於「線性」類型,也就是說,類型被按順序存儲在內存中,模式。數據存儲在內存中並通過指針引用的分支類型不直接受支持,而且必須破解它們。儘管如此,對於非常大的數據對象,構建數據類型比通過網絡發送數據要便宜得多,所以它不應該是一個大問題。 –