【平行運算】OpenMPI教學(二) Blocking Communication

  • OpenMPI 在做訊息 傳遞 時,需要指定
    1. 傳送的資料是什麼?
    2. 傳送的數量多少?
    3. 傳送的資料型別是什麼?
    4. 傳送給哪個 process?
  • OpemMPI 在做訊息 接收 時,需要指定
    1. 收到的資料放到哪裡?
    2. 收到的數量 最多 是多少?
    3. 收到的資料型別是什麼?
    4. 哪個 process 傳送來的?
  • 可以想像以上的指定是很合理的,我們必須要先知道要傳送多少以及傳送給誰,才能預留記憶體並且送到指定的位置。在收資料時也是,要預留記憶體來放接收的資料。
  • 另外當然一個 process 可以傳送多筆資料,也可以接收多筆資料,這樣我們怎麼知道每個 process 要把資料放在哪裡? 這時候就需要幫每筆資料貼上標籤 (tag)。當我們在傳送的資料上貼上標籤,在接收端對應的接收位置也貼上一樣的標籤,如此就可以把資料放到指定的位置,不會出錯

圖片來源: SKIRT project

完整程式碼

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

延伸閱讀

  1. https://skirt.ugent.be/skirt9/_parallel_messaging.html
  2. https://mpitutorial.com/

留言討論區