- OpenMPI 在做訊息 傳遞 時,需要指定
- 傳送的資料是什麼?
- 傳送的數量多少?
- 傳送的資料型別是什麼?
- 傳送給哪個 process?
- OpemMPI 在做訊息 接收 時,需要指定
- 收到的資料放到哪裡?
- 收到的數量 最多 是多少?
- 收到的資料型別是什麼?
- 哪個 process 傳送來的?
- 可以想像以上的指定是很合理的,我們必須要先知道要傳送多少以及傳送給誰,才能預留記憶體並且送到指定的位置。在收資料時也是,要預留記憶體來放接收的資料。
- 另外當然一個 process 可以傳送多筆資料,也可以接收多筆資料,這樣我們怎麼知道每個 process 要把資料放在哪裡? 這時候就需要幫每筆資料貼上標籤 (tag)。當我們在傳送的資料上貼上標籤,在接收端對應的接收位置也貼上一樣的標籤,如此就可以把資料放到指定的位置,不會出錯
圖片來源: SKIRT project
完整程式碼
- github 完整程式碼連結 : https://github.com/grandma-tutorial/OpenMPI-tutorial
OpenMPI 語法介紹
- MPI_Send()
- MPI_Recv()
Blocking Communication
- 在 OpenMPI 裡面有個很重要的觀念是 Blocking Communication,我們使用到的函式 MPI_Send() 和 MPI_Recv() 就是屬於 blocking send 和 blocking receive。當然有blocking 就會有 non-blocking,在 OpenMPI 裡面對應到 MPI_ISend() 和 MPI_IRecv()。
- 在 OpenMPI 的運作機制裡,要傳送一筆資料會先將資料從 Application Buffer 複製一份到 System Buffer,透過網路傳送到對方的 System Buffer 後,再複製一份到 Application Buffer
- blocking send 的意思就是當 application send buffer 可以重複使用時(複製到system send buffer時),才繼續執行後續的程式,否則會停在那邊
- blocking recv 的意思就是當 application recv buffer 接收到資料時,才繼續執行後續的程式,否則會停在那邊
- blocking, non-blocking, sync, async 等等常混淆的觀念及細節會另外寫一篇文章來討論
OpenMP 範例程式 : Hello, world
# === complile 編譯 ===
$ mpic++ ./example_blocking_communication.cpp -o ./example_blocking_communication.out
// ** 檔名 example_blocking_communication.cpp **
// 都會阿嬤 OpenMPI 教學
// 都會阿嬤 https://weikaiwei.com
#include <stdio.h>
#include <mpi.h>
int main(int argc, char *argv[])
{
// Initialize the MPI environment
MPI_Init(NULL, NULL);
// Get the number of processes
int world_size;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
// Get the rank of the process
int process_rank;
MPI_Comm_rank(MPI_COMM_WORLD, &process_rank);
// communication
int data_send = (process_rank + 1) * 100;
int data_recv;
if (process_rank == 0)
{
int target_rank = 1;
//MPI_Send(data, count, datatype, target, tag, communicator)
MPI_Send(&data_send, 1, MPI_INT, target_rank, 123, MPI_COMM_WORLD);
// MPI_Recv(data, count, datatype, source, tag, communicator, status)
MPI_Recv(&data_recv, 1, MPI_INT, target_rank, 123, MPI_COMM_WORLD, MPI_STATUSES_IGNORE);
}
else if (process_rank == 1)
{
int target_rank = 0;
// MPI_Recv(data, count, datatype, source, tag, communicator, status)
MPI_Recv(&data_recv, 1, MPI_INT, target_rank, 123, MPI_COMM_WORLD, MPI_STATUSES_IGNORE);
//MPI_Send(data, count, datatype, target, tag, communicator)
MPI_Send(&data_send, 1, MPI_INT, target_rank, 123, MPI_COMM_WORLD);
}
printf("Rank %d : Send %d, Recv %d\n", process_rank, data_send, data_recv);
// Finalize the MPI environment
MPI_Finalize();
}
# === 執行 execute===
$ mpirun -np 2 ./example_blocking_communication.out
# === 輸出 output===
Rank 0 : Send 100, Recv 200
Rank 1 : Send 200, Recv 100