Program Listing for File time.hpp#
↰ Return to documentation for file (librapid/include/librapid/utils/time.hpp)
#ifndef LIBRAPID_UTILS_TIME_HPP
#define LIBRAPID_UTILS_TIME_HPP
namespace librapid {
namespace time {
constexpr int64_t nanosecond = int64_t(1);
constexpr int64_t microsecond = nanosecond * 1000;
constexpr int64_t millisecond = microsecond * 1000;
constexpr int64_t second = millisecond * 1000;
constexpr int64_t minute = second * 60;
constexpr int64_t hour = minute * 60;
constexpr int64_t day = hour * 24;
} // namespace time
template<int64_t scale = time::second>
LIBRAPID_NODISCARD double now() {
using namespace std::chrono;
#if defined(LIBRAPID_OS_WINDOWS)
using rep = int64_t;
using period = std::nano;
using duration = std::chrono::duration<rep, period>;
static const int64_t clockFreq = []() -> int64_t {
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return frequency.QuadPart;
}();
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
return duration(count.QuadPart * static_cast<int64_t>(std::nano::den) / clockFreq).count() /
(double)scale;
#else
return (double)high_resolution_clock::now().time_since_epoch().count() / (double)scale;
#endif
}
constexpr static double sleepOffset = 0;
template<int64_t scale = time::second>
LIBRAPID_ALWAYS_INLINE void sleep(double time) {
using namespace std::chrono;
time *= scale;
auto start = now<time::nanosecond>();
while (now<time::nanosecond>() - start < time - sleepOffset) {}
}
namespace detail {
struct FormattedTime {
double time;
std::string unit;
};
} // namespace detail
template<int64_t scale = time::second>
detail::FormattedTime formatTime(double time) {
double ns = time * scale;
int numUnits = 8;
static std::string prefix[] = {
"ns",
// Should this be !defined(LIBRAPID_NO_WINDOWS_H)?? I'm not on windows currently so can't test this
#if defined(LIBRAPID_OS_WINDOWS) && defined(LIBRAPID_NO_WINDOWS_H)
"µs",
#else
"us",
#endif
"ms",
"s",
"m",
"h",
"d",
"y"
};
static double divisor[] = {1000, 1000, 1000, 60, 60, 24, 365, 1e300};
for (int i = 0; i < numUnits; ++i) {
// if (ns < divisor[i]) return std::operator+(fmt::format(format, ns), prefix[i]);
if (ns < divisor[i]) return {ns, prefix[i]};
ns /= divisor[i];
}
return {ns, prefix[numUnits - 1]};
}
class Timer {
public:
explicit Timer(std::string name = "") :
m_name(std::move(name)), m_start(now<time::nanosecond>()), m_end(-1) {}
Timer(const Timer &) = default;
Timer(Timer &&) = default;
Timer &operator=(const Timer &) = default;
Timer &operator=(Timer &&) = default;
template<size_t scale = time::second>
Timer &setTargetTime(double time) {
m_iters = 0;
m_targetTime = time * (double)scale;
m_start = now<time::nanosecond>();
return *this;
}
void start() {
m_start = now<time::nanosecond>();
m_end = -1;
}
void stop() { m_end = now<time::nanosecond>(); }
void reset() {
m_start = now<time::nanosecond>();
m_end = -1;
}
template<int64_t scale = time::second>
LIBRAPID_NODISCARD double elapsed() const {
if (m_end == -1) return (now<time::nanosecond>() - m_start) / (double)scale;
return (m_end - m_start) / (double)scale;
}
template<int64_t scale = time::second>
LIBRAPID_NODISCARD double average() const {
return elapsed<scale>() / (double)m_iters;
}
bool isRunning() {
++m_iters;
return now<time::nanosecond>() - m_start < m_targetTime;
}
template<typename T, typename Char, typename Ctx>
void str(const fmt::formatter<T, Char> &formatter, Ctx &ctx) const {
double tmpEnd = m_end;
if (tmpEnd < 0) tmpEnd = now<time::nanosecond>();
// return fmt::format(
// "{}Elapsed: {} | Average: {}",
// (m_name.empty() ? "" : m_name + ": "),
// formatTime<time::nanosecond>(tmpEnd - m_start, format),
// formatTime<time::nanosecond>((tmpEnd - m_start) / (double)m_iters, format));
auto [elapsed, elapsedUnit] = formatTime<time::nanosecond>(tmpEnd - m_start);
auto [average, averageUnit] =
formatTime<time::nanosecond>((tmpEnd - m_start) / (double)m_iters);
fmt::format_to(ctx.out(), "{}Elapsed: ", m_name);
formatter.format(elapsed, ctx);
fmt::format_to(ctx.out(), "{} | Average: ", elapsedUnit);
formatter.format(average, ctx);
fmt::format_to(ctx.out(), "{}", averageUnit);
}
private:
std::string m_name = "Timer";
double m_start = 0;
double m_end = 0;
size_t m_iters = 0;
double m_targetTime = 0;
};
} // namespace librapid
template<typename Char>
struct fmt::formatter<librapid::Timer, Char> {
public:
using Base = fmt::formatter<double, Char>;
Base m_base;
template<typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> const char * {
return m_base.parse(ctx);
}
template<typename FormatContext>
FMT_CONSTEXPR auto format(const librapid::Timer &val, FormatContext &ctx) const
-> decltype(ctx.out()) {
val.str(m_base, ctx);
return ctx.out();
}
};
template<typename Char>
struct fmt::formatter<librapid::detail::FormattedTime, Char> {
public:
using Base = fmt::formatter<double, Char>;
Base m_base;
template<typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> const char * {
return m_base.parse(ctx);
}
template<typename FormatContext>
FMT_CONSTEXPR auto format(const librapid::detail::FormattedTime &val, FormatContext &ctx) const
-> decltype(ctx.out()) {
m_base.format(val.time, ctx);
fmt::format_to(ctx.out(), "{}", val.unit);
return ctx.out();
}
};
#endif // LIBRAPID_UTILS_TIME_HPP