2022-07-15 22:27:26 +00:00
|
|
|
#pragma once
|
|
|
|
|
2022-07-16 00:17:18 +00:00
|
|
|
#include <base/defines.h>
|
2022-07-15 22:27:26 +00:00
|
|
|
#include <base/types.h>
|
2022-07-18 10:21:44 +00:00
|
|
|
|
|
|
|
#include <Common/ExponentiallySmoothedCounter.h>
|
|
|
|
|
2022-07-15 22:27:26 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cmath>
|
2022-07-16 00:17:18 +00:00
|
|
|
#include <cassert>
|
2022-07-18 10:21:44 +00:00
|
|
|
#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:
|
2022-07-18 10:21:44 +00:00
|
|
|
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.
|
2022-07-18 10:21:44 +00:00
|
|
|
void add(double now, double count)
|
2022-07-15 22:27:26 +00:00
|
|
|
{
|
2022-07-18 10:21:44 +00:00
|
|
|
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.
|
2022-07-16 00:17:18 +00:00
|
|
|
/// 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-15 22:27:26 +00:00
|
|
|
double rate(UInt64 now)
|
|
|
|
{
|
|
|
|
add(now, 0);
|
2022-07-16 00:17:18 +00:00
|
|
|
if (unlikely(now <= start))
|
|
|
|
return 0;
|
2022-07-18 10:21:44 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-07-18 10:21:44 +00:00
|
|
|
void reset(double now)
|
2022-07-15 22:27:26 +00:00
|
|
|
{
|
2022-07-16 00:17:18 +00:00
|
|
|
start = now;
|
2022-07-18 10:21:44 +00:00
|
|
|
events = ExponentiallySmoothedAverage();
|
2022-07-15 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-07-18 10:21:44 +00:00
|
|
|
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`
|
2022-07-15 22:27:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|