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.

172 lines
4.1 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. int main(int argc, char *argv[])
  36. {
  37. long **A=NULL, **B=NULL, *B_rot=NULL, *vect=NULL, *vect_c=NULL, *C_rot=NULL;
  38. long rozmiar=0, porcja_new=0, buff_max=0;
  39. char *endptr;
  40. TTiming tt;
  41. long i;
  42. MPI::Status status;
  43. if (argc < 2)
  44. {
  45. cerr << "Usage: " << argv[0] << " <size>" << endl;
  46. exit(1);
  47. }
  48. rozmiar = strtol(argv[1], &endptr, 10);
  49. if (*endptr)
  50. {
  51. cerr << "Invalid array size format" << endl;
  52. exit(1);
  53. }
  54. if (rozmiar <= 0)
  55. {
  56. cerr << "The number of matrix dimension must be positive" << endl;
  57. exit(1);
  58. }
  59. MPI::Init(argc, argv);
  60. int taskid = MPI::COMM_WORLD.Get_rank();
  61. int ntasks = MPI::COMM_WORLD.Get_size();
  62. //alokacja macierzy
  63. array_alloc(A, rozmiar);
  64. if (taskid == 0)
  65. {
  66. array_alloc(B, rozmiar);
  67. vect_alloc(B_rot, rozmiar*rozmiar);
  68. }
  69. // porcja - ile wektorów dostaje jeden proces do liczenia
  70. // jeżeli liczba procesów większa od wektorów - każdy proces dostaje po jednym, niektóre wcale
  71. long porcja = (rozmiar>=ntasks) ? (long)round(rozmiar*1.0/ntasks) : 1;
  72. porcja *= rozmiar; //porcję mnożymy przez ilość elementów w jednym wektorze
  73. porcja_new = porcja;
  74. // dla kompatybilności liczę jeszcze rozmiar bufora odbioru,
  75. // np. jeżeli chunki będą jednolitego rozmiaru, a ostatni będzie większy
  76. // to bufor odbioru musi być zwiększony (żeby go nie ucinało)
  77. buff_max = (rozmiar - (porcja/rozmiar)*(ntasks-1))*rozmiar;
  78. if (porcja > buff_max)
  79. buff_max = porcja; // na wypadek, jeżeli jednak ostatni kawałek będzie mniejszy
  80. if (taskid == 0)
  81. vect_alloc(C_rot, ntasks*buff_max);
  82. vect_alloc(vect, porcja);
  83. vect_alloc(vect_c, buff_max);
  84. if (taskid == 0)
  85. {
  86. // wypełnienie macierzy A liczbami "losowymi"
  87. for (long i=0; i<rozmiar; ++i)
  88. for (long j=0; j<rozmiar; ++j)
  89. //A[i][j] = 3*i+j+1; //test
  90. A[i][j] = (long)(sin(i) * i * j) % 10;
  91. // wypełnienie macierzy B liczbami "losowymi"
  92. for (long i=0; i<rozmiar; ++i)
  93. for (long j=0; j<rozmiar; ++j)
  94. //B[i][j] = j; //test
  95. B[i][j] = (long)(cos(j) *(i+j)) % 10;
  96. // dokonaj obracania macierzy
  97. for (long i=0; i<rozmiar; ++i)
  98. for (long j=0; j<rozmiar; ++j)
  99. B_rot[i*rozmiar+j] = B[j][i];
  100. }
  101. //wysyłanie macierzy A do wszystkich
  102. MPI::COMM_WORLD.Bcast(&A[0][0], rozmiar*rozmiar, MPI::LONG, 0);
  103. MPI::COMM_WORLD.Barrier();
  104. //dla wszystkich lub "rozmiar" procesów należy zadać porcję do obliczenia
  105. MPI::COMM_WORLD.Scatter(&B_rot[0], porcja, MPI::LONG, &vect[0], porcja, MPI::LONG, 0);
  106. //
  107. // część licząca ---------------------------------------------------------------------------------
  108. //
  109. MPI::COMM_WORLD.Barrier();
  110. if (taskid == 0)
  111. tt.Begin();
  112. if (taskid == ntasks -1) //przelicz porcję dla ostatniego procesu (w przypadku dzielenia z resztą)
  113. {
  114. porcja_new = (rozmiar - (porcja/rozmiar)*(ntasks-1))*rozmiar;
  115. // myk jest taki, że muszę podać jakąś niezerową porcję do gathera,
  116. // mimo, że proces nie ma żadnych (sensownych) danych do przetworzenia
  117. if (porcja_new > 0)
  118. porcja = porcja_new;
  119. }
  120. for (i=0; i<porcja_new; ++i)
  121. {
  122. vect_c[i] = 0;
  123. long a_row = i%rozmiar;
  124. long vect_col = (i/rozmiar)*rozmiar;
  125. for (long k=0; k<rozmiar; ++k)
  126. {
  127. vect_c[i] += A[a_row][k]*vect[vect_col];
  128. ++vect_col;
  129. }
  130. }
  131. MPI::COMM_WORLD.Barrier();
  132. if (taskid == 0)
  133. {
  134. long elapsed = tt.End();
  135. cout << "Time: " << elapsed << " ms" << endl;
  136. }
  137. // zwróć wszystko do programu głównego
  138. MPI::COMM_WORLD.Gather(&vect_c[0], buff_max, MPI::LONG, &C_rot[0], buff_max, MPI::LONG, 0);
  139. MPI::Finalize();
  140. exit(0);
  141. }