use crate::{clear::Clear, metric::Histogram};
use parking_lot::Mutex;
use serde::{Serialize, Serializer};
pub struct AtomicHdrHistogram {
inner: Mutex<HdrHistogram>,
}
impl AtomicHdrHistogram {
pub fn histogram(&self) -> HdrHistogram {
self.inner.lock().clone()
}
}
impl Histogram for AtomicHdrHistogram {
fn with_bound(max_bound: u64) -> Self {
let histo = HdrHistogram::with_bound(max_bound);
let inner = Mutex::new(histo);
AtomicHdrHistogram { inner }
}
fn record(&self, value: u64) {
self.inner.lock().record(value);
}
}
impl Clear for AtomicHdrHistogram {
fn clear(&self) {
self.inner.lock().clear();
}
}
impl Serialize for AtomicHdrHistogram {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
use std::ops::Deref;
let inner = self.inner.lock();
let inner = inner.deref();
Serialize::serialize(inner, serializer)
}
}
use std::{fmt, fmt::Debug};
impl Debug for AtomicHdrHistogram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let histo = self.inner.lock();
write!(f, "AtomicHdrHistogram {{ {:?} }}", &*histo)
}
}
#[derive(Clone)]
pub struct HdrHistogram {
histo: hdrhistogram::Histogram<u64>,
}
impl HdrHistogram {
pub fn with_bound(max_bound: u64) -> Self {
let histo = hdrhistogram::Histogram::<u64>::new_with_bounds(1, max_bound, 2)
.expect("Could not instantiate HdrHistogram");
HdrHistogram { histo }
}
pub fn record(&mut self, value: u64) {
self.histo.saturating_record(value);
}
pub fn clear(&mut self) {
self.histo.reset();
}
pub fn len(&self) -> u64 {
self.histo.len()
}
pub fn min(&self) -> u64 {
self.histo.min()
}
pub fn max(&self) -> u64 {
self.histo.max()
}
pub fn mean(&self) -> f64 {
self.histo.mean()
}
pub fn stdev(&self) -> f64 {
self.histo.stdev()
}
pub fn p90(&self) -> u64 {
self.histo.value_at_quantile(0.9)
}
pub fn p95(&self) -> u64 {
self.histo.value_at_quantile(0.95)
}
pub fn p99(&self) -> u64 {
self.histo.value_at_quantile(0.99)
}
pub fn p999(&self) -> u64 {
self.histo.value_at_quantile(0.999)
}
pub fn p9999(&self) -> u64 {
self.histo.value_at_quantile(0.9999)
}
}
impl Serialize for HdrHistogram {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let hdr = &self.histo;
macro_rules! ile {
($e:expr) => {
&MetricAlias(concat!("!|quantile=", $e), hdr.value_at_quantile($e))
};
}
macro_rules! qual {
($e:expr) => {
&MetricAlias("<|", $e)
};
}
use serde::ser::SerializeMap;
let mut tup = serializer.serialize_map(Some(10))?;
tup.serialize_entry("samples", qual!(hdr.len()))?;
tup.serialize_entry("min", qual!(hdr.min()))?;
tup.serialize_entry("max", qual!(hdr.max()))?;
tup.serialize_entry("mean", qual!(hdr.mean()))?;
tup.serialize_entry("stdev", qual!(hdr.stdev()))?;
tup.serialize_entry("90%ile", ile!(0.9))?;
tup.serialize_entry("95%ile", ile!(0.95))?;
tup.serialize_entry("99%ile", ile!(0.99))?;
tup.serialize_entry("99.9%ile", ile!(0.999))?;
tup.serialize_entry("99.99%ile", ile!(0.9999))?;
tup.end()
}
}
struct MetricAlias<T: Serialize>(&'static str, T);
impl<T: Serialize> Serialize for MetricAlias<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_newtype_struct(self.0, &self.1)
}
}
impl Debug for HdrHistogram {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let hdr = &self.histo;
let ile = |v| hdr.value_at_percentile(v);
write!(
f,
"HdrHistogram {{
samples: {}, min: {}, max: {}, mean: {}, stdev: {},
90%ile = {}, 95%ile = {}, 99%ile = {}, 99.9%ile = {}, 99.99%ile = {} }}",
hdr.len(),
hdr.min(),
hdr.max(),
hdr.mean(),
hdr.stdev(),
ile(90.0),
ile(95.0),
ile(99.0),
ile(99.9),
ile(99.99)
)
}
}
use std::cell::RefCell;
impl Histogram for RefCell<HdrHistogram> {
fn with_bound(max_value: u64) -> Self {
RefCell::new(HdrHistogram::with_bound(max_value))
}
fn record(&self, value: u64) {
self.borrow_mut().record(value);
}
}
impl Clear for RefCell<HdrHistogram> {
fn clear(&self) {
self.borrow_mut().clear();
}
}