Простая программа MPI - PullRequest
       41

Простая программа MPI

2 голосов
/ 15 августа 2011

Я ценю, если кто-нибудь скажет мне, почему этот простой код отправки и получения MPI не работает на двух процессорах , когда значение n = 40 (в строке 20), но работает для n < = 30. Другими словами, если размер сообщения выходит за пределы определенного числа (которое не так велико, примерно 1-D массив размером 8100), MPI блокируется.

#include "mpi.h"
#include "stdio.h"
#include "stdlib.h"
#include "iostream"
#include "math.h"
using namespace std;

int main(int argc, char *argv[])
{
    int processor_count, processor_rank;
    double *buff_H, *buff_send_H;
    int N_pa_prim1, l, n, N_p0;
    MPI_Status status;

    MPI_Init (&argc, &argv);
    MPI_Comm_size (MPI_COMM_WORLD, &processor_count);
    MPI_Comm_rank (MPI_COMM_WORLD, &processor_rank);

    N_pa_prim1=14; l=7; n=40; N_p0=7;
    buff_H = new double [n*n*N_p0+1];          //Receive buffer allocation

    buff_send_H = new double [n*n*N_p0+1];     //Send buffer allocation

    for (int j = 0; j < n*n*N_p0+1; j++)
        buff_send_H[j] = 1e-8*rand();

    if (processor_rank == 0)
        MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD);  
else if(processor_rank == 1)
    MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD);

    MPI_Recv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &status);
cout << "Received successfully by " << processor_rank << endl;
MPI_Finalize();
return 0;
}

Ответы [ 2 ]

4 голосов
/ 15 августа 2011

Блокировка - это правильное поведение; у вас тупик в вашем коде.

Спецификация MPI позволяет MPI_Send вести себя как MPI_Ssend, то есть блокировать. Блокирующий коммуникационный примитив не возвращается до тех пор, пока связь в некотором смысле «не завершится», что (в случае блокирующей отправки), вероятно, означает, что прием начался.

Ваш код выглядит так:

If Processor 0:
   Send to processor 1

If Processor 1:
   Send to processor 0

Receive

То есть - получение не начинается до тех пор, пока отправка не будет завершена. Вы отправляете, но они никогда не вернутся, потому что никто не получает! (Тот факт, что это работает для маленьких сообщений, является артефактом реализации - большинство реализаций mpi используют так называемый «нетерпеливый протокол» для «достаточно маленьких» сообщений; но на это вообще нельзя рассчитывать.)

Обратите внимание, что здесь присутствуют и другие логические ошибки - эта программа также заблокируется более чем для 2 процессоров, поскольку процессоры с рангом> = 2 будут ожидать сообщения, которое никогда не поступит.

Вы можете исправить свою программу, чередуя отправку и получение по рангу:

if (processor_rank == 0) {
    MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD);  
    MPI_Recv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &status);
} else if (processor_rank == 1) {
    MPI_Recv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &status);
    MPI_Send(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD);
}

или с помощью MPI_Sendrecv (который является блокирующим (отправка + получение), а не блокирующим отправкой + блокирующее получение):

int sendto;
if (processor_rank == 0)
    sendto = 1;
else if (processor_rank == 1)
    sendto = 0;

if (processor_rank == 0 || processor_rank == 1) {
    MPI_Sendrecv(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, sendto, 163,
                 buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163,
                 MPI_COMM_WORLD, &status);
}

Или с помощью неблокирующих отправок и приемов:

MPI_Request reqs[2];
MPI_Status  statuses[2];
if (processor_rank == 0) {
    MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD, &reqs[0]);
} else if (processor_rank == 1) {
    MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD, &reqs[0]);
}

if (processor_rank == 0 || processor_rank == 1)
    MPI_Irecv(buff_H, n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &reqs[1]);

MPI_Waitall(2, reqs, statuses);
0 голосов
/ 19 августа 2011

Спасибо, Джонатан, за вашу помощь. Здесь я выбрал третье решение и написал код, аналогичный вашему, за исключением добавления циклов «for» для отправки ряда сообщений. На этот раз это не тупик; однако процессоры продолжают получать только последнее сообщение. (поскольку сообщения длинные, я напечатал их последние элементы только для проверки их согласованности)

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <math.h>
using namespace std;

int main(int argc, char *argv[])
{
int processor_count, processor_rank;

//Initialize MPI
MPI_Init (&argc, &argv);
MPI_Comm_size (MPI_COMM_WORLD, &processor_count);
MPI_Comm_rank (MPI_COMM_WORLD, &processor_rank);

double **buff_H, *buff_send_H;
int N_pa_prim1, l, n, N_p0, count, temp;
N_pa_prim1=5; l=7; n=50; N_p0=7;

MPI_Request reqs[N_pa_prim1];
MPI_Status  statuses[N_pa_prim1];
buff_H = new double *[N_pa_prim1];                 //Receive buffer allocation
for (int i = 0; i < N_pa_prim1; i++)
    buff_H[i] = new double [n*n*N_p0+1];  
buff_send_H = new double [n*n*N_p0+1];             //Send buffer allocation

if (processor_rank == 0) {
    for (int i = 0; i < N_pa_prim1; i++){
        for (int j = 0; j < n*n*N_p0+1; j++)
            buff_send_H[j] = 2.0325e-8*rand();

        cout << processor_rank << "\t" << buff_send_H[n*n*N_p0] << "\t" << "Send" << "\t" << endl;  
        MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 1, 163, MPI_COMM_WORLD, &reqs[i]);
    }
}
else if (processor_rank == 1) {
    for (int i = 0; i < N_pa_prim1; i++){
        for (int j = 0; j < n*n*N_p0+1; j++)
            buff_send_H[j] = 3.5871e-8*rand();

        cout << processor_rank << "\t" << buff_send_H[n*n*N_p0] << "\t" << "Send" << "\t" << endl;  
        MPI_Isend(buff_send_H, n*n*N_p0+1, MPI_DOUBLE, 0, 163, MPI_COMM_WORLD, &reqs[i]);
    }
}

for (int i = 0; i < N_pa_prim1; i++)
    MPI_Irecv(buff_H[i], n*n*N_p0+1, MPI_DOUBLE, MPI_ANY_SOURCE, 163, MPI_COMM_WORLD, &reqs[N_pa_prim1+i]);

MPI_Waitall(2*N_pa_prim1, reqs, statuses);

for (int i = 0; i < N_pa_prim1; i++)
    cout << processor_rank << "\t" << buff_H[i][n*n*N_p0] << "\t" << "Receive" << endl;

MPI_Finalize();
return 0;

}

...