220 lines
6.4 KiB
C++
220 lines
6.4 KiB
C++
#pragma once
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cmath>
|
|
#include "../Base/global_include.h"
|
|
#include "global.h"
|
|
namespace Psc {
|
|
class Base_Statistics {
|
|
protected:
|
|
uint64_t start_time;
|
|
[[nodiscard]] static uint64_t get_current_ms() {
|
|
using namespace std::chrono;
|
|
return static_cast<uint64_t>(duration_cast<milliseconds>(steady_clock::now().time_since_epoch()).count());
|
|
}
|
|
public:
|
|
Base_Statistics() : start_time(get_current_ms()) {
|
|
}
|
|
[[nodiscard]] virtual JSON to_json() const = 0;
|
|
virtual ~Base_Statistics() = default;
|
|
[[nodiscard]] unsigned int get_start_time() const {
|
|
return static_cast<unsigned int>(start_time);
|
|
}
|
|
};
|
|
class Speed_Statistics : public Base_Statistics {
|
|
public:
|
|
double cur_total{};
|
|
double instant_speed{};
|
|
double average_speed{};
|
|
size_t times{};
|
|
bool init{};
|
|
Speed_Statistics() {
|
|
clear();
|
|
}
|
|
Speed_Statistics& operator+=(const Speed_Statistics& rhs) {
|
|
cur_total += rhs.cur_total;
|
|
instant_speed += rhs.instant_speed;
|
|
average_speed += rhs.average_speed;
|
|
times += rhs.times;
|
|
init = init || rhs.init;
|
|
return *this;
|
|
}
|
|
void clear() {
|
|
cur_total = 0.0;
|
|
instant_speed = 0.0;
|
|
average_speed = 0.0;
|
|
times = 0;
|
|
init = false;
|
|
start_time = get_current_ms();
|
|
}
|
|
[[nodiscard]] JSON to_json() const override {
|
|
JSON ret = JSON::object();
|
|
Ret_J(instant_speed)
|
|
Ret_J(average_speed)
|
|
Ret_J(times) return ret;
|
|
}
|
|
[[nodiscard]] std::string to_string() const {
|
|
return VAR_STR_4(instant_speed, average_speed, cur_total, times);
|
|
}
|
|
void update(unsigned int len) {
|
|
constexpr uint64_t period_ms = 100;
|
|
constexpr double average_times = 10.0;
|
|
const uint64_t now = get_current_ms();
|
|
cur_total += static_cast<double>(len);
|
|
++times;
|
|
const uint64_t true_period_ms = now - start_time;
|
|
if (true_period_ms <= period_ms) {
|
|
return;
|
|
}
|
|
instant_speed = cur_total / static_cast<double>(true_period_ms) * 1000.0;
|
|
if (init) {
|
|
average_speed = average_speed * (average_times - 1.0) / average_times + instant_speed / average_times;
|
|
}
|
|
else {
|
|
average_speed = instant_speed;
|
|
init = true;
|
|
}
|
|
start_time = now;
|
|
cur_total = 0.0;
|
|
}
|
|
};
|
|
class Value_Statistics : public Base_Statistics {
|
|
public:
|
|
static constexpr std::size_t recent_value_count = 64;
|
|
double max{};
|
|
double min{};
|
|
double average{};
|
|
double smooth{};
|
|
double variation{};
|
|
double instant{};
|
|
double p95{};
|
|
size_t times{};
|
|
size_t recent_count{};
|
|
size_t recent_index{};
|
|
std::array<double, recent_value_count> recent_values{};
|
|
bool init{};
|
|
Value_Statistics() {
|
|
clear();
|
|
}
|
|
void clear() {
|
|
max = 0.0;
|
|
min = 0.0;
|
|
average = 0.0;
|
|
smooth = 0.0;
|
|
variation = 0.0;
|
|
instant = 0.0;
|
|
p95 = 0.0;
|
|
times = 0;
|
|
recent_count = 0;
|
|
recent_index = 0;
|
|
recent_values.fill(0.0);
|
|
init = false;
|
|
}
|
|
[[nodiscard]] JSON to_json() const override {
|
|
JSON ret = JSON::object();
|
|
Ret_J(max)
|
|
Ret_J(min)
|
|
Ret_J(average)
|
|
Ret_J(smooth)
|
|
Ret_J(variation)
|
|
Ret_J(instant)
|
|
Ret_J(p95)
|
|
Ret_J(times) return ret;
|
|
}
|
|
[[nodiscard]] std::string to_string() const {
|
|
return VAR_STR_8(min, max, average, smooth, variation, instant, p95, times);
|
|
}
|
|
void update(double value) {
|
|
constexpr double average_times = 10.0;
|
|
constexpr double smooth_gain = 0.125;
|
|
constexpr double variation_gain = 0.25;
|
|
instant = value;
|
|
if (!init) {
|
|
max = value;
|
|
min = value;
|
|
average = value;
|
|
smooth = value;
|
|
variation = 0.0;
|
|
init = true;
|
|
}
|
|
else {
|
|
double deviation = std::abs(value - smooth);
|
|
max = std::max(max, value);
|
|
min = std::min(min, value);
|
|
average = average * (average_times - 1.0) / average_times + instant / average_times;
|
|
variation = variation * (1.0 - variation_gain) + deviation * variation_gain;
|
|
smooth = smooth * (1.0 - smooth_gain) + value * smooth_gain;
|
|
}
|
|
update_recent(value);
|
|
++times;
|
|
}
|
|
private:
|
|
void update_recent(double value) {
|
|
recent_values[recent_index] = value;
|
|
recent_index = (recent_index + 1) % recent_value_count;
|
|
if (recent_count < recent_value_count)
|
|
++recent_count;
|
|
std::array<double, recent_value_count> sorted = recent_values;
|
|
std::sort(sorted.begin(), sorted.begin() + static_cast<std::ptrdiff_t>(recent_count));
|
|
auto index = static_cast<std::size_t>(std::ceil(static_cast<double>(recent_count) * 0.95));
|
|
if (index > 0)
|
|
--index;
|
|
p95 = sorted[index];
|
|
}
|
|
};
|
|
class Probability_Statistics : public Base_Statistics {
|
|
public:
|
|
unsigned short instant{};
|
|
unsigned short average{};
|
|
unsigned int count{};
|
|
unsigned int total{};
|
|
unsigned int total_max{};
|
|
Probability_Statistics() {
|
|
clear();
|
|
}
|
|
void clear() {
|
|
instant = 0;
|
|
average = 0;
|
|
count = 0;
|
|
total = 0;
|
|
total_max = 10;
|
|
}
|
|
[[nodiscard]] JSON to_json() const override {
|
|
JSON ret = JSON::object();
|
|
Ret_J(instant)
|
|
Ret_J(average)
|
|
Ret_J(count)
|
|
Ret_J(total)
|
|
Ret_J(total_max) return ret;
|
|
}
|
|
void update(bool value) {
|
|
value ? update(1) : update(-1);
|
|
}
|
|
void update(int count_change) {
|
|
if (count_change == 0) {
|
|
count_change = -1;
|
|
}
|
|
if (count_change > 0) {
|
|
const auto change = static_cast<unsigned int>(count_change);
|
|
count += change;
|
|
total += change;
|
|
}
|
|
else {
|
|
total += static_cast<unsigned int>(-static_cast<int64_t>(count_change));
|
|
}
|
|
if (total < total_max) {
|
|
return;
|
|
}
|
|
instant = static_cast<unsigned short>((count * 1000U) / total);
|
|
if (average == 0) {
|
|
average = instant;
|
|
}
|
|
else {
|
|
average = static_cast<unsigned short>(((static_cast<unsigned int>(average) << 3U) - average + instant) >> 3U);
|
|
}
|
|
count = 0;
|
|
total = 0;
|
|
}
|
|
};
|
|
} // namespace Psc
|