AUTH's THMMY "Parallel and distributed systems" course assignments.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 
 

477 行
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. }