find_bit_benchmark_rust.rs 2.8 KB

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