xref: /linux/lib/find_bit_benchmark_rust.rs (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1 // SPDX-License-Identifier: GPL-2.0
2 //! Benchmark for find_bit-like methods in Bitmap Rust API.
3 
4 use kernel::alloc::flags::GFP_KERNEL;
5 use kernel::bindings;
6 use kernel::bitmap::BitmapVec;
7 use kernel::error::{code, Result};
8 use kernel::prelude::module;
9 use kernel::time::{Instant, Monotonic};
10 use kernel::ThisModule;
11 use kernel::{pr_cont, pr_err};
12 
13 const BITMAP_LEN: usize = 4096 * 8 * 10;
14 // Reciprocal of the fraction of bits that are set in sparse bitmap.
15 const SPARSENESS: usize = 500;
16 
17 /// Test module that benchmarks performance of traversing bitmaps.
18 struct Benchmark();
19 
20 fn test_next_bit(bitmap: &BitmapVec) {
21     let time = Instant::<Monotonic>::now();
22     let mut cnt = 0;
23     let mut i = 0;
24 
25     while let Some(index) = bitmap.next_bit(i) {
26         cnt += 1;
27         i = index + 1;
28         // CONFIG_RUST_BITMAP_HARDENED enforces strict bounds.
29         if i == BITMAP_LEN {
30             break;
31         }
32     }
33 
34     let delta = time.elapsed();
35     pr_cont!(
36         "\nnext_bit:           {:18} ns, {:6} iterations",
37         delta.as_nanos(),
38         cnt
39     );
40 }
41 
42 fn test_next_zero_bit(bitmap: &BitmapVec) {
43     let time = Instant::<Monotonic>::now();
44     let mut cnt = 0;
45     let mut i = 0;
46 
47     while let Some(index) = bitmap.next_zero_bit(i) {
48         cnt += 1;
49         i = index + 1;
50         // CONFIG_RUST_BITMAP_HARDENED enforces strict bounds.
51         if i == BITMAP_LEN {
52             break;
53         }
54     }
55 
56     let delta = time.elapsed();
57     pr_cont!(
58         "\nnext_zero_bit:      {:18} ns, {:6} iterations",
59         delta.as_nanos(),
60         cnt
61     );
62 }
63 
64 fn find_bit_test() {
65     pr_err!("Benchmark");
66     pr_cont!("\nStart testing find_bit() Rust with random-filled bitmap");
67 
68     let mut bitmap = BitmapVec::new(BITMAP_LEN, GFP_KERNEL).expect("alloc bitmap failed");
69     bitmap.fill_random();
70 
71     test_next_bit(&bitmap);
72     test_next_zero_bit(&bitmap);
73 
74     pr_cont!("\nStart testing find_bit() Rust with sparse bitmap");
75 
76     let mut bitmap = BitmapVec::new(BITMAP_LEN, GFP_KERNEL).expect("alloc sparse bitmap failed");
77     let nbits = BITMAP_LEN / SPARSENESS;
78     for _i in 0..nbits {
79         // SAFETY: __get_random_u32_below is safe to call with any u32 argument.
80         let bit =
81             unsafe { bindings::__get_random_u32_below(BITMAP_LEN.try_into().unwrap()) as usize };
82         bitmap.set_bit(bit);
83     }
84 
85     test_next_bit(&bitmap);
86     test_next_zero_bit(&bitmap);
87     pr_cont!("\n");
88 }
89 
90 impl kernel::Module for Benchmark {
91     fn init(_module: &'static ThisModule) -> Result<Self> {
92         find_bit_test();
93         // Return error so test module can be inserted again without rmmod.
94         Err(code::EINVAL)
95     }
96 }
97 
98 module! {
99     type: Benchmark,
100     name: "find_bit_benchmark_rust",
101     authors: ["Burak Emir <bqe@google.com>"],
102     description: "Module with benchmark for bitmap Rust API",
103     license: "GPL v2",
104 }
105