2012-11-03 73 views
1

當我嘗試發送MPI派生數據類型與「大」數組(每個100 000浮點數2陣列),我的程序段錯誤。它通常與較小的陣列運行。MPI發送錯誤與派生數據類型(Fortran)

下面是一個小的可重複的例子。 這個小程序段錯誤與以下MPI執行:IntelMPI,BullXMPI。 它的工作原理與OpenMPIPlatformMPI。 這裏是一個帶回溯示例的日誌:http://pastebin.com/FMBpCuj2

更改mpi_sendmpi_ssend沒有幫助。然而,mpi_send與一個單一的更大的陣列2 * 100 000浮動工作正常。在我看來,這指出了派生數據類型的一個問題。

program struct 
include 'mpif.h' 

type Data 
    integer :: id 
    real, allocatable :: ratio(:) 
    real, allocatable :: winds(:) 
end type 

type (Data) :: test 
integer :: datatype, oldtypes(3), blockcounts(3) 
integer :: offsets(3) 
integer :: numtasks, rank, i, ierr 
integer :: n, status(mpi_status_size) 

call mpi_init(ierr) 
call mpi_comm_rank(mpi_comm_world, rank, ierr) 
call mpi_comm_size(mpi_comm_world, numtasks, ierr) 

if (numtasks /= 2) then 
    write (*,*) "Needs 2 procs" 
    call exit(1) 
endif 

n = 100000 
allocate(test%ratio(n)) 
allocate(test%winds(n)) 
if (rank == 0) then 
    test%ratio = 6 
    test%winds = 7 
    test%id = 2 
else 
    test%id = 0 
    test%ratio = 0 
    test%winds = 0 
endif 

call mpi_get_address(test%id, offsets(1), ierr) 
call mpi_get_address(test%ratio, offsets(2), ierr) 
call mpi_get_address(test%winds, offsets(3), ierr) 

do i = 2, size(offsets) 
    offsets(i) = offsets(i) - offsets(1) 
end do 
offsets(1) = 0 

oldtypes = (/mpi_integer, mpi_real, mpi_real/) 
blockcounts = (/1, n, n/) 

call mpi_type_struct(3, blockcounts, offsets, oldtypes, datatype, ierr) 
call mpi_type_commit(datatype, ierr) 

if (rank == 0) then 
    !call mpi_ssend(test, 1, datatype, 1, 0, mpi_comm_world, ierr) 
    call mpi_send(test, 1, datatype, 1, 0, mpi_comm_world, ierr) 
else 
    call mpi_recv(test, 1, datatype, 0, 0, mpi_comm_world, status, ierr) 
end if 

print *, 'rank= ',rank 
print *, 'data= ',test%ratio(1:5),test%winds(1:5) 

deallocate (test%ratio) 
deallocate (test%winds) 
call mpi_finalize(ierr) 


end 

注:不同MPI implentations之間的比較是不客觀的測試是不是所有在同一臺計算機(其中有些是超級計算機)上。不過,我認爲這不應該有所作爲。

編輯:該代碼適用於靜態數組。這是Fortran 90.

+0

我不知道很多的Fortran,但我不認爲MPI工作與自定義數據類型'allocatable'。您可以嘗試從該結構的其餘部分分開轉移該組件。有人糾正我,如果我錯了。 –

+0

沒有更多的段錯誤與靜態數組!我用不同的編譯器(gfortran,pgf90,ifortran)測試了代碼,沒有任何抱怨。直到我開始增加尺寸時纔有問題。 –

回答

6

我可以建議你使用調試器嗎?我只是在Allinea DDT上試過你的例子,並在兩分鐘內看到了問題。你需要使用一個調試器 - 你的代碼看起來是正確的,所以現在是時候觀察它在實踐中的表現了。

我點擊打開內存調試(強制顯示一些隱藏錯誤的一種方式),然後您的示例每次都隨OpenMPI崩潰。碰撞發生在發送者身上。

因此,我開始逐步使用DDT - 打開DDT的內存調試。

首先,調用MPI_Get_address - 填充偏移量數組。看看這些偏移!整數的地址是正數,可分配的數組偏移量是負數:一個不好的符號。地址已經溢出。

所分配的數據的地址將在所述靜態分配整數一個非常不同的區域的存儲器。如果您使用32位算術操作64位指針(MPI_Get_address會對此進行警告),則所有注單都將關閉。對於靜態數組,它不會崩潰,因爲它們的地址足夠接近整數的地址而不會溢出。

你這個不正確的偏移量數組發送到MPI_SEND,它讀取它不應該(看偏移緩衝器再次說服自己),其中,因此段錯誤的數據。這裏

真正的解決辦法是 -

  1. 隨着MPI_Get_address - 使用INTEGER(KIND = MPI_ADDRESS_KIND)的偏移的聲明 - 確保64位代碼獲取64位整數。

  2. MPI_type_struct應該被替換爲MPI_type_create_struct - 前者不推薦使用,並且不以MPI_ADDRESS_KIND整數形式取得偏移量,只有4個字節的整數 - 因此存在缺陷。

通過這些更改,您的代碼將運行。

祝你好運!

+0

感謝您提供非常詳細的答案。我確實用DDT運行代碼,但沒有激活內存調試...經驗教訓! –