OLD | NEW |
| (Empty) |
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 #include "webrtc/base/profiler.h" | |
12 | |
13 #include <math.h> | |
14 #include <algorithm> | |
15 | |
16 #include "webrtc/base/timeutils.h" | |
17 | |
18 namespace { | |
19 | |
20 // When written to an ostream, FormattedTime chooses an appropriate scale and | |
21 // suffix for a time value given in seconds. | |
22 class FormattedTime { | |
23 public: | |
24 explicit FormattedTime(double t) : time_(t) {} | |
25 double time() const { return time_; } | |
26 private: | |
27 double time_; | |
28 }; | |
29 | |
30 std::ostream& operator<<(std::ostream& stream, const FormattedTime& time) { | |
31 if (time.time() < 1.0) { | |
32 stream << (time.time() * 1000.0) << "ms"; | |
33 } else { | |
34 stream << time.time() << 's'; | |
35 } | |
36 return stream; | |
37 } | |
38 | |
39 } // namespace | |
40 | |
41 namespace rtc { | |
42 | |
43 ProfilerEvent::ProfilerEvent() | |
44 : total_time_(0.0), | |
45 mean_(0.0), | |
46 sum_of_squared_differences_(0.0), | |
47 start_count_(0), | |
48 event_count_(0) { | |
49 } | |
50 | |
51 void ProfilerEvent::Start() { | |
52 if (start_count_ == 0) { | |
53 current_start_time_ = TimeNanos(); | |
54 } | |
55 ++start_count_; | |
56 } | |
57 | |
58 void ProfilerEvent::Stop(uint64_t stop_time) { | |
59 --start_count_; | |
60 ASSERT(start_count_ >= 0); | |
61 if (start_count_ == 0) { | |
62 double elapsed = static_cast<double>(stop_time - current_start_time_) / | |
63 kNumNanosecsPerSec; | |
64 total_time_ += elapsed; | |
65 if (event_count_ == 0) { | |
66 minimum_ = maximum_ = elapsed; | |
67 } else { | |
68 minimum_ = std::min(minimum_, elapsed); | |
69 maximum_ = std::max(maximum_, elapsed); | |
70 } | |
71 // Online variance and mean algorithm: http://en.wikipedia.org/wiki/ | |
72 // Algorithms_for_calculating_variance#Online_algorithm | |
73 ++event_count_; | |
74 double delta = elapsed - mean_; | |
75 mean_ = mean_ + delta / event_count_; | |
76 sum_of_squared_differences_ += delta * (elapsed - mean_); | |
77 } | |
78 } | |
79 | |
80 void ProfilerEvent::Stop() { | |
81 Stop(TimeNanos()); | |
82 } | |
83 | |
84 double ProfilerEvent::standard_deviation() const { | |
85 if (event_count_ <= 1) return 0.0; | |
86 return sqrt(sum_of_squared_differences_ / (event_count_ - 1.0)); | |
87 } | |
88 | |
89 Profiler::~Profiler() = default; | |
90 | |
91 Profiler* Profiler::Instance() { | |
92 RTC_DEFINE_STATIC_LOCAL(Profiler, instance, ()); | |
93 return &instance; | |
94 } | |
95 | |
96 Profiler::Profiler() { | |
97 } | |
98 | |
99 void Profiler::StartEvent(const std::string& event_name) { | |
100 lock_.LockShared(); | |
101 EventMap::iterator it = events_.find(event_name); | |
102 bool needs_insert = (it == events_.end()); | |
103 lock_.UnlockShared(); | |
104 | |
105 if (needs_insert) { | |
106 // Need an exclusive lock to modify the map. | |
107 ExclusiveScope scope(&lock_); | |
108 it = events_.insert( | |
109 EventMap::value_type(event_name, ProfilerEvent())).first; | |
110 } | |
111 | |
112 it->second.Start(); | |
113 } | |
114 | |
115 void Profiler::StopEvent(const std::string& event_name) { | |
116 // Get the time ASAP, then wait for the lock. | |
117 uint64_t stop_time = TimeNanos(); | |
118 SharedScope scope(&lock_); | |
119 EventMap::iterator it = events_.find(event_name); | |
120 if (it != events_.end()) { | |
121 it->second.Stop(stop_time); | |
122 } | |
123 } | |
124 | |
125 void Profiler::ReportToLog(const char* file, int line, | |
126 LoggingSeverity severity_to_use, | |
127 const std::string& event_prefix) { | |
128 if (!LogMessage::Loggable(severity_to_use)) { | |
129 return; | |
130 } | |
131 | |
132 SharedScope scope(&lock_); | |
133 | |
134 { // Output first line. | |
135 LogMessage msg(file, line, severity_to_use); | |
136 msg.stream() << "=== Profile report "; | |
137 if (event_prefix.empty()) { | |
138 msg.stream() << "(prefix: '" << event_prefix << "') "; | |
139 } | |
140 msg.stream() << "==="; | |
141 } | |
142 for (EventMap::const_iterator it = events_.begin(); | |
143 it != events_.end(); ++it) { | |
144 if (event_prefix.empty() || it->first.find(event_prefix) == 0) { | |
145 LogMessage(file, line, severity_to_use).stream() | |
146 << it->first << " " << it->second; | |
147 } | |
148 } | |
149 LogMessage(file, line, severity_to_use).stream() | |
150 << "=== End profile report ==="; | |
151 } | |
152 | |
153 void Profiler::ReportAllToLog(const char* file, int line, | |
154 LoggingSeverity severity_to_use) { | |
155 ReportToLog(file, line, severity_to_use, ""); | |
156 } | |
157 | |
158 const ProfilerEvent* Profiler::GetEvent(const std::string& event_name) const { | |
159 SharedScope scope(&lock_); | |
160 EventMap::const_iterator it = | |
161 events_.find(event_name); | |
162 return (it == events_.end()) ? NULL : &it->second; | |
163 } | |
164 | |
165 bool Profiler::Clear() { | |
166 ExclusiveScope scope(&lock_); | |
167 bool result = true; | |
168 // Clear all events that aren't started. | |
169 EventMap::iterator it = events_.begin(); | |
170 while (it != events_.end()) { | |
171 if (it->second.is_started()) { | |
172 ++it; // Can't clear started events. | |
173 result = false; | |
174 } else { | |
175 events_.erase(it++); | |
176 } | |
177 } | |
178 return result; | |
179 } | |
180 | |
181 std::ostream& operator<<(std::ostream& stream, | |
182 const ProfilerEvent& profiler_event) { | |
183 stream << "count=" << profiler_event.event_count() | |
184 << " total=" << FormattedTime(profiler_event.total_time()) | |
185 << " mean=" << FormattedTime(profiler_event.mean()) | |
186 << " min=" << FormattedTime(profiler_event.minimum()) | |
187 << " max=" << FormattedTime(profiler_event.maximum()) | |
188 << " sd=" << profiler_event.standard_deviation(); | |
189 return stream; | |
190 } | |
191 | |
192 } // namespace rtc | |
OLD | NEW |