OLD | NEW |
---|---|
1 // Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 1 // Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the LICENSE file in the root of the source | 4 // that can be found in the LICENSE file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // | 8 // |
9 | 9 |
10 #include "webrtc/system_wrappers/include/metrics_default.h" | |
11 | |
12 #include "webrtc/base/criticalsection.h" | |
13 #include "webrtc/base/thread_annotations.h" | |
10 #include "webrtc/system_wrappers/include/metrics.h" | 14 #include "webrtc/system_wrappers/include/metrics.h" |
11 | 15 |
12 // Default implementation of histogram methods for WebRTC clients that do not | 16 // Default implementation of histogram methods for WebRTC clients that do not |
13 // want to provide their own implementation. | 17 // want to provide their own implementation. |
14 | 18 |
15 namespace webrtc { | 19 namespace webrtc { |
16 namespace metrics { | 20 namespace metrics { |
17 | 21 class Histogram; |
18 Histogram* HistogramFactoryGetCounts(const std::string& name, int min, int max, | 22 |
19 int bucket_count) { return NULL; } | 23 namespace { |
20 | 24 // Limit for the maximum number of sample values that can be stored. |
25 // TODO(asapersson): Consider using bucket count (and set up | |
26 // linearly/exponentially spaced buckets) if samples are logged more frequently. | |
27 const int kMaxSampleMapSize = 2000; | |
28 | |
29 class RtcHistogram { | |
30 public: | |
31 RtcHistogram(const std::string& name, int min, int max, int bucket_count) | |
32 : info_(name, min, max, bucket_count) { | |
33 RTC_CHECK_GT(bucket_count, 0); | |
34 } | |
35 ~RtcHistogram() {} | |
pbos-webrtc
2016/05/17 16:11:04
remove dtor
åsapersson
2016/05/18 09:09:21
Done.
| |
36 | |
37 void Add(int sample) { | |
38 if (sample < info_.min) | |
39 sample = info_.min - 1; // Underflow bucket. | |
40 if (sample > info_.max) | |
41 sample = info_.max; | |
42 | |
43 rtc::CritScope cs(&crit_); | |
44 if (info_.samples.size() == kMaxSampleMapSize && | |
45 info_.samples.find(sample) == info_.samples.end()) { | |
46 return; | |
47 } | |
48 ++info_.samples[sample]; | |
49 } | |
50 | |
51 // Returns a copy (or nullptr if there are no samples) and clears samples. | |
52 std::unique_ptr<SampleInfo> GetAndReset() { | |
53 rtc::CritScope cs(&crit_); | |
54 if (info_.samples.empty()) | |
55 return nullptr; | |
56 | |
57 SampleInfo* copy = | |
58 new SampleInfo(info_.name, info_.min, info_.max, info_.bucket_count); | |
59 copy->samples = info_.samples; | |
60 info_.samples.clear(); | |
61 return std::unique_ptr<SampleInfo>(copy); | |
62 } | |
63 | |
64 const std::string& name() const { return info_.name; } | |
65 | |
66 // Functions only for testing. | |
67 void Reset() { | |
68 rtc::CritScope cs(&crit_); | |
69 info_.samples.clear(); | |
70 } | |
71 | |
72 int NumEvents(int sample) const { | |
73 rtc::CritScope cs(&crit_); | |
74 const auto it = info_.samples.find(sample); | |
75 return (it == info_.samples.end()) ? 0 : it->second; | |
76 } | |
77 | |
78 int NumSamples() const { | |
79 int num_samples = 0; | |
80 rtc::CritScope cs(&crit_); | |
81 for (const auto& sample : info_.samples) { | |
82 num_samples += sample.second; | |
83 } | |
84 return num_samples; | |
85 } | |
86 | |
87 int MinSample() const { | |
88 rtc::CritScope cs(&crit_); | |
89 return (info_.samples.empty()) ? -1 : info_.samples.begin()->first; | |
90 } | |
91 | |
92 private: | |
93 rtc::CriticalSection crit_; | |
94 SampleInfo info_; // |info_.samples| guarded by |crit_| | |
pbos-webrtc
2016/05/17 16:11:03
GUARDED_BY(crit_), add const int min_ and const in
åsapersson
2016/05/18 09:09:21
Done.
| |
95 | |
96 RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogram); | |
97 }; | |
98 | |
99 class RtcHistogramMap { | |
100 public: | |
101 RtcHistogramMap() {} | |
102 ~RtcHistogramMap() {} | |
103 | |
104 Histogram* GetCountsHistogram(const std::string& name, | |
105 int min, | |
106 int max, | |
107 int bucket_count) { | |
108 rtc::CritScope cs(&crit_); | |
109 if (map_.find(name) == map_.end()) { | |
110 map_[name].reset(new RtcHistogram(name, min, max, bucket_count)); | |
111 } | |
112 const auto& it = map_.find(name); | |
pbos-webrtc
2016/05/17 16:11:04
auto* it = &map_.find(name), .. maybe. But don't d
pbos-webrtc
2016/05/17 16:12:17
Something like ...::const_iterator = is probably r
åsapersson
2016/05/18 09:09:21
Changed to not do find twice.
| |
113 return reinterpret_cast<Histogram*>(it->second.get()); | |
114 } | |
115 | |
116 Histogram* GetEnumerationHistogram(const std::string& name, int boundary) { | |
117 rtc::CritScope cs(&crit_); | |
118 if (map_.find(name) == map_.end()) { | |
pbos-webrtc
2016/05/17 16:11:04
same here
åsapersson
2016/05/18 09:09:21
Done.
| |
119 map_[name].reset(new RtcHistogram(name, 1, boundary, boundary + 1)); | |
120 } | |
121 const auto& it = map_.find(name); | |
122 return reinterpret_cast<Histogram*>(it->second.get()); | |
123 } | |
124 | |
125 void GetAndReset( | |
126 std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) { | |
127 rtc::CritScope cs(&crit_); | |
128 for (const auto& kv : map_) { | |
129 std::unique_ptr<SampleInfo> info = kv.second->GetAndReset(); | |
130 if (info.get() != nullptr) | |
pbos-webrtc
2016/05/17 16:11:04
Does "if (info)" work?
åsapersson
2016/05/18 09:09:21
Done.
| |
131 histograms->insert(std::make_pair(kv.first, std::move(info))); | |
132 } | |
133 } | |
134 | |
135 // Functions only for testing. | |
136 void Reset() { | |
137 rtc::CritScope cs(&crit_); | |
138 for (const auto& kv : map_) | |
139 kv.second->Reset(); | |
140 } | |
141 | |
142 int NumEvents(const std::string& name, int sample) const { | |
143 rtc::CritScope cs(&crit_); | |
144 const auto& it = map_.find(name); | |
145 return (it == map_.end()) ? 0 : it->second->NumEvents(sample); | |
146 } | |
147 | |
148 int NumSamples(const std::string& name) const { | |
149 rtc::CritScope cs(&crit_); | |
150 const auto& it = map_.find(name); | |
151 return (it == map_.end()) ? 0 : it->second->NumSamples(); | |
152 } | |
153 | |
154 int MinSample(const std::string& name) const { | |
155 rtc::CritScope cs(&crit_); | |
156 const auto& it = map_.find(name); | |
157 return (it == map_.end()) ? -1 : it->second->MinSample(); | |
158 } | |
159 | |
160 private: | |
161 rtc::CriticalSection crit_; | |
162 std::map<std::string, std::unique_ptr<RtcHistogram>> map_ GUARDED_BY(crit_); | |
163 | |
164 RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogramMap); | |
165 }; | |
166 | |
167 // RtcHistogramMap is allocated upon call to Enable(). | |
168 // The histogram getter functions, which return pointer values to the histograms | |
169 // in the map, are cached in WebRTC. Therefore, this memory is not freed by the | |
170 // application (the memory will be reclaimed by the OS). | |
171 static RtcHistogramMap* volatile g_rtc_histogram_map = nullptr; | |
172 | |
173 void CreateMap() { | |
174 RtcHistogramMap* map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map); | |
175 if (map == nullptr) { | |
176 RtcHistogramMap* new_map = new RtcHistogramMap(); | |
177 RtcHistogramMap* old_map = rtc::AtomicOps::CompareAndSwapPtr( | |
178 &g_rtc_histogram_map, static_cast<RtcHistogramMap*>(nullptr), new_map); | |
179 if (old_map != nullptr) | |
180 delete new_map; | |
181 } | |
182 } | |
183 | |
184 // Set (-1 -> 0 or 1) when the first histogram is created (and is not changed | |
185 // thereafter). Calling Enable() after the status is set has no effect. | |
186 // 0: not enabled - GetMap() -> nullptr | |
187 // 1: enabled - GetMap() -> g_rtc_histogram_map | |
188 static volatile int g_rtc_histogram_status = -1; | |
pbos-webrtc
2016/05/17 16:11:04
I think this should only exist under RTC_DCHECK_IS
åsapersson
2016/05/18 09:09:21
Added check for g_rtc_histogram_called 0 in Enable
pbos-webrtc
2016/05/18 10:30:03
I do think you want to do that in GetMap (but only
| |
189 | |
190 void InitStatus() { | |
191 int status = rtc::AtomicOps::AcquireLoad(&g_rtc_histogram_status); | |
192 if (status == -1) { | |
193 RtcHistogramMap* map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map); | |
194 int new_status = (map == nullptr) ? 0 : 1; | |
195 rtc::AtomicOps::CompareAndSwap(&g_rtc_histogram_status, -1, new_status); | |
196 } | |
197 } | |
198 | |
199 // Gets the map (or nullptr). | |
200 RtcHistogramMap* GetMap() { | |
pbos-webrtc
2016/05/18 10:32:35
I think this should just be:
ReleaseStore(&g_rtc_
åsapersson
2016/05/18 12:53:31
Done.
| |
201 RtcHistogramMap* map = nullptr; | |
202 int status = rtc::AtomicOps::AcquireLoad(&g_rtc_histogram_status); | |
203 if (status == 1) { | |
204 map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map); | |
205 } | |
206 return map; | |
207 } | |
208 | |
209 RtcHistogramMap* InitStatusAndGetMap() { | |
210 InitStatus(); | |
211 return GetMap(); | |
212 } | |
213 } // namespace | |
214 | |
215 // Implementation of histogram methods in | |
216 // webrtc/system_wrappers/interface/metrics.h. | |
217 | |
218 // Histogram with exponentially spaced buckets. | |
219 // Creates (or finds) histogram. | |
220 // The returned histogram pointer is cached (and used for adding samples in | |
221 // subsequent calls). | |
222 Histogram* HistogramFactoryGetCounts(const std::string& name, | |
223 int min, | |
224 int max, | |
225 int bucket_count) { | |
226 RtcHistogramMap* map = InitStatusAndGetMap(); | |
227 if (!map) | |
228 return nullptr; | |
229 | |
230 return map->GetCountsHistogram(name, min, max, bucket_count); | |
231 } | |
232 | |
233 // Histogram with linearly spaced buckets. | |
234 // Creates (or finds) histogram. | |
235 // The returned histogram pointer is cached (and used for adding samples in | |
236 // subsequent calls). | |
21 Histogram* HistogramFactoryGetEnumeration(const std::string& name, | 237 Histogram* HistogramFactoryGetEnumeration(const std::string& name, |
22 int boundary) { return NULL; } | 238 int boundary) { |
23 | 239 RtcHistogramMap* map = InitStatusAndGetMap(); |
24 void HistogramAdd( | 240 if (!map) |
25 Histogram* histogram_pointer, const std::string& name, int sample) {} | 241 return nullptr; |
242 | |
243 return map->GetEnumerationHistogram(name, boundary); | |
244 } | |
245 | |
246 // Fast path. Adds |sample| to cached |histogram_pointer|. | |
247 void HistogramAdd(Histogram* histogram_pointer, | |
248 const std::string& name, | |
249 int sample) { | |
250 if (!histogram_pointer) | |
251 return; | |
252 | |
253 RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer); | |
254 RTC_DCHECK_EQ(name, ptr->name()) << "The name should not vary."; | |
255 ptr->Add(sample); | |
256 } | |
257 | |
258 SampleInfo::SampleInfo(const std::string& name, | |
259 int min, | |
260 int max, | |
261 size_t bucket_count) | |
262 : name(name), min(min), max(max), bucket_count(bucket_count) {} | |
263 | |
264 SampleInfo::~SampleInfo() {} | |
265 | |
266 // Implementation of global functions in metrics_default.h. | |
267 void Enable() { | |
268 CreateMap(); | |
269 } | |
270 | |
271 void GetAndReset( | |
272 std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) { | |
273 histograms->clear(); | |
274 RtcHistogramMap* map = GetMap(); | |
275 if (map) | |
276 map->GetAndReset(histograms); | |
277 } | |
278 | |
279 void Reset() { | |
280 RtcHistogramMap* map = GetMap(); | |
281 if (map) | |
282 map->Reset(); | |
283 } | |
284 | |
285 int NumEvents(const std::string& name, int sample) { | |
286 RtcHistogramMap* map = GetMap(); | |
287 return map ? map->NumEvents(name, sample) : 0; | |
288 } | |
289 | |
290 int NumSamples(const std::string& name) { | |
291 RtcHistogramMap* map = GetMap(); | |
292 return map ? map->NumSamples(name) : 0; | |
293 } | |
294 | |
295 int MinSample(const std::string& name) { | |
296 RtcHistogramMap* map = GetMap(); | |
297 return map ? map->MinSample(name) : -1; | |
298 } | |
26 | 299 |
27 } // namespace metrics | 300 } // namespace metrics |
28 } // namespace webrtc | 301 } // namespace webrtc |
29 | |
OLD | NEW |