【解決方法】ジョブ要件の MPI コードを修正する方法がわかりません


タスク: バリアントに従って、ブロッキング操作とノンブロッキング操作を使用してプログラムを作成します。 操作は複数のプロセスで実行されるようにしてください。 初期データの配布は非ブロッキング操作を使用して実行する必要があり、結果の収集はブロッキング操作を使用して実行する必要があります。
b=分(A+C)

更新:
コード内で 1 つのランク チェックを作成しました

#include <mpi.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cfloat>
#include <algorithm>

#define N 13

int main(int argc, char* argv[])
{
    int rank, size;
    double* A = 0, * C = 0, localMin = DBL_MAX;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    int pSize = N / size;      // Number of data points per process
    int remainder = N % size;  // Distribute remaining data points evenly

    // Consider remaining data points
    if (rank < remainder) {
        pSize++;
    }

    std::cout << "Proc" << rank << ":  pSize=" << pSize << std::endl;

    // Master process: distribution of data to processes (asynchronous)
    MPI_Request* requestA = new MPI_Request[size - 1];
    MPI_Request* requestC = new MPI_Request[size - 1];

    if (rank == 0) {
        srand((unsigned)time(0));
        A = new double[N];
        C = new double[N];
        for (int i = 0; i < N; i++) {
            A[i] = (rand() % 20) / 2.;
            C[i] = (rand() % 20) / 2.;
            std::cout << i << ". sum:" << A[i] + C[i] << std::endl;
        }

        int offset = pSize;
        for (int i = 1; i < size; i++) {
            int send_count = (remainder == 0 || i < remainder) ? pSize : pSize - 1;
            MPI_Isend(A + offset, send_count, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &requestA[i - 1]);
            MPI_Isend(C + offset, send_count, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, &requestC[i - 1]);
            offset += send_count;
        }

        MPI_Waitall(size - 1, requestA, MPI_STATUSES_IGNORE);
        MPI_Waitall(size - 1, requestC, MPI_STATUSES_IGNORE);

        double globalMin = localMin;

        for (int i = 0; i < pSize; i++) {
            double temp = A[i] + C[i];
            globalMin = std::min(globalMin, temp);
        }

        for (int i = 1; i < size; i++) {
            double receivedMin;
            // Collect data from other processes (blocking)
            MPI_Recv(&receivedMin, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            globalMin = std::min(globalMin, receivedMin);
        }
        std::cout << "Minimum min(A+C) = " << globalMin << std::endl;
    }
    else {
        // Blocking receive from A and C
        A = new double[pSize];
        C = new double[pSize];
        MPI_Recv(A, pSize, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        MPI_Recv(C, pSize, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);

        for (int i = 0; i < pSize; i++) {
            double temp = A[i] + C[i];
            localMin = std::min(localMin, temp);
        }

        // Send local result of the process to master
        MPI_Send(&localMin, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
    }

    delete[] A;
    delete[] C;
    delete[] requestA;
    delete[] requestC;
    MPI_Finalize();
}

私が試したこと:

あらゆることを試しましたが、何が問題なのか分かりません。

解決策 1

さて、この「質問」には、取り組むべきものがまったくないため、答えることができません。 「まだ何らかの形で壊れている」ということは(IT が何であれ)誰でも扱えるものではありません。

解決策 3

あなたは提案のごく一部を実装しようとしましたが、残念ながら完全にも正確にも実装できませんでした。

たとえば、ランク 0 のプロセスは通常、タスクの分散を担当します。
次のように、N 個のデータをサイズプロセスに分散しようとしています。

C++
if (!rank)
    {
    ...
    if (rank < remainder) {
       pSize++;
    }

それはすでに、if(!rank) を書くのは不健全であるという事実から始まります。 ここでもおそらくまたうまくいかないでしょう。 N=20、size=8の場合、pSizeはどのような値になり、どのくらいのデータが分散されるのでしょうか?

プロセスごとの pSize を計算することを提案しました…

次に、ランク 0 のプロセスも他のすべてのプロセスと同時にタスクを完了する必要がありますが、あなたの場合、最初にすべてのプロセスを待ってから初めてプロセス 0 が動作し始めます。これは単純に悪いです。

C++
MPI_Waitall(3, request, MPI_STATUSES_IGNORE);
    
for (int i = (size - 1) * pSize; i < N; i++) {
   double temp = A[i] + C[i];
   localMin = min(localMin, temp);
}

ここで提案したのですが

https://www.codeproject.com/Answers/5370748/I-dont- Understand-how-to-fix-the-MPI-code-for-the#answer2

コードの冗長性を回避し、すべてを並列に保ち、待機の必要性を完全に回避する (通常の) MPI フロー。 このルートを利用すると良いでしょう。

したがって、私は私の提案を再度言及するだけです。 あなたのプログラムには非常に多くの癖があるため、教師が満足できないことは明らかです。

// 編集:
設計にはさまざまな問題があります。 ここではさらに助けが必要と思われるため、少し長めの草案を提供します。 コピー&ペーストの解決策にならないように、一部の詳細は意図的に省略しています。 この設計では、考えられる残りを最初のプロセスに分配し、プロセス 0 を計算させ、送信を非同期に実行して受信をブロックします。 また、Ubuntu で mpic++ を使用して次のフレームワークをテストしました。

C++
#define N 13

int main(int argc, char* argv[])
{
    int rank, size;
    double *A, *C;
    double localMin = DBL_MAX;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    srand((unsigned)time(0));

    // Master process: Initialization of the data
    if (rank == 0) {
        A = new double[N];
        C = new double[N];

        for (int i = 0; i < N; i++) {
            A[i] = (rand() % 20) / 2.;
            C[i] = (rand() % 20) / 2.;
            cout << i << ". sum:" << A[i] + C[i] << endl;
        }
    }

    int pSize = N / size;      // Number of data points per process
    int remainder = N % size;  // Distribute remaining data points evenly

    // Consider remaining data points
    if (rank < remainder) {
        pSize++;
    }

   cout << "Proc" << rank << ":  pSize=" << pSize << endl;

   // Master process: distribution of data to processes (asynchronous)
   // Note: Alternatively, you could also use scatter
   MPI_Request requestA[size - 1], requestC[size - 1];
   if (rank == 0) {
        int offset = pSize;
        for (int i = 1; i < size; i++) {
            int send_count = (remainder == 0 || i < remainder) ? pSize : pSize - 1;
            MPI_Isend(A + offset, ...);
            MPI_Isend(C + offset, ...);
            offset += send_count;
        }
    }
    else {
        // Blocking receive from A and C
        A = new double[pSize];
        C = new double[pSize];
        MPI_Recv(A, pSize, ...);
        MPI_Recv(C, pSize, ...);
    }

    for (int i = 0; i < pSize; i++) {
        double temp = A[i] + C[i];
        localMin = min(localMin, temp);
    }

    // Collecting the local minima (blocking)

    // 1. with MPI_Reduce (optimized solution was not wanted
    
    // 2. with blocking MPI_Send and MPI_Recv instead of MPI_Reduce
    if (rank == 0) {
        // Wait for completion of the MPI_Isend processes (optional here)
        MPI_Waitall(size - 1, requestA, MPI_STATUSES_IGNORE);
        MPI_Waitall(size - 1, requestC, MPI_STATUSES_IGNORE);

        double globalMin = localMin;
        for (int i = 1; i < size; i++) {
            double receivedMin;
            // Collect data from other processes (blocking)
            MPI_Recv(&receivedMin, ...);
            globalMin = min(globalMin, receivedMin);
        }
        cout << "Minimum min(A+C) = " << globalMin << endl;
    }
    else {
       // Send local result of the process to master
       MPI_Send(&localMin, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
    }

    delete[] A;
    delete[] C;
    MPI_Finalize();
}

N=13 および 5 プロセスの場合、出力が得られます

Proc2:  pSize=3
0. sum:4
1. sum:9
2. sum:15.5
3. sum:13
4. sum:2.5
5. sum:8
6. sum:5
7. sum:13
Proc1:  pSize=3
8. sum:12.5
9. sum:10
10. sum:10.5
11. sum:2.5
12. sum:17.5
Proc0:  pSize=3
Proc4:  pSize=2
Proc3:  pSize=2
Minimum min(A+C) = 2.5

解決策 2

教師がコード内の正確な問題を指定していない場合は、コードを見直して、考えられるエラーや改善点がないかどうかを確認すると役立つ場合があります。 リンクを参照して内容を確認し、課題を完了することができます。
ブロッキング アルゴリズムとノンブロッキング アルゴリズム – MC++ ブログ[^]

コメント

タイトルとURLをコピーしました