Monitoring System 0.1.0
System resource monitoring with pluggable collectors and alerting
Loading...
Searching...
No Matches
statistics.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
14#pragma once
15
16#include <algorithm>
17#include <cmath>
18#include <cstddef>
19#include <numeric>
20#include <type_traits>
21#include <vector>
22
23namespace kcenon {
24namespace monitoring {
25namespace stats {
26
33template <typename T>
34struct statistics {
35 T min;
36 T max;
39 T p95;
40 T p99;
42 size_t count;
43};
44
45namespace detail {
46
50template <typename T>
51struct is_chrono_duration : std::false_type {};
52
53template <typename Rep, typename Period>
54struct is_chrono_duration<std::chrono::duration<Rep, Period>> : std::true_type {};
55
56template <typename T>
58
62template <typename T>
63constexpr T zero_value() {
64 if constexpr (is_chrono_duration_v<T>) {
65 return T::zero();
66 } else {
67 return T{0};
68 }
69}
70
74template <typename T>
75constexpr T max_value() {
76 if constexpr (is_chrono_duration_v<T>) {
77 return T::max();
78 } else {
79 return std::numeric_limits<T>::max();
80 }
81}
82
86template <typename T>
87constexpr T min_value() {
88 if constexpr (is_chrono_duration_v<T>) {
89 return T::min();
90 } else {
91 return std::numeric_limits<T>::lowest();
92 }
93}
94
98template <typename T>
99T divide(const T& value, size_t count) {
100 if (count == 0) {
101 return zero_value<T>();
102 }
103 if constexpr (is_chrono_duration_v<T>) {
104 return value / static_cast<typename T::rep>(count);
105 } else {
106 return value / static_cast<T>(count);
107 }
108}
109
110} // namespace detail
111
129template <typename T>
130T percentile(const std::vector<T>& sorted_values, double percentile_value) {
131 if (sorted_values.empty()) {
132 return detail::zero_value<T>();
133 }
134
135 if (percentile_value <= 0.0) {
136 return sorted_values.front();
137 }
138
139 if (percentile_value >= 100.0) {
140 return sorted_values.back();
141 }
142
143 double rank = (percentile_value / 100.0) * (sorted_values.size() - 1);
144 size_t lower_idx = static_cast<size_t>(rank);
145 size_t upper_idx = lower_idx + 1;
146
147 if (upper_idx >= sorted_values.size()) {
148 return sorted_values[lower_idx];
149 }
150
151 // For chrono types, use simple index-based selection
152 // For numeric types, use linear interpolation
153 if constexpr (detail::is_chrono_duration_v<T>) {
154 // Use nearest-rank method for duration types
155 return sorted_values[static_cast<size_t>(std::round(rank))];
156 } else {
157 double fraction = rank - static_cast<double>(lower_idx);
158 return sorted_values[lower_idx] +
159 static_cast<T>(fraction * (sorted_values[upper_idx] - sorted_values[lower_idx]));
160 }
161}
162
172template <typename T>
173statistics<T> compute_sorted(const std::vector<T>& sorted_values) {
174 statistics<T> result{};
175
176 if (sorted_values.empty()) {
177 result.min = detail::zero_value<T>();
178 result.max = detail::zero_value<T>();
179 result.mean = detail::zero_value<T>();
180 result.median = detail::zero_value<T>();
181 result.p95 = detail::zero_value<T>();
182 result.p99 = detail::zero_value<T>();
183 result.total = detail::zero_value<T>();
184 result.count = 0;
185 return result;
186 }
187
188 result.count = sorted_values.size();
189 result.min = sorted_values.front();
190 result.max = sorted_values.back();
191
192 // Calculate total
193 result.total = std::accumulate(sorted_values.begin(), sorted_values.end(),
195
196 // Calculate mean
197 result.mean = detail::divide(result.total, result.count);
198
199 // Calculate percentiles
200 result.median = percentile(sorted_values, 50.0);
201 result.p95 = percentile(sorted_values, 95.0);
202 result.p99 = percentile(sorted_values, 99.0);
203
204 return result;
205}
206
227template <typename T>
228statistics<T> compute(const std::vector<T>& values) {
229 if (values.empty()) {
230 return compute_sorted<T>({});
231 }
232
233 std::vector<T> sorted = values;
234 std::sort(sorted.begin(), sorted.end());
235 return compute_sorted(sorted);
236}
237
247template <typename T>
248statistics<T> compute_inplace(std::vector<T>& values) {
249 if (values.empty()) {
250 return compute_sorted<T>({});
251 }
252
253 std::sort(values.begin(), values.end());
254 return compute_sorted(values);
255}
256
257} // namespace stats
258} // namespace monitoring
259} // namespace kcenon
Internal implementation details - not part of public API.
Definition memory_pool.h:27
constexpr T zero_value()
Get zero value for a type.
Definition statistics.h:63
constexpr T min_value()
Get minimum (lowest) value for a type.
Definition statistics.h:87
T divide(const T &value, size_t count)
Divide value by count.
Definition statistics.h:99
constexpr T max_value()
Get maximum value for a type.
Definition statistics.h:75
statistics< T > compute_sorted(const std::vector< T > &sorted_values)
Compute statistics from sorted values.
Definition statistics.h:173
statistics< T > compute_inplace(std::vector< T > &values)
Compute statistics in place (modifies input)
Definition statistics.h:248
T percentile(const std::vector< T > &sorted_values, double percentile_value)
Definition statistics.h:130
statistics< T > compute(const std::vector< T > &values)
Definition statistics.h:228
Type trait to detect std::chrono::duration types.
Definition statistics.h:51
Statistical summary for a collection of values.
Definition statistics.h:34