Отправка и получение 2D-массива по MPI

Проблема, которую я пытаюсь решить, заключается в следующем:

Последовательный код C++, который у меня есть, вычисляет большую двумерную матрицу. Чтобы оптимизировать этот процесс, я хочу разделить эту большую 2D-матрицу и запустить ее на 4 узлах (скажем) с использованием MPI. Единственная связь, которая происходит между узлами, — это совместное использование значений ребер в конце каждого временного шага. Каждый узел разделяет данные массива ребер A[i][j] со своим соседом.

Основываясь на прочитанном о MPI, у меня есть следующая схема, которую нужно реализовать.

if (myrank == 0)
{
 for (i= 0 to x)
 for (y= 0 to y)
 {
  C++ CODE IMPLEMENTATION 
  .... 
  MPI_SEND(A[x][0], A[x][1], A[x][2], Destination= 1.....)
  MPI_RECEIVE(B[0][0], B[0][1]......Sender = 1.....)
  MPI_BARRIER
}

if (myrank == 1)
{
for (i = x+1 to xx)
for (y = 0 to y)
{
 C++ CODE IMPLEMENTATION
 ....
 MPI_SEND(B[x][0], B[x][1], B[x][2], Destination= 0.....)
 MPI_RECEIVE(A[0][0], A[0][1]......Sender = 1.....)
 MPI BARRIER
}

Я хотел знать, правильный ли мой подход, а также был бы признателен за любые рекомендации по другим функциям MPI, которые также необходимо изучить для реализации.

Спасибо, Ашвин.


person Ashmohan    schedule 05.05.2011    source источник


Ответы (2)


Просто чтобы немного усилить точки Джоэла:

Это намного проще, если вы выделяете свои массивы так, чтобы они были смежными (что-то, что "многомерные массивы" C не дают вам автоматически:)

int **alloc_2d_int(int rows, int cols) {
    int *data = (int *)malloc(rows*cols*sizeof(int));
    int **array= (int **)malloc(rows*sizeof(int*));
    for (int i=0; i<rows; i++)
        array[i] = &(data[cols*i]);

    return array;
}

/*...*/
int **A;
/*...*/
A = alloc_2d_init(N,M);

Затем вы можете отправлять и получать весь массив NxM с помощью

MPI_Send(&(A[0][0]), N*M, MPI_INT, destination, tag, MPI_COMM_WORLD);

и когда вы закончите, освободите память с помощью

free(A[0]);
free(A);

Кроме того, MPI_Recv является блокирующим приемом, а MPI_Send может быть блокирующим отправкой. Одна вещь, которая означает, по мнению Джоэла, заключается в том, что вам определенно не нужны Барьеры. Кроме того, это означает, что если у вас есть шаблон отправки/получения, как указано выше, вы можете попасть в тупиковую ситуацию — все отправляют, никто не получает. Безопаснее это:

if (myrank == 0) {
   MPI_Send(&(A[0][0]), N*M, MPI_INT, 1, tagA, MPI_COMM_WORLD);
   MPI_Recv(&(B[0][0]), N*M, MPI_INT, 1, tagB, MPI_COMM_WORLD, &status);
} else if (myrank == 1) {
   MPI_Recv(&(A[0][0]), N*M, MPI_INT, 0, tagA, MPI_COMM_WORLD, &status);
   MPI_Send(&(B[0][0]), N*M, MPI_INT, 0, tagB, MPI_COMM_WORLD);
}

Другой, более общий подход заключается в использовании MPI_Sendrecv:

int *sendptr, *recvptr;
int neigh = MPI_PROC_NULL;

if (myrank == 0) {
   sendptr = &(A[0][0]);
   recvptr = &(B[0][0]);
   neigh = 1;
} else {
   sendptr = &(B[0][0]);
   recvptr = &(A[0][0]);
   neigh = 0;
}
MPI_Sendrecv(sendptr, N*M, MPI_INT, neigh, tagA, recvptr, N*M, MPI_INT, neigh, tagB, MPI_COMM_WORLD, &status);

или неблокирующие отправки и/или получения.

person Jonathan Dursi    schedule 05.05.2011
comment
Обязательно используйте непрерывный мультимассив, это действительно правильный путь. Также +1 на Sendrecv - person Joel Falcou; 05.05.2011
comment
Не две альтернативы - вы бы использовали обе, процедуру выделения, подобную приведенной выше, чтобы убедиться, что ваш массив непрерывен в памяти, а затем использовать «Отправить и получить» для всей этой структуры и, возможно, с обратным порядком, как указано выше. - person Jonathan Dursi; 05.05.2011
comment
Я смотрел на этот код, чтобы решить проблему утечки памяти. У меня был один вопрос: почему вы не говорите здесь о явном освобождении памяти? Существуют ли условия, при которых это явное или неявное ИЛИ, возможно, это просто зависит от кода, который я полагаю? - person Ashmohan; 28.06.2011
comment
Многомерные массивы C представляют собой непрерывный блок памяти; если вы выделяете double d[50][50];, это непрерывный блок памяти. Один из способов обработки динамически выделенных «псевдо-2D» массивов заключается в выделении фрагмента указателей и отдельного (обычно несмежного) набора блоков памяти, по одному на строку. См. обсуждение по адресу Как C выделяет пространство для 2D (3D...) массива при использовании malloc? - person Jonathan Leffler; 25.07.2013

Во-первых, вам не нужен такой большой барьер. Во-вторых, вы действительно должны отправлять свои данные в виде единого блока, поскольку множественная блокировка отправки/получения приведет к снижению производительности.

person Joel Falcou    schedule 05.05.2011
comment
Ваши данные должны находиться в непрерывном блоке памяти. Затем просто MPI_отправьте весь блок сразу - person Joel Falcou; 05.05.2011