| // SPDX-License-Identifier: GPL-2.0 | |
| //! Benchmark for find_bit-like methods in Bitmap Rust API. | |
| use kernel::alloc::flags::GFP_KERNEL; | |
| use kernel::bindings; | |
| use kernel::bitmap::BitmapVec; | |
| use kernel::error::{code, Result}; | |
| use kernel::prelude::module; | |
| use kernel::time::{Instant, Monotonic}; | |
| use kernel::ThisModule; | |
| use kernel::{pr_cont, pr_err}; | |
| const BITMAP_LEN: usize = 4096 * 8 * 10; | |
| // Reciprocal of the fraction of bits that are set in sparse bitmap. | |
| const SPARSENESS: usize = 500; | |
| /// Test module that benchmarks performance of traversing bitmaps. | |
| struct Benchmark(); | |
| fn test_next_bit(bitmap: &BitmapVec) { | |
| let time = Instant::<Monotonic>::now(); | |
| let mut cnt = 0; | |
| let mut i = 0; | |
| while let Some(index) = bitmap.next_bit(i) { | |
| cnt += 1; | |
| i = index + 1; | |
| // CONFIG_RUST_BITMAP_HARDENED enforces strict bounds. | |
| if i == BITMAP_LEN { | |
| break; | |
| } | |
| } | |
| let delta = time.elapsed(); | |
| pr_cont!( | |
| "\nnext_bit: {:18} ns, {:6} iterations", | |
| delta.as_nanos(), | |
| cnt | |
| ); | |
| } | |
| fn test_next_zero_bit(bitmap: &BitmapVec) { | |
| let time = Instant::<Monotonic>::now(); | |
| let mut cnt = 0; | |
| let mut i = 0; | |
| while let Some(index) = bitmap.next_zero_bit(i) { | |
| cnt += 1; | |
| i = index + 1; | |
| // CONFIG_RUST_BITMAP_HARDENED enforces strict bounds. | |
| if i == BITMAP_LEN { | |
| break; | |
| } | |
| } | |
| let delta = time.elapsed(); | |
| pr_cont!( | |
| "\nnext_zero_bit: {:18} ns, {:6} iterations", | |
| delta.as_nanos(), | |
| cnt | |
| ); | |
| } | |
| fn find_bit_test() { | |
| pr_err!("Benchmark"); | |
| pr_cont!("\nStart testing find_bit() Rust with random-filled bitmap"); | |
| let mut bitmap = BitmapVec::new(BITMAP_LEN, GFP_KERNEL).expect("alloc bitmap failed"); | |
| bitmap.fill_random(); | |
| test_next_bit(&bitmap); | |
| test_next_zero_bit(&bitmap); | |
| pr_cont!("\nStart testing find_bit() Rust with sparse bitmap"); | |
| let mut bitmap = BitmapVec::new(BITMAP_LEN, GFP_KERNEL).expect("alloc sparse bitmap failed"); | |
| let nbits = BITMAP_LEN / SPARSENESS; | |
| for _i in 0..nbits { | |
| // SAFETY: __get_random_u32_below is safe to call with any u32 argument. | |
| let bit = | |
| unsafe { bindings::__get_random_u32_below(BITMAP_LEN.try_into().unwrap()) as usize }; | |
| bitmap.set_bit(bit); | |
| } | |
| test_next_bit(&bitmap); | |
| test_next_zero_bit(&bitmap); | |
| pr_cont!("\n"); | |
| } | |
| impl kernel::Module for Benchmark { | |
| fn init(_module: &'static ThisModule) -> Result<Self> { | |
| find_bit_test(); | |
| // Return error so test module can be inserted again without rmmod. | |
| Err(code::EINVAL) | |
| } | |
| } | |
| module! { | |
| type: Benchmark, | |
| name: "find_bit_benchmark_rust", | |
| authors: ["Burak Emir <bqe@google.com>"], | |
| description: "Module with benchmark for bitmap Rust API", | |
| license: "GPL v2", | |
| } |