1a8c51b3fSopenharmony_ci#ifndef BENCHMARK_THREAD_TIMER_H
2a8c51b3fSopenharmony_ci#define BENCHMARK_THREAD_TIMER_H
3a8c51b3fSopenharmony_ci
4a8c51b3fSopenharmony_ci#include "check.h"
5a8c51b3fSopenharmony_ci#include "timers.h"
6a8c51b3fSopenharmony_ci
7a8c51b3fSopenharmony_cinamespace benchmark {
8a8c51b3fSopenharmony_cinamespace internal {
9a8c51b3fSopenharmony_ci
10a8c51b3fSopenharmony_ciclass ThreadTimer {
11a8c51b3fSopenharmony_ci  explicit ThreadTimer(bool measure_process_cpu_time_)
12a8c51b3fSopenharmony_ci      : measure_process_cpu_time(measure_process_cpu_time_) {}
13a8c51b3fSopenharmony_ci
14a8c51b3fSopenharmony_ci public:
15a8c51b3fSopenharmony_ci  static ThreadTimer Create() {
16a8c51b3fSopenharmony_ci    return ThreadTimer(/*measure_process_cpu_time_=*/false);
17a8c51b3fSopenharmony_ci  }
18a8c51b3fSopenharmony_ci  static ThreadTimer CreateProcessCpuTime() {
19a8c51b3fSopenharmony_ci    return ThreadTimer(/*measure_process_cpu_time_=*/true);
20a8c51b3fSopenharmony_ci  }
21a8c51b3fSopenharmony_ci
22a8c51b3fSopenharmony_ci  // Called by each thread
23a8c51b3fSopenharmony_ci  void StartTimer() {
24a8c51b3fSopenharmony_ci    running_ = true;
25a8c51b3fSopenharmony_ci    start_real_time_ = ChronoClockNow();
26a8c51b3fSopenharmony_ci    start_cpu_time_ = ReadCpuTimerOfChoice();
27a8c51b3fSopenharmony_ci  }
28a8c51b3fSopenharmony_ci
29a8c51b3fSopenharmony_ci  // Called by each thread
30a8c51b3fSopenharmony_ci  void StopTimer() {
31a8c51b3fSopenharmony_ci    BM_CHECK(running_);
32a8c51b3fSopenharmony_ci    running_ = false;
33a8c51b3fSopenharmony_ci    real_time_used_ += ChronoClockNow() - start_real_time_;
34a8c51b3fSopenharmony_ci    // Floating point error can result in the subtraction producing a negative
35a8c51b3fSopenharmony_ci    // time. Guard against that.
36a8c51b3fSopenharmony_ci    cpu_time_used_ +=
37a8c51b3fSopenharmony_ci        std::max<double>(ReadCpuTimerOfChoice() - start_cpu_time_, 0);
38a8c51b3fSopenharmony_ci  }
39a8c51b3fSopenharmony_ci
40a8c51b3fSopenharmony_ci  // Called by each thread
41a8c51b3fSopenharmony_ci  void SetIterationTime(double seconds) { manual_time_used_ += seconds; }
42a8c51b3fSopenharmony_ci
43a8c51b3fSopenharmony_ci  bool running() const { return running_; }
44a8c51b3fSopenharmony_ci
45a8c51b3fSopenharmony_ci  // REQUIRES: timer is not running
46a8c51b3fSopenharmony_ci  double real_time_used() const {
47a8c51b3fSopenharmony_ci    BM_CHECK(!running_);
48a8c51b3fSopenharmony_ci    return real_time_used_;
49a8c51b3fSopenharmony_ci  }
50a8c51b3fSopenharmony_ci
51a8c51b3fSopenharmony_ci  // REQUIRES: timer is not running
52a8c51b3fSopenharmony_ci  double cpu_time_used() const {
53a8c51b3fSopenharmony_ci    BM_CHECK(!running_);
54a8c51b3fSopenharmony_ci    return cpu_time_used_;
55a8c51b3fSopenharmony_ci  }
56a8c51b3fSopenharmony_ci
57a8c51b3fSopenharmony_ci  // REQUIRES: timer is not running
58a8c51b3fSopenharmony_ci  double manual_time_used() const {
59a8c51b3fSopenharmony_ci    BM_CHECK(!running_);
60a8c51b3fSopenharmony_ci    return manual_time_used_;
61a8c51b3fSopenharmony_ci  }
62a8c51b3fSopenharmony_ci
63a8c51b3fSopenharmony_ci private:
64a8c51b3fSopenharmony_ci  double ReadCpuTimerOfChoice() const {
65a8c51b3fSopenharmony_ci    if (measure_process_cpu_time) return ProcessCPUUsage();
66a8c51b3fSopenharmony_ci    return ThreadCPUUsage();
67a8c51b3fSopenharmony_ci  }
68a8c51b3fSopenharmony_ci
69a8c51b3fSopenharmony_ci  // should the thread, or the process, time be measured?
70a8c51b3fSopenharmony_ci  const bool measure_process_cpu_time;
71a8c51b3fSopenharmony_ci
72a8c51b3fSopenharmony_ci  bool running_ = false;        // Is the timer running
73a8c51b3fSopenharmony_ci  double start_real_time_ = 0;  // If running_
74a8c51b3fSopenharmony_ci  double start_cpu_time_ = 0;   // If running_
75a8c51b3fSopenharmony_ci
76a8c51b3fSopenharmony_ci  // Accumulated time so far (does not contain current slice if running_)
77a8c51b3fSopenharmony_ci  double real_time_used_ = 0;
78a8c51b3fSopenharmony_ci  double cpu_time_used_ = 0;
79a8c51b3fSopenharmony_ci  // Manually set iteration time. User sets this with SetIterationTime(seconds).
80a8c51b3fSopenharmony_ci  double manual_time_used_ = 0;
81a8c51b3fSopenharmony_ci};
82a8c51b3fSopenharmony_ci
83a8c51b3fSopenharmony_ci}  // namespace internal
84a8c51b3fSopenharmony_ci}  // namespace benchmark
85a8c51b3fSopenharmony_ci
86a8c51b3fSopenharmony_ci#endif  // BENCHMARK_THREAD_TIMER_H
87