4#include <condition_variable> 
   10#include "SyncInterrupt.h" 
   16  double mean, M2, variance, count;
 
   27  WelfordStats UpdateCalculateMeanVariance(
const std::vector<double>& vec)
 
   29    double& mean = this->mean, & M2 = this->M2, & variance = this->variance;
 
   30    double& count = this->count;
 
   31    size_t n = vec.size();
 
   32    for (
size_t i = 0; i < n; ++i, ++count)
 
   34      double delta = vec[i] - mean;
 
   35      mean += delta / (count + 1);
 
   36      M2 += delta * (vec[i] - mean);
 
   37      variance = M2 / (count + 1);
 
   52template<
typename DataType, 
size_t _Size>
 
   53struct locked_buffer_template
 
   56  std::vector<DataType> data;
 
   60  locked_buffer_template() :
 
   64    this->data.resize(_Size, 0);
 
   74  void AddData(
const DataType& datum)
 
   78      this->data[this->index++] = datum;
 
   83    return !(this->index < _Size);
 
   86template<
typename DataType, 
size_t rotating_buffer_count, 
size_t rotating_buffer_size>
 
   87class StatisticsBufferTemplate_RSI : 
public StatisticsBufferTemplate<DataType> {
 
   91  using locked_buffer = locked_buffer_template<DataType, rotating_buffer_size>;
 
   93  std::array<locked_buffer, rotating_buffer_count> buffers;
 
   96  locked_buffer* buffer_in_use;
 
   98  WelfordStats running_stat; 
 
  101  std::mutex mtx_nextData;
 
  102  std::condition_variable cv;
 
  103  std::deque<locked_buffer*> nextData;
 
  105  StatisticsBufferTemplate_RSI() :
 
  107    buffer_in_use(&buffers[0])
 
  116    running_stat.Reset();
 
  117    for (
auto& buf : this->buffers)
 
  119      std::scoped_lock<std::mutex> lock(buf.mutex);
 
  122    this->buffer_in_use->mutex.lock(); 
 
  126    buffer_in_use->mutex.unlock();
 
  127    this->cv.notify_all();
 
  129  void AddData(
const DataType& datum)
 
  131    this->StatisticsBufferTemplate<DataType>::AddData(datum);
 
  132    if (buffer_in_use->IsFull())
 
  134      this->RotateBuffer();
 
  137    this->buffer_in_use->AddData(datum);
 
  147    std::scoped_lock<std::mutex> lock(this->mtx_nextData);
 
  148    this->nextData.emplace_back(buffer_in_use);
 
  150    this->buffer_idx = (this->buffer_idx + 1) % this->buffers.size();
 
  151    auto* next_buffer = &this->buffers[this->buffer_idx];
 
  153    if (!next_buffer->mutex.try_lock())
 
  160      next_buffer->mutex.lock();
 
  162    next_buffer->Reset();
 
  165    this->buffer_in_use->full = 
true;
 
  166    this->buffer_in_use->mutex.unlock();
 
  169    this->buffer_in_use = next_buffer;
 
  170    this->cv.notify_all();
 
  173using StatisticsBufferImpl = StatisticsBufferTemplate_RSI<double, 10, 10>;
 
  179StatisticsBufferImpl buffered_stats_impl;
 
  180StatisticsBuffer& buffered_stats = buffered_stats_impl;
 
  183void StatisticsThread()
 
  185  StatisticsBufferImpl::locked_buffer* buffer;
 
  186  while (!readyToCleanup) 
 
  189      std::unique_lock<std::mutex> lock(buffered_stats_impl.mtx_nextData);
 
  190      buffered_stats_impl.cv.wait(lock, [] { 
return readyToCleanup || !buffered_stats_impl.nextData.empty(); });
 
  195      buffer = buffered_stats_impl.nextData.front();
 
  196      buffered_stats_impl.nextData.pop_front();
 
  199      if (!buffer->mutex.try_lock())
 
  204        buffer->mutex.lock();
 
  209    buffered_stats_impl.running_stat.UpdateCalculateMeanVariance(buffer->data);
 
  210    buffer->mutex.unlock();
 
  215void PrintTimingInfo()
 
  219  if (print && syncInterruptIterations)
 
  221    printf(
"\t\t%ld\t|\t%8.1lfus\t|\t%8.1lfus\t|\t%8.1lfus\t|\t%8.1lfus\t|\t%8.1lf\r",
 
  222      syncInterruptIterations, deltaMicroseconds, buffered_stats_impl.min, buffered_stats_impl.max,
 
  223      buffered_stats_impl.running_stat.mean, buffered_stats_impl.running_stat.variance);
 
  226void printTimingHeaderString()
 
  228  printf(
"Number Processed\t|\tDeltaT (uS)\t|\tMin (uS)\t|\tMax (uS)\t|\tMean (uS)\t|\tVariance\n");