aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/cpp/util/profiler.h
blob: 80098eef8196bdeb76958e0338d86ebb6b183926 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef BAZEL_SRC_MAIN_CPP_UTIL_PROFILER_H_
#define BAZEL_SRC_MAIN_CPP_UTIL_PROFILER_H_

#include <stdint.h>  // int64_t
#include <stdio.h>   // printf

namespace blaze_util {
namespace profiler {

// A time duration, measured in some implementation-dependent units.
//
// Using a struct to wrap int64_t yields a unique type that we can't
// accidentally use as a type-synonym of other int64_t types.
struct Ticks {
  int64_t value_;
  static Ticks Now();
};

// A time duration, measured in microseconds.
//
// Using a struct to wrap int64_t yields a unique type that we can't
// accidentally use as a type-synonym of other int64_t types.
struct Duration {
  int64_t micros_;
  static Duration FromTicks(const Ticks ticks);
};

// Accumulates statistics about a function or some C++ scope.
//
// Usage: see ScopedTask.
//
// Records the number of times the scope was entered (the function called) and
// the total time spent in there. Prints the statistics in the destructor.
class Task {
  const char* name_;
  uint64_t calls_;
  Ticks total_;

 public:
  Task(const char* name) : name_(name), calls_(0), total_({0}) {}
  ~Task();
  void AddCall() { calls_++; }
  void AddTicks(const Ticks t) { total_.value_ += t.value_; }
  uint64_t GetCalls() const { return calls_; }
  Duration GetDuration() const { return Duration::FromTicks(total_); }
};

// Measures elapsed time.
//
// Example:
//   void foo() {
//     StopWatch s;
//     ...
//     s.PrintAndReset("marker 1");  // prints elapsed time since creation
//     ...
//     s.PrintAndReset("marker 2");  // prints elapsed time since "marker 1"
//     ...
//     s.Reset();
//     ...
//     Ticks t1 = s.Elapsed();  // time since Reset
//     ...
//     Ticks t2 = s.Elapsed();  // time since Reset, not since t1
//   }
//
class StopWatch {
  Ticks start_;

 public:
  // Constructor -- it also resets this StopWatch.
  StopWatch() { start_ = Ticks::Now(); }

  // Prints elapsed time since last reset, then resets.
  //
  // Args:
  //   name: a descriptive name, will be printed in the output
  void PrintAndReset(const char* name);

  // Returns the elapsed time since the last reset as `Ticks`.
  Ticks Elapsed() const {
    Ticks now = Ticks::Now();
    return {now.value_ - start_.value_};
  }

  // Returns the elapsed time since the last reset as `Duration`.
  Duration ElapsedTime() const { return Duration::FromTicks(Elapsed()); }

  // Resets this StopWatch to the current time.
  void Reset() { start_ = Ticks::Now(); }
};

// Measures the execution duration of a given C++ scope.
//
// The constructor records one call of the scope in a `Task` object, and the
// destructor records the time spent in the scope in that `Task` object.
//
// Usage:
//   create one Task that accumulates the statistics for a given function
//   or scope, and create one ScopedTask in the beginning of the scope you want
//   to measure. Every time the scope is entered (the function is called), a
//   ScopedTask is created, then destructed when the execution leaves the scope.
//   The destructor then records the statistics in the Task.
//
// Example:
//   Task slow_function_stats("slow function");  // d'tor prints stats
//
//   void slow_function() {
//     ScopedTask prof(&slow_function_stats);
//     ...
//   }
//
class ScopedTask {
 public:
  ScopedTask(Task* s) : stat_(s) { stat_->AddCall(); }
  ~ScopedTask() { stat_->AddTicks(prof_.Elapsed()); }

 private:
  Task* stat_;
  StopWatch prof_;
};

}  // namespace profiler
}  // namespace blaze_util

#endif  // BAZEL_SRC_MAIN_CPP_UTIL_PROFILER_H_