c++ 使用MPI合并来自多个秩的数组

3phpmpom  于 2022-12-15  发布在  其他
关注(0)|答案(1)|浏览(192)

我的代码要求3个进程生成如下所示的2D向量(在第二列上递增0.05),属于其他进程的行的值为零(未显示):

Proc 1
100,0,1,1,1
100,0.05,4,1,5
100,0.10,10,5,11
100,...,...,...,...
100,0.30,12,11,15

Proc 2
100,0.35,40,35,55
100,0.40,45,39,55
100,...,...,...,...
100,0.65,180,90,215

Proc 3
100,0.70,130,67,145
100,...,...,...,...
100,1.0,1,1,1

我尝试使用MPI_Allreduce生成一个相同大小的2D向量:

100,0,1,1,1
100,0.05,2,2,3
100,0.1,3,2,4
100,0.15,3,2,6
100,0.2,4,2,6
100,0.25,14,10,20
100,0.30,15,11,21
100,0.35,10,6,19
100,0.4,13,9,21
100,0.45,16,12,25
100,0.5,33,17,55
100,0.55,70,33,155
100,0.6,80,30,190
100,0.65,110,45,200
100,0.7,145,134,161
100,0.75,131,127,138
100,0.8,123,120,129
100,0.85,117,114,122
100,0.9,111,111,113
100,0.95,110,108,112
100,1.0,1,1,1

到目前为止,我已经尝试了以下方法:

// Function that calculates the average number of steps, incrementing over arraysize and probability
    // Output vector has 21 rows and columns represent [Arraysize, Probability, Average, Min Value, Max Value]
    std::vector<std::vector<double>> forest_fire_average_steps(int arraySize, int numberOfRuns, int rank, int numProcs)
    {
        int count = 21 / numProcs;
        int start = rank * count;
        int end = start + count;

        // init probability
        double p;

        // Create empty vector to store results
        std::vector<std::vector<double>> stepsResults(21, std::vector<double>(5, 0));

        if (rank == 0) p = 0;
        if (rank == 1) p = 0.35;
        if (rank == 2) p = 0.7;
        
        if (rank < 3)
        {
            // Iterates over a range of probability values, from 0 to 1 in 0.05 increments.
            for (int i = start; i < end; ++i)
            {
                // Adds the array size and probability value to the first two columns of the row.
                stepsResults[i][0] = arraySize;
                stepsResults[i][1] = p;

                // Runs the forest fire model 'numberOfRuns' times with a defined array size and p
                // and stores the results.
                std::vector<double> runSteps;
                for (int j = 0; j < numberOfRuns; ++j)
                {
                    runSteps.push_back(forest_fire(arraySize, p).stepCount);
                }

                // Sums the runSteps vector.
                // Could have used std::reduce which is more efficient but the HPC G++ compiler was out of date.
                int sum = 0;

                for (auto& n : runSteps)
                {
                    sum += n;
                }

                // Calculates and stores the average of the results.
                double averageSteps = sum / runSteps.size();
                stepsResults[i][2] = averageSteps;
                stepsResults[i][3] = *min_element(runSteps.begin(), runSteps.end());
                stepsResults[i][4] = *max_element(runSteps.begin(), runSteps.end());

                // Increments probability.
                p += 0.05;
            }
        }

        std::vector<std::vector<double>> finalResults(21, std::vector<double>(5, 0));
        for (unsigned int i=0;i<21;++i){
            int ierr = MPI_Allreduce(stepsResults[i].data(), finalResults[i].data(), 5, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
        }

        MPI_Finalize();

        if (rank == 3)
        {
            for (int i = 0; i < 21; i++)
            {
                    for (int j = 0; j < finalResults[i].size(); j++)
                    {
                        if (j < 4)
                        {
                            std::cout << finalResults[i][j] << ",";
                        } else
                        {
                            std::cout << finalResults[i][j];
                        }
                        
                    }

                std::cout << std::endl;
            }
        }

        return finalResults;
    }

我不完全确定为什么,但输出看起来像这样,其中它明显跳过了一些行(0.6、0.65等),并添加了额外的零行:

100,0,1,1,1
100,0.05,2,2,3
100,0.1,3,2,4
100,0.15,3,2,6
100,0.2,4,2,6
100,0.35,10,6,19
100,0.4,13,9,21
100,0.45,16,12,25
100,0.5,33,17,55
100,0.55,70,33,155
100,0.7,145,134,161
100,0.75,131,127,138
100,0.8,123,120,129
100,0.85,117,114,122
100,0.9,111,111,113
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0

我的实现是否存在导致此问题的错误?

tcbh2hod

tcbh2hod1#

我很惊讶这个程序没有因为segfault而中止。你的问题在于你把矩阵定义为vector<vector<double>>。MPI需要连续的缓冲区,而向量的向量是一堆小数组,随机分散在内存中。为你的对象写一个类,让它存储一个vector<double>,在其中你用i+j*N左右的索引。

相关问题