pub struct HdrHistogram {
sub_count: u32,
sub_count_bits: u32,
counters: Vec<u64>,
total: u64,
high_index: usize,
}
impl HdrHistogram {
pub fn new(significant_digits: u32) -> Self {
let sig = significant_digits.clamp(1, 5);
let target = 2u32 * 10u32.pow(sig);
let sub_count_bits = (32 - target.leading_zeros()).max(1);
let sub_count = 1u32 << sub_count_bits;
Self {
sub_count,
sub_count_bits,
counters: vec![0u64; sub_count as usize],
total: 0,
high_index: 0,
}
}
pub fn count(&self) -> u64 {
self.total
}
pub fn max(&self) -> u64 {
if self.total == 0 {
return 0;
}
value_from_index(self.high_index, self.sub_count_bits)
}
pub fn record(&mut self, value: u64) {
let idx = index_of(value, self.sub_count_bits) as usize;
if idx >= self.counters.len() {
self.counters.resize(idx + 1, 0);
}
self.counters[idx] += 1;
self.total += 1;
if idx > self.high_index {
self.high_index = idx;
}
}
pub fn value_at_percentile(&self, q: f64) -> u64 {
if self.total == 0 {
return 0;
}
let target = ((q.clamp(0.0, 1.0) * self.total as f64) as u64).max(1);
let mut cum = 0u64;
for (i, &c) in self.counters.iter().enumerate() {
cum += c;
if cum >= target {
return value_from_index(i, self.sub_count_bits);
}
}
value_from_index(self.high_index, self.sub_count_bits)
}
pub fn sub_count(&self) -> u32 {
self.sub_count
}
}
fn index_of(value: u64, sub_count_bits: u32) -> u32 {
let sub_mask = (1u64 << sub_count_bits) - 1;
if value <= sub_mask {
return value as u32;
}
let bits = 64 - value.leading_zeros();
let major = bits - sub_count_bits;
let sub = ((value >> (major - 1)) & sub_mask) as u32;
(major << sub_count_bits) | sub
}
fn value_from_index(idx: usize, sub_count_bits: u32) -> u64 {
let sub_count = 1u64 << sub_count_bits;
let sub_mask = sub_count - 1;
let idx = idx as u64;
if idx < sub_count {
return idx;
}
let major = idx >> sub_count_bits;
let sub = idx & sub_mask;
(sub | sub_count) << (major - 1)
}
#[cfg(feature = "harness")]
pub mod recipe;