benchmark.cc 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Copyright 2009 The RE2 Authors. All Rights Reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. #include <stdint.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <algorithm>
  8. #include <chrono>
  9. #include "util/benchmark.h"
  10. #include "util/flags.h"
  11. #include "re2/re2.h"
  12. #ifdef _WIN32
  13. #define snprintf _snprintf
  14. #endif
  15. using ::testing::Benchmark;
  16. static Benchmark* benchmarks[10000];
  17. static int nbenchmarks;
  18. void Benchmark::Register() {
  19. lo_ = std::max(1, lo_);
  20. hi_ = std::max(lo_, hi_);
  21. benchmarks[nbenchmarks++] = this;
  22. }
  23. static int64_t nsec() {
  24. return std::chrono::duration_cast<std::chrono::nanoseconds>(
  25. std::chrono::steady_clock::now().time_since_epoch())
  26. .count();
  27. }
  28. static int64_t t0;
  29. static int64_t ns;
  30. static int64_t bytes;
  31. static int64_t items;
  32. void StartBenchmarkTiming() {
  33. if (t0 == 0) {
  34. t0 = nsec();
  35. }
  36. }
  37. void StopBenchmarkTiming() {
  38. if (t0 != 0) {
  39. ns += nsec() - t0;
  40. t0 = 0;
  41. }
  42. }
  43. void SetBenchmarkBytesProcessed(int64_t b) { bytes = b; }
  44. void SetBenchmarkItemsProcessed(int64_t i) { items = i; }
  45. static void RunFunc(Benchmark* b, int iters, int arg) {
  46. t0 = nsec();
  47. ns = 0;
  48. bytes = 0;
  49. items = 0;
  50. b->func()(iters, arg);
  51. StopBenchmarkTiming();
  52. }
  53. static int round(int n) {
  54. int base = 1;
  55. while (base * 10 < n) base *= 10;
  56. if (n < 2 * base) return 2 * base;
  57. if (n < 5 * base) return 5 * base;
  58. return 10 * base;
  59. }
  60. static void RunBench(Benchmark* b, int arg) {
  61. int iters, last;
  62. // Run once just in case it's expensive.
  63. iters = 1;
  64. RunFunc(b, iters, arg);
  65. while (ns < (int)1e9 && iters < (int)1e9) {
  66. last = iters;
  67. if (ns / iters == 0) {
  68. iters = (int)1e9;
  69. } else {
  70. iters = (int)1e9 / static_cast<int>(ns / iters);
  71. }
  72. iters = std::max(last + 1, std::min(iters + iters / 2, 100 * last));
  73. iters = round(iters);
  74. RunFunc(b, iters, arg);
  75. }
  76. char mb[100];
  77. char suf[100];
  78. mb[0] = '\0';
  79. suf[0] = '\0';
  80. if (ns > 0 && bytes > 0)
  81. snprintf(mb, sizeof mb, "\t%7.2f MB/s",
  82. ((double)bytes / 1e6) / ((double)ns / 1e9));
  83. if (b->has_arg()) {
  84. if (arg >= (1 << 20)) {
  85. snprintf(suf, sizeof suf, "/%dM", arg / (1 << 20));
  86. } else if (arg >= (1 << 10)) {
  87. snprintf(suf, sizeof suf, "/%dK", arg / (1 << 10));
  88. } else {
  89. snprintf(suf, sizeof suf, "/%d", arg);
  90. }
  91. }
  92. printf("%s%s\t%8d\t%10lld ns/op%s\n", b->name(), suf, iters,
  93. (long long)ns / iters, mb);
  94. fflush(stdout);
  95. }
  96. static bool WantBench(const char* name, int argc, const char** argv) {
  97. if (argc == 1) return true;
  98. for (int i = 1; i < argc; i++) {
  99. if (RE2::PartialMatch(name, argv[i]))
  100. return true;
  101. }
  102. return false;
  103. }
  104. int main(int argc, const char** argv) {
  105. for (int i = 0; i < nbenchmarks; i++) {
  106. Benchmark* b = benchmarks[i];
  107. if (!WantBench(b->name(), argc, argv))
  108. continue;
  109. for (int arg = b->lo(); arg <= b->hi(); arg <<= 1)
  110. RunBench(b, arg);
  111. }
  112. }