complexity_test.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #undef NDEBUG
  2. #include <algorithm>
  3. #include <cassert>
  4. #include <cmath>
  5. #include <cstdlib>
  6. #include <vector>
  7. #include "benchmark/benchmark.h"
  8. #include "output_test.h"
  9. namespace {
  10. #define ADD_COMPLEXITY_CASES(...) \
  11. int CONCAT(dummy, __LINE__) = AddComplexityTest(__VA_ARGS__)
  12. int AddComplexityTest(std::string test_name, std::string big_o_test_name,
  13. std::string rms_test_name, std::string big_o) {
  14. SetSubstitutions({{"%name", test_name},
  15. {"%bigo_name", big_o_test_name},
  16. {"%rms_name", rms_test_name},
  17. {"%bigo_str", "[ ]* %float " + big_o},
  18. {"%bigo", big_o},
  19. {"%rms", "[ ]*[0-9]+ %"}});
  20. AddCases(
  21. TC_ConsoleOut,
  22. {{"^%bigo_name %bigo_str %bigo_str[ ]*$"},
  23. {"^%bigo_name", MR_Not}, // Assert we we didn't only matched a name.
  24. {"^%rms_name %rms %rms[ ]*$", MR_Next}});
  25. AddCases(TC_JSONOut, {{"\"name\": \"%bigo_name\",$"},
  26. {"\"run_name\": \"%name\",$", MR_Next},
  27. {"\"run_type\": \"aggregate\",$", MR_Next},
  28. {"\"aggregate_name\": \"BigO\",$", MR_Next},
  29. {"\"cpu_coefficient\": %float,$", MR_Next},
  30. {"\"real_coefficient\": %float,$", MR_Next},
  31. {"\"big_o\": \"%bigo\",$", MR_Next},
  32. {"\"time_unit\": \"ns\"$", MR_Next},
  33. {"}", MR_Next},
  34. {"\"name\": \"%rms_name\",$"},
  35. {"\"run_name\": \"%name\",$", MR_Next},
  36. {"\"run_type\": \"aggregate\",$", MR_Next},
  37. {"\"aggregate_name\": \"RMS\",$", MR_Next},
  38. {"\"rms\": %float$", MR_Next},
  39. {"}", MR_Next}});
  40. AddCases(TC_CSVOut, {{"^\"%bigo_name\",,%float,%float,%bigo,,,,,$"},
  41. {"^\"%bigo_name\"", MR_Not},
  42. {"^\"%rms_name\",,%float,%float,,,,,,$", MR_Next}});
  43. return 0;
  44. }
  45. } // end namespace
  46. // ========================================================================= //
  47. // --------------------------- Testing BigO O(1) --------------------------- //
  48. // ========================================================================= //
  49. void BM_Complexity_O1(benchmark::State& state) {
  50. for (auto _ : state) {
  51. for (int i = 0; i < 1024; ++i) {
  52. benchmark::DoNotOptimize(&i);
  53. }
  54. }
  55. state.SetComplexityN(state.range(0));
  56. }
  57. BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(benchmark::o1);
  58. BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity();
  59. BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity([](int64_t) {
  60. return 1.0;
  61. });
  62. const char *one_test_name = "BM_Complexity_O1";
  63. const char *big_o_1_test_name = "BM_Complexity_O1_BigO";
  64. const char *rms_o_1_test_name = "BM_Complexity_O1_RMS";
  65. const char *enum_big_o_1 = "\\([0-9]+\\)";
  66. // FIXME: Tolerate both '(1)' and 'lgN' as output when the complexity is auto
  67. // deduced.
  68. // See https://github.com/google/benchmark/issues/272
  69. const char *auto_big_o_1 = "(\\([0-9]+\\))|(lgN)";
  70. const char *lambda_big_o_1 = "f\\(N\\)";
  71. // Add enum tests
  72. ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
  73. enum_big_o_1);
  74. // Add auto enum tests
  75. ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
  76. auto_big_o_1);
  77. // Add lambda tests
  78. ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
  79. lambda_big_o_1);
  80. // ========================================================================= //
  81. // --------------------------- Testing BigO O(N) --------------------------- //
  82. // ========================================================================= //
  83. std::vector<int> ConstructRandomVector(int64_t size) {
  84. std::vector<int> v;
  85. v.reserve(static_cast<int>(size));
  86. for (int i = 0; i < size; ++i) {
  87. v.push_back(static_cast<int>(std::rand() % size));
  88. }
  89. return v;
  90. }
  91. void BM_Complexity_O_N(benchmark::State& state) {
  92. auto v = ConstructRandomVector(state.range(0));
  93. // Test worst case scenario (item not in vector)
  94. const int64_t item_not_in_vector = state.range(0) * 2;
  95. for (auto _ : state) {
  96. benchmark::DoNotOptimize(std::find(v.begin(), v.end(), item_not_in_vector));
  97. }
  98. state.SetComplexityN(state.range(0));
  99. }
  100. BENCHMARK(BM_Complexity_O_N)
  101. ->RangeMultiplier(2)
  102. ->Range(1 << 10, 1 << 16)
  103. ->Complexity(benchmark::oN);
  104. BENCHMARK(BM_Complexity_O_N)
  105. ->RangeMultiplier(2)
  106. ->Range(1 << 10, 1 << 16)
  107. ->Complexity([](int64_t n) -> double { return static_cast<double>(n); });
  108. BENCHMARK(BM_Complexity_O_N)
  109. ->RangeMultiplier(2)
  110. ->Range(1 << 10, 1 << 16)
  111. ->Complexity();
  112. const char *n_test_name = "BM_Complexity_O_N";
  113. const char *big_o_n_test_name = "BM_Complexity_O_N_BigO";
  114. const char *rms_o_n_test_name = "BM_Complexity_O_N_RMS";
  115. const char *enum_auto_big_o_n = "N";
  116. const char *lambda_big_o_n = "f\\(N\\)";
  117. // Add enum tests
  118. ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
  119. enum_auto_big_o_n);
  120. // Add lambda tests
  121. ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
  122. lambda_big_o_n);
  123. // ========================================================================= //
  124. // ------------------------- Testing BigO O(N*lgN) ------------------------- //
  125. // ========================================================================= //
  126. static void BM_Complexity_O_N_log_N(benchmark::State& state) {
  127. auto v = ConstructRandomVector(state.range(0));
  128. for (auto _ : state) {
  129. std::sort(v.begin(), v.end());
  130. }
  131. state.SetComplexityN(state.range(0));
  132. }
  133. static const double kLog2E = 1.44269504088896340736;
  134. BENCHMARK(BM_Complexity_O_N_log_N)
  135. ->RangeMultiplier(2)
  136. ->Range(1 << 10, 1 << 16)
  137. ->Complexity(benchmark::oNLogN);
  138. BENCHMARK(BM_Complexity_O_N_log_N)
  139. ->RangeMultiplier(2)
  140. ->Range(1 << 10, 1 << 16)
  141. ->Complexity([](int64_t n) { return kLog2E * n * log(static_cast<double>(n)); });
  142. BENCHMARK(BM_Complexity_O_N_log_N)
  143. ->RangeMultiplier(2)
  144. ->Range(1 << 10, 1 << 16)
  145. ->Complexity();
  146. const char *n_lg_n_test_name = "BM_Complexity_O_N_log_N";
  147. const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_BigO";
  148. const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_RMS";
  149. const char *enum_auto_big_o_n_lg_n = "NlgN";
  150. const char *lambda_big_o_n_lg_n = "f\\(N\\)";
  151. // Add enum tests
  152. ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
  153. rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n);
  154. // Add lambda tests
  155. ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
  156. rms_o_n_lg_n_test_name, lambda_big_o_n_lg_n);
  157. // ========================================================================= //
  158. // --------------------------- TEST CASES END ------------------------------ //
  159. // ========================================================================= //
  160. int main(int argc, char *argv[]) { RunOutputTests(argc, argv); }