From 3dde4d6b554ae17546b3291bf697aa771f116697 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Wed, 21 Aug 2024 19:17:10 +0300 Subject: [PATCH] Remove template dependance on float/double in util::statistics_log_bucket --- libs/prof/source/profiler.cpp | 2 +- libs/util/include/psemek/util/statistics.hpp | 74 +++++++++++++++----- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/libs/prof/source/profiler.cpp b/libs/prof/source/profiler.cpp index b48d58c8..297647c1 100644 --- a/libs/prof/source/profiler.cpp +++ b/libs/prof/source/profiler.cpp @@ -21,7 +21,7 @@ namespace psemek::prof profiler_tree * parent = nullptr; std::mutex * mutex = nullptr; - util::statistics_log_bucket execution_time; + util::statistics_log_bucket execution_time{0.05}; std::map children; std::vector::iterator> children_list; diff --git a/libs/util/include/psemek/util/statistics.hpp b/libs/util/include/psemek/util/statistics.hpp index a25a539a..7859f1fc 100644 --- a/libs/util/include/psemek/util/statistics.hpp +++ b/libs/util/include/psemek/util/statistics.hpp @@ -197,10 +197,19 @@ namespace psemek::util return result; } - template + template struct statistics_log_bucket : statistics_lite { + statistics_log_bucket(T precision); + statistics_log_bucket(statistics_log_bucket && other); + + statistics_log_bucket & operator = (statistics_log_bucket && other); + + T precision() const { return precision_; } + + T bucket_size() const { return precision() / std::log(T{2}); } + // Only accepts non-negative values void push(T const & value, std::size_t count = 1); @@ -209,34 +218,64 @@ namespace psemek::util statistics_lite & lite() { return *this; } statistics_lite const & lite() const { return *this; } - template - friend statistics_log_bucket merge(statistics_log_bucket const & s1, statistics_log_bucket const & s2); + template + friend statistics_log_bucket merge(statistics_log_bucket const & s1, statistics_log_bucket const & s2); private: - static constexpr T bucket_size = Precision / std::log(2.0); + T precision_; std::size_t zero_count_ = 0; util::spatial_array, 1, int> buckets_; mutable util::spatial_array prefix_count_; }; - template - void statistics_log_bucket::push(T const & value, std::size_t count) + template + statistics_log_bucket::statistics_log_bucket(T precision) + : precision_(precision) + {} + + template + statistics_log_bucket::statistics_log_bucket(statistics_log_bucket && other) + : precision_(other.precision_) + , zero_count_(other.zero_count_) + , buckets_(std::move(other.buckets_)) + , prefix_count_(std::move(other.prefix_count_)) + { + other.zero_count_ = 0; + } + + template + statistics_log_bucket & statistics_log_bucket::operator = (statistics_log_bucket && other) + { + if (this == &other) + return *this; + + precision_ = other.precision_; + zero_count_ = other.zero_count_; + buckets_ = std::move(other.buckets_); + prefix_count_ = std::move(other.prefix_count_); + other.zero_count_ = 0; + + return *this; + } + + template + void statistics_log_bucket::push(T const & value, std::size_t count) { lite().push(value, count); if (value == T{0}) [[unlikely]] ++zero_count_; else { - int const bucket = std::floor(std::log2(value) / bucket_size); + int const bucket = std::floor(std::log2(value) / bucket_size()); buckets_.get(bucket).push(value, count); } prefix_count_.clear(); } - template - T statistics_log_bucket::percentile(double p) const + template + T statistics_log_bucket::percentile(double p) const { if (prefix_count_.empty()) { @@ -261,24 +300,27 @@ namespace psemek::util int bucket = buckets_.min(0) + (it - prefix_count_.begin()); - double min = std::exp2(bucket * bucket_size); - double max = std::exp2((bucket + 1) * bucket_size); + double min = std::exp2(bucket * bucket_size()); + double max = std::exp2((bucket + 1) * bucket_size()); double q = double(index - *it) / (*(it + 1) - *it); return buckets_.at(bucket).percentile(q, min, max); } - template - std::ostream & operator << (std::ostream & os, statistics_log_bucket const & s) + template + std::ostream & operator << (std::ostream & os, statistics_log_bucket const & s) { os << s.lite(); return os; } - template - statistics_log_bucket merge(statistics_log_bucket const & s1, statistics_log_bucket const & s2) + template + statistics_log_bucket merge(statistics_log_bucket const & s1, statistics_log_bucket const & s2) { - statistics_log_bucket result; + if (s1.precision() != s2.precision()) + throw util::exception("Cannot merge log-bucket statistics of different precision"); + + statistics_log_bucket result(s1.precision()); result.lite() = merge(s1.lite(), s2.lite()); for (int bucket = s1.buckets_.min(0); bucket < s1.buckets_.max(0); ++bucket)