C++でOpenMPI入門5 構造体のブロードキャスト2

前回, 構造体のブロードキャストをバイト数を用いて行った. この場合, ようするに構造体でもなんでもMPI_BYTEとして送ってしまおうという考え方だが, 他のプリミティブな型と同様に自分の作成した構造体も扱えるようになると便利である.

従って次に構造体を独自の型として登録する方法を試す.

#include <iostream>
#include <mpi.h>

struct parameter
{
    int seed;
    double temperature;
};

int main(int argc, char **argv)
{
    MPI::Init(argc, argv);

    int rank = MPI::COMM_WORLD.Get_rank();
    parameter param;
    if (rank == 0)
    {
        std::cout << "Input a seed : ";
        std::cin >> param.seed;
        std::cout << "Input a temperature : ";
        std::cin >> param.temperature;
    }

    int blocklengths[2] = {1, 1};
    MPI::Aint base = MPI::Get_address(&param);
    MPI::Aint displacements[2];
    displacements[0] = MPI::Get_address(&param.seed) - base;
    displacements[1] = MPI::Get_address(&param.temperature) - base;
    MPI::Datatype types[2] = {MPI::INT, MPI::DOUBLE};

    MPI::Datatype MPI_PARAMETER = MPI::Datatype::Create_struct(
        2, blocklengths, displacements, types);
    MPI_PARAMETER.Commit();

    MPI::COMM_WORLD.Bcast(&param, 1, MPI_PARAMETER, 0);
    std::cout << "rank = " << rank
              << " : seed = " << param.seed
              << " : temperature = " << param.temperature << std::endl;

    MPI::Finalize();

    return 0;
}

基本は前回と同じだが, Bcastで型として指定しているのがMPI::BYTEではなく, MPI_PARAMETERとなっている. この型(MPI::Datatype)はその上のCreate_structで作成され, Commitで登録されている.

Create_structは引数を4つ受け取る.

まず, 構造体に含まれる要素の数(配列もまとめて1つと数える). 次に要素のサイズ(blocklengths), ようするに配列を要素として含む場合, その長さ. 単一の要素なら1で良い. 次のdisplacementsは相対的なアドレスを示す(後述). 最後に各要素の型. 基本的にはプリミティブな型を指定するが, どうやら今試しているようにして作成された独自の型を用いてもよいらしい(試していない).

わかりにくかったのがdisplacementsだが, 要するに構造体の先頭アドレスを0とした場合の構造体内の各要素の相対的なアドレスということらしい. 従って, ここではとりあえず実際に送信する構造体のアドレスを参照して, これを計算している. MPI::Get_addressは単にメモリの絶対アドレスを返す. 先頭(base)は構造体そのもののアドレスだから, これを引けば良い.

前回と比較すると, Bcastの際の要素の数を示す引数がsizeof(param)から1になっているのがわかる. MPI_PARAMETER型の変数を1個ブロードキャストすると, 正しく解釈できる.

よく考えるとわかるが, この型の登録は各プロセスにおいて同期の前に行われる. つまり, ランク0プロセス以外ではparamは入力を受けていない状態でこの型の登録を行っている. 今回の場合, 値を更新していなくても相対アドレス(displacements)は同じなのでこれで良いが, 構造体が可変長などの要素を含んでいる場合, Bcastの前に相対アドレスの情報(可変長要素の長さ)を送受信しておかないと型を登録できない.

http://labo.nshimizu.com/documents/mpiprimj.pdf
http://mikilab.doshisha.ac.jp/dia/research/person/hisashi/research/010615.html
http://mpi.deino.net/mpi_functions/MPI_Type_create_struct.html