Thread System 0.3.1
High-performance C++20 thread pool with work stealing and DAG scheduling
Loading...
Searching...
No Matches
kcenon::thread::metrics::LatencyHistogram Class Reference

HDR-style histogram for latency distribution with logarithmic buckets. More...

#include <latency_histogram.h>

Collaboration diagram for kcenon::thread::metrics::LatencyHistogram:
Collaboration graph

Public Member Functions

 LatencyHistogram ()
 Default constructor - initializes all buckets to zero.
 
 LatencyHistogram (const LatencyHistogram &other)
 Copy constructor.
 
 LatencyHistogram (LatencyHistogram &&other) noexcept
 Move constructor.
 
LatencyHistogramoperator= (const LatencyHistogram &other)
 Copy assignment operator.
 
LatencyHistogramoperator= (LatencyHistogram &&other) noexcept
 Move assignment operator.
 
 ~LatencyHistogram ()=default
 Destructor.
 
void record (std::chrono::nanoseconds value)
 Record a latency value.
 
void record_ns (std::uint64_t nanoseconds)
 Record a raw nanosecond value.
 
double percentile (double p) const
 Calculate the value at a given percentile.
 
double p50 () const
 Get the 50th percentile (median).
 
double p90 () const
 Get the 90th percentile.
 
double p95 () const
 Get the 95th percentile.
 
double p99 () const
 Get the 99th percentile.
 
double p999 () const
 Get the 99.9th percentile.
 
double mean () const
 Calculate the arithmetic mean.
 
double stddev () const
 Calculate the standard deviation.
 
std::uint64_t min () const
 Get the minimum recorded value.
 
std::uint64_t max () const
 Get the maximum recorded value.
 
std::uint64_t count () const
 Get the total count of recorded values.
 
std::uint64_t sum () const
 Get the sum of all recorded values.
 
void reset ()
 Reset all buckets and counters to zero.
 
bool empty () const
 Check if the histogram is empty.
 
void merge (const LatencyHistogram &other)
 Merge another histogram into this one.
 
std::uint64_t bucket_count (std::size_t bucket_index) const
 Get the bucket count at a specific index.
 

Static Public Member Functions

static std::uint64_t bucket_lower_bound (std::size_t bucket_index)
 Get the lower bound of a bucket.
 
static std::uint64_t bucket_upper_bound (std::size_t bucket_index)
 Get the upper bound of a bucket.
 

Static Public Attributes

static constexpr std::size_t BUCKET_COUNT = 64
 Number of histogram buckets.
 

Static Private Member Functions

static std::size_t compute_bucket_index (std::uint64_t value)
 Compute the bucket index for a given value.
 
static double bucket_midpoint (std::size_t bucket_index)
 Get the midpoint value of a bucket for estimation.
 

Private Attributes

std::array< std::atomic< std::uint64_t >, BUCKET_COUNTbuckets_
 Histogram buckets using logarithmic distribution.
 
std::atomic< std::uint64_t > total_count_ {0}
 Total number of recorded values.
 
std::atomic< std::uint64_t > total_sum_ {0}
 Sum of all recorded values.
 
std::atomic< std::uint64_t > min_value_ {std::numeric_limits<std::uint64_t>::max()}
 Minimum recorded value.
 
std::atomic< std::uint64_t > max_value_ {0}
 Maximum recorded value.
 

Detailed Description

HDR-style histogram for latency distribution with logarithmic buckets.

This class provides a lock-free, thread-safe histogram for recording latency measurements. It uses logarithmic bucketing to efficiently represent a wide range of values (from nanoseconds to seconds) with bounded memory usage.

Design Principles

  • Lock-free: All operations use atomic instructions, no mutexes
  • Low overhead: < 100ns per record operation
  • Memory efficient: Fixed-size bucket array (< 1KB total)
  • High accuracy: Accurate percentile calculations within 1%

Bucket Design

Uses 64 logarithmic buckets covering the range from 0 to ~10^19 nanoseconds:

  • Bucket 0: [0, 1) ns
  • Bucket 1: [1, 2) ns
  • Bucket 2: [2, 4) ns
  • Bucket 3: [4, 8) ns
  • ...
  • Bucket 63: [2^62, 2^63) ns
