You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
4.5 KiB

  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <cmath>
  4. #include "Ttiming.h"
  5. #include <mpi.h>
  6. #include <stdio.h>
  7. using namespace std;
  8. void array_alloc(long **&arr, long arrsize)
  9. {
  10. try
  11. {
  12. arr = new long* [arrsize];
  13. arr[0] = new long [arrsize*arrsize];
  14. for(long i = 1; i < arrsize; ++i)
  15. arr[i] = arr[i-1] + arrsize;
  16. }
  17. catch (bad_alloc& ex)
  18. {
  19. cerr << "Could not allocate memory for array" << endl;
  20. exit(1);
  21. }
  22. }
  23. void vect_alloc(long *&arr, long arrsize)
  24. {
  25. try
  26. {
  27. arr = new long [arrsize];
  28. }
  29. catch (bad_alloc& ex)
  30. {
  31. cerr << "Could not allocate memory for vector" << endl;
  32. exit(1);
  33. }
  34. }
  35. void array_destroy(long **arr)
  36. {
  37. delete [] arr[0];
  38. delete [] arr;
  39. }
  40. int main(int argc, char *argv[])
  41. {
  42. long **A=NULL, **B=NULL, **C=NULL, *B_rot=NULL, *vect=NULL, *vect_c=NULL, *C_rot=NULL;
  43. long rozmiar=0, porcja_new=0, buff_max=0;
  44. char *endptr;
  45. TTiming tt;
  46. long i;
  47. MPI::Status status;
  48. if (argc < 2)
  49. {
  50. cerr << "Usage: " << argv[0] << " <size>" << endl;
  51. exit(1);
  52. }
  53. rozmiar = strtol(argv[1], &endptr, 10);
  54. if (*endptr)
  55. {
  56. cerr << "Invalid array size format" << endl;
  57. exit(1);
  58. }
  59. if (rozmiar <= 0)
  60. {
  61. cerr << "The number of matrix dimension must be positive" << endl;
  62. exit(1);
  63. }
  64. MPI::Init(argc, argv);
  65. int taskid = MPI::COMM_WORLD.Get_rank();
  66. int ntasks = MPI::COMM_WORLD.Get_size();
  67. //alokacja macierzy
  68. array_alloc(A, rozmiar);
  69. if (taskid == 0)
  70. {
  71. array_alloc(B, rozmiar);
  72. vect_alloc(B_rot, rozmiar*rozmiar);
  73. }
  74. // porcja - ile wektorów dostaje jeden proces do liczenia
  75. // jeżeli liczba procesów większa od wektorów - każdy proces dostaje po jednym, niektóre wcale
  76. long porcja = (rozmiar>=ntasks) ? (long)round(rozmiar*1.0/ntasks) : 1;
  77. porcja *= rozmiar; //porcję mnożymy przez ilość elementów w jednym wektorze
  78. porcja_new = porcja;
  79. // dla kompatybilności liczę jeszcze rozmiar bufora odbioru,
  80. // np. jeżeli chunki będą jednolitego rozmiaru, a ostatni będzie większy
  81. // to bufor odbioru musi być zwiększony (żeby go nie ucinało)
  82. buff_max = (rozmiar - (porcja/rozmiar)*(ntasks-1))*rozmiar;
  83. if (porcja > buff_max)
  84. buff_max = porcja; // na wypadek, jeżeli jednak ostatni kawałek będzie mniejszy
  85. if (taskid == 0)
  86. vect_alloc(C_rot, ntasks*buff_max);
  87. array_alloc(C, rozmiar);
  88. vect_alloc(vect, porcja);
  89. vect_alloc(vect_c, buff_max);
  90. if (taskid == 0)
  91. {
  92. // wypełnienie macierzy A liczbami "losowymi"
  93. for (long i=0; i<rozmiar; ++i)
  94. for (long j=0; j<rozmiar; ++j)
  95. A[i][j] = 3*i+j+1; //test
  96. //A[i][j] = (long)(sin(i) * i * j) % 10;
  97. // wypełnienie macierzy B liczbami "losowymi"
  98. for (long i=0; i<rozmiar; ++i)
  99. for (long j=0; j<rozmiar; ++j)
  100. B[i][j] = j; //test
  101. //B[i][j] = (long)(cos(j) *(i+j)) % 10;
  102. // dokonaj obracania macierzy
  103. for (long i=0; i<rozmiar; ++i)
  104. for (long j=0; j<rozmiar; ++j)
  105. B_rot[i*rozmiar+j] = B[j][i];
  106. }
  107. //wysyłanie macierzy A do wszystkich
  108. MPI::COMM_WORLD.Bcast(&A[0][0], rozmiar*rozmiar, MPI::LONG, 0);
  109. if (taskid == 0 && false)
  110. {
  111. cout << endl << "WEKTOR DANYCH: " << endl;
  112. for (i=0; i<rozmiar*rozmiar; ++i)
  113. cout << B_rot[i] << " ";
  114. cout << endl;
  115. }
  116. MPI::COMM_WORLD.Barrier();
  117. //dla wszystkich lub "rozmiar" procesów należy zadać porcję do obliczenia
  118. MPI::COMM_WORLD.Scatter(&B_rot[0], porcja, MPI::LONG, &vect[0], porcja, MPI::LONG,0);// (rozmiar>=ntasks) ? 0 : ntasks-rozmiar);
  119. //
  120. // część licząca ---------------------------------------------------------------------------------
  121. //
  122. MPI::COMM_WORLD.Barrier();
  123. if (taskid == 0)
  124. tt.Begin();
  125. if (taskid == ntasks -1) //przelicz porcję dla ostatniego procesu (w przypadku dzielenia z resztą)
  126. {
  127. porcja_new = (rozmiar - (porcja/rozmiar)*(ntasks-1))*rozmiar;
  128. // myk jest taki, że muszę podać jakąś niezerową porcję do gathera,
  129. // mimo, że proces nie ma żadnych (sensownych) danych do przetworzenia
  130. if (porcja_new > 0)
  131. porcja = porcja_new;
  132. }
  133. for (i=0; i<porcja_new; ++i)
  134. {
  135. vect_c[i] = 0;
  136. long a_row = i%rozmiar;
  137. long vect_col = (i/rozmiar)*rozmiar;
  138. for (long k=0; k<rozmiar; ++k)
  139. {
  140. vect_c[i] += A[a_row][k]*vect[vect_col];
  141. ++vect_col;
  142. }
  143. }
  144. MPI::COMM_WORLD.Barrier();
  145. if (taskid == 0)
  146. {
  147. long elapsed = tt.End();
  148. cout << "Time: " << elapsed << " ms" << endl;
  149. }
  150. // zwróć wszystko do programu głównego
  151. MPI::COMM_WORLD.Gather(&vect_c[0], buff_max, MPI::LONG, &C_rot[0], buff_max, MPI::LONG, 0);
  152. if (taskid == 0 && false)
  153. {
  154. for (i=0; i<rozmiar*rozmiar; ++i)
  155. {
  156. cout << C_rot[i] << " ";
  157. }
  158. cout << endl;
  159. }
  160. /*
  161. array_destroy(A);
  162. array_destroy(B);
  163. array_destroy(C);
  164. */
  165. MPI::Finalize();
  166. exit(0);
  167. }