2

私は過去 2 年間、インターネットから C++ を学んできましたが、ついに MPI を掘り下げる必要が生じました。私はstackoverflowとインターネットの残りの部分を精査してきました(http://people.sc.fsu.edu/~jburkardt/cpp_src/mpi/mpi.htmlhttps://computing.llnl.gov/tutorials/mpiを含む) /#LLNL )。ロジックの一部がダウンしていると思いますが、次のことを理解するのに苦労しています。

#include (stuff)
using namespace std;

vector<double> function(vector<double> &foo, const vector<double> &bar, int dim, int rows);

int main(int argc, char** argv)
{
    vector<double> result;//represents a regular 1D vector
    int id_proc, tot_proc, root_proc = 0;
    int dim;//set to number of "columns" in A and B below
    int rows;//set to number of "rows" of A and B below
    vector<double> A(dim*rows), B(dim*rows);//represent matrices as 1D vectors

    MPI::Init(argc,argv);
    id_proc = MPI::COMM_WORLD.Get_rank();
    tot_proc = MPI::COMM_WORLD.Get_size();

    /*
    initialize A and B here on root_proc with RNG and Bcast to everyone else
    */

    //allow all processors to call function() so they can each work on a portion of A
    result = function(A,B,dim,rows);

    //all processors do stuff with A
    //root_proc does stuff with result (doesn't matter if other processors have updated result)

    MPI::Finalize();
    return 0;
}

vector<double> function(vector<double> &foo, const vector<double> &bar, int dim, int rows)
{
    /*
    purpose of function() is two-fold:
    1. update foo because all processors need the updated "matrix"
    2. get the average of the "rows" of foo and return that to main (only root processor needs this)
    */

    vector<double> output(dim,0);

    //add matrices the way I would normally do it in serial
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < dim; j++)
        {
            foo[i*dim + j] += bar[i*dim + j];//perform "matrix" addition (+= ON PURPOSE)
        }
    }

    //obtain average of rows in foo in serial
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < dim; j++)
        {
            output[j] += foo[i*dim + j];//sum rows of A
        }
    }

    for (int j = 0; j < dim; j++)
    {
            output[j] /= rows;//divide to obtain average
    }

    return output;        
}

上記のコードは、概念のみを説明するためのものです。私の主な関心事は行列の追加を並列化することですが、私の心を揺さぶるのはこれです:

1)各プロセッサがそのループの一部でのみ動作する場合(当然、プロセッサごとにループパラメータを変更する必要があります)、Aのすべての部分を単一の更新されたAにマージして、すべてのプロセッサが持っているコマンドは何ですか彼らの記憶。私の推測では、各プロセッサが A の一部を他のすべてのプロセッサに送信する、ある種の Alltoall を実行する必要があると思いますが、(たとえば) プロセッサ 3 によって処理された行 3 が他のプロセッサの行 3 を上書きすることをどのように保証しますか?偶然に行1ではありません。

2)関数()内でAlltoallを使用する場合、すべてのプロセッサが関数()にステップインできるようにする必要がありますか、それとも関数()を使用して分離できますか...

if (id_proc == root_proc)
{
    result = function(A,B,dim,rows);
}

…そして function() 内ですべての並列化を処理します。ばかげているように聞こえるかもしれませんが、私は 1 つのプロセッサ (ブロードキャストを使用) で多くの作業を行い、時間のかかる for ループを並列化しようとしています。コードを概念的にシンプルに保とうとしているだけなので、結果を取得して先に進むことができます。

3) 平均化の部分については、並列化したい場合は縮小コマンドを使用するだけでよいと思いますよね?

また、余談ですが、ブロックするように Bcast() を呼び出す方法はありますか? すべてのプロセッサを同期するために使用したいと思います (ブースト ライブラリはオプションではありません)。そうでない場合は、Barrier() を使用します。この質問への回答と、過去 2 年間のプログラミング方法を教えてくれた stackoverflow のコミュニティに感謝します。:)

4

1 に答える 1