The histogrm object is used both as a general counter for the number of events and for statistics and sampling. This chanage the histogram implementation, so it would support spares sampling while keeping the total number of event accurate. The implementation includes the following: Remove the template nature of the histogram, as it is used only for timer and use the name ihistogram instead. If in the future we'll need a histogram for other types, we can use the histogrma name for it. a total counter was added that count the number of events that are part of the statistic calculation. A helper methods where added to the ihistogram to handle the latency counter object. According to the sample mask it would mark the latency object as start if the counter and the mask are non zero and it would accept the latency object in its mark method, in which if the latency was not start, it will not be added and only the 'count' counter that counts the total number of events will be incremented. This should reduce the impact of latency calculation to a neglectable effect. Signed-off-by: Amnon Heiman <amnon@cloudius-systems.com>
91 lines
2.1 KiB
C++
91 lines
2.1 KiB
C++
/*
|
|
* Copyright 2015 Cloudius Systems
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <boost/circular_buffer.hpp>
|
|
#include "latency.hh"
|
|
|
|
namespace utils {
|
|
|
|
class ihistogram {
|
|
public:
|
|
// count holds all the events
|
|
int64_t count;
|
|
// total holds only the events we sample
|
|
int64_t total;
|
|
int64_t min;
|
|
int64_t max;
|
|
int64_t sum;
|
|
double mean;
|
|
double variance;
|
|
int64_t sample_mask;
|
|
boost::circular_buffer<int64_t> sample;
|
|
ihistogram(size_t size = 1024, int64_t _sample_mask = 0x80)
|
|
: count(0), total(0), min(0), max(0), sum(0), mean(0), variance(0),
|
|
sample_mask(_sample_mask), sample(
|
|
size) {
|
|
}
|
|
void mark(int64_t value) {
|
|
if (total == 0 || value < min) {
|
|
min = value;
|
|
}
|
|
if (total == 0 || value > max) {
|
|
max = value;
|
|
}
|
|
if (total == 0) {
|
|
mean = value;
|
|
variance = 0;
|
|
} else {
|
|
double old_m = mean;
|
|
double old_s = variance;
|
|
|
|
mean = old_m + ((value - old_m) / (total + 1));
|
|
variance = old_s + ((value - old_m) * (value - mean));
|
|
}
|
|
sum += value;
|
|
total++;
|
|
count++;
|
|
sample.push_back(value);
|
|
}
|
|
|
|
void mark(latency_counter& lc) {
|
|
if (lc.is_start()) {
|
|
mark(lc.stop().latency_in_nano());
|
|
} else {
|
|
count++;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return true if the current event should be sample.
|
|
* In the typical case, there is no need to use this method
|
|
* Call set_latency, that would start a latency object if needed.
|
|
*/
|
|
bool should_sample() const {
|
|
return total & sample_mask;
|
|
}
|
|
/**
|
|
* Set the latency according to the sample rate.
|
|
*/
|
|
ihistogram& set_latency(latency_counter& lc) {
|
|
if (should_sample()) {
|
|
lc.start();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Allow to use the histogram as a counter
|
|
* Increment the total number of events without
|
|
* sampling the value.
|
|
*/
|
|
ihistogram& inc() {
|
|
count++;
|
|
return *this;
|
|
}
|
|
};
|
|
|
|
}
|