MPI 六大基本指令及範例程式研讀

 

提醒大家注意一下,MPI 的指令都是呼叫副程式的方式,因此引數堶悸漲W稱是可以自由命名的,位置則都要對得上。

另外,由於這些副程式也是 Fortran,大小寫是等同不區分的,這埵酗j小寫只是為了讓教材表示得更清楚。

mpif.h 內已經宣告了很多 MPI 專用的變數,因此我們引用的時候完全不必再宣告,如下面例子中的 mpi_data_type = {MPI_INTEGER or MPI_REAL or MPI_DOUBLE_PRECISION};communicator = MPI_COMM_WORLD; status = MPI_STATUS; mpi_op_type = {MPI_SUM or MPI_PRODUCT} 。

 

MPI_Init (ierr)

啟動 MPI,所有 MPI 指令之前要有這個初始化指令,唯一個引數是必須宣告成整數的 ierr,如果初始化成功,則 ierr 的傳回值是零。

 

MPI_Finalize (ierr)

關閉 MPI,結束多個 CPU 協同工作的狀態。正常關閉的話則整數 ierr 的回傳值是零。

 

MPI_Comm_rank (communicator, my_rank, ierr)

獲得此 CPU 在全體多 CPU 中的排行順序,排名的編號會存在整數變數 my_rank 堙]從零開始),每個參與的 CPU 都會分到一個連號但不重覆的數字(像到郵局辦事領號碼牌那樣)。communicator 是在選通訊裝置,一般都是用預設的 MPI_COMM_WORLD 不用自己改(參見範例),至於 ierr 則是和前面一種作為錯誤或正常的旗標。

 

MPI_Comm_size (communicator, nproc, ierr)

獲得全體有多少個 CPU 的數目(通常用於切割工作份量的基礎),整數變數 nproc 回傳給每一個 CPU 同樣的數值,即共有多少個 CPU 正在一起工作。ierr 是錯誤回傳檢查用,communicator 的定義與用法跟前面的定義一樣。

 

MPI_Send (buf, count, datatype, dest, tag, communicator, ierr)

送出(由現在這個 CPU 送出一串資料給另一個 CPU),buf 是指要傳送的那一串資料變數的名稱(也就是第一筆資的位址),count 是資料的長度(從前面定的起點開始算起),datatype 是要被傳送之資料的數值型態,只有幾種常見的固定類型,如 MPI_REAL、MPI_INTEGER 等;整數 dest 是要傳的目的地 CPU 的 rank 編號,至於 整數 tag 則是寫程式的人自已設定的標籤。標籤的功能在這堨i以說明一下,當來源端 CPU 發送資料時,送出來的資料未必會被目的地 CPU 收到相同名稱的變數堙A有可能不止送一包資料,也有可能到達的先後順序會打亂,因此一定要利用標簽來設定每一包資料串有精準被接收到。

MPI_Send 指令是一個阻擋性 (blocking) 的指令,也就是說它要等到收到它在等待的東西才會釋放控制權給主程式去執行下一個指令。

 

MPI_Recv (buf, count, datatype, source, tag, communicator, status, ierr)

接收。其中前三個引數 buf、count、datatype 與前面定義一樣,souce 是來源 CPU 的編號,tag 則是要與送方指令相同的整數值,作為接收的認證。隨後的 communicator 與 ierr 與前面同。值得注意是 status ,它是用來表示接收的狀態。接收與送出有一點點不同,送出是可以立即動作的,然而接收就並不是下了接收指令就可以馬上進行完成,因為總是要等待資料到達。

 

 

其他有用的 MPI 指令

 

MPI_Bcast(buf,n,mpi_datatype,i_src_node,MPI_COMM_WORLD,ierr)

廣播 (Broadcast),意指一個 CPU 放送資料出來,其他 CPU 接收,共同取得該比資料的內容。欲傳送資料的啟始位置是 buf 、長度(資料筆數)是 n i_src_node 是 發送源 之 CPU 編號,其他 mpi_datatype 、MPI_COMM_WORLD、ierr 則是與前面的定義的一樣

 

MPI_Reduce(buf,result,n,mpi_datatype,mpi_op_type,i_trgt_node, MPI_COMM_WORLD,ierr)

收集各個 CPU 上的結果。其中 mpi_op_type 可以是 MPI_SUM MPI_PRODUCT, 而結果則收集到 i_trgt_noderesult 變數上(並不是每個 node 的 result 都更新)。

 

MPI_Get_processor_name (nodename,nchar,ierr)

nodename 是字串變數,它會回傳該 CPU 所在的機器名稱; nchar 是整數,回傳 nodename 內含的字元數

 

閱讀範例程式

 

Examples : 使用 MPI_Comm_rank 來區分 master 與 slave CPU 來做不同工作的例子

init.f.txt init.f

add_seq.f.txt add_seq.f

add_mpi.f.txt add_mpi.f

 

Examples : 使用 MPI_Bcast MPI_Reduce 來計算圓周率的例子

fpi.f.txt fpi.f

 

 

 

如何編譯及執行 MPI Fortran 程式

 

編譯你自已的 MPI 程式的方法

首先必須確定 mpich 目錄在該系統中的位置,例如在 S105 教室是置於 /NFS_home/mhl/mpich-1.2.7 之下,若是使用者自行在自已目錄下建構則參照該目錄,在 MPICH 的主目錄下你應該會看到 $MPI_DIR/bin/mpif77 $MPI_DIR/bin/mpif90,要編譯平行程式時,只需要打該 mpif77 mpif90 的完整路徑,後面再接檔名,有需要指定可執行檔的各稱則用 -o 、 指定搜尋程式庫目錄用 -L 、 指定使用之程式庫用 -l ,與一般編譯 Fortran 的習慣一樣。

註:在 S105 電腦教室的環境,MPICH 的主目錄是在 /NFS_home/mhl/mpich-1.2.7

 

執行一個 MPI 程式

記得編譯出來的可執行檔 a.out ,要用 $MPI_DIR/bin/mpirun -np 4 a.out 這種方式來啟動執行。其中 $MPI_DIR 代表 MPICH 主目錄的完整路徑。

若要指定 (多台各別) 機器,則要加用 -machinefile my_machine_file 參數於 mpirun 命令中,使成為:

$MPI_DIR/bin/mpirun -machinefile my_machine_file -np 4 a.out

其中 my_machine_file 是一個普通的文字檔,內容可以像是:

proton2
proton3
proton4
proton8

或是

proton2:2
proton4:2

後者機器明稱後所加之 :2 代表告知該機器有兩顆 CPU。另外很重要的一點是,上述檔案中之機器名稱必須是打 hostname 指令問系統所會呈現的,不是隨便網路可連線的名稱或 IP 地址就可以。

清單中的機器比 mpirun -np # 所要求的 CPU 數還少時,會輪回到第一台再加丟一個工作單元。

 

練習:

請利用 mpif77 (用法如上所述)將前面範例程式 init.f、add_mpi.f、fpi.f 編譯出可執行檔,並且在兩台不同的機器上執行。(記得設定機器可用 -machinefile my_machine_file 參數)