You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bench.cpp 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Copyright (c) 2015-2016 The Bitcoin Core developers
  2. // Distributed under the MIT software license, see the accompanying
  3. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
  4. #include "bench.h"
  5. #include "perf.h"
  6. #include <assert.h>
  7. #include <iostream>
  8. #include <iomanip>
  9. #include <sys/time.h>
  10. benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {
  11. static std::map<std::string, benchmark::BenchFunction> benchmarks_map;
  12. return benchmarks_map;
  13. }
  14. static double gettimedouble(void) {
  15. struct timeval tv;
  16. gettimeofday(&tv, NULL);
  17. return tv.tv_usec * 0.000001 + tv.tv_sec;
  18. }
  19. benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
  20. {
  21. benchmarks().insert(std::make_pair(name, func));
  22. }
  23. void
  24. benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
  25. {
  26. perf_init();
  27. std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
  28. << "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
  29. for (const auto &p: benchmarks()) {
  30. State state(p.first, elapsedTimeForOne);
  31. p.second(state);
  32. }
  33. perf_fini();
  34. }
  35. bool benchmark::State::KeepRunning()
  36. {
  37. if (count & countMask) {
  38. ++count;
  39. return true;
  40. }
  41. double now;
  42. uint64_t nowCycles;
  43. if (count == 0) {
  44. lastTime = beginTime = now = gettimedouble();
  45. lastCycles = beginCycles = nowCycles = perf_cpucycles();
  46. }
  47. else {
  48. now = gettimedouble();
  49. double elapsed = now - lastTime;
  50. double elapsedOne = elapsed * countMaskInv;
  51. if (elapsedOne < minTime) minTime = elapsedOne;
  52. if (elapsedOne > maxTime) maxTime = elapsedOne;
  53. // We only use relative values, so don't have to handle 64-bit wrap-around specially
  54. nowCycles = perf_cpucycles();
  55. uint64_t elapsedOneCycles = (nowCycles - lastCycles) * countMaskInv;
  56. if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;
  57. if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;
  58. if (elapsed*128 < maxElapsed) {
  59. // If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
  60. // The restart avoids including the overhead of this code in the measurement.
  61. countMask = ((countMask<<3)|7) & ((1LL<<60)-1);
  62. countMaskInv = 1./(countMask+1);
  63. count = 0;
  64. minTime = std::numeric_limits<double>::max();
  65. maxTime = std::numeric_limits<double>::min();
  66. minCycles = std::numeric_limits<uint64_t>::max();
  67. maxCycles = std::numeric_limits<uint64_t>::min();
  68. return true;
  69. }
  70. if (elapsed*16 < maxElapsed) {
  71. uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
  72. if ((count & newCountMask)==0) {
  73. countMask = newCountMask;
  74. countMaskInv = 1./(countMask+1);
  75. }
  76. }
  77. }
  78. lastTime = now;
  79. lastCycles = nowCycles;
  80. ++count;
  81. if (now - beginTime < maxElapsed) return true; // Keep going
  82. --count;
  83. assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
  84. // Output results
  85. double average = (now-beginTime)/count;
  86. int64_t averageCycles = (nowCycles-beginCycles)/count;
  87. std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
  88. << minCycles << "," << maxCycles << "," << averageCycles << "\n";
  89. return false;
  90. }