Соберите разделенный 2D-массив с помощью MPI на C

#c #performance #parallel-processing #mpi #openmpi

#c #Производительность #параллельная обработка #mpi #openmpi

Вопрос:

Мне нужно адаптировать эту часть очень длинного кода к mpi на c.

 for (i = 0; i < total; i  ) {
   sum = A[next][0][0]*B[i][0]   A[next][0][1]*B[i][1]   A[next][0][2]*B[i][2];
   next  ;
   while (next < last) {
      col = column[next];
      sum  = A[next][0][0]*B[col][0]   A[next][0][1]*B[col][1]   A[next][0][2]*B[col][2];
      final[col][0]  = A[next][0][0]*B[i][0]   A[next][1][0]*B[i][1]   A[next][2][0]*B[i][2];
      next  ;
}
final[i][0]  = sum;}
 

И я думал о таком коде:

 for (i = 0; i < num_threads; i  ) {
   for (j = 0; j < total; j  ) {
      check_thread[i][j] = false;
   }
}
part = total / num_threads;
for (i = thread_id * part; i < ((thread_id   1) * part); i  ) {
   sum = A[next][0][0]*B[i][0]   A[next][0][1]*B[i][1]   A[next][0][2]*B[i][2];
   next  ;
   while (next < last) {
     col = column[next];
     sum  = A[next][0][0]*B[col][0]   A[next][0][1]*B[col][1]   A[next][0][2]*B[col][2];
     if (!check_thread[thread_id][col]) {
        check_thread[thread_id][col] = true;
        temp[thread_id][col] = 0.0;
     }      
     temp[thread_id][col]  = A[next][0][0]*B[i][0]   A[next][1][0]*B[i][1]   A[next][2][0]*B[i][2];
     next  ;
   }
   if (!check_thread[thread_id][i]) {
      check_thread[thread_id][i] = true;
      temp[thread_id][i] = 0.0;
   }
 temp[thread_id][i]  = sum;
}
*
for (i = 0; i < total; i  ) {
   for (j = 0; j < num_threads; j  ) {
     if (check_thread[j][i]) {
        final[i][0]  = temp[j][i];
     }
   }
}
 

Затем мне нужно собрать все временные части в одну, о чем я думал MPI_Allgather , и что-то вроде этого непосредственно перед последними двумя для (где *):

   MPI_Allgather(temp, (part*sizeof(double)), MPI_DOUBLE, temp, sizeof(**temp), MPI_DOUBLE, MPI_COMM_WORLD);
 

Но я получаю сообщение об ошибке выполнения, возможно ли отправлять и получать в одной и той же переменной?, если нет, каким может быть другое решение в этом случае ?.

Ответ №1:

Вы вызываете MPI_Allgather с неправильными параметрами:

  MPI_Allgather(temp, (part*sizeof(double)), MPI_DOUBLE, temp, sizeof(**temp), MPI_DOUBLE, MPI_COMM_WORLD);
 

Вместо этого у вас должен быть (исходный код) :

MPI_Allgather

Собирает данные из всех задач и распределяет объединенные данные по всем задачам

Входные параметры
sendbuf начальный адрес буфера отправки (выбор)
количество отправленных элементов в буфере отправки (целое число)
тип данных отправки Тип данных элементов буфера отправки (дескриптор)
количество элементов, полученных от любого процесса (целое число)
тип данных recvtype элементов буфера приема (дескриптор)
коммуникатор связи (дескриптор)

Ваши sendcount recvcount аргументы и оба неверны, вместо (part*sizeof(double)) и sizeof(**temp) вы должны передать количество элементов из матрицы temp , которые будут собираться всеми задействованными процессами.

Матрица может быть собрана за один вызов, если эта матрица постоянно выделяется в памяти, если она была создана как массив указателей, тогда вам придется вызывать MPI_Allgather для каждой строки матрицы или вместо этого использовать MPI_Allgatherv.

Возможно ли отправлять и получать в одной и той же переменной?

Да, с помощью опции на месте

Когда коммуникатор является внутрикоммуникатором, вы можете выполнить операцию сбора всех данных на месте (выходной буфер используется в качестве входного буфера). Используйте переменную MPI_IN_PLACE в качестве значения sendbuf . В этом случае sendcount и sendtype игнорируются. Предполагается, что входные данные каждого процесса находятся в области, где этот процесс будет получать свой вклад в буфер приема. В частности, результат вызова MPI_Allgather, который использовал параметр in-place, идентичен случаю, в котором все процессы выполнили n вызовов

MPI_GATHER ( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, recvbuf, recvcount, recvtype, root, comm)