本当は怖い情報科学

とあるHPC屋の趣味&実益ブログ

MPI Communicatorのattributesを利用して、MPI_Finalize()時にコールバック関数を起動する

MPIのややマニアックな機能の1つに、attriburtesがあります。これは、コミュニケータに、整数をキーとした辞書のようなデータ構造で値(属性)を登録できるというものです。関係する関数としては、 MPI_Comm_create_keyvalMPI_Comm_set_attrなどがあります。

一方、定義済みコミュニケーターの1つに、 MPI_COMM_SELF というものがあります。これは、そのプロセス自分自身のみが属する大きさ1の特殊なコミュニケータです。このコミュニケーターは、普通はあまり役に立たないのですが、MPIの終了時に最初に破壊されることが保証されているという特殊な性質を持っており、これを利用して MPI_Finalize() 時のコールバック関数を登録することができます。

MPI 3.1仕様書の当該箇所を引用します。

8.7.1 Allowing User Functions at Process Termination

There are times in which it would be convenient to have actions happen when an MPI process finishes. This can be accomplished in MPI by attaching an attribute to MPI_COMM_SELF with a callback function. When MPI_FINALIZE is called, it will first execute the equivalent of an MPI_COMM_FREE on MPI_COMM_SELF. This will cause the delete callback function to be executed on all keys associated with MPI_COMM_SELF

日本語訳

8.71. プロセス終了時に関数を呼び出す

MPIプロセスの終了時に動作を起こすことができると便利な場合があります。(中略)これは、MPI_COMM_SELF にコールバック付きのattributeを設定することで、MPIに実行させることができます。MPI_FINALIZE が呼ばれるとき、最初に MPI_COMM_FREE 相当の処理を MPI_COMM_SELF に対して行います。これにより、attributesの削除コールバックが起動されます。(以下略)

というわけで、この仕組を使うと、MPIの終了時にフックした関数を実行できます。以下は、具体的なコード例です。

#include <stdio.h>
#include <mpi.h>

// MPI_Comm_delete_attr_function
int my_comm_attr_delete_fun(MPI_Comm comm, int keyval, void* attr_val, void* extra_state) {
    fprintf(stderr, "my_comm_attr_delete_fun is called()\n");
    MPI_Comm *newcomm = (MPI_Comm*) attr_val;
    MPI_Comm_free(newcomm);
    return MPI_SUCCESS;
}

int main(int argc, char **argv) {
    MPI_Init(&argc, &argv);

    /* 独自のCommunicatorを作成。サンプルとして、終了時にこのCommunicatorを削除してみる */
    MPI_Comm newcomm;
    MPI_Comm_dup(MPI_COMM_WORLD, &newcomm);

    /* 新しく作る属性のKey */
    int keyval;

    /* 属性を作成 */
    MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, my_comm_attr_delete_fun, &keyval, NULL);

    /* COMM_SELFに属性を設定 */
    MPI_Comm_set_attr(MPI_COMM_SELF, keyval, &newcomm);

    /* 通常通り MPI_Finalize() を呼ぶ */
    MPI_Finalize();

    return 0;
}
# 実行例
$ mpicc test.c
$ mpiexec -n 2 ./a.out
my_comm_attr_delete_fun is called()
my_comm_attr_delete_fun is called()

コールバックが実行されていることがわかります。

【広告】