Thread Safety:
Thread-safe for concurrent recording and reading.
See also
EnhancedThreadPoolMetrics

Definition at line 51 of file latency_histogram.h.

Constructor & Destructor Documentation

◆ LatencyHistogram() [1/3]

kcenon::thread::metrics::LatencyHistogram::LatencyHistogram ( )

Default constructor - initializes all buckets to zero.

Definition at line 13 of file latency_histogram.cpp.

13 {
14 for (auto& bucket : buckets_) {
15 bucket.store(0, std::memory_order_relaxed);
16 }
17}
std::array< std::atomic< std::uint64_t >, BUCKET_COUNT > buckets_
Histogram buckets using logarithmic distribution.

References buckets_.

◆ LatencyHistogram() [2/3]

kcenon::thread::metrics::LatencyHistogram::LatencyHistogram ( const LatencyHistogram & other)

Copy constructor.

Parameters
otherThe histogram to copy from.

Definition at line 19 of file latency_histogram.cpp.

19 {
20 for (std::size_t i = 0; i < BUCKET_COUNT; ++i) {
21 buckets_[i].store(other.buckets_[i].load(std::memory_order_relaxed),
22 std::memory_order_relaxed);
23 }
24 total_count_.store(other.total_count_.load(std::memory_order_relaxed),
25 std::memory_order_relaxed);
26 total_sum_.store(other.total_sum_.load(std::memory_order_relaxed),
27 std::memory_order_relaxed);
28 min_value_.store(other.min_value_.load(std::memory_order_relaxed),
29 std::memory_order_relaxed);
30 max_value_.store(other.max_value_.load(std::memory_order_relaxed),
31 std::memory_order_relaxed);
32}
static constexpr std::size_t BUCKET_COUNT
Number of histogram buckets.
std::atomic< std::uint64_t > min_value_
Minimum recorded value.
std::atomic< std::uint64_t > total_count_
Total number of recorded values.
std::atomic< std::uint64_t > max_value_
Maximum recorded value.
std::atomic< std::uint64_t > total_sum_
Sum of all recorded values.

References BUCKET_COUNT, buckets_, max_value_, min_value_, total_count_, and total_sum_.

◆ LatencyHistogram() [3/3]

kcenon::thread::metrics::LatencyHistogram::LatencyHistogram ( LatencyHistogram && other)
noexcept

Move constructor.

Parameters
otherThe histogram to move from.

Definition at line 34 of file latency_histogram.cpp.

34 {
35 for (std::size_t i = 0; i < BUCKET_COUNT; ++i) {
36 buckets_[i].store(other.buckets_[i].load(std::memory_order_relaxed),
37 std::memory_order_relaxed);
38 other.buckets_[i].store(0, std::memory_order_relaxed);
39 }
40 total_count_.store(other.total_count_.exchange(0, std::memory_order_relaxed),
41 std::memory_order_relaxed);
42 total_sum_.store(other.total_sum_.exchange(0, std::memory_order_relaxed),
43 std::memory_order_relaxed);
44 min_value_.store(other.min_value_.exchange(
45 std::numeric_limits<std::uint64_t>::max(),
46 std::memory_order_relaxed),
47 std::memory_order_relaxed);
48 max_value_.store(other.max_value_.exchange(0, std::memory_order_relaxed),
49 std::memory_order_relaxed);
50}

◆ ~LatencyHistogram()

kcenon::thread::metrics::LatencyHistogram::~LatencyHistogram ( )
default

Destructor.

Member Function Documentation

◆ bucket_count()

std::uint64_t kcenon::thread::metrics::LatencyHistogram::bucket_count ( std::size_t bucket_index) const
nodiscard

Get the bucket count at a specific index.

Parameters
bucket_indexThe bucket index (0 to BUCKET_COUNT-1).
Returns
The count in the specified bucket.

Definition at line 259 of file latency_histogram.cpp.

259 {
260 if (bucket_index >= BUCKET_COUNT) {
261 return 0;
262 }
263 return buckets_[bucket_index].load(std::memory_order_relaxed);
264}

References BUCKET_COUNT, and buckets_.

◆ bucket_lower_bound()

std::uint64_t kcenon::thread::metrics::LatencyHistogram::bucket_lower_bound ( std::size_t bucket_index)
staticnodiscard

