1/*
2 *  Copyright 2013 The WebRTC Project Authors. All rights reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11// A simple wall-clock profiler for instrumented code.
12// Example:
13//   void MyLongFunction() {
14//     PROFILE_F();  // Time the execution of this function.
15//     // Do something
16//     {  // Time just what is in this scope.
17//       PROFILE("My event");
18//       // Do something else
19//     }
20//   }
21// Another example:
22//   void StartAsyncProcess() {
23//     PROFILE_START("My async event");
24//     DoSomethingAsyncAndThenCall(&Callback);
25//   }
26//   void Callback() {
27//     PROFILE_STOP("My async event");
28//     // Handle callback.
29//   }
30
31#ifndef WEBRTC_BASE_PROFILER_H_
32#define WEBRTC_BASE_PROFILER_H_
33
34#include <map>
35#include <string>
36
37#include "webrtc/base/basictypes.h"
38#include "webrtc/base/common.h"
39#include "webrtc/base/logging.h"
40#include "webrtc/base/sharedexclusivelock.h"
41
42// Profiling could be switched via a build flag, but for now, it's always on.
43#ifndef ENABLE_PROFILING
44#define ENABLE_PROFILING
45#endif
46
47#ifdef ENABLE_PROFILING
48
49#define UV_HELPER2(x) _uv_ ## x
50#define UV_HELPER(x) UV_HELPER2(x)
51#define UNIQUE_VAR UV_HELPER(__LINE__)
52
53// Profiles the current scope.
54#define PROFILE(msg) rtc::ProfilerScope UNIQUE_VAR(msg)
55// When placed at the start of a function, profiles the current function.
56#define PROFILE_F() PROFILE(__FUNCTION__)
57// Reports current timings to the log at severity |sev|.
58#define PROFILE_DUMP_ALL(sev) \
59  rtc::Profiler::Instance()->ReportAllToLog(__FILE__, __LINE__, sev)
60// Reports current timings for all events whose names are prefixed by |prefix|
61// to the log at severity |sev|. Using a unique event name as |prefix| will
62// report only that event.
63#define PROFILE_DUMP(sev, prefix) \
64  rtc::Profiler::Instance()->ReportToLog(__FILE__, __LINE__, sev, prefix)
65// Starts and stops a profile event. Useful when an event is not easily
66// captured within a scope (eg, an async call with a callback when done).
67#define PROFILE_START(msg) rtc::Profiler::Instance()->StartEvent(msg)
68#define PROFILE_STOP(msg) rtc::Profiler::Instance()->StopEvent(msg)
69// TODO(ryanpetrie): Consider adding PROFILE_DUMP_EVERY(sev, iterations)
70
71#undef UV_HELPER2
72#undef UV_HELPER
73#undef UNIQUE_VAR
74
75#else  // ENABLE_PROFILING
76
77#define PROFILE(msg) (void)0
78#define PROFILE_F() (void)0
79#define PROFILE_DUMP_ALL(sev) (void)0
80#define PROFILE_DUMP(sev, prefix) (void)0
81#define PROFILE_START(msg) (void)0
82#define PROFILE_STOP(msg) (void)0
83
84#endif  // ENABLE_PROFILING
85
86namespace rtc {
87
88// Tracks information for one profiler event.
89class ProfilerEvent {
90 public:
91  ProfilerEvent();
92  void Start();
93  void Stop();
94  void Stop(uint64_t stop_time);
95  double standard_deviation() const;
96  double total_time() const { return total_time_; }
97  double mean() const { return mean_; }
98  double minimum() const { return minimum_; }
99  double maximum() const { return maximum_; }
100  int event_count() const { return event_count_; }
101  bool is_started() const { return start_count_ > 0; }
102
103 private:
104  uint64_t current_start_time_;
105  double total_time_;
106  double mean_;
107  double sum_of_squared_differences_;
108  double minimum_;
109  double maximum_;
110  int start_count_;
111  int event_count_;
112};
113
114// Singleton that owns ProfilerEvents and reports results. Prefer to use
115// macros, defined above, rather than directly calling Profiler methods.
116class Profiler {
117 public:
118  ~Profiler();
119  void StartEvent(const std::string& event_name);
120  void StopEvent(const std::string& event_name);
121  void ReportToLog(const char* file, int line, LoggingSeverity severity_to_use,
122                   const std::string& event_prefix);
123  void ReportAllToLog(const char* file, int line,
124                      LoggingSeverity severity_to_use);
125  const ProfilerEvent* GetEvent(const std::string& event_name) const;
126  // Clears all _stopped_ events. Returns true if _all_ events were cleared.
127  bool Clear();
128
129  static Profiler* Instance();
130 private:
131  Profiler();
132
133  typedef std::map<std::string, ProfilerEvent> EventMap;
134  EventMap events_;
135  mutable SharedExclusiveLock lock_;
136
137  RTC_DISALLOW_COPY_AND_ASSIGN(Profiler);
138};
139
140// Starts an event on construction and stops it on destruction.
141// Used by PROFILE macro.
142class ProfilerScope {
143 public:
144  explicit ProfilerScope(const std::string& event_name)
145      : event_name_(event_name) {
146    Profiler::Instance()->StartEvent(event_name_);
147  }
148  ~ProfilerScope() {
149    Profiler::Instance()->StopEvent(event_name_);
150  }
151 private:
152  std::string event_name_;
153
154  RTC_DISALLOW_COPY_AND_ASSIGN(ProfilerScope);
155};
156
157std::ostream& operator<<(std::ostream& stream,
158                         const ProfilerEvent& profiler_event);
159
160}  // namespace rtc
161
162#endif  // WEBRTC_BASE_PROFILER_H_
163