Skip to content

Commit 759475a

Browse files
author
Igor Erin
committed
add: Becnher.iter_reuse
1 parent 260e2f1 commit 759475a

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

src/bencher.rs

+75
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,81 @@ impl<'a, M: Measurement> Bencher<'a, M> {
9494
self.elapsed_time = time_start.elapsed();
9595
}
9696

97+
/// Times a `routine` by executing it many times and timing the total elapsed time.
98+
///
99+
/// Prefer this timing loop when `routine` returns a value that can be reused in
100+
/// the next iteration.
101+
///
102+
/// # Timing model
103+
///
104+
/// Note that the `Bencher` also times the time required to move a value from one call to another.
105+
/// Therefore prefer this timing loop when the runtime of this movement is negligible.
106+
///
107+
/// ```text
108+
/// elapsed = Instant::now + iters * (routine + Range::next)
109+
/// ```
110+
///
111+
/// # Example
112+
///
113+
/// ```rust
114+
/// use criterion::{criterion_group, criterion_main, Criterion};
115+
///
116+
/// const HANDLE_COUNT: usize = 100;
117+
///
118+
/// fn spawn_task(f: impl FnOnce() -> Vec<usize>) {
119+
/// todo!()
120+
/// }
121+
///
122+
/// fn await_task() -> Vec<usize> {
123+
/// todo!()
124+
/// }
125+
///
126+
/// // The function to benchmark that accept, use and returns a empty vector of a certain length
127+
/// fn spawn_and_await(mut vec: Vec<usize>) -> Vec<usize> {
128+
/// // move to closure
129+
/// spawn_task(move || {
130+
/// // use vec here and return
131+
/// vec
132+
/// });
133+
///
134+
/// // move back
135+
/// let mut vec = await_task();
136+
/// vec.clear();
137+
///
138+
/// vec
139+
/// }
140+
///
141+
/// fn bench(c: &mut Criterion) {
142+
/// c.bench_function("iter", move |b| {
143+
/// b.iter_reuse(Vec::with_capacity(HANDLE_COUNT), |vec| spawn_and_await(vec))
144+
/// });
145+
/// }
146+
///
147+
/// criterion_group!(benches, bench);
148+
/// criterion_main!(benches);
149+
/// ```
150+
///
151+
#[inline(never)]
152+
pub fn iter_reuse<IO, R>(&mut self, input: IO, mut routine: R)
153+
where
154+
R: FnMut(IO) -> IO,
155+
{
156+
self.iterated = true;
157+
158+
let time_start = Instant::now();
159+
let start = self.measurement.start();
160+
161+
let mut input_output = input;
162+
for _ in 0..self.iters {
163+
input_output = black_box(routine(input_output));
164+
}
165+
166+
self.value = self.measurement.end(start);
167+
self.elapsed_time = time_start.elapsed();
168+
169+
black_box(drop(input_output));
170+
}
171+
97172
/// Times a `routine` by executing it many times and relying on `routine` to measure its own execution time.
98173
///
99174
/// Prefer this timing loop in cases where `routine` has to do its own measurements to

0 commit comments

Comments
 (0)