Get the lower bound of a bucket.

Parameters
bucket_indexThe bucket index.
Returns
The lower bound in nanoseconds.

Definition at line 266 of file latency_histogram.cpp.

266 {
267 if (bucket_index == 0) {
268 return 0;
269 }
270 if (bucket_index >= BUCKET_COUNT) {
271 return std::numeric_limits<std::uint64_t>::max();
272 }
273 return static_cast<std::uint64_t>(1ULL << (bucket_index - 1));
274}

References BUCKET_COUNT.

Referenced by bucket_midpoint(), and percentile().

Here is the caller graph for this function:

◆ bucket_midpoint()

double kcenon::thread::metrics::LatencyHistogram::bucket_midpoint ( std::size_t bucket_index)
staticnodiscardprivate

Get the midpoint value of a bucket for estimation.

Parameters
bucket_indexThe bucket index.
Returns
The midpoint value in nanoseconds.

Definition at line 309 of file latency_histogram.cpp.

309 {
310 const auto lower = bucket_lower_bound(bucket_index);
311 const auto upper = bucket_upper_bound(bucket_index);
312
313 if (upper == std::numeric_limits<std::uint64_t>::max()) {
314 // For the last bucket, use lower bound as estimate
315 return static_cast<double>(lower);
316 }
317
318 return (static_cast<double>(lower) + static_cast<double>(upper)) / 2.0;
319}
static std::uint64_t bucket_lower_bound(std::size_t bucket_index)
Get the lower bound of a bucket.
static std::uint64_t bucket_upper_bound(std::size_t bucket_index)
Get the upper bound of a bucket.

References bucket_lower_bound(), and bucket_upper_bound().

Referenced by percentile(), and stddev().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ bucket_upper_bound()

std::uint64_t kcenon::thread::metrics::LatencyHistogram::bucket_upper_bound ( std::size_t bucket_index)
staticnodiscard

Get the upper bound of a bucket.

Parameters
bucket_indexThe bucket index.
Returns
The upper bound in nanoseconds.

Definition at line 276 of file latency_histogram.cpp.

276 {
277 if (bucket_index >= BUCKET_COUNT - 1) {
278 return std::numeric_limits<std::uint64_t>::max();
279 }
280 return static_cast<std::uint64_t>(1ULL << bucket_index);
281}

References BUCKET_COUNT.

Referenced by bucket_midpoint(), and percentile().

Here is the caller graph for this function:

◆ compute_bucket_index()

std::size_t kcenon::thread::metrics::LatencyHistogram::compute_bucket_index ( std::uint64_t value)
staticnodiscardprivate

Compute the bucket index for a given value.

Parameters
valueThe value in nanoseconds.
Returns
The bucket index (0 to BUCKET_COUNT-1).

Definition at line 283 of file latency_histogram.cpp.

283 {
284 if (value == 0) {
285 return 0;
286 }
287
288 // Use bit manipulation to find the highest set bit (floor of log2)
289 // This gives us the bucket index directly
290#if defined(__GNUC__) || defined(__clang__)
291 const auto leading_zeros = __builtin_clzll(value);
292 const auto highest_bit = 63 - leading_zeros;
293#elif defined(_MSC_VER)
294 unsigned long highest_bit;
295 _BitScanReverse64(&highest_bit, value);
296#else
297 // Fallback: portable implementation
298 std::size_t highest_bit = 0;
299 auto temp = value;
300 while (temp >>= 1) {
301 ++highest_bit;
302 }
303#endif
304
305 // Bucket index is highest_bit + 1, capped at BUCKET_COUNT - 1
306 return std::min(static_cast<std::size_t>(highest_bit + 1), BUCKET_COUNT - 1);
307}

References BUCKET_COUNT.

Referenced by record_ns().

Here is the caller graph for this function:

◆ count()

std::uint64_t kcenon::thread::metrics::LatencyHistogram::count ( ) const
nodiscard

Get the total count of recorded values.

Returns
The number of recorded values.

Definition at line 203 of file latency_histogram.cpp.

203 {
204 return total_count_.load(std::memory_order_relaxed);
205}

References total_count_.

◆ empty()

bool kcenon::thread::metrics::LatencyHistogram::empty ( ) const
nodiscard

