|
|
@@ -65,6 +65,10 @@ struct MPI_t { |
|
|
|
mpi_throw(err, "(MPI) MPI_Comm_rank() - "); |
|
|
|
size_ = static_cast<ID_t>(size_value); |
|
|
|
rank_ = static_cast<ID_t>(rank_value); |
|
|
|
if (size_ > static_cast<ID_t>(MAX_MPI_SIZE)) |
|
|
|
throw std::runtime_error( |
|
|
|
"(MPI) size - Not supported number of nodes [over " + std::to_string(MAX_MPI_SIZE) + "]\n" |
|
|
|
); |
|
|
|
|
|
|
|
// Get the name of the processor |
|
|
|
char processor_name[MPI_MAX_PROCESSOR_NAME]; |
|
|
@@ -74,63 +78,56 @@ struct MPI_t { |
|
|
|
name_ = std::string (processor_name, name_len); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*! |
|
|
|
* Exchange data with partner as part of the sorting network of both bubbletonic or bitonic |
|
|
|
* sorting algorithms. |
|
|
|
* Initiate a data exchange data with partner using non-blocking Isend-Irecv, as part of the |
|
|
|
* sorting network of both bubbletonic or bitonic sorting algorithms. |
|
|
|
* |
|
|
|
* This function matches a transmit and a receive in order for fully exchanged data between |
|
|
|
* current node and partner. |
|
|
|
* @note |
|
|
|
* This call MUST paired with exchange_wait() for each MPI_t object. |
|
|
|
* Calling 2 consecutive exchange_start() for the same MPI_t object is undefined. |
|
|
|
* |
|
|
|
* @tparam T The inner valur type used in buffer |
|
|
|
* @tparam ValueT The underlying value type used in buffers |
|
|
|
* |
|
|
|
* @param ldata [std::vector<T>] Reference to local data to send |
|
|
|
* @param rdata [std::vector<T>] Reference to buffer to receive data from partner |
|
|
|
* @param partner [mpi_id_t] The partner for the exchange |
|
|
|
* @param tag [int] The tag to use for the MPI communication |
|
|
|
* @param ldata [const ValueT*] Pointer to local data to send |
|
|
|
* @param rdata [ValueT*] Pointer to buffer to receive data from partner |
|
|
|
* @param count [size_t] The number of data to exchange |
|
|
|
* @param partner [mpi_id_t] The partner for the exchange |
|
|
|
* @param tag [int] The tag to use for the MPI communication |
|
|
|
*/ |
|
|
|
template<typename T> |
|
|
|
void exchange_data(const std::vector<T>& ldata, std::vector<T>& rdata, ID_t partner, int tag) { |
|
|
|
template<typename ValueT> |
|
|
|
void exchange_start(const ValueT* ldata, ValueT* rdata, size_t count, ID_t partner, int tag) { |
|
|
|
if (tag < 0) |
|
|
|
throw std::runtime_error("(MPI) exchange_data() [tag] - Out of bound"); |
|
|
|
|
|
|
|
MPI_Datatype datatype = MPI_TypeMapper<T>::getType(); |
|
|
|
int count = static_cast<int>(ldata.size()); |
|
|
|
MPI_Status status; |
|
|
|
MPI_Datatype datatype = MPI_TypeMapper<ValueT>::getType(); |
|
|
|
int err; |
|
|
|
if ((err = MPI_Sendrecv( |
|
|
|
ldata.data(), count, datatype, partner, tag, |
|
|
|
rdata.data(), count, datatype, partner, tag, |
|
|
|
MPI_COMM_WORLD, &status |
|
|
|
)) != MPI_SUCCESS) |
|
|
|
mpi_throw(err, "(MPI) MPI_Sendrecv() [data] - "); |
|
|
|
err = MPI_Isend(ldata, count, datatype, partner, tag, MPI_COMM_WORLD, &handle_tx); |
|
|
|
if (err != MPI_SUCCESS) |
|
|
|
mpi_throw(err, "(MPI) MPI_Isend() - "); |
|
|
|
err = MPI_Irecv(rdata, count, datatype, partner, tag, MPI_COMM_WORLD, &handle_rx); |
|
|
|
if (err != MPI_SUCCESS) |
|
|
|
mpi_throw(err, "(MPI) MPI_Irecv() - "); |
|
|
|
} |
|
|
|
|
|
|
|
/*! |
|
|
|
* Exchange a data object with partner as part of the sorting network of both bubbletonic |
|
|
|
* or bitonic sorting algorithms. |
|
|
|
* |
|
|
|
* This function matches a transmit and a receive in order for fully exchanged the data object |
|
|
|
* between current node and partner. |
|
|
|
* Block wait for the completion of the previously called exchange_start() |
|
|
|
* |
|
|
|
* @tparam T The object type |
|
|
|
* |
|
|
|
* @param local [const T&] Reference to the local object to send |
|
|
|
* @param remote [T&] Reference to the object to receive data from partner |
|
|
|
* @param partner [mpi_id_t] The partner for the exchange |
|
|
|
* @param tag [int] The tag to use for the MPI communication |
|
|
|
* @note |
|
|
|
* This call MUST paired with exchange_start() for each MPI_t object. |
|
|
|
* Calling 2 consecutive exchange_wait() for the same MPI_t object is undefined. |
|
|
|
*/ |
|
|
|
template<typename T> |
|
|
|
void exchange_it(const T& local, T& remote, ID_t partner, int tag) { |
|
|
|
if (tag < 0) |
|
|
|
throw std::runtime_error("(MPI) exchange_it() [tag] - Out of bound"); |
|
|
|
void exchange_wait() { |
|
|
|
MPI_Status status; |
|
|
|
|
|
|
|
int err; |
|
|
|
if ((err = MPI_Sendrecv( |
|
|
|
&local, sizeof(T), MPI_BYTE, partner, tag, |
|
|
|
&remote, sizeof(T), MPI_BYTE, partner, tag, |
|
|
|
MPI_COMM_WORLD, &status |
|
|
|
)) != MPI_SUCCESS) |
|
|
|
mpi_throw(err, "(MPI) MPI_Sendrecv() [item] - "); |
|
|
|
if ((err = MPI_Wait(&handle_tx, &status)) != MPI_SUCCESS) |
|
|
|
mpi_throw(err, "(MPI) MPI_Wait() [send] - "); |
|
|
|
|
|
|
|
if ((err = MPI_Wait(&handle_rx, &status)) != MPI_SUCCESS) |
|
|
|
mpi_throw(err, "(MPI) MPI_Wait() [recv] - "); |
|
|
|
} |
|
|
|
|
|
|
|
// Accessors |
|
|
@@ -181,6 +178,8 @@ private: |
|
|
|
ID_t size_{}; //!< MPI total size of the execution |
|
|
|
std::string name_{}; //!< The name of the local machine |
|
|
|
bool initialized_{}; //!< RAII helper flag |
|
|
|
MPI_Request handle_tx{}; //!< MPI async exchange handler for Transmission |
|
|
|
MPI_Request handle_rx{}; //!< MPI async exchange handler for Receptions |
|
|
|
}; |
|
|
|
|
|
|
|
/* |
|
|
@@ -377,9 +376,13 @@ struct Timing { |
|
|
|
else if (std::chrono::duration_cast<milliseconds>(duration_).count() < 10000) |
|
|
|
std::cout << "[Timing] (Rank " << rank << ") " << what << ": " |
|
|
|
<< std::to_string(std::chrono::duration_cast<milliseconds>(duration_).count()) << " [msec]\n"; |
|
|
|
else |
|
|
|
std::cout << "[Timing] (Rank " << rank << ") " << what << ": " |
|
|
|
<< std::to_string(std::chrono::duration_cast<seconds>(duration_).count()) << " [sec]\n"; |
|
|
|
else { |
|
|
|
char stime[26]; // fit ulong |
|
|
|
auto sec = std::chrono::duration_cast<seconds>(duration_).count(); |
|
|
|
auto msec = (std::chrono::duration_cast<milliseconds>(duration_).count() % 1000) / 10; // keep 2 digit |
|
|
|
std::sprintf(stime, "%ld.%1ld", sec, msec); |
|
|
|
std::cout << "[Timing] (Rank " << rank << ") " << what << ": " << stime << " [sec]\n"; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
@@ -402,4 +405,17 @@ private: |
|
|
|
Tim.stop(); \ |
|
|
|
|
|
|
|
|
|
|
|
/*! |
|
|
|
* A utility to check if a number is power of two |
|
|
|
* |
|
|
|
* @tparam Integral The integral type of the number to check |
|
|
|
* @param x The number to check |
|
|
|
* @return True if it is power of 2, false otherwise |
|
|
|
*/ |
|
|
|
template <typename Integral> |
|
|
|
constexpr inline bool isPowerOfTwo(Integral x) noexcept { |
|
|
|
return (!(x & (x - 1)) && x); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#endif /* UTILS_HPP_ */ |