| |
| #include <memory> |
| #undef NDEBUG |
| |
| #include <chrono> |
| #include <thread> |
| |
| #include "../src/timers.h" |
| #include "benchmark/benchmark.h" |
| |
| namespace { |
| |
| const std::chrono::duration<double, std::milli> time_frame(50); |
| const double time_frame_in_sec( |
| std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1>>>( |
| time_frame) |
| .count()); |
| |
| void MyBusySpinwait() { |
| const auto start = benchmark::ChronoClockNow(); |
| |
| while (true) { |
| const auto now = benchmark::ChronoClockNow(); |
| const auto elapsed = now - start; |
| |
| if (std::chrono::duration<double, std::chrono::seconds::period>(elapsed) >= |
| time_frame) { |
| return; |
| } |
| } |
| } |
| |
| int numRunThreadsCalled_ = 0; |
| |
| class ManualThreadRunner : public benchmark::ThreadRunnerBase { |
| public: |
| explicit ManualThreadRunner(int num_threads) |
| : pool(static_cast<size_t>(num_threads - 1)) {} |
| |
| void RunThreads(const std::function<void(int)>& fn) final { |
| for (std::size_t ti = 0; ti < pool.size(); ++ti) { |
| pool[ti] = std::thread(fn, static_cast<int>(ti + 1)); |
| } |
| |
| fn(0); |
| |
| for (std::thread& thread : pool) { |
| thread.join(); |
| } |
| |
| ++numRunThreadsCalled_; |
| } |
| |
| private: |
| std::vector<std::thread> pool; |
| }; |
| |
| // ========================================================================= // |
| // --------------------------- TEST CASES BEGIN ---------------------------- // |
| // ========================================================================= // |
| |
| // ========================================================================= // |
| // BM_ManualThreading |
| // Creation of threads is done before the start of the measurement, |
| // joining after the finish of the measurement. |
| void BM_ManualThreading(benchmark::State& state) { |
| for (auto _ : state) { |
| MyBusySpinwait(); |
| state.SetIterationTime(time_frame_in_sec); |
| } |
| state.counters["invtime"] = |
| benchmark::Counter{1, benchmark::Counter::kIsRate}; |
| } |
| |
| } // end namespace |
| |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(1); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(1) |
| ->UseRealTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(1) |
| ->UseManualTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(1) |
| ->MeasureProcessCPUTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(1) |
| ->MeasureProcessCPUTime() |
| ->UseRealTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(1) |
| ->MeasureProcessCPUTime() |
| ->UseManualTime(); |
| |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(2); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(2) |
| ->UseRealTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(2) |
| ->UseManualTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(2) |
| ->MeasureProcessCPUTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(2) |
| ->MeasureProcessCPUTime() |
| ->UseRealTime(); |
| BENCHMARK(BM_ManualThreading) |
| ->Iterations(1) |
| ->ThreadRunner([](int num_threads) { |
| return std::make_unique<ManualThreadRunner>(num_threads); |
| }) |
| ->Threads(2) |
| ->MeasureProcessCPUTime() |
| ->UseManualTime(); |
| |
| // ========================================================================= // |
| // ---------------------------- TEST CASES END ----------------------------- // |
| // ========================================================================= // |
| |
| int main(int argc, char* argv[]) { |
| benchmark::MaybeReenterWithoutASLR(argc, argv); |
| benchmark::Initialize(&argc, argv); |
| benchmark::RunSpecifiedBenchmarks(); |
| benchmark::Shutdown(); |
| assert(numRunThreadsCalled_ > 0); |
| } |