Advertisement
Guest User

Untitled

a guest
Apr 25th, 2018
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.99 KB | None | 0 0
  1. /* Произведение двух матриц в топологии
  2.  * "двумерная решетка". В примере, данные
  3.  * генерируются в нулевом компьютере.
  4.  * В примере предполагается, что количество строк
  5.  * матрицы A и количество столбцов матрицы B
  6.  * делятся без остатка на количество компьютеров
  7.  * в системе.
  8.  * В данном примере задачу запускаем на 4-х
  9.  * компьютерах и на решетке 2х2.
  10.  */
  11.  #include<stdio.h>
  12.  #include<stdlib.h>
  13.  #include<mpi.h>
  14.  #include<time.h>
  15.  #include<sys/time.h>
  16. /* NUM_DIMS - размер декартовой топологии.
  17.  * "двумерная решетка" P0xP1 */
  18.  #define NUM_DIMS 2
  19.  #define P0 2
  20.  #define P1 2
  21. /* Задаем размеры матриц A = MxN, B = NxK и C =
  22. MxK (Эти размеры значимы в ветви 0) */
  23.  #define M 8
  24.  #define N 8
  25.  #define K 8
  26.  #define A(i,j) A[N*i+j]
  27.  #define B(i,j) B[K*i+j]
  28.  #define C(i,j) C[K*i+j]
  29. /* Подпрограмма, осуществляющая перемножение
  30. матриц */
  31. PMATMAT_2(n, A, B, C, p, comm)
  32. /* Аргументы A, B, C, n, p значимы в данном
  33. случае только в ветви 0 */
  34.  int *n; /* Размеры исходных матриц */
  35. /* Исходные матрицы:A[n[0]][n[1]], B[n[1]][n[2]],
  36.  * C[n[0]][n[2]]; */
  37. double *A, *B, *C;
  38. /* Данные */
  39.  int *p;
  40. /* размеров решетки компьютеров. p[0]
  41.  * соответствует n[0],
  42.  * p[1] соответствует n[2]
  43.  * и произведение p[0]*p[1] будет эквивалентно
  44.  * размеру группы comm
  45.  * Коммуникатор для процессов, участвующих в
  46.  * умножении матрицы на матрицу */
  47.  MPI_Comm comm;
  48.  {
  49. /* Далее все описываемые переменные значимы во
  50. всех ветвях, в том числе и ветви 0 */
  51. /* Локальные подматрицы (полосы) */
  52.  double *AA, *BB, *CC;
  53. /* Размеры полос в A и B и подматриц CC в C */
  54.  int nn[2];
  55. /* Декартовы координаты ветвей */
  56.  int coords[2];
  57.  int rank; /* Порядковые номера ветвей */
  58. /* Смещения и размер подматриц CС для сборки в
  59. корневом процессе (ветви) */
  60.  int *countc, *dispc, *countb, *dispb;
  61. /* Типы данных и массивы для создаваемых типов */
  62.  MPI_Datatype typeb, typec, types[2];
  63.  int blen[2];
  64.  int i, j, k;
  65.  int periods[2], remains[2];
  66.  int sizeofdouble, disp[2];
  67.  /* Коммуникаторы для 2D решетки, для подрешеток
  68. 1D, и копии коммуникатора comm */
  69.  MPI_Comm comm_2D, comm_1D[2], pcomm;
  70.  /* Создаем новый коммуникатор */
  71.  MPI_Comm_dup(comm, &pcomm);
  72.  /* Нулевая ветвь передает всем ветвям массивы
  73. n[] и p[] */
  74.  MPI_Bcast(n, 3, MPI_INT, 0, pcomm);
  75.  MPI_Bcast(p, 2, MPI_INT, 0, pcomm);
  76.  /* Создаем 2D решетку компьютеров размером
  77. p[0]*p[1] */
  78.  periods[0] = 0;
  79.  periods[1] = 0;
  80.  MPI_Cart_create(pcomm, 2, p, periods, 0,
  81.  &comm_2D);
  82.  /* Находим ранги и декартовы координаты ветвей в
  83. этой решетке */
  84.  MPI_Comm_rank(comm_2D, &rank);
  85.  MPI_Cart_coords(comm_2D, rank, 2, coords);
  86.  
  87.  /* Нахождение коммуникаторов для подрешеток 1D
  88. для рассылки полос матриц A и B */
  89.  for(i = 0; i < 2; i++)
  90.  { for(j = 0; j < 2; j++)
  91.  remains[j] = (i == j);
  92.  MPI_Cart_sub(comm_2D, remains,
  93.  &comm_1D[i]);
  94.  }
  95.  /* Во всех ветвях задаем подматрицы (полосы) */
  96.  /* Здесь предполагается, что деление без остатка
  97.  */
  98.  nn[0] = n[0]/p[0];
  99.  nn[1] = n[2]/p[1];
  100.  
  101.  #define AA(i,j) AA[n[1]*i+j]
  102.  #define BB(i,j) BB[nn[1]*i+j]
  103.  #define CC(i,j) CC[nn[1]*i+j]
  104.  AA=(double*)malloc(nn[0]*n[1]*sizeof(double));
  105.  BB=(double*)malloc(n[1]*nn[1]*sizeof(double));
  106.  CC=(double*)malloc(nn[0]*nn[1]*sizeof(double));
  107.  /* Работа нулевой ветви */
  108.  if(rank == 0)
  109.  {
  110.  /* Задание типа данных для вертикальной
  111. полосы в В. Этот тип создать необходимо, т.к. в
  112. языке С массив в памяти располагается по строкам.
  113. Для массива А такой тип создавать нет
  114. необходимости, т.к. там передаются горизонтальные
  115. полосы, а они в памяти расположены непрерывно.
  116. */
  117.  MPI_Type_vector(n[1], nn[1], n[2], MPI_DOUBLE,
  118.  &types[0]);
  119.  /* и корректируем диапазон размера полосы */
  120.  MPI_Type_extent(MPI_DOUBLE, &sizeofdouble);
  121.  blen[0] = 1;
  122.  blen[1] = 1;
  123.  disp[0] = 0;
  124.  disp[1] = sizeofdouble * nn[1];
  125.  types[1] = MPI_UB;
  126.  MPI_Type_struct(2, blen, disp, types,
  127.  &typeb);
  128.  MPI_Type_commit(&typeb);
  129.  /* Вычисление размера подматрицы BB и
  130. смещений каждой подматрицы в матрице B.
  131. Подматрицы BB упорядочены в B в соответствии с
  132. порядком номеров компьютеров в решетке, т.к.
  133. массивы расположены в памяти по строкам, то
  134. подматрицы BB в памяти (в B) должны располагаться
  135. в следующей последовательности: BB0, BB1,.... */
  136.  dispb = (int *)malloc(p[1] * sizeof(int));
  137.  countb = (int *)malloc(p[1] * sizeof(int));
  138.  for(j = 0; j < p[1]; j++)
  139.  { dispb[j] = j;
  140.  countb[j] = 1;
  141.  }
  142. /* Задание типа данных для подматрицы CC в C */
  143. MPI_Type_vector(nn[0], nn[1], n[2], MPI_DOUBLE,
  144.  &types[0]);
  145. /* и корректируем размер диапазона */
  146. MPI_Type_struct(2, blen, disp, types, &typec);
  147.  MPI_Type_commit(&typec);
  148. /* Вычисление размера подматрицы CС и смещений
  149. каждой подматрицы в матрице C. Подматрицы CC
  150. упорядочены в С в соответствии с порядком номеров
  151. компьютеров в решетке, т.к. массивы расположены в
  152. памяти по строкам, то подматрицы СС в памяти (в
  153. С) должны располагаться в следующей
  154. последовательности: СС0, СС1, СС2, CC3, СС4,
  155. СС5, СС6, СС7. */
  156. dispc=(int *)malloc(p[0]*p[1]*sizeof(int));
  157. countc=(int *)malloc(p[0]*p[1]*sizeof(int));
  158.  for(i = 0; i < p[0]; i++)
  159.  { for(j = 0; j < p[1]; j++)
  160.  { dispc[i*p[1]+j]=(i*p[1]*nn[0]+j);
  161.  countc[i*p[1]+j] = 1;
  162.  }
  163.  }
  164.  } /* Нулевая ветвь завершает
  165. подготовительную работу */
  166.  
  167. /* Вычисления (этапы указаны на рис. 8.5) */
  168. /* 1. Нулевая ветвь передает (scatter)
  169. горизонтальные полосы матрицы A по x координате
  170. */
  171.  if(coords[1] == 0)
  172.  {
  173. MPI_Scatter(A,nn[0]*n[1],MPI_DOUBLE,AA,nn[0]*n[1]
  174.  ,MPI_DOUBLE,0,comm_1D[0]);
  175.  }
  176. /* 2. Нулевая ветвь передает (scatter)
  177. горизонтальные полосы матрицы B по y координате
  178. */
  179. if(coords[0] == 0)
  180.  { MPI_Scatterv(B,countb,dispb, typeb, BB,
  181.  n[1]*nn[1], MPI_DOUBLE, 0,comm_1D[1]);
  182.  }
  183.  
  184. /* 3. Передача подматриц AA в измерении y */
  185. MPI_Bcast(AA, nn[0]*n[1], MPI_DOUBLE, 0,
  186.  comm_1D[1]);
  187.  
  188. /* 4. Передача подматриц BB в измерении x */
  189.  MPI_Bcast(BB, n[1]*nn[1], MPI_DOUBLE, 0,
  190.  comm_1D[0]);
  191.  /* 5. Вычисление подматриц СС в каждой ветви */
  192.  for(i = 0; i < nn[0]; i++)
  193.  { for(j = 0; j < nn[1]; j++)
  194.  { CC(i,j) = 0.0;
  195.  for(k = 0; k < n[1]; k++)
  196.  { CC(i,j)=CC(i,j)+AA(i,k)*BB(k,j);
  197.  }
  198.  }
  199.  }
  200.  /* 6. Сбор всех подматриц СС в ветви 0 */
  201.  MPI_Gatherv(CC, nn[0]*nn[1], MPI_DOUBLE, C,
  202.  countc, dispc, typec, 0, comm_2D);
  203.  /* Освобождение памяти всеми ветвями и
  204. завершение подпрограммы */
  205.  free(AA);
  206.  free(BB);
  207.  free(CC);
  208.  MPI_Comm_free(&pcomm);
  209.  MPI_Comm_free(&comm_2D);
  210.  for(i = 0; i < 2; i++)
  211.  { MPI_Comm_free(&comm_1D[i]);
  212.  }
  213.  if(rank == 0)
  214.  { free(countc);
  215.  free(dispc);
  216. MPI_Type_free(&typeb);
  217.  MPI_Type_free(&typec);
  218.  MPI_Type_free(&types[0]);
  219.  }
  220.  return 0;
  221.  }
  222.  /* Главная программа */
  223. int main(int argc, char **argv)
  224.  {
  225.  int size, MyP, n[3], p[2], i, j, k;
  226.  int dims[NUM_DIMS], periods[NUM_DIMS];
  227.  double *A, *B, *C;
  228.  int reorder = 0;
  229.  struct timeval tv1, tv2;
  230.  int dt1;
  231.  MPI_Comm comm;
  232. /* Инициализация библиотеки MPI */
  233.  MPI_Init(&argc, &argv);
  234. /* Каждая ветвь узнает количество задач в
  235. стартовавшем приложении */
  236.  MPI_Comm_size(MPI_COMM_WORLD, &size);
  237. /* и свой собственный номер (ранг) */
  238.  MPI_Comm_rank(MPI_COMM_WORLD, &MyP);
  239. /* Обнуляем массив dims и заполняем массив
  240. periods для топологии "двумерная решетка" */
  241.  for(i = 0; i < NUM_DIMS; i++)
  242.  { dims[i] = 0;
  243.  periods[i] = 0;
  244.  }
  245.  /* Заполняем массив dims, где указываются
  246. размеры двумерной решетки */
  247.  MPI_Dims_create(size, NUM_DIMS, dims);
  248.  /* Создаем топологию "двумерная решетка" с
  249. communicator(ом) comm */
  250.  MPI_Cart_create(MPI_COMM_WORLD,NUM_DIMS,dims,periods, reorder, &comm);
  251.  /* В первой ветви выделяем в памяти место для
  252. исходных матриц */
  253.  if(MyP == 0)
  254.  {
  255.  /* Задаем размеры матриц и размеры двумерной
  256. решетки компьютеров */
  257.  n[0] = M;
  258.  n[1] = N;
  259.  n[2] = K;
  260.  p[0] = P0;
  261.  p[1] = P1;
  262. A=(double *)malloc(M*N*sizeof(double));
  263. B=(double *)malloc(N*K*sizeof(double));
  264. C=(double *)malloc(M*K*sizeof(double));
  265.  
  266. /* Генерируем в первой ветви исходные матрицы A и
  267. B, матрицу C обнуляем */
  268.  for(i = 0; i < M; i++)
  269.  for(j = 0; j < N; j++)
  270.  A(i,j) = i+1;
  271.  for(j = 0; j < N; j++)
  272.  for(k = 0; k < K; k++)
  273.  B(j,k) = 21+j;
  274.  for(i = 0; i < M; i++)
  275.  for(k = 0; k < K; k++)
  276.  C(i,k) = 0.0;
  277.  } /* Подготовка матриц ветвью 0 завершина */
  278. /* Засекаем начало умножения матриц во всех
  279. ветвях */
  280.  gettimeofday(&tv1, (struct timezone*)0);
  281.  / Все ветви вызывают функцию перемножения матриц
  282. */
  283.  PMATMAT_2(n, A, B, C, p, comm);
  284.  /* Умножение завершено. Каждая ветвь умножила
  285. свою полосу строк матрицы A на полосу столбцов
  286. матрицы B. Результат находится в нулевой ветви.
  287. * Засекаем время и результат печатаем */
  288.  gettimeofday(&tv2, (struct timezone*)0);
  289.  dt1 = (tv2.tv_sec - tv1.tv_sec) * 1000000 +
  290.  tv2.tv_usec - tv1.tv_usec;
  291.  printf("MyP = %d Time = %d\n", MyP, dt1);
  292.  /* Для контроля 0-я ветвь печатает результат */
  293.  if(MyP == 0)
  294.  { for(i = 0; i < M; i++)
  295.  { for(j = 0; j < K; j++)
  296.  printf(" %3.1f",C(i,j));
  297.  printf("\n");
  298.  }
  299.  }
  300.  /* Все ветви завершают системные процессы,
  301. связанные с топологией comm и завершают
  302. выполнение программы */
  303.  if(MyP == 0)
  304.  { free(A);
  305.  free(B);
  306.  free(C);
  307.  }
  308.  MPI_Comm_free(&comm);
  309.  MPI_Finalize();
  310.  return(0);
  311.  }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement