#pragma once #include #include #include #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(duration_cast(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(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(len); ++times; const uint64_t true_period_ms = now - start_time; if (true_period_ms <= period_ms) { return; } instant_speed = cur_total / static_cast(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 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 sorted = recent_values; std::sort(sorted.begin(), sorted.begin() + static_cast(recent_count)); auto index = static_cast(std::ceil(static_cast(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(count_change); count += change; total += change; } else { total += static_cast(-static_cast(count_change)); } if (total < total_max) { return; } instant = static_cast((count * 1000U) / total); if (average == 0) { average = instant; } else { average = static_cast(((static_cast(average) << 3U) - average + instant) >> 3U); } count = 0; total = 0; } }; } // namespace Psc