4#include <condition_variable>
11#include "SyncInterrupt.h"
17 double mean, M2, variance, count;
28 WelfordStats UpdateCalculateMeanVariance(
const std::vector<double>& vec)
30 double& mean = this->mean, & M2 = this->M2, & variance = this->variance;
31 double& count = this->count;
32 size_t n = vec.size();
33 for (
size_t i = 0; i < n; ++i, ++count)
35 double delta = vec[i] - mean;
36 mean += delta / (count + 1);
37 M2 += delta * (vec[i] - mean);
38 variance = M2 / (count + 1);
53template<
typename DataType,
size_t _Size>
54struct locked_buffer_template
57 std::vector<DataType> data;
61 locked_buffer_template() :
65 this->data.resize(_Size, 0);
75 void AddData(
const DataType& datum)
79 this->data[this->index++] = datum;
84 return !(this->index < _Size);
87template<
typename DataType,
size_t rotating_buffer_count,
size_t rotating_buffer_size>
88class StatisticsBufferTemplate_RSI :
public StatisticsBufferTemplate<DataType> {
92 using locked_buffer = locked_buffer_template<DataType, rotating_buffer_size>;
94 std::array<locked_buffer, rotating_buffer_count> buffers;
97 locked_buffer* buffer_in_use;
99 WelfordStats running_stat;
102 std::mutex mtx_nextData;
103 std::condition_variable cv;
104 std::deque<locked_buffer*> nextData;
106 StatisticsBufferTemplate_RSI() :
108 buffer_in_use(&buffers[0])
117 running_stat.Reset();
118 for (
auto& buf : this->buffers)
120 std::scoped_lock<std::mutex> lock(buf.mutex);
123 this->buffer_in_use->mutex.lock();
127 buffer_in_use->mutex.unlock();
128 this->cv.notify_all();
130 void AddData(
const DataType& datum)
132 this->StatisticsBufferTemplate<DataType>::AddData(datum);
133 if (buffer_in_use->IsFull())
135 this->RotateBuffer();
138 this->buffer_in_use->AddData(datum);
148 std::scoped_lock<std::mutex> lock(this->mtx_nextData);
149 this->nextData.emplace_back(buffer_in_use);
151 this->buffer_idx = (this->buffer_idx + 1) % this->buffers.size();
152 auto* next_buffer = &this->buffers[this->buffer_idx];
154 if (!next_buffer->mutex.try_lock())
161 next_buffer->mutex.lock();
163 next_buffer->Reset();
166 this->buffer_in_use->full =
true;
167 this->buffer_in_use->mutex.unlock();
170 this->buffer_in_use = next_buffer;
171 this->cv.notify_all();
174using StatisticsBufferImpl = StatisticsBufferTemplate_RSI<double, 10, 10>;
180StatisticsBufferImpl buffered_stats_impl;
181StatisticsBuffer& buffered_stats = buffered_stats_impl;
184void StatisticsThread()
186 StatisticsBufferImpl::locked_buffer* buffer;
187 while (!readyToCleanup)
190 std::unique_lock<std::mutex> lock(buffered_stats_impl.mtx_nextData);
191 buffered_stats_impl.cv.wait(lock, [] {
return readyToCleanup || !buffered_stats_impl.nextData.empty(); });
196 buffer = buffered_stats_impl.nextData.front();
197 buffered_stats_impl.nextData.pop_front();
200 if (!buffer->mutex.try_lock())
205 buffer->mutex.lock();
210 buffered_stats_impl.running_stat.UpdateCalculateMeanVariance(buffer->data);
211 buffer->mutex.unlock();
216void PrintTimingInfo()
220 if (print && syncInterruptIterations)
222 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",
223 syncInterruptIterations, deltaMicroseconds, buffered_stats_impl.min, buffered_stats_impl.max,
224 buffered_stats_impl.running_stat.mean, buffered_stats_impl.running_stat.variance);
227void printTimingHeaderString()
229 printf(
"Number Processed\t|\tDeltaT (uS)\t|\tMin (uS)\t|\tMax (uS)\t|\tMean (uS)\t|\tVariance\n");