Check if the histogram is empty.

Returns
True if no values have been recorded.

Definition at line 222 of file latency_histogram.cpp.

222 {
223 return total_count_.load(std::memory_order_relaxed) == 0;
224}

References total_count_.

◆ max()

std::uint64_t kcenon::thread::metrics::LatencyHistogram::max ( ) const
nodiscard

Get the maximum recorded value.

Returns
The maximum latency in nanoseconds.

Returns 0 if the histogram is empty.

Definition at line 195 of file latency_histogram.cpp.

195 {
196 const auto total = total_count_.load(std::memory_order_relaxed);
197 if (total == 0) {
198 return 0;
199 }
200 return max_value_.load(std::memory_order_relaxed);
201}

References max_value_, and total_count_.

◆ mean()

double kcenon::thread::metrics::LatencyHistogram::mean ( ) const
nodiscard

Calculate the arithmetic mean.

Returns
The mean latency in nanoseconds.

Returns 0.0 if the histogram is empty. Note: The mean is approximated using bucket midpoints.

Definition at line 158 of file latency_histogram.cpp.

158 {
159 const auto total = total_count_.load(std::memory_order_relaxed);
160 if (total == 0) {
161 return 0.0;
162 }
163 return static_cast<double>(total_sum_.load(std::memory_order_relaxed)) / total;
164}

References total_count_, and total_sum_.

Referenced by stddev().

Here is the caller graph for this function:

◆ merge()

void kcenon::thread::metrics::LatencyHistogram::merge ( const LatencyHistogram & other)

Merge another histogram into this one.

Parameters
otherThe histogram to merge.

All bucket counts from other are added to this histogram.

Definition at line 226 of file latency_histogram.cpp.

226 {
227 for (std::size_t i = 0; i < BUCKET_COUNT; ++i) {
228 buckets_[i].fetch_add(other.buckets_[i].load(std::memory_order_relaxed),
229 std::memory_order_relaxed);
230 }
231 total_count_.fetch_add(other.total_count_.load(std::memory_order_relaxed),
232 std::memory_order_relaxed);
233 total_sum_.fetch_add(other.total_sum_.load(std::memory_order_relaxed),
234 std::memory_order_relaxed);
235
236 // Update min atomically
237 auto other_min = other.min_value_.load(std::memory_order_relaxed);
238 auto current_min = min_value_.load(std::memory_order_relaxed);
239 while (other_min < current_min) {
240 if (min_value_.compare_exchange_weak(current_min, other_min,
241 std::memory_order_relaxed,
242 std::memory_order_relaxed)) {
243 break;
244 }
245 }
246
247 // Update max atomically
248 auto other_max = other.max_value_.load(std::memory_order_relaxed);
249 auto current_max = max_value_.load(std::memory_order_relaxed);
250 while (other_max > current_max) {
251 if (max_value_.compare_exchange_weak(current_max, other_max,
252 std::memory_order_relaxed,
253 std::memory_order_relaxed)) {
254 break;
255 }
256 }
257}

References BUCKET_COUNT, buckets_, max_value_, min_value_, total_count_, and total_sum_.

◆ min()

std::uint64_t kcenon::thread::metrics::LatencyHistogram::min ( ) const
nodiscard

Get the minimum recorded value.

Returns
The minimum latency in nanoseconds.

Returns 0 if the histogram is empty.

Definition at line 187 of file latency_histogram.cpp.

187 {
188 const auto total = total_count_.load(std::memory_order_relaxed);
189 if (total == 0) {
190 return 0;
191 }
192 return min_value_.load(std::memory_order_relaxed);
193}

References min_value_, and total_count_.

◆ operator=() [1/2]

LatencyHistogram & kcenon::thread::metrics::LatencyHistogram::operator= ( const LatencyHistogram & other)

Copy assignment operator.

Parameters
otherThe histogram to copy from.
Returns
Reference to this histogram.

Definition at line 52 of file latency_histogram.cpp.

