ClickHouse/src/Common/EventRateMeter.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

74 lines
2.4 KiB
C++
Raw Normal View History

2022-07-15 22:27:26 +00:00
#pragma once
#include <base/defines.h>
#include <Common/ExponentiallySmoothedCounter.h>
#include <numbers>
2022-07-15 22:27:26 +00:00
namespace DB
{
/// Event count measurement with exponential smoothing intended for computing time derivatives
2022-07-18 11:26:33 +00:00
class EventRateMeter
{
2022-07-15 22:27:26 +00:00
public:
explicit EventRateMeter(double now, double period_)
: period(period_)
, half_decay_time(period * std::numbers::ln2) // for `ExponentiallySmoothedAverage::sumWeights()` to be equal to `1/period`
{
reset(now);
}
2022-07-15 22:27:26 +00:00
/// Add `count` events happened at `now` instant.
/// Previous events that are older than `period` from `now` will be forgotten
/// in a way to keep average event rate the same, using exponential smoothing.
/// NOTE: Adding events into distant past (further than `period`) must be avoided.
void add(double now, double count)
2022-07-15 22:27:26 +00:00
{
// Remove data for initial heating stage that can present at the beginning of a query.
2022-11-17 16:20:21 +00:00
// Otherwise it leads to wrong gradual increase of average value, turning algorithm into not very reactive.
if (count != 0.0 && ++data_points < 5)
{
start = events.time;
events = ExponentiallySmoothedAverage();
}
if (now - period <= start) // precise counting mode
events = ExponentiallySmoothedAverage(events.value + count, now);
else // exponential smoothing mode
events.add(count, now, half_decay_time);
2022-07-15 22:27:26 +00:00
}
2022-07-18 11:26:33 +00:00
/// Compute average event rate throughout `[now - period, now]` period.
/// If measurements are just started (`now - period < start`), then average
/// is computed based on shorter `[start; now]` period to avoid initial linear growth.
2022-07-18 11:31:32 +00:00
double rate(double now)
2022-07-15 22:27:26 +00:00
{
add(now, 0);
if (unlikely(now <= start))
return 0;
if (now - period <= start) // precise counting mode
return events.value / (now - start);
else // exponential smoothing mode
return events.get(half_decay_time); // equals to `events.value / period`
2022-07-15 22:27:26 +00:00
}
void reset(double now)
2022-07-15 22:27:26 +00:00
{
start = now;
events = ExponentiallySmoothedAverage();
data_points = 0;
2022-07-15 22:27:26 +00:00
}
private:
const double period;
const double half_decay_time;
double start; // Instant in past without events before it; when measurement started or reset
ExponentiallySmoothedAverage events; // Estimated number of events in the last `period`
size_t data_points = 0;
2022-07-15 22:27:26 +00:00
};
}