hdrhistogram/lib.rs
1//! HdrSample is a port of Gil Tene's HdrHistogram to native Rust. It provides recording and
2//! analyzing of sampled data value counts across a large, configurable value range with
3//! configurable precision within the range. The resulting "HDR" histogram allows for fast and
4//! accurate analysis of the extreme ranges of data with non-normal distributions, like latency.
5//!
6//! # HdrHistogram
7//!
8//! What follows is a description from [the HdrHistogram
9//! website](https://hdrhistogram.github.io/HdrHistogram/). Users are encouraged to read the
10//! documentation from the original [Java
11//! implementation](https://github.com/HdrHistogram/HdrHistogram), as most of the concepts
12//! translate directly to the Rust port.
13//!
14//! HdrHistogram supports the recording and analyzing of sampled data value counts across a
15//! configurable integer value range with configurable value precision within the range. Value
16//! precision is expressed as the number of significant digits in the value recording, and provides
17//! control over value quantization behavior across the value range and the subsequent value
18//! resolution at any given level.
19//!
20//! For example, a Histogram could be configured to track the counts of observed integer values
21//! between 0 and 3,600,000,000 while maintaining a value precision of 3 significant digits across
22//! that range. Value quantization within the range will thus be no larger than 1/1,000th (or 0.1%)
23//! of any value. This example Histogram could be used to track and analyze the counts of observed
24//! response times ranging between 1 microsecond and 1 hour in magnitude, while maintaining a value
25//! resolution of 1 microsecond up to 1 millisecond, a resolution of 1 millisecond (or better) up
26//! to one second, and a resolution of 1 second (or better) up to 1,000 seconds. At it's maximum
27//! tracked value (1 hour), it would still maintain a resolution of 3.6 seconds (or better).
28//!
29//! HDR Histogram is designed for recording histograms of value measurements in latency and
30//! performance sensitive applications. Measurements show value recording times as low as 3-6
31//! nanoseconds on modern (circa 2014) Intel CPUs. The HDR Histogram maintains a fixed cost in both
32//! space and time. A Histogram's memory footprint is constant, with no allocation operations
33//! involved in recording data values or in iterating through them. The memory footprint is fixed
34//! regardless of the number of data value samples recorded, and depends solely on the dynamic
35//! range and precision chosen. The amount of work involved in recording a sample is constant, and
36//! directly computes storage index locations such that no iteration or searching is ever involved
37//! in recording data values.
38//!
39//! If you are looking for FFI bindings to
40//! [`HdrHistogram_c`](https://github.com/HdrHistogram/HdrHistogram_c), you want the
41//! [`hdrhistogram_c`](https://crates.io/crates/hdrhistogram_c) crate instead.
42//!
43//! # Interacting with the library
44//!
45//! HdrSample's API follows that of the original HdrHistogram Java implementation, with some
46//! modifications to make its use more idiomatic in Rust. The description in this section has been
47//! adapted from that given by the [Python port](https://github.com/HdrHistogram/HdrHistogram_py),
48//! as it gives a nicer first-time introduction to the use of HdrHistogram than the Java docs do.
49//!
50//! HdrSample is generally used in one of two modes: recording samples, or querying for analytics.
51//! In distributed deployments, the recording may be performed remotely (and possibly in multiple
52//! locations), to then be aggregated later in a central location for analysis.
53//!
54//! ## Recording samples
55//!
56//! A histogram instance is created using the `::new` methods on the `Histogram` struct. These come
57//! in three variants: `new`, `new_with_max`, and `new_with_bounds`. The first of these only sets
58//! the required precision of the sampled data, but leaves the value range open such that any value
59//! may be recorded. A `Histogram` created this way (or one where auto-resize has been explicitly
60//! enabled) will automatically resize itself if a value that is too large to fit in the current
61//! dataset is encountered. `new_with_max` sets an upper bound on the values to be recorded, and
62//! disables auto-resizing, thus preventing any re-allocation during recording. If the application
63//! attempts to record a larger value than this maximum bound, the `record` call will return an
64//! error. Finally, `new_with_bounds` restricts the lowest representable value of the dataset,
65//! such that a smaller range needs to be covered (thus reducing the overall allocation size).
66//!
67//! For example the example below shows how to create a `Histogram` that can count values in the
68//! `[1..3600000]` range with 1% precision, which could be used to track latencies in the range `[1
69//! msec..1 hour]`).
70//!
71//! ```
72//! use hdrhistogram::Histogram;
73//! let mut hist = Histogram::<u64>::new_with_bounds(1, 60 * 60 * 1000, 2).unwrap();
74//!
75//! // samples can be recorded using .record, which will error if the value is too small or large
76//! hist.record(54321).expect("value 54321 should be in range");
77//!
78//! // for ergonomics, samples can also be recorded with +=
79//! // this call will panic if the value is out of range!
80//! hist += 54321;
81//!
82//! // if the code that generates the values is subject to Coordinated Omission,
83//! // the self-correcting record method should be used instead.
84//! // for example, if the expected sampling interval is 10 msec:
85//! hist.record_correct(54321, 10).expect("value 54321 should be in range");
86//! ```
87//!
88//! Note the `u64` type. This type can be changed to reduce the storage overhead for all the
89//! histogram bins, at the cost of a risk of saturating if a large number of samples end up in the
90//! same bin.
91//!
92//! ## Querying samples
93//!
94//! At any time, the histogram can be queried to return interesting statistical measurements, such
95//! as the total number of recorded samples, or the value at a given quantile:
96//!
97//! ```
98//! use hdrhistogram::Histogram;
99//! let hist = Histogram::<u64>::new(2).unwrap();
100//! // ...
101//! println!("# of samples: {}", hist.len());
102//! println!("99.9'th percentile: {}", hist.value_at_quantile(0.999));
103//! ```
104//!
105//! Several useful iterators are also provided for quickly getting an overview of the dataset. The
106//! simplest one is `iter_recorded()`, which yields one item for every non-empty sample bin. All
107//! the HdrHistogram iterators are supported in HdrSample, so look for the `*Iterator` classes in
108//! the [Java documentation](https://hdrhistogram.github.io/HdrHistogram/JavaDoc/).
109//!
110//! ```
111//! use hdrhistogram::Histogram;
112//! let hist = Histogram::<u64>::new(2).unwrap();
113//! // ...
114//! for v in hist.iter_recorded() {
115//! println!("{}'th percentile of data is {} with {} samples",
116//! v.percentile(), v.value_iterated_to(), v.count_at_value());
117//! }
118//! ```
119//!
120//! ## Panics and error handling
121//!
122//! As long as you're using safe, non-panicking functions (see below), this library should never
123//! panic. Any panics you encounter are a bug; please file them in the issue tracker.
124//!
125//! A few functions have their functionality exposed via `AddAssign` and `SubAssign`
126//! implementations. These alternate forms are equivalent to simply calling `unwrap()` on the
127//! normal functions, so the normal rules of `unwrap()` apply: view with suspicion when used in
128//! production code, etc.
129//!
130//! | Returns Result | Panics on error | Functionality |
131//! | ------------------------------ | ------------------ | ------------------------------- |
132//! | `h.record(v)` | `h += v` | Increment count for value `v` |
133//! | `h.add(h2)` | `h += h2` | Add `h2`'s counts to `h` |
134//! | `h.subtract(h2)` | `h -= h2` | Subtract `h2`'s counts from `h` |
135//!
136//! Other than the panicking forms of the above functions, everything will return `Result` or
137//! `Option` if it can fail.
138//!
139//! ## `usize` limitations
140//!
141//! Depending on the configured number of significant digits and maximum value, a histogram's
142//! internal storage may have hundreds of thousands of cells. Systems with a 16-bit `usize` cannot
143//! represent pointer offsets that large, so relevant operations (creation, deserialization, etc)
144//! will fail with a suitable error (e.g. `CreationError::UsizeTypeTooSmall`). If you are using such
145//! a system and hitting these errors, reducing the number of significant digits will greatly reduce
146//! memory consumption (and therefore the need for large `usize` values). Lowering the max value may
147//! also help as long as resizing is disabled.
148//!
149//! 32- and above systems will not have any such issues, as all possible histograms fit within a
150//! 32-bit index.
151//!
152//! ## Floating point accuracy
153//!
154//! Some calculations inherently involve floating point values, like `value_at_quantile`, and are
155//! therefore subject to the precision limits of IEEE754 floating point calculations. The user-
156//! visible consequence of this is that in certain corner cases, you might end up with a bucket (and
157//! therefore value) that is higher or lower than it would be if the calculation had been done
158//! with arbitrary-precision arithmetic. However, double-precision IEEE754 (i.e. `f64`) is very
159//! good at its job, so these cases should be rare. Also, we haven't seen a case that was off by
160//! more than one bucket.
161//!
162//! To minimize FP precision losses, we favor working with quantiles rather than percentiles. A
163//! quantile represents a portion of a set with a number in `[0, 1]`. A percentile is the same
164//! concept, except it uses the range `[0, 100]`. Working just with quantiles means we can skip an
165//! FP operation in a few places, and therefore avoid opportunities for precision loss to creep in.
166//!
167//! # Limitations and Caveats
168//!
169//! As with all the other HdrHistogram ports, the latest features and bug fixes from the upstream
170//! HdrHistogram implementations may not be available in this port. A number of features have also
171//! not (yet) been implemented:
172//!
173//! - Concurrency support (`AtomicHistogram`, `ConcurrentHistogram`, …).
174//! - `DoubleHistogram`.
175//! - The `Recorder` feature of HdrHistogram.
176//! - Value shifting ("normalization").
177//! - Textual output methods. These seem almost orthogonal to HdrSample, though it might be
178//! convenient if we implemented some relevant traits (CSV, JSON, and possibly simple
179//! `fmt::Display`).
180//!
181//! Most of these should be fairly straightforward to add, as the code aligns pretty well with the
182//! original Java/C# code. If you do decide to implement one and send a PR, please make sure you
183//! also port the [test
184//! cases](https://github.com/HdrHistogram/HdrHistogram/tree/master/src/test/java/org/HdrHistogram),
185//! and try to make sure you implement appropriate traits to make the use of the feature as
186//! ergonomic as possible.
187
188#![deny(
189 missing_docs,
190 trivial_casts,
191 trivial_numeric_casts,
192 unused_extern_crates,
193 unused_import_braces,
194 unused_results,
195 variant_size_differences
196)]
197// Enable feature(test) is enabled so that we can have benchmarks of private code
198#![cfg_attr(all(test, feature = "bench_private"), feature(test))]
199
200#[cfg(all(test, feature = "bench_private"))]
201extern crate test;
202
203#[cfg(feature = "serialization")]
204#[macro_use]
205extern crate nom;
206
207use num_traits::ToPrimitive;
208use std::borrow::Borrow;
209use std::cmp;
210use std::ops::{Add, AddAssign, Sub, SubAssign};
211
212use iterators::HistogramIterator;
213
214/// Min value of a new histogram.
215/// Equivalent to `u64::max_value()`, but const functions aren't allowed (yet).
216/// See <https://github.com/rust-lang/rust/issues/24111>
217const ORIGINAL_MIN: u64 = (-1_i64 >> 63) as u64;
218/// Max value of a new histogram.
219const ORIGINAL_MAX: u64 = 0;
220
221/// `Histogram` is the core data structure in HdrSample. It records values, and performs analytics.
222///
223/// At its heart, it keeps the count for recorded samples in "buckets" of values. The resolution
224/// and distribution of these buckets is tuned based on the desired highest trackable value, as
225/// well as the user-specified number of significant decimal digits to preserve. The values for the
226/// buckets are kept in a way that resembles floats and doubles: there is a mantissa and an
227/// exponent, and each bucket represents a different exponent. The "sub-buckets" within a bucket
228/// represent different values for the mantissa.
229///
230/// To a first approximation, the sub-buckets of the first
231/// bucket would hold the values `0`, `1`, `2`, `3`, …, the sub-buckets of the second bucket would
232/// hold `0`, `2`, `4`, `6`, …, the third would hold `0`, `4`, `8`, and so on. However, the low
233/// half of each bucket (except bucket 0) is unnecessary, since those values are already covered by
234/// the sub-buckets of all the preceeding buckets. Thus, `Histogram` keeps the top half of every
235/// such bucket.
236///
237/// For the purposes of explanation, consider a `Histogram` with 2048 sub-buckets for every bucket,
238/// and a lowest discernible value of 1:
239///
240/// <pre>
241/// The 0th bucket covers 0...2047 in multiples of 1, using all 2048 sub-buckets
242/// The 1st bucket covers 2048..4097 in multiples of 2, using only the top 1024 sub-buckets
243/// The 2nd bucket covers 4096..8191 in multiple of 4, using only the top 1024 sub-buckets
244/// ...
245/// </pre>
246///
247/// Bucket 0 is "special" here. It is the only one that has 2048 entries. All the rest have
248/// 1024 entries (because their bottom half overlaps with and is already covered by the all of
249/// the previous buckets put together). In other words, the `k`'th bucket could represent `0 *
250/// 2^k` to `2048 * 2^k` in 2048 buckets with `2^k` precision, but the midpoint of `1024 * 2^k
251/// = 2048 * 2^(k-1)`, which is the k-1'th bucket's end. So, we would use the previous bucket
252/// for those lower values as it has better precision.
253///
254#[derive(Debug)]
255pub struct Histogram<T: Counter> {
256 auto_resize: bool,
257
258 // >= 2 * lowest_discernible_value
259 highest_trackable_value: u64,
260 // >= 1
261 lowest_discernible_value: u64,
262 // in [0, 5]
263 significant_value_digits: u8,
264
265 // in [1, 64]
266 bucket_count: u8,
267 // 2^(sub_bucket_half_count_magnitude + 1) = [2, 2^18]
268 sub_bucket_count: u32,
269 // sub_bucket_count / 2 = [1, 2^17]
270 sub_bucket_half_count: u32,
271 // In [0, 17]
272 sub_bucket_half_count_magnitude: u8,
273 // The bottom sub bucket's bits set, shifted by unit magnitude.
274 // The highest bit will be (one-indexed) sub bucket count magnitude + unit_magnitude.
275 sub_bucket_mask: u64,
276
277 // Number of leading zeros that would be used by the largest value in bucket 0.
278 // in [1, 63]
279 leading_zero_count_base: u8,
280
281 // Largest exponent of 2 that's smaller than the lowest discernible value. In [0, 62].
282 unit_magnitude: u8,
283 // low unit_magnitude bits set
284 unit_magnitude_mask: u64,
285
286 max_value: u64,
287 min_non_zero_value: u64,
288
289 total_count: u64,
290 counts: Vec<T>,
291}
292
293/// Module containing the implementations of all `Histogram` iterators.
294pub mod iterators;
295
296impl<T: Counter> Histogram<T> {
297 // ********************************************************************************************
298 // Histogram administrative read-outs
299 // ********************************************************************************************
300
301 /// Get the current number of distinct values that can be represented in the histogram.
302 pub fn distinct_values(&self) -> usize {
303 self.counts.len()
304 }
305
306 /// Get the lowest discernible value for the histogram in its current configuration.
307 pub fn low(&self) -> u64 {
308 self.lowest_discernible_value
309 }
310
311 /// Get the highest trackable value for the histogram in its current configuration.
312 pub fn high(&self) -> u64 {
313 self.highest_trackable_value
314 }
315
316 /// Get the number of significant value digits kept by this histogram.
317 pub fn sigfig(&self) -> u8 {
318 self.significant_value_digits
319 }
320
321 /// Get the total number of samples recorded.
322 #[deprecated(since = "6.0.0", note = "use `len` instead")]
323 pub fn count(&self) -> u64 {
324 self.total_count
325 }
326
327 /// Get the total number of samples recorded.
328 pub fn len(&self) -> u64 {
329 self.total_count
330 }
331
332 /// Returns true if this histogram has no recorded values.
333 pub fn is_empty(&self) -> bool {
334 self.total_count == 0
335 }
336
337 /// Get the number of buckets used by the histogram to cover the highest trackable value.
338 ///
339 /// This method differs from `.len()` in that it does not count the sub buckets within each
340 /// bucket.
341 ///
342 /// This method is probably only useful for testing purposes.
343 pub fn buckets(&self) -> u8 {
344 self.bucket_count
345 }
346
347 // ********************************************************************************************
348 // Methods for looking up the count for a given value/index
349 // ********************************************************************************************
350
351 /// Find the bucket the given value should be placed in.
352 /// Returns `None` if the corresponding index cannot be represented in `usize`.
353 fn index_for(&self, value: u64) -> Option<usize> {
354 let bucket_index = self.bucket_for(value);
355 let sub_bucket_index = self.sub_bucket_for(value, bucket_index);
356
357 debug_assert!(sub_bucket_index < self.sub_bucket_count);
358 debug_assert!(bucket_index == 0 || (sub_bucket_index >= self.sub_bucket_half_count));
359
360 // Calculate the index for the first entry that will be used in the bucket (halfway through
361 // sub_bucket_count). For bucket_index 0, all sub_bucket_count entries may be used, but
362 // bucket_base_index is still set in the middle.
363 let bucket_base_index =
364 (i32::from(bucket_index) + 1) << self.sub_bucket_half_count_magnitude;
365
366 // Calculate the offset in the bucket. This subtraction will result in a positive value in
367 // all buckets except the 0th bucket (since a value in that bucket may be less than half
368 // the bucket's 0 to sub_bucket_count range). However, this works out since we give bucket 0
369 // twice as much space.
370 let offset_in_bucket = sub_bucket_index as i32 - self.sub_bucket_half_count as i32;
371
372 let index = bucket_base_index + offset_in_bucket;
373 // This is always non-negative because offset_in_bucket is only negative (and only then by
374 // sub_bucket_half_count at most) for bucket 0, and bucket_base_index will be halfway into
375 // bucket 0's sub buckets in that case.
376 debug_assert!(index >= 0);
377 index.to_usize()
378 }
379
380 /// Find the bucket the given value should be placed in.
381 /// If the value is bigger than what this histogram can express, the last valid bucket index
382 /// is returned instead.
383 fn index_for_or_last(&self, value: u64) -> usize {
384 self.index_for(value)
385 .map_or(self.last_index(), |i| cmp::min(i, self.last_index()))
386 }
387
388 /// Get a mutable reference to the count bucket for the given value, if it is in range.
389 fn mut_at(&mut self, value: u64) -> Option<&mut T> {
390 self.index_for(value)
391 .and_then(move |i| self.counts.get_mut(i))
392 }
393
394 /// Get the index of the last histogram bin.
395 fn last_index(&self) -> usize {
396 self.distinct_values()
397 .checked_sub(1)
398 .expect("Empty counts array?")
399 }
400
401 // ********************************************************************************************
402 // Histograms should be cloneable.
403 // ********************************************************************************************
404
405 /// Get a copy of this histogram, corrected for coordinated omission.
406 ///
407 /// To compensate for the loss of sampled values when a recorded value is larger than the
408 /// expected interval between value samples, the new histogram will include an auto-generated
409 /// additional series of decreasingly-smaller (down to the `interval`) value records for each
410 /// count found in the current histogram that is larger than the `interval`.
411 ///
412 /// Note: This is a post-correction method, as opposed to the at-recording correction method
413 /// provided by `record_correct`. The two methods are mutually exclusive, and only one of the
414 /// two should be be used on a given data set to correct for the same coordinated omission
415 /// issue.
416 ///
417 /// See notes in the description of the Histogram calls for an illustration of why this
418 /// corrective behavior is important.
419 ///
420 /// If `interval` is larger than 0, add auto-generated value records as appropriate if value is
421 /// larger than `interval`.
422 pub fn clone_correct(&self, interval: u64) -> Histogram<T> {
423 let mut h = Histogram::new_from(self);
424 for v in self.iter_recorded() {
425 h.record_n_correct(v.value_iterated_to(), v.count_at_value(), interval)
426 .expect("Same dimensions; all values should be representable");
427 }
428 h
429 }
430
431 /// Overwrite this histogram with the given histogram. All data and statistics in this
432 /// histogram will be overwritten.
433 pub fn set_to<B: Borrow<Histogram<T>>>(&mut self, source: B) -> Result<(), AdditionError> {
434 self.reset();
435 self.add(source.borrow())
436 }
437
438 /// Overwrite this histogram with the given histogram while correcting for coordinated
439 /// omission. All data and statistics in this histogram will be overwritten. See
440 /// `clone_correct` for more detailed explanation about how correction is applied
441 pub fn set_to_corrected<B: Borrow<Histogram<T>>>(
442 &mut self,
443 source: B,
444 interval: u64,
445 ) -> Result<(), RecordError> {
446 self.reset();
447 self.add_correct(source, interval)
448 }
449
450 // ********************************************************************************************
451 // Add and subtract methods for, well, adding or subtracting two histograms
452 // ********************************************************************************************
453
454 /// Add the contents of another histogram to this one.
455 ///
456 /// Returns an error if values in the other histogram cannot be stored; see `AdditionError`.
457 pub fn add<B: Borrow<Histogram<T>>>(&mut self, source: B) -> Result<(), AdditionError> {
458 let source = source.borrow();
459
460 // make sure we can take the values in source
461 let top = self.highest_equivalent(self.value_for(self.last_index()));
462 if top < source.max() {
463 if !self.auto_resize {
464 return Err(AdditionError::OtherAddendValueExceedsRange);
465 }
466 // We're growing the histogram, so new high > old high and is therefore >= 2x low.
467 self.resize(source.max())
468 .map_err(|_| AdditionError::ResizeFailedUsizeTypeTooSmall)?;
469 }
470
471 if self.bucket_count == source.bucket_count
472 && self.sub_bucket_count == source.sub_bucket_count
473 && self.unit_magnitude == source.unit_magnitude
474 {
475 // Counts arrays are of the same length and meaning,
476 // so we can just iterate and add directly:
477 let mut observed_other_total_count: u64 = 0;
478 for i in 0..source.distinct_values() {
479 let other_count = source
480 .count_at_index(i)
481 .expect("iterating inside source length");
482 if other_count != T::zero() {
483 // indexing is safe: same configuration as `source`, and the index was valid for
484 // `source`.
485 self.counts[i] = self.counts[i].saturating_add(other_count);
486 observed_other_total_count =
487 observed_other_total_count.saturating_add(other_count.as_u64());
488 }
489 }
490
491 self.total_count = self.total_count.saturating_add(observed_other_total_count);
492 let mx = source.max();
493 if mx > self.max() {
494 self.update_max(mx);
495 }
496 let mn = source.min_nz();
497 if mn < self.min_nz() {
498 self.update_min(mn);
499 }
500 } else {
501 // Arrays are not a direct match (or the other could change on the fly in some valid
502 // way), so we can't just stream through and add them. Instead, go through the array
503 // and add each non-zero value found at it's proper value:
504
505 // Do max value first, to avoid max value updates on each iteration:
506 let other_max_index = source
507 .index_for(source.max())
508 .expect("Index for max value must exist");
509 let other_count = source
510 .count_at_index(other_max_index)
511 .expect("max's index must exist");
512 self.record_n(source.value_for(other_max_index), other_count)
513 .expect("Record must succeed; already resized for max value");
514
515 // Record the remaining values, up to but not including the max value:
516 for i in 0..other_max_index {
517 let other_count = source
518 .count_at_index(i)
519 .expect("index before max must exist");
520 if other_count != T::zero() {
521 self.record_n(source.value_for(i), other_count)
522 .expect("Record must succeed; already recorded max value");
523 }
524 }
525 }
526
527 // TODO:
528 // if source.start_time < self.start_time {
529 // self.start_time = source.start_time;
530 // }
531 // if source.end_time > self.end_time {
532 // self.end_time = source.end_time;
533 // }
534 Ok(())
535 }
536
537 /// Add the contents of another histogram to this one, while correcting for coordinated
538 /// omission.
539 ///
540 /// To compensate for the loss of sampled values when a recorded value is larger than the
541 /// expected interval between value samples, the values added will include an auto-generated
542 /// additional series of decreasingly-smaller (down to the given `interval`) value records for
543 /// each count found in the current histogram that is larger than `interval`.
544 ///
545 /// Note: This is a post-recording correction method, as opposed to the at-recording correction
546 /// method provided by `record_correct`. The two methods are mutually exclusive, and only one
547 /// of the two should be be used on a given data set to correct for the same coordinated
548 /// omission issue.
549 ///
550 /// See notes in the description of the `Histogram` calls for an illustration of why this
551 /// corrective behavior is important.
552 ///
553 /// See `RecordError` for error conditions.
554 pub fn add_correct<B: Borrow<Histogram<T>>>(
555 &mut self,
556 source: B,
557 interval: u64,
558 ) -> Result<(), RecordError> {
559 let source = source.borrow();
560
561 for v in source.iter_recorded() {
562 self.record_n_correct(v.value_iterated_to(), v.count_at_value(), interval)?;
563 }
564 Ok(())
565 }
566
567 /// Subtract the contents of another histogram from this one.
568 ///
569 /// See `SubtractionError` for error conditions.
570 pub fn subtract<B: Borrow<Histogram<T>>>(
571 &mut self,
572 subtrahend: B,
573 ) -> Result<(), SubtractionError> {
574 let subtrahend = subtrahend.borrow();
575
576 // make sure we can take the values in source
577 let top = self.highest_equivalent(self.value_for(self.last_index()));
578 if top < self.highest_equivalent(subtrahend.max()) {
579 return Err(SubtractionError::SubtrahendValueExceedsMinuendRange);
580 }
581
582 let old_min_highest_equiv = self.highest_equivalent(self.min());
583 let old_max_lowest_equiv = self.lowest_equivalent(self.max());
584
585 // If total_count is at the max value, it may have saturated, so we must restat
586 let mut needs_restat = self.total_count == u64::max_value();
587
588 for i in 0..subtrahend.distinct_values() {
589 let other_count = subtrahend
590 .count_at_index(i)
591 .expect("index inside subtrahend len must exist");
592 if other_count != T::zero() {
593 let other_value = subtrahend.value_for(i);
594 {
595 let mut_count = self.mut_at(other_value);
596
597 if let Some(c) = mut_count {
598 // TODO Perhaps we should saturating sub here? Or expose some form of
599 // pluggability so users could choose to error or saturate? Both seem
600 // useful. It's also sort of inconsistent with overflow, which now
601 // saturates.
602 *c = (*c)
603 .checked_sub(&other_count)
604 .ok_or(SubtractionError::SubtrahendCountExceedsMinuendCount)?;
605 } else {
606 panic!("Tried to subtract value outside of range: {}", other_value);
607 }
608 }
609
610 // we might have just set the min / max to have zero count.
611 if other_value <= old_min_highest_equiv || other_value >= old_max_lowest_equiv {
612 needs_restat = true;
613 }
614
615 if !needs_restat {
616 // if we're not already going to recalculate everything, subtract from
617 // total_count
618 self.total_count = self
619 .total_count
620 .checked_sub(other_count.as_u64())
621 .expect("total count underflow on subtraction");
622 }
623 }
624 }
625
626 if needs_restat {
627 let l = self.distinct_values();
628 self.restat(l);
629 }
630
631 Ok(())
632 }
633
634 // ********************************************************************************************
635 // Setters and resetters.
636 // ********************************************************************************************
637
638 /// Clear the contents of this histogram while preserving its statistics and configuration.
639 pub fn clear(&mut self) {
640 for c in &mut self.counts {
641 *c = T::zero();
642 }
643 self.total_count = 0;
644 }
645
646 /// Reset the contents and statistics of this histogram, preserving only its configuration.
647 pub fn reset(&mut self) {
648 self.clear();
649
650 self.reset_max(ORIGINAL_MAX);
651 self.reset_min(ORIGINAL_MIN);
652 // self.normalizing_index_offset = 0;
653 // self.start_time = time::Instant::now();
654 // self.end_time = time::Instant::now();
655 // self.tag = String::new();
656 }
657
658 /// Control whether or not the histogram can auto-resize and auto-adjust it's highest trackable
659 /// value as high-valued samples are recorded.
660 pub fn auto(&mut self, enabled: bool) {
661 self.auto_resize = enabled;
662 }
663
664 // ********************************************************************************************
665 // Construction.
666 // ********************************************************************************************
667
668 /// Construct an auto-resizing `Histogram` with a lowest discernible value of 1 and an
669 /// auto-adjusting highest trackable value. Can auto-resize up to track values up to
670 /// `(i64::max_value() / 2)`.
671 ///
672 /// See [`new_with_bounds`] for info on `sigfig`.
673 ///
674 /// [`new_with_bounds`]: #method.new_with_bounds
675 pub fn new(sigfig: u8) -> Result<Histogram<T>, CreationError> {
676 let mut h = Self::new_with_bounds(1, 2, sigfig);
677 if let Ok(ref mut h) = h {
678 h.auto_resize = true;
679 }
680 h
681 }
682
683 /// Construct a `Histogram` given a known maximum value to be tracked, and a number of
684 /// significant decimal digits. The histogram will be constructed to implicitly track
685 /// (distinguish from 0) values as low as 1. Auto-resizing will be disabled.
686 ///
687 /// See [`new_with_bounds`] for info on `high` and `sigfig`.
688 ///
689 /// [`new_with_bounds`]: #method.new_with_bounds
690 pub fn new_with_max(high: u64, sigfig: u8) -> Result<Histogram<T>, CreationError> {
691 Self::new_with_bounds(1, high, sigfig)
692 }
693
694 /// Construct a `Histogram` with known upper and lower bounds for recorded sample values.
695 ///
696 /// `low` is the lowest value that can be discerned (distinguished from 0) by the histogram,
697 /// and must be a positive integer that is >= 1. It may be internally rounded down to nearest
698 /// power of 2. Providing a lowest discernible value (`low`) is useful is situations where the
699 /// units used for the histogram's values are much smaller that the minimal accuracy required.
700 /// E.g. when tracking time values stated in nanosecond units, where the minimal accuracy
701 /// required is a microsecond, the proper value for `low` would be 1000. If you're not sure,
702 /// use 1.
703 ///
704 /// `high` is the highest value to be tracked by the histogram, and must be a
705 /// positive integer that is `>= (2 * low)`. If you're not sure, use `u64::max_value()`.
706 ///
707 /// `sigfig` Specifies the number of significant figures to maintain. This is the number of
708 /// significant decimal digits to which the histogram will maintain value resolution and
709 /// separation. Must be in the range [0, 5]. If you're not sure, use 3. As `sigfig` increases,
710 /// memory usage grows exponentially, so choose carefully if there will be many histograms in
711 /// memory at once or if storage is otherwise a concern.
712 ///
713 /// Returns an error if the provided parameters are invalid; see `CreationError`.
714 pub fn new_with_bounds(low: u64, high: u64, sigfig: u8) -> Result<Histogram<T>, CreationError> {
715 // Verify argument validity
716 if low < 1 {
717 return Err(CreationError::LowIsZero);
718 }
719 if low > u64::max_value() / 2 {
720 // avoid overflow in 2 * low
721 return Err(CreationError::LowExceedsMax);
722 }
723 if high < 2 * low {
724 return Err(CreationError::HighLessThanTwiceLow);
725 }
726 if sigfig > 5 {
727 return Err(CreationError::SigFigExceedsMax);
728 }
729
730 // Given a 3 decimal point accuracy, the expectation is obviously for "+/- 1 unit at 1000".
731 // It also means that it's "ok to be +/- 2 units at 2000". The "tricky" thing is that it is
732 // NOT ok to be +/- 2 units at 1999. Only starting at 2000. So internally, we need to
733 // maintain single unit resolution to 2x 10^decimal_points.
734
735 // largest value with single unit resolution, in [2, 200_000].
736 let largest = 2 * 10_u32.pow(u32::from(sigfig));
737
738 let unit_magnitude = (low as f64).log2().floor() as u8;
739 let unit_magnitude_mask = (1 << unit_magnitude) - 1;
740
741 // We need to maintain power-of-two sub_bucket_count (for clean direct indexing) that is
742 // large enough to provide unit resolution to at least
743 // largest_value_with_single_unit_resolution. So figure out
744 // largest_value_with_single_unit_resolution's nearest power-of-two (rounded up), and use
745 // that.
746 // In [1, 18]. 2^18 > 2 * 10^5 (the largest possible
747 // largest_value_with_single_unit_resolution)
748 let sub_bucket_count_magnitude = (f64::from(largest)).log2().ceil() as u8;
749 let sub_bucket_half_count_magnitude = sub_bucket_count_magnitude - 1;
750 let sub_bucket_count = 1_u32 << u32::from(sub_bucket_count_magnitude);
751
752 if unit_magnitude + sub_bucket_count_magnitude > 63 {
753 // sub_bucket_count entries can't be represented, with unit_magnitude applied, in a
754 // u64. Technically it still sort of works if their sum is 64: you can represent all
755 // but the last number in the shifted sub_bucket_count. However, the utility of such a
756 // histogram vs ones whose magnitude here fits in 63 bits is debatable, and it makes
757 // it harder to work through the logic. Sums larger than 64 are totally broken as
758 // leading_zero_count_base would go negative.
759 return Err(CreationError::CannotRepresentSigFigBeyondLow);
760 };
761
762 let sub_bucket_half_count = sub_bucket_count / 2;
763 // sub_bucket_count is always at least 2, so subtraction won't underflow
764 let sub_bucket_mask = (u64::from(sub_bucket_count) - 1) << unit_magnitude;
765
766 let mut h = Histogram {
767 auto_resize: false,
768
769 highest_trackable_value: high,
770 lowest_discernible_value: low,
771 significant_value_digits: sigfig,
772
773 // set by resize() below
774 bucket_count: 0,
775 sub_bucket_count,
776
777 // Establish leading_zero_count_base, used in bucket_index_of() fast path:
778 // subtract the bits that would be used by the largest value in bucket 0.
779 leading_zero_count_base: 64 - unit_magnitude - sub_bucket_count_magnitude,
780 sub_bucket_half_count_magnitude,
781
782 unit_magnitude,
783 sub_bucket_half_count,
784
785 sub_bucket_mask,
786
787 unit_magnitude_mask,
788 max_value: ORIGINAL_MAX,
789 min_non_zero_value: ORIGINAL_MIN,
790
791 total_count: 0,
792 // set by alloc() below
793 counts: Vec::new(),
794 };
795
796 // Already checked that high >= 2*low
797 h.resize(high)
798 .map_err(|_| CreationError::UsizeTypeTooSmall)?;
799 Ok(h)
800 }
801
802 /// Construct a `Histogram` with the same range settings as a given source histogram,
803 /// duplicating the source's start/end timestamps (but NOT its contents).
804 pub fn new_from<F: Counter>(source: &Histogram<F>) -> Histogram<T> {
805 let mut h = Self::new_with_bounds(
806 source.lowest_discernible_value,
807 source.highest_trackable_value,
808 source.significant_value_digits,
809 )
810 .expect("Using another histogram's parameters failed");
811
812 // h.start_time = source.start_time;
813 // h.end_time = source.end_time;
814 h.auto_resize = source.auto_resize;
815 h.counts.resize(source.distinct_values(), T::zero());
816 h
817 }
818
819 // ********************************************************************************************
820 // Recording samples.
821 // ********************************************************************************************
822
823 /// Record `value` in the histogram.
824 ///
825 /// Returns an error if `value` exceeds the highest trackable value and auto-resize is
826 /// disabled.
827 pub fn record(&mut self, value: u64) -> Result<(), RecordError> {
828 self.record_n(value, T::one())
829 }
830
831 /// Record `value` in the histogram, clamped to the range of the histogram.
832 ///
833 /// This method cannot fail, as any values that are too small or too large to be tracked will
834 /// automatically be clamed to be in range. Be aware that this *will* hide extreme outliers
835 /// from the resulting histogram without warning. Since the values are clamped, the histogram
836 /// will also not be resized to accomodate the value, even if auto-resize is enabled.
837 pub fn saturating_record(&mut self, value: u64) {
838 self.saturating_record_n(value, T::one())
839 }
840
841 /// Record multiple samples for a value in the histogram, adding to the value's current count.
842 ///
843 /// `count` is the number of occurrences of this value to record.
844 ///
845 /// Returns an error if `value` cannot be recorded; see `RecordError`.
846 pub fn record_n(&mut self, value: u64, count: T) -> Result<(), RecordError> {
847 self.record_n_inner(value, count, false)
848 }
849
850 /// Record multiple samples for a value in the histogram, each one clamped to the histogram's
851 /// range.
852 ///
853 /// `count` is the number of occurrences of this value to record.
854 ///
855 /// This method cannot fail, as values that are too small or too large to be recorded will
856 /// automatically be clamed to be in range. Be aware that this *will* hide extreme outliers
857 /// from the resulting histogram without warning. Since the values are clamped, the histogram
858 /// will also not be resized to accomodate the value, even if auto-resize is enabled.
859 pub fn saturating_record_n(&mut self, value: u64, count: T) {
860 self.record_n_inner(value, count, true).unwrap()
861 }
862
863 fn record_n_inner(&mut self, mut value: u64, count: T, clamp: bool) -> Result<(), RecordError> {
864 let recorded_without_resize = if let Some(c) = self.mut_at(value) {
865 *c = (*c).saturating_add(count);
866 true
867 } else {
868 false
869 };
870
871 if !recorded_without_resize {
872 if clamp {
873 value = if value > self.highest_trackable_value {
874 self.highest_trackable_value
875 } else {
876 // must be smaller than the lowest_discernible_value, since self.mut_at(value)
877 // failed, and it's not too large (per above).
878 self.lowest_discernible_value
879 };
880
881 let c = self
882 .mut_at(value)
883 .expect("unwrap must succeed since low and high are always representable");
884 *c = c.saturating_add(count);
885 } else if !self.auto_resize {
886 return Err(RecordError::ValueOutOfRangeResizeDisabled);
887 } else {
888 // We're growing the histogram, so new high > old high and is therefore >= 2x low.
889 self.resize(value)
890 .map_err(|_| RecordError::ResizeFailedUsizeTypeTooSmall)?;
891 self.highest_trackable_value =
892 self.highest_equivalent(self.value_for(self.last_index()));
893
894 {
895 let c = self.mut_at(value).expect("value should fit after resize");
896 // after resize, should be no possibility of overflow because this is a new slot
897 *c = (*c)
898 .checked_add(&count)
899 .expect("count overflow after resize");
900 }
901 }
902 }
903
904 self.update_min_max(value);
905 self.total_count = self.total_count.saturating_add(count.as_u64());
906 Ok(())
907 }
908
909 /// Record a value in the histogram while correcting for coordinated omission.
910 ///
911 /// See `record_n_correct` for further documentation.
912 pub fn record_correct(&mut self, value: u64, interval: u64) -> Result<(), RecordError> {
913 self.record_n_correct(value, T::one(), interval)
914 }
915
916 /// Record multiple values in the histogram while correcting for coordinated omission.
917 ///
918 /// To compensate for the loss of sampled values when a recorded value is larger than the
919 /// expected interval between value samples, this method will auto-generate and record an
920 /// additional series of decreasingly-smaller (down to `interval`) value records.
921 ///
922 /// Note: This is a at-recording correction method, as opposed to the post-recording correction
923 /// method provided by `correct_clone`. The two methods are mutually exclusive, and only one of
924 /// the two should be be used on a given data set to correct for the same coordinated omission
925 /// issue.
926 ///
927 /// Returns an error if `value` exceeds the highest trackable value and auto-resize is
928 /// disabled.
929 pub fn record_n_correct(
930 &mut self,
931 value: u64,
932 count: T,
933 interval: u64,
934 ) -> Result<(), RecordError> {
935 self.record_n(value, count)?;
936 if interval == 0 {
937 return Ok(());
938 }
939
940 if value > interval {
941 // only enter loop when calculations will stay non-negative
942 let mut missing_value = value - interval;
943 while missing_value >= interval {
944 self.record_n_inner(missing_value, count, false)?;
945 missing_value -= interval;
946 }
947 }
948
949 Ok(())
950 }
951
952 // ********************************************************************************************
953 // Iterators
954 // ********************************************************************************************
955
956 /// Iterate through histogram values by quantile levels.
957 ///
958 /// The iteration mechanic for this iterator may appear somewhat confusing, but it yields
959 /// fairly pleasing output. The iterator starts with a *quantile step size* of
960 /// `1/halving_period`. For every iteration, it yields a value whose quantile is that much
961 /// greater than the previously emitted quantile (i.e., initially 0, 0.1, 0.2, etc.). Once
962 /// `halving_period` values have been emitted, the quantile step size is halved, and the
963 /// iteration continues.
964 ///
965 /// `ticks_per_half_distance` must be at least 1.
966 ///
967 /// The iterator yields an `iterators::IterationValue` struct.
968 ///
969 /// One subtlety of this iterator is that you can reach a value whose cumulative count yields
970 /// a quantile of 1.0 far sooner than the quantile iteration would reach 1.0. Consider a
971 /// histogram with count 1 at value 1, and count 1000000 at value 1000. At any quantile
972 /// iteration above `1/1000001 = 0.000000999`, iteration will have necessarily proceeded to
973 /// the index for value 1000, which has all the remaining counts, and therefore quantile (for
974 /// the value) of 1.0. This is why `IterationValue` has both `quantile()` and
975 /// `quantile_iterated_to()`. Additionally, to avoid a bunch of unhelpful iterations once
976 /// iteration has reached the last value with non-zero count, quantile iteration will skip
977 /// straight to 1.0 as well.
978 ///
979 /// ```
980 /// use hdrhistogram::Histogram;
981 /// use hdrhistogram::iterators::IterationValue;
982 /// let mut hist = Histogram::<u64>::new_with_max(10000, 4).unwrap();
983 /// for i in 0..10000 {
984 /// hist += i;
985 /// }
986 ///
987 /// let mut perc = hist.iter_quantiles(1);
988 ///
989 /// println!("{:?}", hist.iter_quantiles(1).collect::<Vec<_>>());
990 ///
991 /// assert_eq!(
992 /// perc.next(),
993 /// Some(IterationValue::new(hist.value_at_quantile(0.0001), 0.0001, 0.0, 1, 1))
994 /// );
995 /// // step size = 50
996 /// assert_eq!(
997 /// perc.next(),
998 /// Some(IterationValue::new(hist.value_at_quantile(0.5), 0.5, 0.5, 1, 5000 - 1))
999 /// );
1000 /// // step size = 25
1001 /// assert_eq!(
1002 /// perc.next(),
1003 /// Some(IterationValue::new(hist.value_at_quantile(0.75), 0.75, 0.75, 1, 2500))
1004 /// );
1005 /// // step size = 12.5
1006 /// assert_eq!(
1007 /// perc.next(),
1008 /// Some(IterationValue::new(hist.value_at_quantile(0.875), 0.875, 0.875, 1, 1250))
1009 /// );
1010 /// // step size = 6.25
1011 /// assert_eq!(
1012 /// perc.next(),
1013 /// Some(IterationValue::new(hist.value_at_quantile(0.9375), 0.9375, 0.9375, 1, 625))
1014 /// );
1015 /// // step size = 3.125
1016 /// assert_eq!(
1017 /// perc.next(),
1018 /// Some(IterationValue::new(hist.value_at_quantile(0.9688), 0.9688, 0.96875, 1, 313))
1019 /// );
1020 /// // etc...
1021 /// ```
1022 pub fn iter_quantiles(
1023 &self,
1024 ticks_per_half_distance: u32,
1025 ) -> HistogramIterator<T, iterators::quantile::Iter<T>> {
1026 // TODO upper bound on ticks per half distance? 2^31 ticks is not useful
1027 iterators::quantile::Iter::new(self, ticks_per_half_distance)
1028 }
1029
1030 /// Iterates through histogram values using linear value steps. The iteration is performed in
1031 /// steps of size `step`, each one yielding the count for all values in the preceeding value
1032 /// range of size `step`. The iterator terminates when all recorded histogram values are
1033 /// exhausted.
1034 ///
1035 /// The iterator yields an `iterators::IterationValue` struct.
1036 ///
1037 /// ```
1038 /// use hdrhistogram::Histogram;
1039 /// use hdrhistogram::iterators::IterationValue;
1040 /// let mut hist = Histogram::<u64>::new_with_max(1000, 3).unwrap();
1041 /// hist += 100;
1042 /// hist += 500;
1043 /// hist += 800;
1044 /// hist += 850;
1045 ///
1046 /// let mut perc = hist.iter_linear(100);
1047 /// assert_eq!(
1048 /// perc.next(),
1049 /// Some(IterationValue::new(99, hist.quantile_below(99), hist.quantile_below(99), 0, 0))
1050 /// );
1051 /// assert_eq!(
1052 /// perc.next(),
1053 /// Some(IterationValue::new(199, hist.quantile_below(199), hist.quantile_below(199), 0, 1))
1054 /// );
1055 /// assert_eq!(
1056 /// perc.next(),
1057 /// Some(IterationValue::new(299, hist.quantile_below(299), hist.quantile_below(299), 0, 0))
1058 /// );
1059 /// assert_eq!(
1060 /// perc.next(),
1061 /// Some(IterationValue::new(399, hist.quantile_below(399), hist.quantile_below(399), 0, 0))
1062 /// );
1063 /// assert_eq!(
1064 /// perc.next(),
1065 /// Some(IterationValue::new(499, hist.quantile_below(499), hist.quantile_below(499), 0, 0))
1066 /// );
1067 /// assert_eq!(
1068 /// perc.next(),
1069 /// Some(IterationValue::new(599, hist.quantile_below(599), hist.quantile_below(599), 0, 1))
1070 /// );
1071 /// assert_eq!(
1072 /// perc.next(),
1073 /// Some(IterationValue::new(699, hist.quantile_below(699), hist.quantile_below(699), 0, 0))
1074 /// );
1075 /// assert_eq!(
1076 /// perc.next(),
1077 /// Some(IterationValue::new(799, hist.quantile_below(799), hist.quantile_below(799), 0, 0))
1078 /// );
1079 /// assert_eq!(
1080 /// perc.next(),
1081 /// Some(IterationValue::new(899, hist.quantile_below(899), hist.quantile_below(899), 0, 2))
1082 /// );
1083 /// assert_eq!(perc.next(), None);
1084 /// ```
1085 pub fn iter_linear(&self, step: u64) -> HistogramIterator<T, iterators::linear::Iter<T>> {
1086 iterators::linear::Iter::new(self, step)
1087 }
1088
1089 /// Iterates through histogram values at logarithmically increasing levels. The iteration is
1090 /// performed in steps that start at `start` and increase exponentially according to `exp`. The
1091 /// iterator terminates when all recorded histogram values are exhausted.
1092 ///
1093 /// The iterator yields an `iterators::IterationValue` struct.
1094 ///
1095 /// ```
1096 /// use hdrhistogram::Histogram;
1097 /// use hdrhistogram::iterators::IterationValue;
1098 /// let mut hist = Histogram::<u64>::new_with_max(1000, 3).unwrap();
1099 /// hist += 100;
1100 /// hist += 500;
1101 /// hist += 800;
1102 /// hist += 850;
1103 ///
1104 /// let mut perc = hist.iter_log(1, 10.0);
1105 /// assert_eq!(
1106 /// perc.next(),
1107 /// Some(IterationValue::new(0, hist.quantile_below(0), hist.quantile_below(0), 0, 0))
1108 /// );
1109 /// assert_eq!(
1110 /// perc.next(),
1111 /// Some(IterationValue::new(9, hist.quantile_below(9), hist.quantile_below(9), 0, 0))
1112 /// );
1113 /// assert_eq!(
1114 /// perc.next(),
1115 /// Some(IterationValue::new(99, hist.quantile_below(99), hist.quantile_below(99), 0, 0))
1116 /// );
1117 /// assert_eq!(
1118 /// perc.next(),
1119 /// Some(IterationValue::new(999, hist.quantile_below(999), hist.quantile_below(999), 0, 4))
1120 /// );
1121 /// assert_eq!(perc.next(), None);
1122 /// ```
1123 pub fn iter_log(&self, start: u64, exp: f64) -> HistogramIterator<T, iterators::log::Iter<T>> {
1124 iterators::log::Iter::new(self, start, exp)
1125 }
1126
1127 /// Iterates through all recorded histogram values using the finest granularity steps supported
1128 /// by the underlying representation. The iteration steps through all non-zero recorded value
1129 /// counts, and terminates when all recorded histogram values are exhausted.
1130 ///
1131 /// The iterator yields an `iterators::IterationValue` struct.
1132 ///
1133 /// ```
1134 /// use hdrhistogram::Histogram;
1135 /// use hdrhistogram::iterators::IterationValue;
1136 /// let mut hist = Histogram::<u64>::new_with_max(1000, 3).unwrap();
1137 /// hist += 100;
1138 /// hist += 500;
1139 /// hist += 800;
1140 /// hist += 850;
1141 ///
1142 /// let mut perc = hist.iter_recorded();
1143 /// assert_eq!(
1144 /// perc.next(),
1145 /// Some(IterationValue::new(100, hist.quantile_below(100), hist.quantile_below(100), 1, 1))
1146 /// );
1147 /// assert_eq!(
1148 /// perc.next(),
1149 /// Some(IterationValue::new(500, hist.quantile_below(500), hist.quantile_below(500), 1, 1))
1150 /// );
1151 /// assert_eq!(
1152 /// perc.next(),
1153 /// Some(IterationValue::new(800, hist.quantile_below(800), hist.quantile_below(800), 1, 1))
1154 /// );
1155 /// assert_eq!(
1156 /// perc.next(),
1157 /// Some(IterationValue::new(850, hist.quantile_below(850), hist.quantile_below(850), 1, 1))
1158 /// );
1159 /// assert_eq!(perc.next(), None);
1160 /// ```
1161 pub fn iter_recorded(&self) -> HistogramIterator<T, iterators::recorded::Iter> {
1162 iterators::recorded::Iter::new(self)
1163 }
1164
1165 /// Iterates through all histogram values using the finest granularity steps supported by the
1166 /// underlying representation. The iteration steps through all possible unit value levels,
1167 /// regardless of whether or not there were recorded values for that value level, and
1168 /// terminates when all recorded histogram values are exhausted.
1169 ///
1170 /// The iterator yields an `iterators::IterationValue` struct.
1171 ///
1172 /// ```
1173 /// use hdrhistogram::Histogram;
1174 /// use hdrhistogram::iterators::IterationValue;
1175 /// let mut hist = Histogram::<u64>::new_with_max(10, 1).unwrap();
1176 /// hist += 1;
1177 /// hist += 5;
1178 /// hist += 8;
1179 ///
1180 /// let mut perc = hist.iter_all();
1181 /// assert_eq!(perc.next(), Some(IterationValue::new(0, 0.0, 0.0, 0, 0)));
1182 /// assert_eq!(
1183 /// perc.next(),
1184 /// Some(IterationValue::new(1, hist.quantile_below(1), hist.quantile_below(1), 1, 1))
1185 /// );
1186 /// assert_eq!(
1187 /// perc.next(),
1188 /// Some(IterationValue::new(2, hist.quantile_below(2), hist.quantile_below(2), 0, 0))
1189 /// );
1190 /// assert_eq!(
1191 /// perc.next(),
1192 /// Some(IterationValue::new(3, hist.quantile_below(3), hist.quantile_below(3), 0, 0))
1193 /// );
1194 /// assert_eq!(
1195 /// perc.next(),
1196 /// Some(IterationValue::new(4, hist.quantile_below(4), hist.quantile_below(4), 0, 0))
1197 /// );
1198 /// assert_eq!(
1199 /// perc.next(),
1200 /// Some(IterationValue::new(5, hist.quantile_below(5), hist.quantile_below(5), 1, 1))
1201 /// );
1202 /// assert_eq!(
1203 /// perc.next(),
1204 /// Some(IterationValue::new(6, hist.quantile_below(6), hist.quantile_below(6), 0, 0))
1205 /// );
1206 /// assert_eq!(
1207 /// perc.next(),
1208 /// Some(IterationValue::new(7, hist.quantile_below(7), hist.quantile_below(7), 0, 0))
1209 /// );
1210 /// assert_eq!(
1211 /// perc.next(),
1212 /// Some(IterationValue::new(8, hist.quantile_below(8), hist.quantile_below(8), 1, 1))
1213 /// );
1214 /// assert_eq!(
1215 /// perc.next(),
1216 /// Some(IterationValue::new(9, hist.quantile_below(9), hist.quantile_below(9), 0, 0))
1217 /// );
1218 /// assert_eq!(perc.next(), Some(IterationValue::new(10, 1.0, 1.0, 0, 0)));
1219 /// ```
1220 pub fn iter_all(&self) -> HistogramIterator<T, iterators::all::Iter> {
1221 iterators::all::Iter::new(self)
1222 }
1223
1224 // ********************************************************************************************
1225 // Data statistics
1226 // ********************************************************************************************
1227
1228 /// Get the lowest recorded value level in the histogram.
1229 /// If the histogram has no recorded values, the value returned will be 0.
1230 pub fn min(&self) -> u64 {
1231 if self.total_count == 0
1232 || self
1233 .count_at_index(0)
1234 .expect("counts array must be non-empty")
1235 != T::zero()
1236 {
1237 0
1238 } else {
1239 self.min_nz()
1240 }
1241 }
1242
1243 /// Get the highest recorded value level in the histogram.
1244 /// If the histogram has no recorded values, the value returned is undefined.
1245 pub fn max(&self) -> u64 {
1246 if self.max_value == ORIGINAL_MAX {
1247 ORIGINAL_MAX
1248 } else {
1249 self.highest_equivalent(self.max_value)
1250 }
1251 }
1252
1253 /// Get the lowest recorded non-zero value level in the histogram.
1254 /// If the histogram has no recorded values, the value returned is `u64::max_value()`.
1255 pub fn min_nz(&self) -> u64 {
1256 if self.min_non_zero_value == ORIGINAL_MIN {
1257 ORIGINAL_MIN
1258 } else {
1259 self.lowest_equivalent(self.min_non_zero_value)
1260 }
1261 }
1262
1263 /// Determine if two values are equivalent with the histogram's resolution. Equivalent here
1264 /// means that value samples recorded for any two equivalent values are counted in a common
1265 /// total count.
1266 pub fn equivalent(&self, value1: u64, value2: u64) -> bool {
1267 self.lowest_equivalent(value1) == self.lowest_equivalent(value2)
1268 }
1269
1270 /// Get the computed mean value of all recorded values in the histogram.
1271 pub fn mean(&self) -> f64 {
1272 if self.total_count == 0 {
1273 return 0.0;
1274 }
1275
1276 self.iter_recorded().fold(0.0_f64, |total, v| {
1277 // TODO overflow?
1278 total
1279 + self.median_equivalent(v.value_iterated_to()) as f64 * v.count_at_value().as_f64()
1280 / self.total_count as f64
1281 })
1282 }
1283
1284 /// Get the computed standard deviation of all recorded values in the histogram
1285 pub fn stdev(&self) -> f64 {
1286 if self.total_count == 0 {
1287 return 0.0;
1288 }
1289
1290 let mean = self.mean();
1291 let geom_dev_tot = self.iter_recorded().fold(0.0_f64, |gdt, v| {
1292 let dev = self.median_equivalent(v.value_iterated_to()) as f64 - mean;
1293 gdt + (dev * dev) * v.count_since_last_iteration() as f64
1294 });
1295
1296 (geom_dev_tot / self.total_count as f64).sqrt()
1297 }
1298
1299 /// Get the value at a given percentile.
1300 ///
1301 /// This is simply `value_at_quantile` multiplied by 100.0. For best floating-point precision,
1302 /// use `value_at_quantile` directly.
1303 pub fn value_at_percentile(&self, percentile: f64) -> u64 {
1304 self.value_at_quantile(percentile / 100.0)
1305 }
1306
1307 /// Get the value at a given quantile.
1308 ///
1309 /// When the given quantile is > 0.0, the value returned is the value that the given
1310 /// percentage of the overall recorded value entries in the histogram are either smaller than
1311 /// or equivalent to. When the given quantile is 0.0, the value returned is the value that
1312 /// all value entries in the histogram are either larger than or equivalent to.
1313 ///
1314 /// Two values are considered "equivalent" if `self.equivalent` would return true.
1315 ///
1316 /// If the total count of the histogram has exceeded `u64::max_value()`, this will return
1317 /// inaccurate results.
1318 pub fn value_at_quantile(&self, quantile: f64) -> u64 {
1319 // Cap at 1.0
1320 let quantile = if quantile > 1.0 { 1.0 } else { quantile };
1321
1322 let fractional_count = quantile * self.total_count as f64;
1323 // If we're part-way into the next highest int, we should use that as the count
1324 let mut count_at_quantile = fractional_count.ceil() as u64;
1325
1326 // Make sure we at least reach the first recorded entry
1327 if count_at_quantile == 0 {
1328 count_at_quantile = 1;
1329 }
1330
1331 let mut total_to_current_index: u64 = 0;
1332 for i in 0..self.counts.len() {
1333 // Direct indexing is safe; indexes must reside in counts array.
1334 // TODO overflow
1335 total_to_current_index += self.counts[i].as_u64();
1336 if total_to_current_index >= count_at_quantile {
1337 let value_at_index = self.value_for(i);
1338 return if quantile == 0.0 {
1339 self.lowest_equivalent(value_at_index)
1340 } else {
1341 self.highest_equivalent(value_at_index)
1342 };
1343 }
1344 }
1345
1346 0
1347 }
1348
1349 /// Get the percentile of samples at and below a given value.
1350 ///
1351 /// This is simply `quantile_below* multiplied by 100.0. For best floating-point precision, use
1352 /// `quantile_below` directly.
1353 pub fn percentile_below(&self, value: u64) -> f64 {
1354 self.quantile_below(value) * 100.0
1355 }
1356
1357 /// Get the quantile of samples at or below a given value.
1358 ///
1359 /// The value returned is the quantile of values recorded in the histogram that are
1360 /// smaller than or equivalent to the given value.
1361 ///
1362 /// Two values are considered "equivalent" if `self.equivalent` would return true.
1363 ///
1364 /// If the value is larger than the maximum representable value, it will be clamped to the
1365 /// max representable value.
1366 ///
1367 /// If the total count of the histogram has reached `u64::max_value()`, this will return
1368 /// inaccurate results.
1369 pub fn quantile_below(&self, value: u64) -> f64 {
1370 if self.total_count == 0 {
1371 return 1.0;
1372 }
1373
1374 let target_index = self.index_for_or_last(value);
1375 // TODO use RangeInclusive when it's stable to avoid checked_add
1376 let total_to_current_index = (0..target_index.checked_add(1).expect("usize overflow"))
1377 .map(|i| self.count_at_index(i).expect("index is <= last_index()"))
1378 .fold(0_u64, |t, v| t.saturating_add(v.as_u64()));
1379 total_to_current_index.as_f64() / self.total_count as f64
1380 }
1381
1382 /// Get the count of recorded values within a range of value levels (inclusive to within the
1383 /// histogram's resolution).
1384 ///
1385 /// `low` gives the lower value bound on the range for which to provide the recorded count.
1386 /// Will be rounded down with `lowest_equivalent`. Similarly, `high` gives the higher value
1387 /// bound on the range, and will be rounded up with `highest_equivalent`. The function returns
1388 /// the total count of values recorded in the histogram within the value range that is `>=
1389 /// lowest_equivalent(low)` and `<= highest_equivalent(high)`.
1390 ///
1391 /// If either value is larger than the maximum representable value, it will be clamped to the
1392 /// max representable value.
1393 ///
1394 /// The count will saturate at u64::max_value().
1395 pub fn count_between(&self, low: u64, high: u64) -> u64 {
1396 let low_index = self.index_for_or_last(low);
1397 let high_index = self.index_for_or_last(high);
1398 // TODO use RangeInclusive when it's stable to avoid checked_add
1399 (low_index..high_index.checked_add(1).expect("usize overflow"))
1400 .map(|i| self.count_at_index(i).expect("index is <= last_index()"))
1401 .fold(0_u64, |t, v| t.saturating_add(v.as_u64()))
1402 }
1403
1404 /// Get the count of recorded values at a specific value (to within the histogram resolution at
1405 /// the value level).
1406 ///
1407 /// The count is computed across values recorded in the histogram that are within the value
1408 /// range that is `>= lowest_equivalent(value)` and `<= highest_equivalent(value)`.
1409 ///
1410 /// If the value is larger than the maximum representable value, it will be clamped to the
1411 /// max representable value.
1412 pub fn count_at(&self, value: u64) -> T {
1413 self.count_at_index(self.index_for_or_last(value))
1414 .expect("index is <= last_index()")
1415 }
1416
1417 // ********************************************************************************************
1418 // Public helpers
1419 // ********************************************************************************************
1420
1421 /// Get the lowest value that is equivalent to the given value within the histogram's
1422 /// resolution. Equivalent here means that value samples recorded for any two equivalent values
1423 /// are counted in a common total count.
1424 pub fn lowest_equivalent(&self, value: u64) -> u64 {
1425 let bucket_index = self.bucket_for(value);
1426 let sub_bucket_index = self.sub_bucket_for(value, bucket_index);
1427 self.value_from_loc(bucket_index, sub_bucket_index)
1428 }
1429
1430 /// Get the highest value that is equivalent to the given value within the histogram's
1431 /// resolution. Equivalent here means that value samples recorded for any two equivalent values
1432 /// are counted in a common total count.
1433 ///
1434 /// Note that the return value is capped at `u64::max_value()`.
1435 pub fn highest_equivalent(&self, value: u64) -> u64 {
1436 if value == u64::max_value() {
1437 u64::max_value()
1438 } else {
1439 self.next_non_equivalent(value) - 1
1440 }
1441 }
1442
1443 /// Get a value that lies in the middle (rounded up) of the range of values equivalent the
1444 /// given value. Equivalent here means that value samples recorded for any two equivalent
1445 /// values are counted in a common total count.
1446 ///
1447 /// Note that the return value is capped at `u64::max_value()`.
1448 pub fn median_equivalent(&self, value: u64) -> u64 {
1449 // adding half of the range to the bottom of the range shouldn't overflow
1450 self.lowest_equivalent(value)
1451 .checked_add(self.equivalent_range(value) >> 1)
1452 .expect("median equivalent should not overflow")
1453 }
1454
1455 /// Get the next value that is *not* equivalent to the given value within the histogram's
1456 /// resolution. Equivalent means that value samples recorded for any two equivalent values are
1457 /// counted in a common total count.
1458 ///
1459 /// Note that the return value is capped at `u64::max_value()`.
1460 pub fn next_non_equivalent(&self, value: u64) -> u64 {
1461 self.lowest_equivalent(value)
1462 .saturating_add(self.equivalent_range(value))
1463 }
1464
1465 /// Get the size (in value units) of the range of values that are equivalent to the given value
1466 /// within the histogram's resolution. Equivalent here means that value samples recorded for
1467 /// any two equivalent values are counted in a common total count.
1468 pub fn equivalent_range(&self, value: u64) -> u64 {
1469 let bucket_index = self.bucket_for(value);
1470 1_u64 << (self.unit_magnitude + bucket_index)
1471 }
1472
1473 /// Turn this histogram into a [`SyncHistogram`].
1474 #[cfg(feature = "sync")]
1475 pub fn into_sync(self) -> SyncHistogram<T> {
1476 SyncHistogram::from(self)
1477 }
1478
1479 // ********************************************************************************************
1480 // Internal helpers
1481 // ********************************************************************************************
1482
1483 /// Computes the matching histogram value for the given histogram bin.
1484 ///
1485 /// `index` must be no larger than `u32::max_value()`; no possible histogram uses that much
1486 /// storage anyway. So, any index that comes from a valid histogram location will be safe.
1487 ///
1488 /// If the index is for a position beyond what this histogram is configured for, the correct
1489 /// corresponding value will be returned, but of course it won't have a corresponding count.
1490 ///
1491 /// If the index maps to a value beyond `u64::max_value()`, the result will be garbage.
1492 fn value_for(&self, index: usize) -> u64 {
1493 // Dividing by sub bucket half count will yield 1 in top half of first bucket, 2 in
1494 // in the top half (i.e., the only half that's used) of the 2nd bucket, etc, so subtract 1
1495 // to get 0-indexed bucket indexes. This will be -1 for the bottom half of the first bucket.
1496 let mut bucket_index = (index >> self.sub_bucket_half_count_magnitude) as isize - 1;
1497
1498 // Calculate the remainder of dividing by sub_bucket_half_count, shifted into the top half
1499 // of the corresponding bucket. This will (temporarily) map indexes in the lower half of
1500 // first bucket into the top half.
1501
1502 // The subtraction won't underflow because half count is always at least 1.
1503 // TODO precalculate sub_bucket_half_count mask if benchmarks show improvement
1504 let mut sub_bucket_index = ((index.to_u32().expect("index must fit in u32"))
1505 & (self.sub_bucket_half_count - 1))
1506 + self.sub_bucket_half_count;
1507 if bucket_index < 0 {
1508 // lower half of first bucket case; move sub bucket index back
1509 sub_bucket_index -= self.sub_bucket_half_count;
1510 bucket_index = 0;
1511 }
1512 self.value_from_loc(bucket_index as u8, sub_bucket_index)
1513 }
1514
1515 /// Returns count at index, or None if out of bounds
1516 fn count_at_index(&self, index: usize) -> Option<T> {
1517 self.counts.get(index).cloned()
1518 }
1519
1520 /// Returns an error if the index doesn't exist.
1521 #[cfg(feature = "serialization")]
1522 fn set_count_at_index(&mut self, index: usize, count: T) -> Result<(), ()> {
1523 let r = self.counts.get_mut(index).ok_or(())?;
1524 *r = count;
1525 Ok(())
1526 }
1527
1528 /// Compute the lowest (and therefore highest precision) bucket index whose sub-buckets can
1529 /// represent the value.
1530 #[inline]
1531 fn bucket_for(&self, value: u64) -> u8 {
1532 // Calculates the number of powers of two by which the value is greater than the biggest
1533 // value that fits in bucket 0. This is the bucket index since each successive bucket can
1534 // hold a value 2x greater. The mask maps small values to bucket 0.
1535 // Will not underflow because sub_bucket_mask caps the leading zeros to no more than
1536 // leading_zero_count_base.
1537 self.leading_zero_count_base - (value | self.sub_bucket_mask).leading_zeros() as u8
1538 }
1539
1540 /// Compute the position inside a bucket at which the given value should be recorded, indexed
1541 /// from position 0 in the bucket (in the first half, which is not used past the first bucket).
1542 /// For bucket_index > 0, the result will be in the top half of the bucket.
1543 #[inline]
1544 fn sub_bucket_for(&self, value: u64, bucket_index: u8) -> u32 {
1545 // Since bucket_index is simply how many powers of 2 greater value is than what will fit in
1546 // bucket 0 (that is, what will fit in [0, sub_bucket_count)), we shift off that many
1547 // powers of two, and end up with a number in [0, sub_bucket_count).
1548 // For bucket_index 0, this is just value. For bucket index k > 0, we know value won't fit
1549 // in bucket (k - 1) by definition, so this calculation won't end up in the lower half of
1550 // [0, sub_bucket_count) because that would mean it would also fit in bucket (k - 1).
1551 // As unit magnitude grows, the maximum possible bucket index should shrink because it is
1552 // based off of sub_bucket_mask, so this shouldn't lead to an overlarge shift.
1553 (value >> (bucket_index + self.unit_magnitude)) as u32
1554 }
1555
1556 /// Compute the value corresponding to the provided bucket and sub bucket indices.
1557 /// The indices given must map to an actual u64; providing contrived indices that would map to
1558 /// a value larger than u64::max_value() will yield garbage.
1559 #[inline]
1560 fn value_from_loc(&self, bucket_index: u8, sub_bucket_index: u32) -> u64 {
1561 // Sum won't overflow; bucket_index and unit_magnitude are both <= 64.
1562 // However, the resulting shift may overflow given bogus input, e.g. if unit magnitude is
1563 // large and the input sub_bucket_index is for an entry in the counts index that shouldn't
1564 // be used (because this calculation will overflow).
1565 u64::from(sub_bucket_index) << (bucket_index + self.unit_magnitude)
1566 }
1567
1568 /// Find the number of buckets needed such that `value` is representable.
1569 fn buckets_to_cover(&self, value: u64) -> u8 {
1570 // Shift won't overflow because sub_bucket_magnitude + unit_magnitude <= 63.
1571 // the k'th bucket can express from 0 * 2^k to sub_bucket_count * 2^k in units of 2^k
1572 let mut smallest_untrackable_value =
1573 u64::from(self.sub_bucket_count) << self.unit_magnitude;
1574
1575 // always have at least 1 bucket
1576 let mut buckets_needed = 1;
1577 while smallest_untrackable_value <= value {
1578 if smallest_untrackable_value > u64::max_value() / 2 {
1579 // next shift will overflow, meaning that bucket could represent values up to ones
1580 // greater than i64::max_value, so it's the last bucket
1581 return buckets_needed + 1;
1582 }
1583 smallest_untrackable_value <<= 1;
1584 buckets_needed += 1;
1585 }
1586 buckets_needed
1587 }
1588
1589 /// Compute the actual number of bins to use for the given bucket count (that is, including the
1590 /// sub-buckets within each top-level bucket).
1591 ///
1592 /// If we have `N` such that `sub_bucket_count * 2^N > high`, we need storage for `N+1` buckets,
1593 /// each with enough slots to hold the top half of the `sub_bucket_count` (the lower half is
1594 /// covered by previous buckets), and the +1 being used for the lower half of the 0'th bucket.
1595 /// Or, equivalently, we need 1 more bucket to capture the max value if we consider the
1596 /// sub-bucket length to be halved.
1597 fn num_bins(&self, number_of_buckets: u8) -> u32 {
1598 (u32::from(number_of_buckets) + 1) * (self.sub_bucket_half_count)
1599 }
1600
1601 /// Resize the underlying counts array such that it can cover the given `high` value.
1602 ///
1603 /// `high` must be at least 2x the lowest discernible value.
1604 ///
1605 /// Returns an error if the new size cannot be represented as a `usize`.
1606 fn resize(&mut self, high: u64) -> Result<(), UsizeTypeTooSmall> {
1607 // will not overflow because lowest_discernible_value must be at least as small as
1608 // u64::max_value() / 2 to have passed initial validation
1609 assert!(
1610 high >= 2 * self.lowest_discernible_value,
1611 "highest trackable value must be >= (2 * lowest discernible value)"
1612 );
1613
1614 // establish counts array length:
1615 let buckets_needed = self.buckets_to_cover(high);
1616 let len = self
1617 .num_bins(buckets_needed)
1618 .to_usize()
1619 .ok_or(UsizeTypeTooSmall)?;
1620
1621 // establish exponent range needed to support the trackable value with no overflow:
1622 self.bucket_count = buckets_needed;
1623
1624 // establish the new highest trackable value:
1625 self.highest_trackable_value = high;
1626
1627 // expand counts to also hold the new counts
1628 self.counts.resize(len, T::zero());
1629 Ok(())
1630 }
1631
1632 /// Set internally tracked max_value to new value if new value is greater than current one.
1633 fn update_max(&mut self, value: u64) {
1634 let internal_value = value | self.unit_magnitude_mask; // Max unit-equivalent value
1635 if internal_value > self.max_value {
1636 self.max_value = internal_value;
1637 }
1638 }
1639
1640 /// Set internally tracked min_non_zero_value to new value if new value is smaller than current
1641 /// one.
1642 fn update_min(&mut self, value: u64) {
1643 if value <= self.unit_magnitude_mask {
1644 return; // Unit-equivalent to 0.
1645 }
1646
1647 let internal_value = value & !self.unit_magnitude_mask; // Min unit-equivalent value
1648 if internal_value < self.min_non_zero_value {
1649 self.min_non_zero_value = internal_value;
1650 }
1651 }
1652
1653 fn update_min_max(&mut self, value: u64) {
1654 if value > self.max_value {
1655 self.update_max(value);
1656 }
1657 if value < self.min_non_zero_value && value != 0 {
1658 self.update_min(value);
1659 }
1660 }
1661
1662 fn reset_max(&mut self, max: u64) {
1663 self.max_value = max | self.unit_magnitude_mask; // Max unit-equivalent value
1664 }
1665
1666 fn reset_min(&mut self, min: u64) {
1667 let internal_value = min & !self.unit_magnitude_mask; // Min unit-equivalent value
1668 self.min_non_zero_value = if min == u64::max_value() {
1669 min
1670 } else {
1671 internal_value
1672 };
1673 }
1674
1675 /// Recalculate min, max, total_count.
1676 fn restat(&mut self, length_to_scan: usize) {
1677 self.reset_max(ORIGINAL_MAX);
1678 self.reset_min(ORIGINAL_MIN);
1679
1680 let mut restat_state = RestatState::new();
1681
1682 assert!(length_to_scan <= self.counts.len());
1683 for i in 0..length_to_scan {
1684 // Direct indexing safe because of assert above
1685 let count = self.counts[i];
1686 if count != T::zero() {
1687 restat_state.on_nonzero_count(i, count);
1688 }
1689 }
1690
1691 restat_state.update_histogram(self);
1692 }
1693}
1694
1695/// Stores the state to calculate the max, min, and total count for a histogram by iterating across
1696/// the counts.
1697struct RestatState<T: Counter> {
1698 max_index: Option<usize>,
1699 min_index: Option<usize>,
1700 total_count: u64,
1701 phantom: std::marker::PhantomData<T>,
1702}
1703
1704impl<T: Counter> RestatState<T> {
1705 fn new() -> RestatState<T> {
1706 RestatState {
1707 max_index: None,
1708 min_index: None,
1709 total_count: 0,
1710 phantom: std::marker::PhantomData,
1711 }
1712 }
1713
1714 /// Should be called on every non-zero count found
1715 #[inline]
1716 fn on_nonzero_count(&mut self, index: usize, count: T) {
1717 self.total_count = self.total_count.saturating_add(count.as_u64());
1718
1719 self.max_index = Some(index);
1720
1721 if self.min_index.is_none() && index != 0 {
1722 self.min_index = Some(index);
1723 }
1724 }
1725
1726 /// Write updated min, max, total_count into histogram.
1727 /// Called once all counts have been iterated across.
1728 fn update_histogram(self, h: &mut Histogram<T>) {
1729 if let Some(max_i) = self.max_index {
1730 let max = h.highest_equivalent(h.value_for(max_i));
1731 h.update_max(max);
1732 }
1733 if let Some(min_i) = self.min_index {
1734 let min = h.value_for(min_i);
1735 h.update_min(min);
1736 }
1737
1738 h.total_count = self.total_count;
1739 }
1740}
1741
1742// ********************************************************************************************
1743// Trait implementations
1744// ********************************************************************************************
1745
1746impl<T: Counter> Clone for Histogram<T> {
1747 fn clone(&self) -> Self {
1748 let mut h = Histogram::new_from(self);
1749 h += self;
1750 h
1751 }
1752}
1753
1754// make it more ergonomic to add and subtract histograms
1755impl<'a, T: Counter> AddAssign<&'a Histogram<T>> for Histogram<T> {
1756 fn add_assign(&mut self, source: &'a Histogram<T>) {
1757 self.add(source).unwrap();
1758 }
1759}
1760
1761impl<T: Counter> AddAssign<Histogram<T>> for Histogram<T> {
1762 fn add_assign(&mut self, source: Histogram<T>) {
1763 self.add(&source).unwrap();
1764 }
1765}
1766
1767impl<T: Counter> Add<Histogram<T>> for Histogram<T> {
1768 type Output = Histogram<T>;
1769 fn add(mut self, rhs: Histogram<T>) -> Self::Output {
1770 self += rhs;
1771 self
1772 }
1773}
1774
1775impl<'a, T: Counter> Add<&'a Histogram<T>> for Histogram<T> {
1776 type Output = Histogram<T>;
1777 fn add(mut self, rhs: &'a Histogram<T>) -> Self::Output {
1778 self += rhs;
1779 self
1780 }
1781}
1782
1783use std::iter;
1784impl<T: Counter> iter::Sum for Histogram<T> {
1785 fn sum<I>(mut iter: I) -> Self
1786 where
1787 I: Iterator<Item = Self>,
1788 {
1789 match iter.next() {
1790 Some(mut first) => {
1791 for h in iter {
1792 first += h;
1793 }
1794 first
1795 }
1796 None => Histogram::new(3).expect("histograms with sigfig=3 should always work"),
1797 }
1798 }
1799}
1800
1801impl<'a, T: Counter> SubAssign<&'a Histogram<T>> for Histogram<T> {
1802 fn sub_assign(&mut self, other: &'a Histogram<T>) {
1803 self.subtract(other).unwrap();
1804 }
1805}
1806
1807impl<T: Counter> SubAssign<Histogram<T>> for Histogram<T> {
1808 fn sub_assign(&mut self, source: Histogram<T>) {
1809 self.subtract(&source).unwrap();
1810 }
1811}
1812
1813impl<T: Counter> Sub<Histogram<T>> for Histogram<T> {
1814 type Output = Histogram<T>;
1815 fn sub(mut self, rhs: Histogram<T>) -> Self::Output {
1816 self -= rhs;
1817 self
1818 }
1819}
1820
1821impl<'a, T: Counter> Sub<&'a Histogram<T>> for Histogram<T> {
1822 type Output = Histogram<T>;
1823 fn sub(mut self, rhs: &'a Histogram<T>) -> Self::Output {
1824 self -= rhs;
1825 self
1826 }
1827}
1828
1829// make it more ergonomic to record samples
1830impl<T: Counter> AddAssign<u64> for Histogram<T> {
1831 fn add_assign(&mut self, value: u64) {
1832 self.record(value).unwrap();
1833 }
1834}
1835
1836// allow comparing histograms
1837impl<T: Counter, F: Counter> PartialEq<Histogram<F>> for Histogram<T>
1838where
1839 T: PartialEq<F>,
1840{
1841 fn eq(&self, other: &Histogram<F>) -> bool {
1842 if self.lowest_discernible_value != other.lowest_discernible_value
1843 || self.significant_value_digits != other.significant_value_digits
1844 {
1845 return false;
1846 }
1847 if self.total_count != other.total_count {
1848 return false;
1849 }
1850 if self.max() != other.max() {
1851 return false;
1852 }
1853 if self.min_nz() != other.min_nz() {
1854 return false;
1855 }
1856
1857 (0..self.counts.len()).all(|i| {
1858 self.counts[i]
1859 == match other.count_at_index(i) {
1860 Some(c) => c,
1861 None => return false,
1862 }
1863 })
1864 }
1865}
1866
1867// /**
1868// * Indicate whether or not the histogram is capable of supporting auto-resize functionality.
1869// * Note that this is an indication that enabling auto-resize by calling set_auto_resize() is
1870// * allowed, and NOT that the histogram will actually auto-resize. Use is_auto_resize() to
1871// * determine if the histogram is in auto-resize mode.
1872// * @return auto_resize setting
1873// */
1874// public boolean supports_auto_resize() { return true; }
1875
1876// TODO: shift
1877// TODO: hash
1878
1879#[path = "tests/tests.rs"]
1880#[cfg(test)]
1881mod tests;
1882
1883mod core;
1884pub mod errors;
1885#[cfg(feature = "serialization")]
1886pub mod serialization;
1887pub use self::core::counter::*;
1888pub use errors::*;
1889#[cfg(feature = "sync")]
1890pub mod sync;
1891#[cfg(feature = "sync")]
1892pub use sync::SyncHistogram;