52 {
53 if (this != &other) {
54 for (std::size_t i = 0; i < BUCKET_COUNT; ++i) {
55 buckets_[i].store(other.buckets_[i].load(std::memory_order_relaxed),
56 std::memory_order_relaxed);
57 }
58 total_count_.store(other.total_count_.load(std::memory_order_relaxed),
59 std::memory_order_relaxed);
60 total_sum_.store(other.total_sum_.load(std::memory_order_relaxed),
61 std::memory_order_relaxed);
62 min_value_.store(other.min_value_.load(std::memory_order_relaxed),
63 std::memory_order_relaxed);
64 max_value_.store(other.max_value_.load(std::memory_order_relaxed),
65 std::memory_order_relaxed);
66 }
67 return *this;
68}

References BUCKET_COUNT, buckets_, max_value_, min_value_, total_count_, and total_sum_.

◆ operator=() [2/2]

LatencyHistogram & kcenon::thread::metrics::LatencyHistogram::operator= ( LatencyHistogram && other)
noexcept

Move assignment operator.

Parameters
otherThe histogram to move from.
Returns
Reference to this histogram.

Definition at line 70 of file latency_histogram.cpp.

70 {
71 if (this != &other) {
72 for (std::size_t i = 0; i < BUCKET_COUNT; ++i) {
73 buckets_[i].store(other.buckets_[i].load(std::memory_order_relaxed),
74 std::memory_order_relaxed);
75 other.buckets_[i].store(0, std::memory_order_relaxed);
76 }
77 total_count_.store(other.total_count_.exchange(0, std::memory_order_relaxed),
78 std::memory_order_relaxed);
79 total_sum_.store(other.total_sum_.exchange(0, std::memory_order_relaxed),
80 std::memory_order_relaxed);
81 min_value_.store(other.min_value_.exchange(
82 std::numeric_limits<std::uint64_t>::max(),
83 std::memory_order_relaxed),
84 std::memory_order_relaxed);
85 max_value_.store(other.max_value_.exchange(0, std::memory_order_relaxed),
86 std::memory_order_relaxed);
87 }
88 return *this;
89}

◆ p50()

double kcenon::thread::metrics::LatencyHistogram::p50 ( ) const
inlinenodiscard

Get the 50th percentile (median).

Returns
The median latency in nanoseconds.

Definition at line 124 of file latency_histogram.h.

124{ return percentile(0.50); }
double percentile(double p) const
Calculate the value at a given percentile.

References percentile().

Referenced by kcenon::thread::metrics::EnhancedThreadPoolMetrics::snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ p90()

double kcenon::thread::metrics::LatencyHistogram::p90 ( ) const
inlinenodiscard

Get the 90th percentile.

Returns
The P90 latency in nanoseconds.

Definition at line 130 of file latency_histogram.h.

130{ return percentile(0.90); }

References percentile().

Referenced by kcenon::thread::metrics::EnhancedThreadPoolMetrics::snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ p95()

double kcenon::thread::metrics::LatencyHistogram::p95 ( ) const
inlinenodiscard

Get the 95th percentile.

Returns
The P95 latency in nanoseconds.

Definition at line 136 of file latency_histogram.h.

136{ return percentile(0.95); }

References percentile().

Here is the call graph for this function:

◆ p99()

double kcenon::thread::metrics::LatencyHistogram::p99 ( ) const
inlinenodiscard

Get the 99th percentile.

Returns
The P99 latency in nanoseconds.

Definition at line 142 of file latency_histogram.h.

142{ return percentile(0.99); }

References percentile().

Referenced by kcenon::thread::metrics::EnhancedThreadPoolMetrics::snapshot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ p999()

double kcenon::thread::metrics::LatencyHistogram::p999 ( ) const
inlinenodiscard

Get the 99.9th percentile.

Returns
The P99.9 latency in nanoseconds.

Definition at line 148 of file latency_histogram.h.

148{ return percentile(0.999); }

References percentile().

Here is the call graph for this function:

◆ percentile()

double kcenon::thread::metrics::LatencyHistogram::percentile ( double p) const
nodiscard

Calculate the value at a given percentile.

Parameters
pThe percentile (0.0 to 1.0, e.g., 0.99 for P99).
Returns
The latency value in nanoseconds at the given percentile.

Returns 0 if the histogram is empty. For an empty bucket at the target percentile, returns the bucket's upper bound to provide an upper estimate.

Definition at line 122 of file latency_histogram.cpp.

