Произошла ошибка в MPI_Recv при отправке массива - PullRequest
2 голосов
/ 19 февраля 2020
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
int main(int argc, char **argv)
{
    int N;
    scanf("%d", &N);
    double *a = (double *)malloc(N * sizeof(double));
    int i, rank, size, tag = 99, tag1 = 100;
    MPI_Status status;
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    if (rank == 0) 
    {
        for(int j=0;j<N;++j)
        {
            a[j] = j+0.1;
        }
        for (i = 1; i < size; i++)
        {
            MPI_Send(&N, 1, MPI_INT, i, tag1, MPI_COMM_WORLD);
            MPI_Send(a, N, MPI_DOUBLE, i, tag, MPI_COMM_WORLD);
        }
    }
    else 
    {
        MPI_Recv(&N, 1, MPI_INT, 0, tag1, MPI_COMM_WORLD, &status);
        MPI_Recv(a, N, MPI_DOUBLE, 0, tag, MPI_COMM_WORLD, &status);
        // for(int j=0;j<N*2;++j)
            // printf("%d %f\n", rank, a[j]);
    }
    MPI_Barrier(MPI_COMM_WORLD);
    printf("Message from process %d : %f\n", rank, a[rank]);
    MPI_Finalize();
    return 0;
} 

Я создаю массив 'a' в 0-м процессе и отправляю его остальным процессам. Но при этом я получаю следующую ошибку:

[nikhil:8599] *** An error occurred in MPI_Recv
[nikhil:8599] *** reported by process [4228579329,1]
[nikhil:8599] *** on communicator MPI_COMM_WORLD
[nikhil:8599] *** MPI_ERR_BUFFER: invalid buffer pointer
[nikhil:8599] *** MPI_ERRORS_ARE_FATAL (processes in this communicator will now abort,
[nikhil:8599] ***    and potentially your MPI job)
[nikhil:08593] 2 more processes have sent help message help-mpi-errors.txt / mpi_errors_are_fatal
[nikhil:08593] Set MCA parameter "orte_base_help_aggregate" to 0 to see all help / error messages

Кто-нибудь может объяснить, почему я получаю эту ошибку?

Как вы можете видеть в коде, есть для l oop, содержащий заявление для печати, которое комментируется. Странная вещь ... при комментировании этого l oop. Работает нормально.

1 Ответ

2 голосов
/ 20 февраля 2020

Мысли:

  1. MPI_Init должно быть первым в вашей программе.
  2. Только один ранг должен scanf.
  3. N не передается между рядами, поэтому вы выделяете память неопределенного размера.
  4. Определяйте переменные как можно ближе к точке их использования. Помещение int i в начале вашей функции - это катастрофа, ожидающая, что произойдет.
  5. Барьер в конце не нужен.
  6. Все ряды должны распределить свои собственная память.

Это приводит нас к следующему коду:

#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"

int main(int argc, char **argv){
    MPI_Init(&argc, &argv);

    const int tag = 99;
    const int tag1 = 100;

    int rank, size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    double *a; //Pointer to the memory we will allocate
    int N;

    if (rank == 0){
        scanf("%d", &N);

        a = (double *)malloc(N * sizeof(double));

        for(int j=0;j<N;++j){
            a[j] = j+0.1;
        }
        for (int i = 1; i < size; i++){
            MPI_Send(&N, 1, MPI_INT, i, tag1, MPI_COMM_WORLD);
            MPI_Send(a, N, MPI_DOUBLE, i, tag, MPI_COMM_WORLD);
        }
    } else {
        MPI_Status status;
        MPI_Recv(&N, 1, MPI_INT, 0, tag1, MPI_COMM_WORLD, &status);
        //Have to allocate memory on all ranks
        a = (double *)malloc(N * sizeof(double)); 
        MPI_Recv(a, N, MPI_DOUBLE, 0, tag, MPI_COMM_WORLD, &status);
        // for(int j=0;j<N*2;++j)
            // printf("%d %f\n", rank, a[j]);
    }

    printf("Message from process %d : %f\n", rank, a[rank]);

    MPI_Finalize();
    return 0;
} 

Делаем лучше

Команда вещания - ваш друг здесь:

#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"

#define MPI_Error_Check(x) {const int err=x; if(x!=MPI_SUCCESS) { fprintf(stderr, "MPI ERROR %d at %d.", err, __LINE__);}}

int main(int argc, char **argv){
    MPI_Init(&argc, &argv);

    int rank, size;
    MPI_Error_Check(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
    MPI_Error_Check(MPI_Comm_size(MPI_COMM_WORLD, &size));

    int N;
    if (rank==0){
        scanf("%d", &N);
    }

    MPI_Error_Check(MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD));

    double *a = (double *)malloc(N * sizeof(double));

    if(rank==0){
        for(int j=0;j<N;++j){
            a[j] = j+0.1;
        }
    }

    printf("Message from process %d : N=%d\n", rank, N);

    MPI_Error_Check(MPI_Bcast(a, N, MPI_DOUBLE, 0, MPI_COMM_WORLD));

    fprintf(stderr, "Message from process %d : %f\n", rank, a[rank]);

    free(a);

    MPI_Finalize();
    return 0;
} 

Делая это еще лучше

Самая быстрая форма общения - это вообще отсутствие общения. В вашем случае, когда известно значение N, каждый ранг может воссоздать данные самостоятельно:

#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"

#define MPI_Error_Check(x) {const int err=x; if(x!=MPI_SUCCESS) { fprintf(stderr, "MPI ERROR %d at %d.", err, __LINE__);}}

int main(int argc, char **argv){
    MPI_Init(&argc, &argv);

    int rank, size;
    MPI_Error_Check(MPI_Comm_rank(MPI_COMM_WORLD, &rank));
    MPI_Error_Check(MPI_Comm_size(MPI_COMM_WORLD, &size));

    int N;
    if (rank==0){
        scanf("%d", &N);
    }

    MPI_Error_Check(MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD));

    double *a = (double *)malloc(N * sizeof(double));

    for(int j=0;j<N;++j){
        a[j] = j+0.1;
    }

    printf("Message from process %d : N=%d\n", rank, N);

    fprintf(stderr, "Message from process %d : %f\n", rank, a[rank]);

    free(a);

    MPI_Finalize();
    return 0;
} 
...