test_speed.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #include <cstdint>
  2. #include <cinttypes>
  3. #include <atomic>
  4. #include <functional>
  5. #include <memory>
  6. #include <vector>
  7. #include <string>
  8. #include <thread>
  9. #include <condition_variable>
  10. #include "test_switch.h"
  11. namespace
  12. {
  13. class thread_latch
  14. {
  15. public:
  16. thread_latch(): _go(false), _halt(false) {}
  17. void wait() const;
  18. void release();
  19. bool halted() const;
  20. void halt();
  21. private:
  22. mutable std::mutex _m;
  23. mutable std::condition_variable _cv;
  24. bool _go;
  25. std::atomic<bool> _halt;
  26. };
  27. void thread_latch::wait() const
  28. {
  29. std::unique_lock<std::mutex> lock(_m);
  30. while (!_go)
  31. {
  32. _cv.wait(lock);
  33. }
  34. }
  35. void thread_latch::release()
  36. {
  37. const std::lock_guard<std::mutex> lock(_m);
  38. _go = true;
  39. _cv.notify_all();
  40. }
  41. bool thread_latch::halted() const
  42. {
  43. return _halt;
  44. }
  45. void thread_latch::halt()
  46. {
  47. _halt = true;
  48. }
  49. class thread_group
  50. {
  51. public:
  52. thread_group(const thread_latch &latch, const unsigned n);
  53. void start(const std::function<void(void)> f);
  54. uint64_t join();
  55. private:
  56. void run();
  57. const thread_latch &_latch;
  58. const unsigned _n;
  59. std::atomic<uint64_t> _count;
  60. std::function<void(void)> _f;
  61. std::vector<std::thread> _ths;
  62. };
  63. thread_group::thread_group(const thread_latch &latch, const unsigned n):
  64. _latch(latch), _n(n), _count(0)
  65. {
  66. }
  67. void thread_group::start(const std::function<void(void)> f)
  68. {
  69. _f = std::move(f);
  70. for (auto i = _n; 0 < i--;)
  71. {
  72. _ths.push_back(std::thread(&thread_group::run, this));
  73. }
  74. }
  75. uint64_t thread_group::join()
  76. {
  77. for (auto &th : _ths)
  78. {
  79. th.join();
  80. }
  81. _ths.clear();
  82. return _count;
  83. }
  84. void thread_group::run()
  85. {
  86. uint64_t count = 0;
  87. while (!_latch.halted())
  88. {
  89. _f();
  90. ++count;
  91. }
  92. _count += count;
  93. }
  94. class bench
  95. {
  96. public:
  97. bench() {}
  98. void setup(const std::function<void(void)> f);
  99. unsigned run(const unsigned n, const unsigned seconds);
  100. private:
  101. std::function<void(void)> _f;
  102. };
  103. void bench::setup(const std::function<void(void)> f)
  104. {
  105. _f = std::move(f);
  106. }
  107. unsigned bench::run(const unsigned n, const unsigned seconds)
  108. {
  109. thread_latch latch;
  110. thread_group tg(latch, n);
  111. tg.start(_f);
  112. latch.release();
  113. std::this_thread::sleep_for(std::chrono::seconds(seconds));
  114. latch.halt();
  115. return tg.join();
  116. }
  117. }
  118. int main(int argc, char *argv[])
  119. {
  120. XLOG_INIT();
  121. unsigned n = 1;
  122. if (1 < argc)
  123. {
  124. n = std::stoi(argv[1]);
  125. if (n <= 0 || 99 < n)
  126. {
  127. fprintf(stderr, "Bad thread count (%u).\n", n);
  128. return -1;
  129. }
  130. }
  131. unsigned seconds = 1;
  132. if (2 < argc)
  133. {
  134. seconds = std::stoi(argv[2]);
  135. if (seconds <= 0 || 60*60 < seconds)
  136. {
  137. fprintf(stderr, "Bad duration (%u).\n", seconds);
  138. return -1;
  139. }
  140. }
  141. bench b;
  142. b.setup([](){
  143. XLOG_STATEMENT();
  144. });
  145. const uint64_t k = b.run(n, seconds);
  146. fprintf(stdout, "%" PRIu64 "\n", static_cast<uint64_t>(k));
  147. return 0;
  148. }