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>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cmath>
|
2022-07-16 00:17:18 +00:00
|
|
|
#include <cassert>
|
2022-07-15 22:27:26 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
/// Event count measurement with exponential smoothing intended for computing time derivatives
|
|
|
|
class EventRateMeter {
|
|
|
|
public:
|
|
|
|
explicit EventRateMeter(UInt64 period_, UInt64 resolution = 1000)
|
|
|
|
: period(std::max(period_, 1ul))
|
|
|
|
, step(std::max(period / resolution, 1ul))
|
|
|
|
, decay(1.0 - 1.0 / resolution)
|
|
|
|
{}
|
|
|
|
|
|
|
|
/// 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-16 00:17:18 +00:00
|
|
|
void add(UInt64 now, UInt64 count = 1)
|
2022-07-15 22:27:26 +00:00
|
|
|
{
|
|
|
|
if (unlikely(end == 0))
|
|
|
|
{
|
|
|
|
// Initialization during the first call
|
2022-07-16 00:17:18 +00:00
|
|
|
if (start == 0)
|
|
|
|
start = now;
|
|
|
|
end = start + period;
|
2022-07-15 22:27:26 +00:00
|
|
|
}
|
|
|
|
else if (now > end)
|
|
|
|
{
|
|
|
|
// Compute number of steps we have to move for `now <= end` to became true
|
|
|
|
UInt64 steps = (now - end + step - 1) / step;
|
|
|
|
end += steps * step;
|
|
|
|
assert(now <= end);
|
|
|
|
|
|
|
|
// Forget old events, assuming all events are distributed evenly throughout whole `period`.
|
|
|
|
// This assumption leads to exponential decay in case no new events will come.
|
|
|
|
if (steps == 1)
|
|
|
|
events *= decay;
|
|
|
|
else
|
|
|
|
events *= std::pow(decay, steps);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add new events
|
|
|
|
events += count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Compute average event rate thoughout `[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;
|
|
|
|
return double(events) / std::min(period, now - start);
|
2022-07-15 22:27:26 +00:00
|
|
|
}
|
|
|
|
|
2022-07-16 00:17:18 +00:00
|
|
|
void reset(UInt64 now)
|
2022-07-15 22:27:26 +00:00
|
|
|
{
|
|
|
|
events = 0;
|
2022-07-16 00:17:18 +00:00
|
|
|
start = now;
|
2022-07-15 22:27:26 +00:00
|
|
|
end = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const UInt64 period;
|
|
|
|
const UInt64 step;
|
|
|
|
const double decay;
|
2022-07-16 00:17:18 +00:00
|
|
|
double events = 0; // Estimated number of events in [end - period, end] range
|
|
|
|
UInt64 start = 0; // Instant in past without events before it; when measurement started or reset
|
|
|
|
UInt64 end = 0; // Instant in future to start decay; moving in steps
|
2022-07-15 22:27:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|