0

C で MPI を使用して行列乗算を実行しようとしていますが、逐次バージョンと並列バージョンを実行する必要があります。私の並列バージョンでは正しい答えが得られず、その理由がわかりません。プロセスに正しい通信を送信していないと思いますが、確信が持てません。教授はさまざまな送信/受信/収集などのメッセージを調べましたが、実際にはあまり詳細にはなりませんでした...私は多くの異なる例を見てきましたが、完全なものはなく、スキャッター/ギャザーを使用したものもありません. 誰かが私のコードを見て、何かが飛び出すかどうか教えていただければ幸いです。私の問題は、スキャッター/ギャザー メッセージまたは c 行列の実際の計算にあると確信しています。

#define N 512

#include <stdio.h>
#include <math.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stddef.h>
#include "mpi.h"


print_results(char *prompt, float a[N][N]);

int main(int argc, char *argv[])
{
    int i, j, k, rank, size, tag = 99, blksz, sum = 0;
    float a[N][N], b[N][N], c[N][N];
    char *usage = "Usage: %s file\n";
    FILE *fd;
    double elapsed_time, start_time, end_time;
    struct timeval tv1, tv2;

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

    if (argc < 2) {
            fprintf (stderr, usage, argv[0]);
            return -1;
    }

    if ((fd = fopen (argv[1], "r")) == NULL) {
            fprintf (stderr, "%s: Cannot open file %s for reading.\n",
                                    argv[0], argv[1]);
            fprintf (stderr, usage, argv[0]);
            return -1;
    }

    for (i = 0; i < N; i++)
            for (j = 0; j < N; j++)
                    fscanf (fd, "%f", &a[i][j]);

    for (i = 0; i < N; i++)
            for (j = 0; j < N; j++)
                    fscanf (fd, "%f", &b[i][j]);

    MPI_Barrier(MPI_COMM_WORLD);

    gettimeofday(&tv1, NULL);

    MPI_Scatter(a, N*N/size, MPI_INT, a, N*N/size, MPI_INT, 0,
                                                    MPI_COMM_WORLD);
    MPI_Bcast(b, N*N, MPI_INT, 0, MPI_COMM_WORLD);


    if (rank != 0) {
            for (i = 0; i < N; i++)
            {
                    for (j = 0; j < N; j++)
                    {
                            for (k = 0; k < N; k++)
                            {
                                    sum = sum + a[i][k] * b[k][j];
                            }
                            c[i][j] = sum;
                            sum = 0;
                    }
            }
    }

    MPI_Gather(c, N*N/size, MPI_INT, c, N*N/size, MPI_INT, 0,
                                                     MPI_COMM_WORLD);
    MPI_Finalize();

    gettimeofday(&tv2, NULL);

    elapsed_time = (tv2.tv_sec - tv1.tv_sec) + ((tv2.tv_usec - tv1.tv_usec)/1000000.0);

    printf ("elapsed_time=\t%lf (seconds)\n", elapsed_time);

    print_results("C = ", c);
}

print_results(char *prompt, float a[N][N])
{
    int i, j;

    printf ("\n\n%s\n", prompt);
    for (i = 0; i < N; i++) {
            for (j = 0; j < N; j++) {
                    printf(" %.2f", a[i][j]);
            }
            printf ("\n");
    }
    printf ("\n\n");
}

コードの更新部分:

for (i=0;i<size; i++)
            {
                    if (rank == i)
                    {
                            for (i = rank*(N/size); i < (rank*(N/size)+(N/size)); i++)
                            {
                                    for (j = rank*(N/size); j < (rank*(N/size)+(N/size)); j++)
                                    {
                                            for (k = rank*N; k < rank*N+N; k++)
                                            {
                                                    sum = sum + a[i][k] * b[k][j];
                                            }
                                            c[i][j] = sum;
                                            sum = 0;
                                    }
                            }
                    }
            }
4

1 に答える 1

3

コードの最初の問題は、sizeが分割されない可能性があることNです。つまりsize、長さのあるパケットを分散N*N/sizeしても、必ずしもマトリックス全体が送信されるとは限りません。これはおそらく正しく理解するのが最も難しい点です。

Greg Inozemtsevが指摘しているように、2番目の問題は、マトリックスの一部を担当しているにもかかわらず、プロセス0を計算から除外することです。

さらに別の問題は、すべてのI / O操作(最初に係数を読み取り、最後に結果を出力する)をプロセス0によってのみ実行する必要があることです。

別の注意点として、前方宣言と定義の両方で、関数の戻り型(voidこの場合)を指定する必要があります。print_result

于 2012-09-17T06:19:03.997 に答える