netstack3_base/testutil/
benchmarks.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Netstack3 benchmark utilities.
6
7/// Declare a benchmark function.
8///
9/// If `cfg(benchmark)` is enabled, a function named `name` is emitted and it
10/// receives [`RealBencher`].
11///
12/// If `cfg(test)` is enabled, a module named `name` with a single test called
13/// `test_bench` is emitted and it receives [`TestBencher`].
14///
15/// This setup allows for all benchmarking functions to run in unit test mode,
16/// allowing problems to be noticed sooner.
17///
18/// Note that `$fn` doesn't have to be a named function - it can also be an
19/// anonymous closure.
20#[macro_export]
21macro_rules! bench {
22    ($name:ident, $fn:expr) => {
23        #[cfg(benchmark)]
24        pub(crate) fn $name(b: &mut $crate::testutil::RealBencher) {
25            $fn(b);
26        }
27
28        #[cfg(test)]
29        mod $name {
30            use super::*;
31            #[test]
32            fn test_bench() {
33                $fn(&mut $crate::testutil::TestBencher);
34            }
35        }
36    };
37}
38
39/// A trait to allow faking of the type providing benchmarking.
40pub trait Bencher {
41    /// Benchmarks `inner` by running it multiple times.
42    fn iter<T, F: FnMut() -> T>(&mut self, inner: F);
43
44    /// Abstracts blackboxing.
45    ///
46    /// `black_box` prevents the compiler from optimizing a function with an
47    /// unused return type.
48    fn black_box<T>(placeholder: T) -> T;
49}
50
51/// An alias for the bencher used in real benchmarks.
52pub use criterion::Bencher as RealBencher;
53
54impl Bencher for RealBencher {
55    fn iter<T, F: FnMut() -> T>(&mut self, inner: F) {
56        criterion::Bencher::iter(self, inner)
57    }
58
59    #[inline(always)]
60    fn black_box<T>(placeholder: T) -> T {
61        criterion::black_box(placeholder)
62    }
63}
64
65/// A `Bencher` whose `iter` method runs the provided argument a small,
66/// fixed number of times.
67pub struct TestBencher;
68
69impl Bencher for TestBencher {
70    fn iter<T, F: FnMut() -> T>(&mut self, mut inner: F) {
71        const NUM_TEST_ITERS: u32 = 3;
72        for _ in 0..NUM_TEST_ITERS {
73            let _: T = inner();
74        }
75    }
76
77    #[inline(always)]
78    fn black_box<T>(placeholder: T) -> T {
79        placeholder
80    }
81}