HW2: RC1 - Model version

This commit is contained in:
2025-01-03 14:45:16 +02:00
parent 4dc47bb8f4
commit 1bd0cbb8d0
7 changed files with 116 additions and 70 deletions
+3 -3
View File
@@ -44,15 +44,15 @@ using distValue_t = uint32_t;
/*!
* Session option for each invocation of the executable
*/
struct session_t {
struct config_t {
size_t arraySize{DEFAULT_DATA_SIZE}; //!<
bool validation{false}; //!< Request a full validation at the end, performed by process rank 0
bool ndebug{false}; //!< Skips debug trap on DEBUG builds
bool timing{false}; //!< Enable timing measurements and prints
bool perf{false}; //!< Enable performance timing measurements and prints
bool verbose{false}; //!< Flag to enable verbose output to stdout
};
extern session_t session;
extern config_t config;
#endif /* CONFIG_H_ */
+15 -12
View File
@@ -12,6 +12,7 @@
#include <vector>
#include <algorithm>
//#include <parallel/algorithm>
#include <cmath>
#include <cstdint>
#if !defined DEBUG
@@ -20,8 +21,8 @@
#include <cassert>
#include "utils.hpp"
#include "config.h"
extern Timing TfullSort, Texchange, Tminmax, TelbowSort;
/*!
* Enumerator for the different versions of the sorting method
@@ -159,11 +160,13 @@ bool isActive(mpi_id_t node, size_t nodes);
*/
template<typename RangeT>
void fullSort(RangeT& data, bool ascending) noexcept {
// Use introsort from stdlib++ here, unless ...
if (ascending)
// Use introsort from stdlib++ here, unless ... __gnu_parallel
if (ascending) {
std::sort(data.begin(), data.end(), std::less<>());
else
}
else {
std::sort(data.begin(), data.end(), std::greater<>());
}
}
/*!
@@ -270,7 +273,7 @@ void minmax(RangeT& local, const RangeT& remote, bool keepSmall) noexcept {
template<typename ShadowedDataT>
void distBubbletonic(ShadowedDataT& data, mpi_id_t Processes, mpi_id_t rank) {
// Initially sort to create a half part of a bitonic sequence
fullSort(data, ascending<SortMode::Bubbletonic>(rank, 0));
timeCall(TfullSort, fullSort, data, ascending<SortMode::Bubbletonic>(rank, 0));
// Sort network (O(N) iterations)
for (size_t step = 0; step < static_cast<size_t>(Processes); ++step) {
@@ -280,9 +283,9 @@ void distBubbletonic(ShadowedDataT& data, mpi_id_t Processes, mpi_id_t rank) {
if ( isActive(rank, Processes) &&
isActive(part, Processes) ) {
// Exchange with partner, keep nim-or-max and sort - O(N)
mpi.exchange(data.getActive(), data.getShadow(), part, step);
minmax(data.getActive(), data.getShadow(), ks);
elbowSort(data, ascending<SortMode::Bubbletonic>(rank, Processes));
timeCall(Texchange, mpi.exchange, data.getActive(), data.getShadow(), part, step);
timeCall(Tminmax, minmax, data.getActive(), data.getShadow(), ks);
timeCall(TelbowSort, elbowSort, data, ascending<SortMode::Bubbletonic>(rank, Processes));
}
}
@@ -308,7 +311,7 @@ void distBubbletonic(ShadowedDataT& data, mpi_id_t Processes, mpi_id_t rank) {
template<typename ShadowedDataT>
void distBitonic(ShadowedDataT& data, mpi_id_t Processes, mpi_id_t rank) {
// Initially sort to create a half part of a bitonic sequence
fullSort(data, ascending<SortMode::Bitonic>(rank, 0));
timeCall(TfullSort, fullSort, data, ascending<SortMode::Bitonic>(rank, 0));
// Run through sort network using elbow-sort ( O(LogN * LogN) iterations )
auto p = static_cast<uint32_t>(std::log2(Processes));
@@ -319,11 +322,11 @@ void distBitonic(ShadowedDataT& data, mpi_id_t Processes, mpi_id_t rank) {
auto part = partner<SortMode::Bitonic>(rank, step);
auto ks = keepSmall<SortMode::Bitonic>(rank, part, depth);
// Exchange with partner, keep nim-or-max
mpi.exchange(data.getActive(), data.getShadow(), part, (depth << 8) | step);
minmax(data.getActive(), data.getShadow(), ks);
timeCall(Texchange, mpi.exchange, data.getActive(), data.getShadow(), part, (depth << 8) | step);
timeCall(Tminmax, minmax, data.getActive(), data.getShadow(), ks);
}
// sort - O(N)
elbowSort (data, ascending<SortMode::Bitonic>(rank, depth));
timeCall(TelbowSort, elbowSort, data, ascending<SortMode::Bitonic>(rank, depth));
}
}
+54 -21
View File
@@ -14,6 +14,7 @@
#include <chrono>
#include <unistd.h>
#include <mpi.h>
//#include <functional>
#include "config.h"
@@ -286,7 +287,7 @@ struct Log {
//! We provide logging via << operator
template<typename T>
Log &operator<<(T &&t) {
if (session.verbose) {
if (config.verbose) {
if (line_) {
std::cout << "[Log]: " << t;
line_ = false;
@@ -299,7 +300,7 @@ struct Log {
// overload for special end line handling
Log &operator<<(Endl e) {
(void) e;
if (session.verbose) {
if (config.verbose) {
std::cout << '\n';
line_ = true;
}
@@ -317,39 +318,71 @@ extern Log logger;
*/
struct Timing {
using Tpoint = std::chrono::steady_clock::time_point;
using Tduration = std::chrono::microseconds;
using microseconds = std::chrono::microseconds;
using milliseconds = std::chrono::milliseconds;
using seconds = std::chrono::seconds;
//! tool to mark the starting point
Tpoint start() noexcept { return start_ = std::chrono::steady_clock::now(); }
Tpoint start() noexcept { return mark_ = std::chrono::steady_clock::now(); }
//! tool to mark the ending point
Tpoint stop() noexcept { return stop_ = std::chrono::steady_clock::now(); }
Tpoint stop() noexcept {
Tpoint now = std::chrono::steady_clock::now();
duration_ += dt(now, mark_);
return now;
}
auto dt() noexcept {
return std::chrono::duration_cast<std::chrono::microseconds>(stop_ - start_).count();
Tduration dt(Tpoint t2, Tpoint t1) noexcept {
return std::chrono::duration_cast<Tduration>(t2 - t1);
}
//! tool to print the time interval
void print_dt(const char *what) noexcept {
if (session.timing) {
auto t = stop_ - start_;
if (std::chrono::duration_cast<microseconds>(t).count() < 10000)
std::cout << "[Timing]: " << what << ": "
<< std::to_string(std::chrono::duration_cast<microseconds>(t).count()) << " [usec]\n";
else if (std::chrono::duration_cast<milliseconds>(t).count() < 10000)
std::cout << "[Timing]: " << what << ": "
<< std::to_string(std::chrono::duration_cast<milliseconds>(t).count()) << " [msec]\n";
else
std::cout << "[Timing]: " << what << ": "
<< std::to_string(std::chrono::duration_cast<seconds>(t).count()) << " [sec]\n";
}
void print_duration(const char *what, mpi_id_t rank) noexcept {
if (std::chrono::duration_cast<microseconds>(duration_).count() < 10000)
std::cout << "[Timing] (Rank " << rank << ") " << what << ": "
<< std::to_string(std::chrono::duration_cast<microseconds>(duration_).count()) << " [usec]\n";
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";
}
private:
Tpoint start_;
Tpoint stop_;
Tpoint mark_{};
Tduration duration_{};
};
/*!
* Utility high level function to forward a function call to std::invoke and measure
* the excecution time
*
* @tparam Func The function type
* @tparam Args The argument
* @param func
* @param args
* @return
*/
#define timeCall(Tim, Func, ...) \
Tim.start(); \
Func(__VA_ARGS__); \
Tim.stop(); \
//template <typename Ret, typename Func, typename... Args>
//auto timeCall_r(Ret& ret, Func&& func, Args&&... args) {
// Timing timer;
//
// timer.start();
// ret = std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
// timer.stop();
//
// return timer.dt();
//}
#endif /* UTILS_HPP_ */