122 {
123 const auto total = total_count_.load(std::memory_order_relaxed);
124 if (total == 0) {
125 return 0.0;
126 }
127
128 // Clamp percentile to valid range
129 p = std::clamp(p, 0.0, 1.0);
130 const auto target_count = static_cast<std::uint64_t>(std::ceil(p * total));
131
132 std::uint64_t cumulative = 0;
133 for (std::size_t i = 0; i < BUCKET_COUNT; ++i) {
134 cumulative += buckets_[i].load(std::memory_order_relaxed);
135 if (cumulative >= target_count) {
136 // Linear interpolation within the bucket
137 const auto bucket_count_val = buckets_[i].load(std::memory_order_relaxed);
138 if (bucket_count_val == 0) {
139 return bucket_midpoint(i);
140 }
141
142 const auto prev_cumulative = cumulative - bucket_count_val;
143 const auto target_in_bucket = target_count - prev_cumulative;
144 const auto fraction =
145 static_cast<double>(target_in_bucket) / bucket_count_val;
146
147 const auto lower = bucket_lower_bound(i);
148 const auto upper = bucket_upper_bound(i);
149
150 return lower + fraction * (upper - lower);
151 }
152 }
153
154 // Should not reach here, but return max bucket value
155 return static_cast<double>(bucket_upper_bound(BUCKET_COUNT - 1));
156}
static double bucket_midpoint(std::size_t bucket_index)
Get the midpoint value of a bucket for estimation.

References BUCKET_COUNT, bucket_lower_bound(), bucket_midpoint(), bucket_upper_bound(), buckets_, and total_count_.

Referenced by p50(), p90(), p95(), p99(), and p999().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ record()

void kcenon::thread::metrics::LatencyHistogram::record ( std::chrono::nanoseconds value)

Record a latency value.

Parameters
valueThe latency duration to record.

This operation is lock-free and thread-safe. Complexity: O(1) - single atomic increment.

Definition at line 91 of file latency_histogram.cpp.

91 {
92 record_ns(static_cast<std::uint64_t>(value.count()));
93}
void record_ns(std::uint64_t nanoseconds)
Record a raw nanosecond value.

References record_ns().

Referenced by kcenon::thread::metrics::EnhancedThreadPoolMetrics::record_enqueue(), kcenon::thread::metrics::EnhancedThreadPoolMetrics::record_execution(), and kcenon::thread::metrics::EnhancedThreadPoolMetrics::record_wait_time().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ record_ns()

void kcenon::thread::metrics::LatencyHistogram::record_ns ( std::uint64_t nanoseconds)

Record a raw nanosecond value.

Parameters
nanosecondsThe latency in nanoseconds.

Definition at line 95 of file latency_histogram.cpp.

95 {
96 const auto bucket_index = compute_bucket_index(nanoseconds);
97 buckets_[bucket_index].fetch_add(1, std::memory_order_relaxed);
98 total_count_.fetch_add(1, std::memory_order_relaxed);
99 total_sum_.fetch_add(nanoseconds, std::memory_order_relaxed);
100
101 // Update min atomically using CAS
102 auto current_min = min_value_.load(std::memory_order_relaxed);
103 while (nanoseconds < current_min) {
104 if (min_value_.compare_exchange_weak(current_min, nanoseconds,
105 std::memory_order_relaxed,
106 std::memory_order_relaxed)) {
107 break;
108 }
109 }
110
111 // Update max atomically using CAS
112 auto current_max = max_value_.load(std::memory_order_relaxed);
113 while (nanoseconds > current_max) {
114 if (max_value_.compare_exchange_weak(current_max, nanoseconds,
115 std::memory_order_relaxed,
116 std::memory_order_relaxed)) {
117 break;
118 }
119 }
120}
static std::size_t compute_bucket_index(std::uint64_t value)
Compute the bucket index for a given value.

References buckets_, compute_bucket_index(), max_value_, min_value_, total_count_, and total_sum_.

Referenced by record().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reset()

void kcenon::thread::metrics::LatencyHistogram::reset ( )

Reset all buckets and counters to zero.

This operation is thread-safe but not atomic with respect to concurrent records. Some in-flight records may be lost during reset.

Definition at line 211 of file latency_histogram.cpp.

