find-bit-bench.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Benchmark find_next_bit and related bit operations.
  4. *
  5. * Copyright 2020 Google LLC.
  6. */
  7. #include <stdlib.h>
  8. #include "bench.h"
  9. #include "../util/stat.h"
  10. #include <linux/bitmap.h>
  11. #include <linux/bitops.h>
  12. #include <linux/time64.h>
  13. #include <subcmd/parse-options.h>
  14. static unsigned int outer_iterations = 5;
  15. static unsigned int inner_iterations = 100000;
  16. static const struct option options[] = {
  17. OPT_UINTEGER('i', "outer-iterations", &outer_iterations,
  18. "Number of outer iterations used"),
  19. OPT_UINTEGER('j', "inner-iterations", &inner_iterations,
  20. "Number of inner iterations used"),
  21. OPT_END()
  22. };
  23. static const char *const bench_usage[] = {
  24. "perf bench mem find_bit <options>",
  25. NULL
  26. };
  27. static unsigned int accumulator;
  28. static unsigned int use_of_val;
  29. static noinline void workload(int val)
  30. {
  31. use_of_val += val;
  32. accumulator++;
  33. }
  34. #if (defined(__i386__) || defined(__x86_64__)) && defined(__GCC_ASM_FLAG_OUTPUTS__)
  35. static bool asm_test_bit(long nr, const unsigned long *addr)
  36. {
  37. bool oldbit;
  38. asm volatile("bt %2,%1"
  39. : "=@ccc" (oldbit)
  40. : "m" (*(unsigned long *)addr), "Ir" (nr) : "memory");
  41. return oldbit;
  42. }
  43. #else
  44. #define asm_test_bit test_bit
  45. #endif
  46. static int do_for_each_set_bit(unsigned int num_bits)
  47. {
  48. unsigned long *to_test = bitmap_zalloc(num_bits);
  49. struct timeval start, end, diff;
  50. u64 runtime_us;
  51. struct stats fb_time_stats, tb_time_stats;
  52. double time_average, time_stddev;
  53. unsigned int bit, i, j;
  54. unsigned int set_bits, skip;
  55. init_stats(&fb_time_stats);
  56. init_stats(&tb_time_stats);
  57. for (set_bits = 1; set_bits <= num_bits; set_bits <<= 1) {
  58. bitmap_zero(to_test, num_bits);
  59. skip = num_bits / set_bits;
  60. for (i = 0; i < num_bits; i += skip)
  61. __set_bit(i, to_test);
  62. for (i = 0; i < outer_iterations; i++) {
  63. #ifndef NDEBUG
  64. unsigned int old = accumulator;
  65. #endif
  66. gettimeofday(&start, NULL);
  67. for (j = 0; j < inner_iterations; j++) {
  68. for_each_set_bit(bit, to_test, num_bits)
  69. workload(bit);
  70. }
  71. gettimeofday(&end, NULL);
  72. assert(old + (inner_iterations * set_bits) == accumulator);
  73. timersub(&end, &start, &diff);
  74. runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
  75. update_stats(&fb_time_stats, runtime_us);
  76. #ifndef NDEBUG
  77. old = accumulator;
  78. #endif
  79. gettimeofday(&start, NULL);
  80. for (j = 0; j < inner_iterations; j++) {
  81. for (bit = 0; bit < num_bits; bit++) {
  82. if (asm_test_bit(bit, to_test))
  83. workload(bit);
  84. }
  85. }
  86. gettimeofday(&end, NULL);
  87. assert(old + (inner_iterations * set_bits) == accumulator);
  88. timersub(&end, &start, &diff);
  89. runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec;
  90. update_stats(&tb_time_stats, runtime_us);
  91. }
  92. printf("%d operations %d bits set of %d bits\n",
  93. inner_iterations, set_bits, num_bits);
  94. time_average = avg_stats(&fb_time_stats);
  95. time_stddev = stddev_stats(&fb_time_stats);
  96. printf(" Average for_each_set_bit took: %.3f usec (+- %.3f usec)\n",
  97. time_average, time_stddev);
  98. time_average = avg_stats(&tb_time_stats);
  99. time_stddev = stddev_stats(&tb_time_stats);
  100. printf(" Average test_bit loop took: %.3f usec (+- %.3f usec)\n",
  101. time_average, time_stddev);
  102. if (use_of_val == accumulator) /* Try to avoid compiler tricks. */
  103. printf("\n");
  104. }
  105. bitmap_free(to_test);
  106. return 0;
  107. }
  108. int bench_mem_find_bit(int argc, const char **argv)
  109. {
  110. int err = 0, i;
  111. argc = parse_options(argc, argv, options, bench_usage, 0);
  112. if (argc) {
  113. usage_with_options(bench_usage, options);
  114. exit(EXIT_FAILURE);
  115. }
  116. for (i = 1; i <= 2048; i <<= 1)
  117. do_for_each_set_bit(i);
  118. return err;
  119. }