PDS/homework_3/src/utils.hpp

153 lines
4.3 KiB
C++

/**
* \file
* \brief Utilities header
*
* \author
* Christos Choutouridis AEM:8997
* <cchoutou@ece.auth.gr>
*/
#ifndef UTILS_HPP_
#define UTILS_HPP_
#include <vector>
#include <iostream>
#include <chrono>
#include <unistd.h>
#include <algorithm>
#include "config.h"
/*!
* A Logger for entire program.
*/
struct Log {
struct Endl {} endl; //!< a tag object to to use it as a new line request.
//! We provide logging via << operator
template<typename T>
Log &operator<<(T &&t) {
if (config.verbose) {
if (line_) {
std::cout << "[Log]: " << t;
line_ = false;
} else
std::cout << t;
}
return *this;
}
// overload for special end line handling
Log &operator<<(Endl e) {
(void) e;
if (config.verbose) {
std::cout << '\n';
line_ = true;
}
return *this;
}
private:
bool line_{true};
};
extern Log logger;
/*!
* A small timing utility based on chrono that supports timing rounds
* and returning the median of them. Time can accumulate to the measurement
* for each round.
*/
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;
//! Setup measurement rounds
void init(size_t rounds) {
duration_.resize(rounds);
for (auto& d : duration_)
d = Tduration::zero();
}
//! tool to mark the starting point
Tpoint start() noexcept { return mark_ = std::chrono::steady_clock::now(); }
//! tool to mark the ending point
Tpoint stop() noexcept {
Tpoint now = std::chrono::steady_clock::now();
duration_[current_] += dt(now, mark_);
return now;
}
//! Switch timing slot
void next() noexcept {
++current_;
current_ %= duration_.size();
}
Tduration& median() noexcept {
std::sort(duration_.begin(), duration_.end());
return duration_[duration_.size()/2];
}
//! A duration calculation utility
static Tduration dt(Tpoint t2, Tpoint t1) noexcept {
return std::chrono::duration_cast<Tduration>(t2 - t1);
}
//! Tool to print the time interval
static void print_duration(const Tduration& duration, const char *what) noexcept {
if (std::chrono::duration_cast<microseconds>(duration).count() < 10000)
std::cout << "[Timing] " << 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] " << what << ": "
<< std::to_string(std::chrono::duration_cast<milliseconds>(duration).count()) << " [msec]\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] " << what << ": " << stime << " [sec]\n";
}
}
private:
size_t current_{0};
Tpoint mark_{};
std::vector<Tduration> duration_{1};
};
/*!
* A "high level function"-like utility macro to forward a function call
* and accumulate the execution time to the corresponding timing object.
*
* @param Tim The Timing object [Needs to have methods start() and stop()]
* @param Func The function name
* @param ... The arguments to pass to function (the preprocessor way)
*/
#define timeCall(Tim, Func, ...) \
Tim.start(); \
Func(__VA_ARGS__); \
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_ */