16 mutex.enter(200, __FUNCTION__);
17 this->
binTime = binTimeMS * 1000;
29 mutex.enter(200, __FUNCTION__);
52 while (binShift > 0) {
68 mutex.enter(200, __FUNCTION__);
80 entries[(uint64)oldBin].value += val;
81 entries[(uint64)oldBin].count += count;
104 while (binShift > 0) {
125 if (!
getSum(ms, val, count, now))
134 uint32 ms1, uint32 ms2, uint32 ms3,
135 double& avg1, uint64& count1,
136 double& avg2, uint64& count2,
137 double& avg3, uint64& count3, uint64 now) {
139 double val1 = 0, val2 = 0, val3 = 0;
140 if (!
getSumMulti(ms1, ms2, ms3, val1, count1, val2, count2, val3, count3, now))
143 avg1 = avg2 = avg3 = 0;
145 avg1 = val1 / count1;
147 avg2 = val2 / count2;
149 avg3 = val3 / count3;
155 uint64 bins = ((uint64)ms*1000)/
binTime;
164 mutex.enter(200, __FUNCTION__);
180 for (uint64 n=0; n<bins; n++) {
182 count += entry->
count;
193 uint32 ms1, uint32 ms2, uint32 ms3,
194 double& sum1, uint64& count1,
195 double& sum2, uint64& count2,
196 double& sum3, uint64& count3, uint64 now) {
198 uint64 bins1 = ((uint64)ms1*1000)/
binTime;
200 uint64 bins2 = ((uint64)ms2*1000)/
binTime;
202 uint64 bins3 = ((uint64)ms3*1000)/
binTime;
205 uint64 bins =
clmax(
clmax(bins1, bins2), bins3);
206 sum1 = sum2 = sum3 = 0;
207 count1 = count2 = count3 = 0;
209 mutex.enter(200, __FUNCTION__);
225 for (uint64 n=0; n<bins; n++) {
227 sum1 += entry->
value;
228 count1 += entry->
count;
231 sum2 += entry->
value;
232 count2 += entry->
count;
235 sum3 += entry->
value;
236 count3 += entry->
count;
250 mutex.enter(200, __FUNCTION__);
260 if (!
getSum(ms, val, count, now))
263 double sec = (double)ms/1000.0;
265 valPerSec = val / sec;
266 countPerSec = count / sec;
271bool MovingAverage::getThroughputMulti(uint32 ms1, uint32 ms2, uint32 ms3,
double& valPerSec1,
double& countPerSec1,
double& valPerSec2,
double& countPerSec2,
double& valPerSec3,
double& countPerSec3, uint64 now ) {
273 double val1 = 0, val2 = 0, val3 = 0;
274 uint64 count1 = 0, count2 = 0, count3 = 0;
275 if (!
getSumMulti(ms1, ms2, ms3, val1, count1, val2, count2, val3, count3, now))
278 double sec = (double)ms1/1000.0;
280 valPerSec1 = val1 / sec;
281 countPerSec1 = count1 / sec;
284 sec = (double)ms2/1000.0;
286 valPerSec2 = val2 / sec;
287 countPerSec2 = count2 / sec;
290 sec = (double)ms3/1000.0;
292 valPerSec3 = val3 / sec;
293 countPerSec3 = count3 / sec;
301 uint64 binSize = ((uint64)binMS * 1000) /
binTime;
302 uint64 bins = binNum * binSize;
308 uint32 actualBins = 0;
310 mutex.enter(200, __FUNCTION__);
311 std::string xml =
"";
316 uint32 binCounter = 0;
323 for (uint64 n = 0; n < bins; n++) {
325 count += entry->
count;
330 if (binCounter >= binSize) {
332 xml +=
utils::StringFormat(
"<count=\"%llu\" avg=\"%.6f\" total=\"%.6f\" />\n", count, val / count, val);
342 xml +=
utils::StringFormat(
"<count=\"%llu\" avg=\"%.6f\" total=\"%.6f\" />\n", count, val / count, val);
347 for (uint32 c = actualBins; c < binNum; c++)
356 uint64 binSize = ((uint64)binMS * 1000) /
binTime;
357 uint64 bins = binNum * binSize;
363 uint32 actualBins = 0;
365 mutex.enter(200, __FUNCTION__);
366 std::string json =
"";
371 uint32 binCounter = 0;
378 for (uint64 n = 0; n < bins; n++) {
380 count += entry->
count;
385 if (binCounter >= binSize) {
387 json +=
utils::StringFormat(
"%s{\"count\":%llu ,\"avg\":%.6f, \"total\":%.6f}", json.length() ?
"," :
"", count, val / count, val);
389 json +=
utils::StringFormat(
"%s{\"count\":0 ,\"avg\":0, \"total\":0}", json.length() ?
"," :
"");
397 json +=
utils::StringFormat(
"%s{\"count\":%llu ,\"avg\":%.6f, \"total\":%.6f}", json.length() ?
"," :
"", count, val / count, val);
402 for (uint32 c = actualBins; c < binNum; c++)
403 json +=
utils::StringFormat(
"%s{\"count\":0 ,\"avg\":0, \"total\":0}", json.length() ?
"," :
"");
429 uint32 innerCount = 100000;
430 uint32 outerCount = 30;
434 double val, v1, v2, v3;
441 uint64 totalAdds = 0;
442 for (n=0; n<outerCount; n++) {
444 for (m=0; m<innerCount; m++) {
445 stats.
add(1024, 1, now);
453 unittest::metric(
"add_throughput", (
double)totalAdds / addUs * 1e6,
"ops/s",
true);
461 if (!stats.
getTotal(totVal, totCount)) {
465 if (totCount != totalAdds) {
466 unittest::fail(
"MovingAverage test: getTotal count %llu != expected %llu\n", totCount, totalAdds);
469 if (totVal < (
double)totalAdds * 1024.0 * 0.999 || totVal > (
double)totalAdds * 1024.0 * 1.001) {
470 unittest::fail(
"MovingAverage test: getTotal value %f != expected %f\n", totVal, (
double)totalAdds * 1024.0);
481 for (n=0; n<outerCount; n++) {
482 if (!stats.
getAverage(1000, val, count, now)) {
488 unittest::fail(
"MovingAverage test: getAverage returned zero count\n");
491 if (val < 1023.0 || val > 1025.0) {
492 unittest::fail(
"MovingAverage test: getAverage value %f not ~1024\n", val);
501 for (n=0; n<outerCount; n++) {
502 if (!stats.
getSum(1000, val, count, now)) {
507 if (count == 0 || val <= 0) {
508 unittest::fail(
"MovingAverage test: getSum returned empty window\n");
512 if (val / (
double)count < 1023.0 || val / (
double)count > 1025.0) {
513 unittest::fail(
"MovingAverage test: getSum avg %f not ~1024\n", val / (
double)count);
522 for (n=0; n<outerCount; n++) {
528 if (v1 <= 0 || c1 <= 0) {
529 unittest::fail(
"MovingAverage test: getThroughput non-positive rate\n");
538 for (n=0; n<outerCount; n++) {
540 unittest::fail(
"MovingAverage test: getThroughputMulti failed\n");
544 if (v1 <= 0 || v2 <= 0 || v3 <= 0) {
545 unittest::fail(
"MovingAverage test: getThroughputMulti non-positive rate\n");
549 unittest::detail(
"1sec %s %.3f msg/s 10sec %s %.3f msg/s 30sec %s %.3f msg/s",
560 "Moving average bin stats: add, sum, average, throughput",
"core");
Time-binned moving average / throughput tracker.
Small, dependency-free unit test harness used by all CMSDK object tests.
static bool UnitTest()
Self test.
bool shiftBins(uint64 now)
Advance the circular buffer so the bin containing now becomes current, zeroing expired bins.
bool getSum(uint32 ms, double &val, uint64 &count, uint64 now=GetTimeNow())
Value sum over the last ms milliseconds.
MovingAverage(uint32 binTimeMS=100, uint16 binCount=600)
Create a tracker.
bool getTotal(double &val, uint64 &count)
Lifetime totals since construction (not limited to the bin window).
uint32 binTime
Bin duration in µs (constructor's binTimeMS multiplied by 1000).
bool getSumMulti(uint32 ms1, uint32 ms2, uint32 ms3, double &sum1, uint64 &count1, double &sum2, uint64 &count2, double &sum3, uint64 &count3, uint64 now=GetTimeNow())
Sums for three windows in one locked pass; parameters parallel getThroughputMulti().
bool getAverageMulti(uint32 ms1, uint32 ms2, uint32 ms3, double &avg1, uint64 &count1, double &avg2, uint64 &count2, double &avg3, uint64 &count3, uint64 now=GetTimeNow())
Averages for three windows in one locked pass; parameters parallel getThroughputMulti().
std::string getPerfJSON(uint32 binMS=1000, uint32 binNum=60)
Render recent history as JSON performance bins.
bool add(double val, uint32 count=1, uint64 time=GetTimeNow())
Record a sample.
std::string getPerfXML(uint32 binMS=1000, uint32 binNum=60)
Render recent history as XML performance bins.
bool getThroughputMulti(uint32 ms1, uint32 ms2, uint32 ms3, double &valPerSec1, double &countPerSec1, double &valPerSec2, double &countPerSec2, double &valPerSec3, double &countPerSec3, uint64 now=GetTimeNow())
Compute throughput for three windows in one locked pass (cheaper than three getThroughput() calls).
bool getThroughput(uint32 ms, double &valPerSec, double &countPerSec, uint64 now=GetTimeNow())
Compute rates over the last ms milliseconds.
bool getAverage(uint32 ms, double &val, uint64 &count, uint64 now=GetTimeNow())
Average value over the last ms milliseconds.
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
int64 GetTimeAge(uint64 t)
Age of a timestamp relative to now.
std::string StringFormat(const char *format,...)
printf into a std::string.
std::string BytifyRate(double val)
Format a byte rate, e.g.
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
void Register_MovingAverage_Tests()
Accumulated samples of one time bin: number of samples and their value sum.
double value
Sum of sample values in this bin.
uint64 count
Number of samples added to this bin.