使用 Scatter 和 Gather 的 MPI 矩阵乘法

MPI Matrix Multiplication Using Scatter and Gather

我正在尝试使用 MPI Scatter()Gather() 函数计算矩阵乘法,我希望能够选择矩阵大小而不必更改所用进程的数量。

我浏览了 MPI Matrix Multiplication with scatter gather and 的帖子,但他们都使用了在定义更大的矩阵大小时不起作用的方法,但只有当矩阵大小与 [=36] 相同时=]尺寸。

我的示例矩阵大小为 8 的代码:

#define MAT_SIZE 8

void initialiseMatricies(float a[][MAT_SIZE], float b[][MAT_SIZE], float c[][MAT_SIZE])
{
    int num = 11;
    for (int i = 0; i < MAT_SIZE; i++)
    {
        for (int j = 0; j < MAT_SIZE; j++)
        {
            a[i][j] = num;
            b[i][j] = num+1;
            c[i][j] = 0;
        }
        num++;
    }
}

int main(int argc, char **argv)
{   
    // MPI Variables
    int rank, size;

    // Create the main matrices with the predefined size
    float matrixA[MAT_SIZE][MAT_SIZE];
    float matrixB[MAT_SIZE][MAT_SIZE];
    float matrixC[MAT_SIZE][MAT_SIZE];

    // Create the separate arrays for storing the scattered rows from the main matrices
    float matrixARows[MAT_SIZE];
    float matrixCRows[MAT_SIZE];

    // Initialise the matrices
    initialiseMatricies(matrixA, matrixB, matrixC);

    // Start the MPI parallel sequence
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    int count = MAT_SIZE * MAT_SIZE / (size * (MAT_SIZE / size));

    // Scatter rows of first matrix to different processes
    MPI_Scatter(matrixA, count, MPI_INT, matrixARows, count, MPI_INT, 0, MPI_COMM_WORLD);

    // Broadcast second matrix to all processes
    MPI_Bcast(matrixB, MAT_SIZE * MAT_SIZE, MPI_INT, 0, MPI_COMM_WORLD);

    MPI_Barrier(MPI_COMM_WORLD);

    // Matrix Multiplication
    int sum = 0;
    for (int i = 0; i < MAT_SIZE; i++)
    {
        for (int j = 0; j < MAT_SIZE; j++)
        {
            sum += matARows[j] * matB[j][i];
        }
        matCRows[i] = sum;
    }

    // Gather the row sums from the buffer and put it in matrix C
    MPI_Gather(matrixCRows, count, MPI_INT, matrixC, count, MPI_INT, 0, MPI_COMM_WORLD);

    MPI_Barrier(MPI_COMM_WORLD);

    MPI_Finalize();

    // if it's on the master node
    if (rank == 0)
        printResults(matrixA, matrixB, matrixC, calcTime);

    return 0;
}

输出:

1364 2728 4092 5456 6820 8184 9548 10912 
1488 2976 4464 5952 7440 8928 10416 11904 
1612 3224 4836 6448 8060 9672 11284 12896 
1736 3472 5208 6944 8680 10416 12152 13888 
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 0 0 

输出是正确的,如果我将进程数设置为 8(与矩阵大小相同),则可以正确计算整个矩阵,但我不想这样做。我相信我的问题源于 Scatter()Gather() 中的计数。如果我将计数设置为:

int count = MAT_SIZE * MAT_SIZE / size;

则输出变为:

1364 2728 4092 5456 6820 8184 9548 10912 
-1.07374e+08 -1.07374e+08 11 11 11 11 11 11 
1612 3224 4836 6448 8060 9672 11284 12896 
-1.07374e+08 -1.07374e+08 13 13 13 13 13 13 
1860 3720 5580 7440 9300 11160 13020 14880 
-1.07374e+08 -1.07374e+08 15 15 15 15 15 15 
2108 4216 6324 8432 10540 12648 14756 16864 
-1.07374e+08 -1.07374e+08 17 17 17 17 17 17 

因为计数基本上从 8(前一个)变为 16,并且每个进程都给我一个调试错误

"Run-Time Check Failure #2 - Stack around the variable 'matrixC' was corrupted"

几天来我一直在修改这个计数公式,但仍然无法弄明白。我试过更改我的矩阵乘法开始和结束迭代,但也无法解决。

允许设置更大的矩阵大小,单独的数组应该是二维数组,第一维设置为基于 tasks/processes:

数量的段的大小
float matrixARows[MAT_SIZE/size][MAT_SIZE];
float matrixCRows[MAT_SIZE/size][MAT_SIZE];

计数应为:

int count = MAT_SIZE * MAT_SIZE / size;

矩阵乘法变为:

int sum = 0;
for (int k = 0; k < MAT_SIZE/size; k++)
{
    for (int i = 0; i < MAT_SIZE; i++)
    {
        for (int j = 0; j < MAT_SIZE; j++)
        {
            sum += matARows[k][j] * matB[j][i];
        }
        matCRows[k][i] = sum;
        sum = 0;
    }
}

注意:矩阵大小必须能被tasks/processes的个数整除。例如。如果使用 4 个任务,矩阵大小必须为 4、8、16、32、64、128 等...