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.
 
 
 
 
 
 

307 lignes
10 KiB

  1. /**
  2. * \file
  3. * \brief Utilities header
  4. *
  5. * \author
  6. * Christos Choutouridis AEM:8997
  7. * <cchoutou@ece.auth.gr>
  8. */
  9. #ifndef UTILS_HPP_
  10. #define UTILS_HPP_
  11. #include <vector>
  12. #include <iostream>
  13. #include <chrono>
  14. #include <unistd.h>
  15. #include <mpi.h>
  16. //#include "matrix.hpp"
  17. #include "config.h"
  18. template <typename T> struct MPI_TypeMapper;
  19. // Specializations for supported types
  20. template <> struct MPI_TypeMapper<char> { static MPI_Datatype getType() { return MPI_CHAR; } };
  21. template <> struct MPI_TypeMapper<unsigned char> { static MPI_Datatype getType() { return MPI_UNSIGNED_CHAR; } };
  22. template <> struct MPI_TypeMapper<short> { static MPI_Datatype getType() { return MPI_SHORT; } };
  23. template <> struct MPI_TypeMapper<int> { static MPI_Datatype getType() { return MPI_INT; } };
  24. template <> struct MPI_TypeMapper<long> { static MPI_Datatype getType() { return MPI_LONG; } };
  25. template <> struct MPI_TypeMapper<long long> { static MPI_Datatype getType() { return MPI_LONG_LONG; } };
  26. template <> struct MPI_TypeMapper<unsigned short>{ static MPI_Datatype getType() { return MPI_UNSIGNED_SHORT; } };
  27. template <> struct MPI_TypeMapper<unsigned int> { static MPI_Datatype getType() { return MPI_UNSIGNED; } };
  28. template <> struct MPI_TypeMapper<unsigned long> { static MPI_Datatype getType() { return MPI_UNSIGNED_LONG; } };
  29. template <> struct MPI_TypeMapper<unsigned long long> { static MPI_Datatype getType() { return MPI_UNSIGNED_LONG_LONG; } };
  30. template <> struct MPI_TypeMapper<float> { static MPI_Datatype getType() { return MPI_FLOAT; } };
  31. template <> struct MPI_TypeMapper<double> { static MPI_Datatype getType() { return MPI_DOUBLE; } };
  32. template<typename TID = int>
  33. struct MPI_t {
  34. using ID_t = TID; // Export TID type (currently int defined by the standard)
  35. void init(int *argc, char ***argv) {
  36. // Initialize the MPI environment
  37. MPI_Init(argc, argv);
  38. initialized_ = true;
  39. // Get the number of processes
  40. int size_value, rank_value;
  41. MPI_Comm_size(MPI_COMM_WORLD, &size_value);
  42. MPI_Comm_rank(MPI_COMM_WORLD, &rank_value);
  43. size_ = static_cast<ID_t>(size_value);
  44. rank_ = static_cast<ID_t>(rank_value);
  45. // Get the name of the processor
  46. char processor_name[MPI_MAX_PROCESSOR_NAME];
  47. int name_len;
  48. MPI_Get_processor_name(processor_name, &name_len);
  49. name_ = std::string (processor_name, name_len);
  50. }
  51. template<typename T>
  52. void exchange(ID_t partner, const std::vector<T>& send_data, std::vector<T>& recv_data, int tag) {
  53. using namespace std::string_literals;
  54. MPI_Status status;
  55. MPI_Datatype datatype = MPI_TypeMapper<T>::getType();
  56. int send_count = static_cast<int>(send_data.size());
  57. int err = MPI_Sendrecv(
  58. send_data.data(), send_count, datatype, partner, tag,
  59. recv_data.data(), send_count, datatype, partner, tag,
  60. MPI_COMM_WORLD, &status
  61. );
  62. if (err != MPI_SUCCESS) {
  63. char err_msg[MPI_MAX_ERROR_STRING];
  64. int msg_len;
  65. MPI_Error_string(err, err_msg, &msg_len);
  66. throw std::runtime_error("(MPI) MPI_Sendrecv() - " + std::string (err_msg) + '\n');
  67. }
  68. }
  69. // Accessors
  70. [[nodiscard]] ID_t rank() const noexcept { return rank_; }
  71. [[nodiscard]] ID_t size() const noexcept { return size_; }
  72. [[nodiscard]] const std::string& name() const noexcept { return name_; }
  73. void finalize() {
  74. // Finalize the MPI environment
  75. initialized_ = false;
  76. MPI_Finalize();
  77. }
  78. ~MPI_t() {
  79. // Finalize the MPI environment even on unexpected errors
  80. if (initialized_)
  81. MPI_Finalize();
  82. }
  83. private:
  84. ID_t rank_{};
  85. ID_t size_{};
  86. std::string name_{};
  87. bool initialized_{};
  88. };
  89. extern MPI_t<> mpi;
  90. using mpi_id_t = MPI_t<>::ID_t;
  91. template <typename Value_t>
  92. struct ShadowedVec_t {
  93. // STL requirements
  94. using value_type = Value_t;
  95. using iterator = typename std::vector<Value_t>::iterator;
  96. using const_iterator = typename std::vector<Value_t>::const_iterator;
  97. using size_type = typename std::vector<Value_t>::size_type;
  98. // Default constructor
  99. ShadowedVec_t() = default;
  100. // Constructor from an std::vector
  101. explicit ShadowedVec_t(const std::vector<Value_t>& vec)
  102. : North(vec), South(), active(north) {
  103. South.resize(North.size());
  104. }
  105. explicit ShadowedVec_t(std::vector<Value_t>&& vec)
  106. : North(std::move(vec)), South(), active(north) {
  107. South.resize(North.size());
  108. }
  109. // Copy assignment operator
  110. ShadowedVec_t& operator=(const ShadowedVec_t& other) {
  111. if (this != &other) { // Avoid self-assignment
  112. North = other.North;
  113. South = other.South;
  114. active = other.active;
  115. }
  116. return *this;
  117. }
  118. // Move assignment operator
  119. ShadowedVec_t& operator=(ShadowedVec_t&& other) noexcept {
  120. if (this != &other) { // Avoid self-assignment
  121. North = std::move(other.North);
  122. South = std::move(other.South);
  123. active = other.active;
  124. // There is no need to zero out other since it is valid but in a non-defined state
  125. }
  126. return *this;
  127. }
  128. // Dispatch to active vector
  129. Value_t& operator[](size_type index) { return getActive()[index]; }
  130. const Value_t& operator[](size_type index) const { return getActive()[index]; }
  131. Value_t& at(size_type index) { return getActive().at(index); }
  132. const Value_t& at(size_type index) const { return getActive().at(index); }
  133. void push_back(const Value_t& value) { getActive().push_back(value); }
  134. void push_back(Value_t&& value) { getActive().push_back(std::move(value)); }
  135. void pop_back() { getActive().pop_back(); }
  136. Value_t& front() { return getActive().front(); }
  137. const Value_t& front() const { return getActive().front(); }
  138. Value_t& back() { return getActive().back(); }
  139. const Value_t& back() const { return getActive().back(); }
  140. iterator begin() { return getActive().begin(); }
  141. const_iterator begin() const { return getActive().begin(); }
  142. iterator end() { return getActive().end(); }
  143. const_iterator end() const { return getActive().end(); }
  144. size_type size() const { return getActive().size(); }
  145. void resize(size_t new_size) {
  146. North.resize(new_size);
  147. South.resize(new_size);
  148. }
  149. void reserve(size_t new_capacity) {
  150. North.reserve(new_capacity);
  151. South.reserve(new_capacity);
  152. }
  153. [[nodiscard]] size_t capacity() const { return getActive().capacity(); }
  154. [[nodiscard]] bool empty() const { return getActive().empty(); }
  155. void clear() { getActive().clear(); }
  156. void swap(std::vector<Value_t>& other) { getActive().swap(other); }
  157. // Switching vectors
  158. void switch_active() { active = (active == north) ? south : north; }
  159. // Accessors
  160. const std::vector<Value_t>& getNorth() const { return North; }
  161. const std::vector<Value_t>& getSouth() const { return South; }
  162. std::vector<Value_t>& getActive() {
  163. return (active == north) ? North : South;
  164. }
  165. const std::vector<Value_t>& getActive() const {
  166. return (active == north) ? North : South;
  167. }
  168. std::vector<Value_t>& getShadow() {
  169. return (active == north) ? South : North;
  170. }
  171. const std::vector<Value_t>& getShadow() const {
  172. return (active == north) ? South : North;
  173. }
  174. // Comparisons
  175. bool operator== (const ShadowedVec_t& other) {
  176. return getActive() == other.getActive();
  177. }
  178. bool operator!= (const ShadowedVec_t& other) {
  179. return getActive() != other.getActive();
  180. }
  181. bool operator== (const std::vector<value_type>& other) {
  182. return getActive() == other;
  183. }
  184. bool operator!= (const std::vector<value_type>& other) {
  185. return getActive() != other;
  186. }
  187. private:
  188. std::vector<Value_t> North{};
  189. std::vector<Value_t> South{};
  190. enum { north, south } active{north};
  191. };
  192. using distBuffer_t = ShadowedVec_t<distValue_t>;
  193. extern distBuffer_t Data;
  194. /*!
  195. * A Logger for entire program.
  196. */
  197. struct Log {
  198. struct Endl {} endl; //!< a tag object to to use it as a new line request.
  199. //! We provide logging via << operator
  200. template<typename T>
  201. Log &operator<<(T &&t) {
  202. if (session.verbose) {
  203. if (line_) {
  204. std::cout << "[Log]: " << t;
  205. line_ = false;
  206. } else
  207. std::cout << t;
  208. }
  209. return *this;
  210. }
  211. // overload for special end line handling
  212. Log &operator<<(Endl e) {
  213. (void) e;
  214. if (session.verbose) {
  215. std::cout << '\n';
  216. line_ = true;
  217. }
  218. return *this;
  219. }
  220. private:
  221. bool line_{true};
  222. };
  223. extern Log logger;
  224. /*!
  225. * A small timing utility based on chrono.
  226. */
  227. struct Timing {
  228. using Tpoint = std::chrono::steady_clock::time_point;
  229. using microseconds = std::chrono::microseconds;
  230. using milliseconds = std::chrono::milliseconds;
  231. using seconds = std::chrono::seconds;
  232. //! tool to mark the starting point
  233. Tpoint start() noexcept { return start_ = std::chrono::steady_clock::now(); }
  234. //! tool to mark the ending point
  235. Tpoint stop() noexcept { return stop_ = std::chrono::steady_clock::now(); }
  236. auto dt() noexcept {
  237. return std::chrono::duration_cast<std::chrono::microseconds>(stop_ - start_).count();
  238. }
  239. //! tool to print the time interval
  240. void print_dt(const char *what) noexcept {
  241. if (session.timing) {
  242. auto t = stop_ - start_;
  243. if (std::chrono::duration_cast<microseconds>(t).count() < 10000)
  244. std::cout << "[Timing]: " << what << ": "
  245. << std::to_string(std::chrono::duration_cast<microseconds>(t).count()) << " [usec]\n";
  246. else if (std::chrono::duration_cast<milliseconds>(t).count() < 10000)
  247. std::cout << "[Timing]: " << what << ": "
  248. << std::to_string(std::chrono::duration_cast<milliseconds>(t).count()) << " [msec]\n";
  249. else
  250. std::cout << "[Timing]: " << what << ": "
  251. << std::to_string(std::chrono::duration_cast<seconds>(t).count()) << " [sec]\n";
  252. }
  253. }
  254. private:
  255. Tpoint start_;
  256. Tpoint stop_;
  257. };
  258. #endif /* UTILS_HPP_ */