- use a helper class with a series of timer variables - these can be addressed like the buffer ring »slots« - commit each individual measurement into an EMA
106 lines
2.8 KiB
C++
106 lines
2.8 KiB
C++
/*
|
||
commons.hpp - common definitions and utils for the io_uring video output demo code
|
||
|
||
Copyright (C)
|
||
2026 Hermann Vosseler <Ichthyostega@web.de>
|
||
|
||
This program is free software; you can redistribute it and/or modify it
|
||
under the terms of the GNU GPL version 2+ See the LICENSE file for details.
|
||
|
||
* ************************************************************************/
|
||
|
||
#ifndef COMMONS_H
|
||
#define COMMONS_H
|
||
|
||
|
||
#include <cstdint>
|
||
#include <iostream>
|
||
#include <chrono>
|
||
#include <string>
|
||
#include <array>
|
||
|
||
#include <linux/time_types.h> // for struct __kernel_timespec
|
||
|
||
using std::string;
|
||
using uint = unsigned int;
|
||
using FrameRate = uint;
|
||
|
||
|
||
inline void
|
||
__FAIL (string msg)
|
||
{
|
||
std::cerr << "FAIL: " << msg << std::endl;
|
||
std::abort();
|
||
}
|
||
|
||
/**
|
||
* Marker class: any copy and copy construction prohibited
|
||
*/
|
||
class NonCopyable
|
||
{
|
||
protected:
|
||
~NonCopyable() = default;
|
||
NonCopyable() = default;
|
||
NonCopyable (NonCopyable const&) = delete;
|
||
NonCopyable& operator= (NonCopyable const&) = delete;
|
||
};
|
||
|
||
|
||
|
||
/**
|
||
* Generate a kernel timespec from a given C++ chrono duration
|
||
*/
|
||
template<class REP, class SCALE>
|
||
constexpr struct __kernel_timespec
|
||
asKernelTimespec (std::chrono::duration<REP, SCALE> dur)
|
||
{
|
||
using namespace std::chrono;
|
||
auto secs = duration_cast<seconds>(dur);
|
||
auto nsecs = duration_cast<nanoseconds>(dur - secs);
|
||
return __kernel_timespec{ static_cast<long long> (secs.count())
|
||
, static_cast<long long> (nsecs.count())
|
||
};
|
||
}
|
||
|
||
|
||
/**
|
||
* A series of timers for performance measurement, that can be used in interleaved.
|
||
* When marking the end of each timed interval, the resulting duration is committed
|
||
* into an exponential moving average of all observed timings.
|
||
* @note not threadsafe, only to be used from within a single thread.
|
||
*/
|
||
template<uint cnt, uint ema_period>
|
||
class OverlappingTimers
|
||
{
|
||
using Scale = std::micro; // timings in µs
|
||
using Clock = std::chrono::steady_clock;
|
||
using Time = decltype(Clock::now());
|
||
using Dur = std::chrono::duration<double, Scale>;
|
||
|
||
std::array<Time, cnt> timer_{Time{}};
|
||
|
||
/** damping factor to compute exponential moving average
|
||
EMA(i) = value(i)/N + (N-1)/N · EMA(i-1) */
|
||
static constexpr double ALPHA = 1.0 / ema_period;
|
||
double expMA_{1};
|
||
|
||
public:
|
||
double expMA() { return expMA_; }
|
||
|
||
void
|
||
markStart (uint timerID)
|
||
{
|
||
timer_[timerID % cnt] = Clock::now();
|
||
}
|
||
|
||
double
|
||
markStop (uint timerID)
|
||
{
|
||
Dur duration = Clock::now () - timer_[timerID % cnt];
|
||
double runTime = duration.count();
|
||
expMA_ = ALPHA * runTime + (1-ALPHA) * expMA_;
|
||
return runTime;
|
||
}
|
||
};
|
||
|
||
#endif /*COMMONS_H*/
|