Lumiera
The new emerging NLE for GNU/Linux
/*
  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*/