211 {
212 for (auto& bucket : buckets_) {
213 bucket.store(0, std::memory_order_relaxed);
214 }
215 total_count_.store(0, std::memory_order_relaxed);
216 total_sum_.store(0, std::memory_order_relaxed);
217 min_value_.store(std::numeric_limits<std::uint64_t>::max(),
218 std::memory_order_relaxed);
219 max_value_.store(0, std::memory_order_relaxed);
220}

References buckets_, max_value_, min_value_, total_count_, and total_sum_.

Referenced by kcenon::thread::metrics::EnhancedThreadPoolMetrics::reset().

Here is the caller graph for this function:

◆ stddev()

double kcenon::thread::metrics::LatencyHistogram::stddev ( ) const
nodiscard

Calculate the standard deviation.

Returns
The standard deviation in nanoseconds.

Returns 0.0 if the histogram has fewer than 2 samples.

Definition at line 166 of file latency_histogram.cpp.

166 {
167 const auto total = total_count_.load(std::memory_order_relaxed);
168 if (total < 2) {
169 return 0.0;
170 }
171
172 const auto mean_val = mean();
173 double sum_squared_diff = 0.0;
174
175 for (std::size_t i = 0; i < BUCKET_COUNT; ++i) {
176 const auto bucket_count_val = buckets_[i].load(std::memory_order_relaxed);
177 if (bucket_count_val > 0) {
178 const auto midpoint = bucket_midpoint(i);
179 const auto diff = midpoint - mean_val;
180 sum_squared_diff += bucket_count_val * diff * diff;
181 }
182 }
183
184 return std::sqrt(sum_squared_diff / (total - 1));
185}
double mean() const
Calculate the arithmetic mean.

References BUCKET_COUNT, bucket_midpoint(), buckets_, mean(), and total_count_.

Here is the call graph for this function:

◆ sum()

std::uint64_t kcenon::thread::metrics::LatencyHistogram::sum ( ) const
nodiscard

Get the sum of all recorded values.

Returns
The sum of all latencies in nanoseconds.

Definition at line 207 of file latency_histogram.cpp.

207 {
208 return total_sum_.load(std::memory_order_relaxed);
209}

References total_sum_.

Member Data Documentation

◆ BUCKET_COUNT

std::size_t kcenon::thread::metrics::LatencyHistogram::BUCKET_COUNT = 64
staticconstexpr

◆ buckets_

std::array<std::atomic<std::uint64_t>, BUCKET_COUNT> kcenon::thread::metrics::LatencyHistogram::buckets_
private

Histogram buckets using logarithmic distribution.

Definition at line 242 of file latency_histogram.h.

Referenced by bucket_count(), LatencyHistogram(), LatencyHistogram(), merge(), operator=(), percentile(), record_ns(), reset(), and stddev().

◆ max_value_

std::atomic<std::uint64_t> kcenon::thread::metrics::LatencyHistogram::max_value_ {0}
private

Maximum recorded value.

Definition at line 262 of file latency_histogram.h.

262{0};

Referenced by LatencyHistogram(), max(), merge(), operator=(), record_ns(), and reset().

◆ min_value_

std::atomic<std::uint64_t> kcenon::thread::metrics::LatencyHistogram::min_value_ {std::numeric_limits<std::uint64_t>::max()}
private

Minimum recorded value.

Definition at line 257 of file latency_histogram.h.

257{std::numeric_limits<std::uint64_t>::max()};

Referenced by LatencyHistogram(), merge(), min(), operator=(), record_ns(), and reset().

◆ total_count_

std::atomic<std::uint64_t> kcenon::thread::metrics::LatencyHistogram::total_count_ {0}
private

Total number of recorded values.

Definition at line 247 of file latency_histogram.h.

247{0};

Referenced by count(), empty(), LatencyHistogram(), max(), mean(), merge(), min(), operator=(), percentile(), record_ns(), reset(), and stddev().

◆ total_sum_

std::atomic<std::uint64_t> kcenon::thread::metrics::LatencyHistogram::total_sum_ {0}
private

Sum of all recorded values.

Definition at line 252 of file latency_histogram.h.

252{0};

Referenced by LatencyHistogram(), mean(), merge(), operator=(), record_ns(), reset(), and sum().


The documentation for this class was generated from the following files: