AUTH's THMMY "Parallel and distributed systems" course assignments.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

477 lignes
16 KiB

  1. /**
  2. * \file
  3. * \brief PDS HW2 tests
  4. *
  5. * To run these test execute:
  6. * export OMP_NUM_THREADS=4 # optional to see parallelization speed-up
  7. * make tests
  8. * mpirun -np <N> ./out/tests
  9. *
  10. * Note:
  11. * Yes each process runs the entire test suite!!
  12. *
  13. * \author
  14. * Christos Choutouridis AEM:8997
  15. * <cchoutou@ece.auth.gr>
  16. */
  17. #include <gtest/gtest.h>
  18. #include <mpi.h>
  19. #include <random>
  20. #include "distsort.hpp"
  21. /*
  22. * Global fixtures
  23. */
  24. // MPI handler for the test session
  25. MPI_t<> ts_mpi;
  26. // Mersenne seeded from hw if possible. range: [type_min, type_max]
  27. std::random_device ts_rd;
  28. std::mt19937 ts_gen(ts_rd());
  29. class TMPIdistSort : public ::testing::Test {
  30. protected:
  31. static void SetUpTestSuite() {
  32. int argc = 0;
  33. char** argv = nullptr;
  34. ts_mpi.init(&argc, &argv);
  35. }
  36. static void TearDownTestSuite() {
  37. ts_mpi.finalize();
  38. }
  39. };
  40. /*
  41. * MPI: SysTest (acceptance)
  42. * Each process executes distBubbletonic for uin8_t [16]
  43. */
  44. TEST_F(TMPIdistSort, distBubbletonic_test1) {
  45. // Create and fill vector
  46. using tsValue_t = uint8_t; // Test parameters
  47. size_t ts_buffer_size = 16;
  48. ShadowedVec_t<tsValue_t> ts_Data;
  49. std::uniform_int_distribution<tsValue_t > dis(
  50. std::numeric_limits<tsValue_t>::min(),
  51. std::numeric_limits<tsValue_t>::max()
  52. );
  53. ts_Data.resize(ts_buffer_size);
  54. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  55. // Execute function under test in all processes
  56. distBubbletonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  57. // Local min and max
  58. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  59. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  60. // Gather min/max to rank 0
  61. std::vector<tsValue_t> global_mins(ts_mpi.size());
  62. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  63. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  64. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  65. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  66. // Check results
  67. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  68. if (ts_mpi.rank() == 0) {
  69. for (size_t i = 1; i < global_mins.size(); ++i) {
  70. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  71. }
  72. }
  73. }
  74. /*
  75. * MPI: SysTest (acceptance)
  76. * Each process executes distBubbletonic for uin32_t [1 << 16]
  77. */
  78. TEST_F(TMPIdistSort, distBubbletonic_test2) {
  79. // Create and fill vector
  80. using tsValue_t = uint32_t; // Test parameters
  81. size_t ts_buffer_size = 1 << 16;
  82. ShadowedVec_t<tsValue_t> ts_Data;
  83. std::uniform_int_distribution<tsValue_t > dis(
  84. std::numeric_limits<tsValue_t>::min(),
  85. std::numeric_limits<tsValue_t>::max()
  86. );
  87. ts_Data.resize(ts_buffer_size);
  88. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  89. // Execute function under test in all processes
  90. distBubbletonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  91. // Local min and max
  92. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  93. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  94. // Gather min/max to rank 0
  95. std::vector<tsValue_t> global_mins(ts_mpi.size());
  96. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  97. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  98. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  99. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  100. // Check results
  101. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  102. if (ts_mpi.rank() == 0) {
  103. for (size_t i = 1; i < global_mins.size(); ++i) {
  104. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  105. }
  106. }
  107. }
  108. /*
  109. * MPI: SysTest (acceptance)
  110. * Each process executes distBubbletonic for uin32_t [1 << 16] with pipeline
  111. */
  112. TEST_F(TMPIdistSort, distBubbletonic_test3) {
  113. // Create and fill vector
  114. using tsValue_t = uint32_t; // Test parameters
  115. size_t ts_buffer_size = 1 << 16;
  116. ShadowedVec_t<tsValue_t> ts_Data;
  117. std::uniform_int_distribution<tsValue_t > dis(
  118. std::numeric_limits<tsValue_t>::min(),
  119. std::numeric_limits<tsValue_t>::max()
  120. );
  121. ts_Data.resize(ts_buffer_size);
  122. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  123. // Set pipeline
  124. config.pipeline = 8;
  125. // Execute function under test in all processes
  126. distBubbletonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  127. // Local min and max
  128. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  129. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  130. // Gather min/max to rank 0
  131. std::vector<tsValue_t> global_mins(ts_mpi.size());
  132. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  133. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  134. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  135. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  136. // Check results
  137. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  138. if (ts_mpi.rank() == 0) {
  139. for (size_t i = 1; i < global_mins.size(); ++i) {
  140. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  141. }
  142. }
  143. }
  144. /*
  145. * MPI: SysTest (acceptance)
  146. * Each process executes distBubbletonic for uin32_t [1 << 16] with exchange optimization
  147. */
  148. TEST_F(TMPIdistSort, distBubbletonic_test4) {
  149. // Create and fill vector
  150. using tsValue_t = uint32_t; // Test parameters
  151. size_t ts_buffer_size = 1 << 16;
  152. ShadowedVec_t<tsValue_t> ts_Data;
  153. std::uniform_int_distribution<tsValue_t > dis(
  154. std::numeric_limits<tsValue_t>::min(),
  155. std::numeric_limits<tsValue_t>::max()
  156. );
  157. ts_Data.resize(ts_buffer_size);
  158. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  159. // Set exchange optimization
  160. config.exchangeOpt = true;
  161. // Execute function under test in all processes
  162. distBubbletonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  163. // Local min and max
  164. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  165. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  166. // Gather min/max to rank 0
  167. std::vector<tsValue_t> global_mins(ts_mpi.size());
  168. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  169. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  170. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  171. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  172. // Check results
  173. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  174. if (ts_mpi.rank() == 0) {
  175. for (size_t i = 1; i < global_mins.size(); ++i) {
  176. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  177. }
  178. }
  179. }
  180. /*
  181. * MPI: SysTest (acceptance)
  182. * Each process executes distBubbletonic for uin32_t [1 << 16] with
  183. * exchange optimization and pipeline
  184. */
  185. TEST_F(TMPIdistSort, distBubbletonic_test5) {
  186. // Create and fill vector
  187. using tsValue_t = uint32_t; // Test parameters
  188. size_t ts_buffer_size = 1 << 16;
  189. ShadowedVec_t<tsValue_t> ts_Data;
  190. std::uniform_int_distribution<tsValue_t > dis(
  191. std::numeric_limits<tsValue_t>::min(),
  192. std::numeric_limits<tsValue_t>::max()
  193. );
  194. ts_Data.resize(ts_buffer_size);
  195. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  196. // Set exchange optimization + pipeline
  197. config.exchangeOpt = true;
  198. config.pipeline = 8;
  199. // Execute function under test in all processes
  200. distBubbletonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  201. // Local min and max
  202. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  203. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  204. // Gather min/max to rank 0
  205. std::vector<tsValue_t> global_mins(ts_mpi.size());
  206. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  207. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  208. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  209. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  210. // Check results
  211. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  212. if (ts_mpi.rank() == 0) {
  213. for (size_t i = 1; i < global_mins.size(); ++i) {
  214. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  215. }
  216. }
  217. }
  218. /*
  219. * MPI: SysTest (acceptance)
  220. * Each process executes distBitonic for uin8_t [16]
  221. */
  222. TEST_F(TMPIdistSort, distBitonic_test1) {
  223. // Create and fill vector
  224. using tsValue_t = uint8_t; // Test parameters
  225. size_t ts_buffer_size = 16;
  226. ShadowedVec_t<tsValue_t> ts_Data;
  227. std::uniform_int_distribution<tsValue_t > dis(
  228. std::numeric_limits<tsValue_t>::min(),
  229. std::numeric_limits<tsValue_t>::max()
  230. );
  231. ts_Data.resize(ts_buffer_size);
  232. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  233. // Execute function under test in all processes
  234. distBitonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  235. // Local min and max
  236. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  237. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  238. // Gather min/max to rank 0
  239. std::vector<tsValue_t> global_mins(ts_mpi.size());
  240. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  241. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  242. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  243. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  244. // Check results
  245. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  246. if (ts_mpi.rank() == 0) {
  247. for (size_t i = 1; i < global_mins.size(); ++i) {
  248. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  249. }
  250. }
  251. }
  252. /*
  253. * MPI: SysTest (acceptance)
  254. * Each process executes distBitonic for uin32_t [1 << 16]
  255. */
  256. TEST_F(TMPIdistSort, distBitonic_test2) {
  257. // Create and fill vector
  258. using tsValue_t = uint32_t; // Test parameters
  259. size_t ts_buffer_size = 1 << 16;
  260. ShadowedVec_t<tsValue_t> ts_Data;
  261. std::uniform_int_distribution<tsValue_t > dis(
  262. std::numeric_limits<tsValue_t>::min(),
  263. std::numeric_limits<tsValue_t>::max()
  264. );
  265. ts_Data.resize(ts_buffer_size);
  266. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  267. // Execute function under test in all processes
  268. distBitonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  269. // Local min and max
  270. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  271. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  272. // Gather min/max to rank 0
  273. std::vector<tsValue_t> global_mins(ts_mpi.size());
  274. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  275. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  276. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  277. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  278. // Check results
  279. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  280. if (ts_mpi.rank() == 0) {
  281. for (size_t i = 1; i < global_mins.size(); ++i) {
  282. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  283. }
  284. }
  285. }
  286. /*
  287. * MPI: SysTest (acceptance)
  288. * Each process executes distBitonic for uin32_t [1 << 16] with pipeline
  289. */
  290. TEST_F(TMPIdistSort, distBitonic_test3) {
  291. // Create and fill vector
  292. using tsValue_t = uint32_t; // Test parameters
  293. size_t ts_buffer_size = 1 << 16;
  294. ShadowedVec_t<tsValue_t> ts_Data;
  295. std::uniform_int_distribution<tsValue_t > dis(
  296. std::numeric_limits<tsValue_t>::min(),
  297. std::numeric_limits<tsValue_t>::max()
  298. );
  299. ts_Data.resize(ts_buffer_size);
  300. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  301. // Set pipeline
  302. config.pipeline = 8;
  303. // Execute function under test in all processes
  304. distBitonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  305. // Local min and max
  306. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  307. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  308. // Gather min/max to rank 0
  309. std::vector<tsValue_t> global_mins(ts_mpi.size());
  310. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  311. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  312. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  313. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  314. // Check results
  315. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  316. if (ts_mpi.rank() == 0) {
  317. for (size_t i = 1; i < global_mins.size(); ++i) {
  318. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  319. }
  320. }
  321. }
  322. /*
  323. * MPI: SysTest (acceptance)
  324. * Each process executes distBitonic for uin32_t [1 << 16] with exchange optimization
  325. */
  326. TEST_F(TMPIdistSort, distBitonic_test4) {
  327. // Create and fill vector
  328. using tsValue_t = uint32_t; // Test parameters
  329. size_t ts_buffer_size = 1 << 16;
  330. ShadowedVec_t<tsValue_t> ts_Data;
  331. std::uniform_int_distribution<tsValue_t > dis(
  332. std::numeric_limits<tsValue_t>::min(),
  333. std::numeric_limits<tsValue_t>::max()
  334. );
  335. ts_Data.resize(ts_buffer_size);
  336. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  337. // Set exchange optimization
  338. config.exchangeOpt = true;
  339. // Execute function under test in all processes
  340. distBitonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  341. // Local min and max
  342. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  343. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  344. // Gather min/max to rank 0
  345. std::vector<tsValue_t> global_mins(ts_mpi.size());
  346. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  347. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  348. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  349. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  350. // Check results
  351. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  352. if (ts_mpi.rank() == 0) {
  353. for (size_t i = 1; i < global_mins.size(); ++i) {
  354. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  355. }
  356. }
  357. }
  358. /*
  359. * MPI: SysTest (acceptance)
  360. * Each process executes distBitonic for uin32_t [1 << 16] with
  361. * exchange optimization and pipeline
  362. */
  363. TEST_F(TMPIdistSort, distBitonic_test5) {
  364. // Create and fill vector
  365. using tsValue_t = uint32_t; // Test parameters
  366. size_t ts_buffer_size = 1 << 16;
  367. ShadowedVec_t<tsValue_t> ts_Data;
  368. std::uniform_int_distribution<tsValue_t > dis(
  369. std::numeric_limits<tsValue_t>::min(),
  370. std::numeric_limits<tsValue_t>::max()
  371. );
  372. ts_Data.resize(ts_buffer_size);
  373. std::generate(ts_Data.begin(), ts_Data.end(), [&]() { return dis(ts_gen); });
  374. // Set exchange optimization + pipeline
  375. config.exchangeOpt = true;
  376. config.pipeline = 8;
  377. // Execute function under test in all processes
  378. distBitonic(ts_Data, ts_mpi.size(), ts_mpi.rank());
  379. // Local min and max
  380. auto local_min = *std::min_element(ts_Data.begin(), ts_Data.end());
  381. auto local_max = *std::max_element(ts_Data.begin(), ts_Data.end());
  382. // Gather min/max to rank 0
  383. std::vector<tsValue_t> global_mins(ts_mpi.size());
  384. std::vector<tsValue_t> global_maxes(ts_mpi.size());
  385. MPI_Datatype datatype = MPI_TypeMapper<tsValue_t>::getType();
  386. MPI_Gather(&local_min, 1, datatype, global_mins.data(), 1, datatype, 0, MPI_COMM_WORLD);
  387. MPI_Gather(&local_max, 1, datatype, global_maxes.data(), 1, datatype, 0, MPI_COMM_WORLD);
  388. // Check results
  389. EXPECT_EQ(std::is_sorted(ts_Data.begin(), ts_Data.end()), true);
  390. if (ts_mpi.rank() == 0) {
  391. for (size_t i = 1; i < global_mins.size(); ++i) {
  392. EXPECT_LE(global_maxes[i - 1], global_mins[i]);
  393. }
  394. }
  395. }