Подматрица MPI_Scatterv с MPI_Type_struct

В настоящее время я работаю над MPI-программой и пытаюсь отправить блоки матрицы с помощью scatterv всем процессам.

Описание процесса

Матрица представлена ​​в виде массива. Сначала я создаю тип данных с помощью MPI_Type_vector, чтобы создать необходимый блок из исходного массива. Во-вторых, я создаю MPI_Type_struct, которая должна содержать ряды блоков.

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

#define n 16

int main(int argc, char *argv[])
{
  MPI_Init(&argc, &argv);
  MPI_Comm comm = MPI_COMM_WORLD;
  int p,r;
  MPI_Comm_size(comm, &p);
  MPI_Comm_rank(comm, &r);
  int *arr;
  arr = NULL;
  if (r == 0){
    arr = (int *) malloc(n * n * sizeof(int));
    for (int i = 0; i < n * n; i++) arr[i] = i;
    for (int i = 0; i < n; i++){
      printf("\n");
      for (int j = 0; j < n; j++)
        printf("%4d", arr[i * n + j]);
    }
  }
  printf("\n");
  int ps = sqrt(p);
  int ns = n / ps;

  if (r == 0) {
    printf("ps: %d ns: %d\n", ps, ns);
  }
  /* create datatype */
  MPI_Datatype block;
  MPI_Type_vector(ns, ns, n, MPI_INT, &block);
  int blocks[ps];
  MPI_Aint displs[ps];
  for (int i = 0; i < ps; i++) { 
    blocks[i] = 1;
    displs[i] = i  * sizeof(int);
  }
  MPI_Datatype types[ps];
  //for (int i = 0; i < ps - 1; i++) types[i] = block;
  //types[ps - 1] = MPI_UB;
  types[0] = block;
  for (int i = 1; i < ps; i++) types[i] = MPI_UB; 
  //types[0] = block;
  //types[1] = MPI_UB;
  if (r == 0) {
    printf("displs:\n");
    for(int i = 0; i < ps; i++) printf("%3ld", displs[i]);
    printf("\n");
  }

  MPI_Datatype row;
  MPI_Type_struct(ps, blocks, displs, types, &row);
  MPI_Type_commit(&row);

  /* prepare scatter */
  int sdispl[p]; int sendcounts[p];
  for (int i = 0; i < p; i++) {
    sdispl[i] = (i % ps) + (i / ps) * (ns * ps);
    sendcounts[i] = 1;
  }
  if (r == 0) {
    printf("sdispl: \n");
    for (int i = 0; i < 4; i++) printf("%3d", sdispl[i]);
    printf("\n");
  }

  int rcv[ns * ns];
  MPI_Scatterv(arr, sendcounts, sdispl, row, rcv, ns * ns, MPI_INT, 0, comm);

  int result = 1;
  if (r == result) {
    printf("result for %d:\n", result);
    for (int i = 0; i < ns * ns; i++) {
      printf("%4d", rcv[i]);
      if ((i+1) % ns == 0) printf("\n");
    }
  }

  if (arr != NULL) free(arr);
  MPI_Finalize();
  return 0;
}

Пока структура блоков правильная.

Проблема

Блок, отправленный процессу r = 1, начинается с 3 вместо 4. Блок для процесса r = 2 также начинается с 6, а блок для процесса r = 3 начинается с 9. Для r == 4 он переходит на 48. .

Что он должен делать

r start
0 0
1 4
2 8
3 12
4 64
5 68
6 ...
15 204

Помощь, которая мне понадобится

Я думаю, что я делаю какую-то ошибку с displ и sdispl.

Компиляция и запуск примера

Код компилируется следующей командой:

mpicc -o main main.c -lm

Я запускаю код с помощью:

mpirun -np 16 ./main

Спасибо за любую помощь заранее!


person nando    schedule 25.03.2017    source источник
comment
Вы должны проверить этот отличный ответ на связанный вопрос. Не уверен, чего вы действительно пытаетесь достичь с помощью своего типа структуры, я думаю, что вы слишком усложняете вещи. Старайтесь не оставлять в коде всевозможные //закомментированные операторы.   -  person Zulan    schedule 25.03.2017
comment
Спасибо! Я постараюсь решить мою проблему, основываясь на вашей подсказке.   -  person nando    schedule 25.03.2017


Ответы (1)


С подсказкой Зулан я смог решить свою проблему.

Следующий код основан на отличном ответе на подмассивы.

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

#define n 8

void print_arr(int *arr, int x) {
  printf("\n");
  for (int i = 0; i < x*x; i++){
    if (i % x == 0) printf("\n");
    printf("%4d", arr[i]);
  }
  printf("\n");
}

int main(int argc, char *argv[])
{
  MPI_Init(&argc, &argv);
  MPI_Comm comm = MPI_COMM_WORLD;
  int p, r;
  MPI_Comm_size(comm, &p);
  MPI_Comm_rank(comm, &r);

  /* number of proceses in dim x and dim y */
  int ps = sqrt(p);

  /* number of elements in dim x and dim y in sarr */
  int ns = n/ps;

  /* array of data - distributed by process 0 */
  int *arr = NULL;
  if (r==0) {
    arr = (int *) malloc(n * n * sizeof(int));
    for (int i = 0; i < n*n; i++) arr[i] = i;
    print_arr(arr, n);
  }

  MPI_Datatype type, resizedtype;
  int sizes[2] = {n,n};
  int subsizes[2] = {ns,ns};
  int starts[2] = {0,0};

  MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_INT, &type);
  MPI_Type_create_resized(type, 0, ns*sizeof(int), &resizedtype);
  MPI_Type_commit(&resizedtype);

  int counts[p];
  for (int i = 0; i < p; i++) counts[i] = 1;
  int displs[p];
  for (int i = 0; i < p; i++) displs[i] = i%ps + i/ps * ns * ps;

  /* subarray to store distributed data */
  int sarr[ns * ns];

  /* send submatrices to all processes */
  MPI_Scatterv(arr, counts, displs, resizedtype, sarr, ns*ns, MPI_INT, 0, comm);

  /* print received data for process pr */
  int pr = 3;
  if (r == pr)
    print_arr(sarr, ns);

  /* free arr */
  if (arr != NULL) free(arr);

  MPI_Finalize();
  return 0;
}

Вы можете скомпилировать пример с

mpicc -o main main.c

и запустить его с

mpirun -np 4 ./main
person nando    schedule 26.03.2017