codspeed_divan_compat_walltime/counter/
mod.rs

1//! Count values processed in each iteration to measure throughput.
2//!
3//! # Examples
4//!
5//! The following example measures throughput of converting
6//! [`&[i32]`](prim@slice) into [`Vec<i32>`](Vec) by providing [`BytesCount`]
7//! via [`Bencher::counter`](crate::Bencher::counter):
8//!
9//! ```
10//! use divan::counter::BytesCount;
11//!
12//! #[divan::bench]
13//! fn slice_into_vec(bencher: divan::Bencher) {
14//!     let ints: &[i32] = &[
15//!         // ...
16//!     ];
17//!
18//!     let bytes = BytesCount::of_slice(ints);
19//!
20//!     bencher
21//!         .counter(bytes)
22//!         .bench(|| -> Vec<i32> {
23//!             divan::black_box(ints).into()
24//!         });
25//! }
26//! ```
27
28use std::any::Any;
29
30mod any_counter;
31mod collection;
32mod into_counter;
33mod sealed;
34mod uint;
35
36pub(crate) use self::{
37    any_counter::{AnyCounter, KnownCounterKind},
38    collection::{CounterCollection, CounterSet},
39    sealed::Sealed,
40    uint::{AsCountUInt, CountUInt, MaxCountUInt},
41};
42pub use into_counter::IntoCounter;
43
44/// Counts the number of values processed in each iteration of a benchmarked
45/// function.
46///
47/// This is used via:
48/// - [`#[divan::bench(counters = ...)]`](macro@crate::bench#counters)
49/// - [`#[divan::bench_group(counters = ...)]`](macro@crate::bench_group#counters)
50/// - [`Bencher::counter`](crate::Bencher::counter)
51/// - [`Bencher::input_counter`](crate::Bencher::input_counter)
52#[doc(alias = "throughput")]
53pub trait Counter: Sized + Any + Sealed {}
54
55/// Process N bytes.
56#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
57pub struct BytesCount {
58    count: MaxCountUInt,
59}
60
61/// Process N [`char`s](char).
62///
63/// This is beneficial when comparing benchmarks between ASCII and Unicode
64/// implementations, since the number of code points is a common baseline
65/// reference.
66#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
67pub struct CharsCount {
68    count: MaxCountUInt,
69}
70
71/// Process N cycles, displayed as Hertz.
72///
73/// This value is user-provided and does not necessarily correspond to the CPU's
74/// cycle frequency, so it may represent cycles of anything appropriate for the
75/// benchmarking context.
76#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
77pub struct CyclesCount {
78    count: MaxCountUInt,
79}
80
81/// Process N items.
82#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
83pub struct ItemsCount {
84    count: MaxCountUInt,
85}
86
87impl Sealed for BytesCount {}
88impl Sealed for CharsCount {}
89impl Sealed for CyclesCount {}
90impl Sealed for ItemsCount {}
91
92impl Counter for BytesCount {}
93impl Counter for CharsCount {}
94impl Counter for CyclesCount {}
95impl Counter for ItemsCount {}
96
97impl<C: AsCountUInt> From<C> for BytesCount {
98    #[inline]
99    fn from(count: C) -> Self {
100        Self::new(count.as_max_uint())
101    }
102}
103
104impl<C: AsCountUInt> From<C> for CharsCount {
105    #[inline]
106    fn from(count: C) -> Self {
107        Self::new(count.as_max_uint())
108    }
109}
110
111impl<C: AsCountUInt> From<C> for CyclesCount {
112    #[inline]
113    fn from(count: C) -> Self {
114        Self::new(count.as_max_uint())
115    }
116}
117
118impl<C: AsCountUInt> From<C> for ItemsCount {
119    #[inline]
120    fn from(count: C) -> Self {
121        Self::new(count.as_max_uint())
122    }
123}
124
125impl BytesCount {
126    /// Count N bytes.
127    #[inline]
128    pub fn new<N: CountUInt>(count: N) -> Self {
129        Self { count: count.into_max_uint() }
130    }
131
132    /// Counts the size of a type with [`size_of`].
133    #[inline]
134    #[doc(alias = "size_of")]
135    pub const fn of<T>() -> Self {
136        Self { count: size_of::<T>() as MaxCountUInt }
137    }
138
139    /// Counts the size of multiple instances of a type with [`size_of`].
140    #[inline]
141    #[doc(alias = "size_of")]
142    pub const fn of_many<T>(n: usize) -> Self {
143        match (size_of::<T>() as MaxCountUInt).checked_mul(n as MaxCountUInt) {
144            Some(count) => Self { count },
145            None => panic!("overflow"),
146        }
147    }
148
149    /// Counts the size of a value with [`size_of_val`].
150    #[inline]
151    #[doc(alias = "size_of_val")]
152    pub fn of_val<T: ?Sized>(val: &T) -> Self {
153        // TODO: Make const, https://github.com/rust-lang/rust/issues/46571
154        Self { count: size_of_val(val) as MaxCountUInt }
155    }
156
157    /// Counts the bytes of [`Iterator::Item`s](Iterator::Item).
158    #[inline]
159    pub fn of_iter<T, I>(iter: I) -> Self
160    where
161        I: IntoIterator<Item = T>,
162    {
163        Self::of_many::<T>(iter.into_iter().count())
164    }
165
166    /// Counts the bytes of a [`&str`].
167    ///
168    /// This is like [`BytesCount::of_val`] with the convenience of behaving as
169    /// expected for [`&String`](String) and other types that convert to
170    /// [`&str`].
171    ///
172    /// [`&str`]: prim@str
173    #[inline]
174    pub fn of_str<S: ?Sized + AsRef<str>>(s: &S) -> Self {
175        Self::of_val(s.as_ref())
176    }
177
178    /// Counts the bytes of a [slice](prim@slice).
179    ///
180    /// This is like [`BytesCount::of_val`] with the convenience of behaving as
181    /// expected for [`&Vec<T>`](Vec) and other types that convert to
182    /// [`&[T]`](prim@slice).
183    #[inline]
184    pub fn of_slice<T, S: ?Sized + AsRef<[T]>>(s: &S) -> Self {
185        Self::of_val(s.as_ref())
186    }
187}
188
189macro_rules! type_bytes {
190    ($ty:ident) => {
191        /// Counts the bytes of multiple
192        #[doc = concat!("[`", stringify!($ty), "`s](", stringify!($ty), ").")]
193        #[inline]
194        pub const fn $ty(n: usize) -> Self {
195            Self::of_many::<$ty>(n)
196        }
197    };
198}
199
200/// Count bytes of multiple values.
201impl BytesCount {
202    type_bytes!(f32);
203    type_bytes!(f64);
204
205    type_bytes!(i8);
206    type_bytes!(u8);
207    type_bytes!(i16);
208    type_bytes!(u16);
209    type_bytes!(i32);
210    type_bytes!(u32);
211    type_bytes!(i64);
212    type_bytes!(u64);
213    type_bytes!(i128);
214    type_bytes!(u128);
215    type_bytes!(isize);
216    type_bytes!(usize);
217}
218
219impl CharsCount {
220    /// Count N [`char`s](char).
221    #[inline]
222    pub fn new<N: CountUInt>(count: N) -> Self {
223        Self { count: count.into_max_uint() }
224    }
225
226    /// Counts the [`char`s](prim@char) of a [`&str`](prim@str).
227    #[inline]
228    pub fn of_str<S: ?Sized + AsRef<str>>(s: &S) -> Self {
229        Self::new(s.as_ref().chars().count())
230    }
231}
232
233impl CyclesCount {
234    /// Count N cycles.
235    #[inline]
236    pub fn new<N: CountUInt>(count: N) -> Self {
237        Self { count: count.into_max_uint() }
238    }
239}
240
241impl ItemsCount {
242    /// Count N items.
243    #[inline]
244    pub fn new<N: CountUInt>(count: N) -> Self {
245        Self { count: count.into_max_uint() }
246    }
247
248    /// Counts [`Iterator::Item`s](Iterator::Item).
249    #[inline]
250    pub fn of_iter<T, I>(iter: I) -> Self
251    where
252        I: IntoIterator<Item = T>,
253    {
254        Self::new(iter.into_iter().count())
255    }
256}
257
258/// The numerical base for [`BytesCount`] in benchmark outputs.
259///
260/// See [`Divan::bytes_format`](crate::Divan::bytes_format) for more info.
261#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
262#[non_exhaustive]
263pub enum BytesFormat {
264    /// Powers of 1000, starting with KB (kilobyte). This is the default.
265    #[default]
266    Decimal,
267
268    /// Powers of 1024, starting with KiB (kibibyte).
269    Binary,
270}
271
272/// Private `BytesFormat` that prevents leaking trait implementations we don't
273/// want to publicly commit to.
274#[derive(Clone, Copy)]
275pub(crate) struct PrivBytesFormat(pub BytesFormat);
276
277impl clap::ValueEnum for PrivBytesFormat {
278    fn value_variants<'a>() -> &'a [Self] {
279        &[Self(BytesFormat::Decimal), Self(BytesFormat::Binary)]
280    }
281
282    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
283        let name = match self.0 {
284            BytesFormat::Decimal => "decimal",
285            BytesFormat::Binary => "binary",
286        };
287        Some(clap::builder::PossibleValue::new(name))
288    }
289}
290
291#[cfg(test)]
292mod tests {
293    use super::*;
294
295    mod bytes_count {
296        use super::*;
297
298        #[test]
299        fn of_iter() {
300            assert_eq!(BytesCount::of_iter::<i32, _>([1, 2, 3]), BytesCount::of_slice(&[1, 2, 3]));
301        }
302    }
303}