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: &'static str = 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}
304