blob: 6ca90dafdc84933c8805f0f550809c1ceb36fe66 [file] [log] [blame]
asapersson@webrtc.org580d3672014-10-23 12:57:56 +00001// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
2//
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
5// tree. An additional intellectual property rights grant can be found
6// in the file PATENTS. All contributing project authors may
7// be found in the AUTHORS file in the root of the source tree.
8//
9
asapersson01d70a32016-05-20 06:29:46 -070010#include "webrtc/system_wrappers/include/metrics_default.h"
11
asapersson1731c9c2016-11-30 00:29:09 -080012#include <algorithm>
13
asapersson01d70a32016-05-20 06:29:46 -070014#include "webrtc/base/criticalsection.h"
15#include "webrtc/base/thread_annotations.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010016#include "webrtc/system_wrappers/include/metrics.h"
asapersson@webrtc.org580d3672014-10-23 12:57:56 +000017
18// Default implementation of histogram methods for WebRTC clients that do not
19// want to provide their own implementation.
20
21namespace webrtc {
22namespace metrics {
asapersson01d70a32016-05-20 06:29:46 -070023class Histogram;
asapersson@webrtc.org580d3672014-10-23 12:57:56 +000024
asapersson01d70a32016-05-20 06:29:46 -070025namespace {
26// Limit for the maximum number of sample values that can be stored.
27// TODO(asapersson): Consider using bucket count (and set up
28// linearly/exponentially spaced buckets) if samples are logged more frequently.
asapersson7d569972016-05-24 06:03:38 -070029const int kMaxSampleMapSize = 300;
asapersson@webrtc.org580d3672014-10-23 12:57:56 +000030
asapersson01d70a32016-05-20 06:29:46 -070031class RtcHistogram {
32 public:
33 RtcHistogram(const std::string& name, int min, int max, int bucket_count)
34 : min_(min), max_(max), info_(name, min, max, bucket_count) {
35 RTC_DCHECK_GT(bucket_count, 0);
36 }
37
38 void Add(int sample) {
asapersson1731c9c2016-11-30 00:29:09 -080039 sample = std::min(sample, max_);
40 sample = std::max(sample, min_ - 1); // Underflow bucket.
asapersson01d70a32016-05-20 06:29:46 -070041
42 rtc::CritScope cs(&crit_);
43 if (info_.samples.size() == kMaxSampleMapSize &&
44 info_.samples.find(sample) == info_.samples.end()) {
45 return;
46 }
47 ++info_.samples[sample];
48 }
49
50 // Returns a copy (or nullptr if there are no samples) and clears samples.
51 std::unique_ptr<SampleInfo> GetAndReset() {
52 rtc::CritScope cs(&crit_);
53 if (info_.samples.empty())
54 return nullptr;
55
56 SampleInfo* copy =
57 new SampleInfo(info_.name, info_.min, info_.max, info_.bucket_count);
asapersson1731c9c2016-11-30 00:29:09 -080058
59 std::swap(info_.samples, copy->samples);
60
asapersson01d70a32016-05-20 06:29:46 -070061 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 const int min_;
95 const int max_;
96 SampleInfo info_ GUARDED_BY(crit_);
97
98 RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogram);
99};
100
101class RtcHistogramMap {
102 public:
103 RtcHistogramMap() {}
104 ~RtcHistogramMap() {}
105
106 Histogram* GetCountsHistogram(const std::string& name,
107 int min,
108 int max,
109 int bucket_count) {
110 rtc::CritScope cs(&crit_);
111 const auto& it = map_.find(name);
112 if (it != map_.end())
113 return reinterpret_cast<Histogram*>(it->second.get());
114
115 RtcHistogram* hist = new RtcHistogram(name, min, max, bucket_count);
116 map_[name].reset(hist);
117 return reinterpret_cast<Histogram*>(hist);
118 }
119
120 Histogram* GetEnumerationHistogram(const std::string& name, int boundary) {
121 rtc::CritScope cs(&crit_);
122 const auto& it = map_.find(name);
123 if (it != map_.end())
124 return reinterpret_cast<Histogram*>(it->second.get());
125
126 RtcHistogram* hist = new RtcHistogram(name, 1, boundary, boundary + 1);
127 map_[name].reset(hist);
128 return reinterpret_cast<Histogram*>(hist);
129 }
130
131 void GetAndReset(
132 std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) {
133 rtc::CritScope cs(&crit_);
134 for (const auto& kv : map_) {
135 std::unique_ptr<SampleInfo> info = kv.second->GetAndReset();
136 if (info)
137 histograms->insert(std::make_pair(kv.first, std::move(info)));
138 }
139 }
140
141 // Functions only for testing.
142 void Reset() {
143 rtc::CritScope cs(&crit_);
144 for (const auto& kv : map_)
145 kv.second->Reset();
146 }
147
148 int NumEvents(const std::string& name, int sample) const {
149 rtc::CritScope cs(&crit_);
150 const auto& it = map_.find(name);
151 return (it == map_.end()) ? 0 : it->second->NumEvents(sample);
152 }
153
154 int NumSamples(const std::string& name) const {
155 rtc::CritScope cs(&crit_);
156 const auto& it = map_.find(name);
157 return (it == map_.end()) ? 0 : it->second->NumSamples();
158 }
159
160 int MinSample(const std::string& name) const {
161 rtc::CritScope cs(&crit_);
162 const auto& it = map_.find(name);
163 return (it == map_.end()) ? -1 : it->second->MinSample();
164 }
165
166 private:
167 rtc::CriticalSection crit_;
168 std::map<std::string, std::unique_ptr<RtcHistogram>> map_ GUARDED_BY(crit_);
169
170 RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogramMap);
171};
172
173// RtcHistogramMap is allocated upon call to Enable().
174// The histogram getter functions, which return pointer values to the histograms
175// in the map, are cached in WebRTC. Therefore, this memory is not freed by the
176// application (the memory will be reclaimed by the OS).
177static RtcHistogramMap* volatile g_rtc_histogram_map = nullptr;
178
179void CreateMap() {
180 RtcHistogramMap* map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map);
181 if (map == nullptr) {
182 RtcHistogramMap* new_map = new RtcHistogramMap();
183 RtcHistogramMap* old_map = rtc::AtomicOps::CompareAndSwapPtr(
184 &g_rtc_histogram_map, static_cast<RtcHistogramMap*>(nullptr), new_map);
185 if (old_map != nullptr)
186 delete new_map;
187 }
188}
189
190// Set the first time we start using histograms. Used to make sure Enable() is
191// not called thereafter.
192#if RTC_DCHECK_IS_ON
193static volatile int g_rtc_histogram_called = 0;
194#endif
195
196// Gets the map (or nullptr).
197RtcHistogramMap* GetMap() {
198#if RTC_DCHECK_IS_ON
199 rtc::AtomicOps::ReleaseStore(&g_rtc_histogram_called, 1);
200#endif
201 return g_rtc_histogram_map;
202}
203} // namespace
204
205// Implementation of histogram methods in
206// webrtc/system_wrappers/interface/metrics.h.
207
208// Histogram with exponentially spaced buckets.
209// Creates (or finds) histogram.
210// The returned histogram pointer is cached (and used for adding samples in
211// subsequent calls).
212Histogram* HistogramFactoryGetCounts(const std::string& name,
213 int min,
214 int max,
215 int bucket_count) {
henrik.lundinf29e05d2016-12-01 09:58:45 -0800216 // TODO(asapersson): Alternative implementation will be needed if this
217 // histogram type should be truly exponential.
218 return HistogramFactoryGetCountsLinear(name, min, max, bucket_count);
219}
220
221// Histogram with linearly spaced buckets.
222// Creates (or finds) histogram.
223// The returned histogram pointer is cached (and used for adding samples in
224// subsequent calls).
225Histogram* HistogramFactoryGetCountsLinear(const std::string& name,
226 int min,
227 int max,
228 int bucket_count) {
asapersson01d70a32016-05-20 06:29:46 -0700229 RtcHistogramMap* map = GetMap();
230 if (!map)
231 return nullptr;
232
233 return map->GetCountsHistogram(name, min, max, bucket_count);
234}
235
236// Histogram with linearly spaced buckets.
237// Creates (or finds) histogram.
238// The returned histogram pointer is cached (and used for adding samples in
239// subsequent calls).
asapersson@webrtc.org580d3672014-10-23 12:57:56 +0000240Histogram* HistogramFactoryGetEnumeration(const std::string& name,
asapersson01d70a32016-05-20 06:29:46 -0700241 int boundary) {
242 RtcHistogramMap* map = GetMap();
243 if (!map)
244 return nullptr;
asapersson@webrtc.org580d3672014-10-23 12:57:56 +0000245
asapersson01d70a32016-05-20 06:29:46 -0700246 return map->GetEnumerationHistogram(name, boundary);
247}
248
sakal71b83932016-09-16 06:56:15 -0700249const std::string& GetHistogramName(Histogram* histogram_pointer) {
asapersson01d70a32016-05-20 06:29:46 -0700250 RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer);
sakal71b83932016-09-16 06:56:15 -0700251 return ptr->name();
asapersson01d70a32016-05-20 06:29:46 -0700252}
253
sakal2a5f3712016-09-09 00:11:48 -0700254// Fast path. Adds |sample| to cached |histogram_pointer|.
255void HistogramAdd(Histogram* histogram_pointer, int sample) {
sakal2a5f3712016-09-09 00:11:48 -0700256 RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer);
257 ptr->Add(sample);
258}
259
asapersson01d70a32016-05-20 06:29:46 -0700260SampleInfo::SampleInfo(const std::string& name,
261 int min,
262 int max,
263 size_t bucket_count)
264 : name(name), min(min), max(max), bucket_count(bucket_count) {}
265
266SampleInfo::~SampleInfo() {}
267
268// Implementation of global functions in metrics_default.h.
269void Enable() {
270 RTC_DCHECK(g_rtc_histogram_map == nullptr);
271#if RTC_DCHECK_IS_ON
272 RTC_DCHECK_EQ(0, rtc::AtomicOps::AcquireLoad(&g_rtc_histogram_called));
273#endif
274 CreateMap();
275}
276
277void GetAndReset(
278 std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) {
279 histograms->clear();
280 RtcHistogramMap* map = GetMap();
281 if (map)
282 map->GetAndReset(histograms);
283}
284
285void Reset() {
286 RtcHistogramMap* map = GetMap();
287 if (map)
288 map->Reset();
289}
290
291int NumEvents(const std::string& name, int sample) {
292 RtcHistogramMap* map = GetMap();
293 return map ? map->NumEvents(name, sample) : 0;
294}
295
296int NumSamples(const std::string& name) {
297 RtcHistogramMap* map = GetMap();
298 return map ? map->NumSamples(name) : 0;
299}
300
301int MinSample(const std::string& name) {
302 RtcHistogramMap* map = GetMap();
303 return map ? map->MinSample(name) : -1;
304}
asapersson@webrtc.org580d3672014-10-23 12:57:56 +0000305
306} // namespace metrics
307} // namespace webrtc