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");