Files
scylladb/utils/histogram.hh
Amnon Heiman bd9a758b80 Utils: Support sample based histogram
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>
2015-08-11 10:00:53 +03:00

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;
}
};
}