blob: 39ca5900704a154fec58418907066f8386e3907e [file] [log] [blame]
asapersson@webrtc.org580d3672014-10-23 12:57:561// 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
Mirko Bonadeic1c2a882018-09-06 11:34:5110#include "system_wrappers/include/metrics.h"
asapersson01d70a32016-05-20 13:29:4611
asapersson1731c9c2016-11-30 08:29:0912#include <algorithm>
13
Ali Tofigh969c13562022-05-13 08:26:5814#include "absl/strings/string_view.h"
15#include "rtc_base/string_utils.h"
Markus Handell85585f42020-07-08 21:04:3716#include "rtc_base/synchronization/mutex.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3117#include "rtc_base/thread_annotations.h"
asapersson@webrtc.org580d3672014-10-23 12:57:5618
19// Default implementation of histogram methods for WebRTC clients that do not
20// want to provide their own implementation.
21
22namespace webrtc {
23namespace metrics {
asapersson01d70a32016-05-20 13:29:4624class Histogram;
asapersson@webrtc.org580d3672014-10-23 12:57:5625
asapersson01d70a32016-05-20 13:29:4626namespace {
27// Limit for the maximum number of sample values that can be stored.
28// TODO(asapersson): Consider using bucket count (and set up
29// linearly/exponentially spaced buckets) if samples are logged more frequently.
asapersson7d569972016-05-24 13:03:3830const int kMaxSampleMapSize = 300;
asapersson@webrtc.org580d3672014-10-23 12:57:5631
asapersson01d70a32016-05-20 13:29:4632class RtcHistogram {
33 public:
Ali Tofigh969c13562022-05-13 08:26:5834 RtcHistogram(absl::string_view name, int min, int max, int bucket_count)
asapersson01d70a32016-05-20 13:29:4635 : min_(min), max_(max), info_(name, min, max, bucket_count) {
36 RTC_DCHECK_GT(bucket_count, 0);
37 }
38
Byoungchan Leec065e732022-01-18 00:35:4839 RtcHistogram(const RtcHistogram&) = delete;
40 RtcHistogram& operator=(const RtcHistogram&) = delete;
41
asapersson01d70a32016-05-20 13:29:4642 void Add(int sample) {
asapersson1731c9c2016-11-30 08:29:0943 sample = std::min(sample, max_);
44 sample = std::max(sample, min_ - 1); // Underflow bucket.
asapersson01d70a32016-05-20 13:29:4645
Markus Handell85585f42020-07-08 21:04:3746 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:4647 if (info_.samples.size() == kMaxSampleMapSize &&
48 info_.samples.find(sample) == info_.samples.end()) {
49 return;
50 }
51 ++info_.samples[sample];
52 }
53
54 // Returns a copy (or nullptr if there are no samples) and clears samples.
55 std::unique_ptr<SampleInfo> GetAndReset() {
Markus Handell85585f42020-07-08 21:04:3756 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:4657 if (info_.samples.empty())
58 return nullptr;
59
60 SampleInfo* copy =
61 new SampleInfo(info_.name, info_.min, info_.max, info_.bucket_count);
asapersson1731c9c2016-11-30 08:29:0962
63 std::swap(info_.samples, copy->samples);
64
asapersson01d70a32016-05-20 13:29:4665 return std::unique_ptr<SampleInfo>(copy);
66 }
67
68 const std::string& name() const { return info_.name; }
69
70 // Functions only for testing.
71 void Reset() {
Markus Handell85585f42020-07-08 21:04:3772 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:4673 info_.samples.clear();
74 }
75
76 int NumEvents(int sample) const {
Markus Handell85585f42020-07-08 21:04:3777 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:4678 const auto it = info_.samples.find(sample);
79 return (it == info_.samples.end()) ? 0 : it->second;
80 }
81
82 int NumSamples() const {
83 int num_samples = 0;
Markus Handell85585f42020-07-08 21:04:3784 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:4685 for (const auto& sample : info_.samples) {
86 num_samples += sample.second;
87 }
88 return num_samples;
89 }
90
91 int MinSample() const {
Markus Handell85585f42020-07-08 21:04:3792 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:4693 return (info_.samples.empty()) ? -1 : info_.samples.begin()->first;
94 }
95
Steve Antonc1e6e862019-03-04 22:43:4496 std::map<int, int> Samples() const {
Markus Handell85585f42020-07-08 21:04:3797 MutexLock lock(&mutex_);
Steve Antonc1e6e862019-03-04 22:43:4498 return info_.samples;
99 }
100
asapersson01d70a32016-05-20 13:29:46101 private:
Markus Handell85585f42020-07-08 21:04:37102 mutable Mutex mutex_;
asapersson01d70a32016-05-20 13:29:46103 const int min_;
104 const int max_;
Markus Handell85585f42020-07-08 21:04:37105 SampleInfo info_ RTC_GUARDED_BY(mutex_);
asapersson01d70a32016-05-20 13:29:46106};
107
108class RtcHistogramMap {
109 public:
110 RtcHistogramMap() {}
111 ~RtcHistogramMap() {}
112
Byoungchan Leec065e732022-01-18 00:35:48113 RtcHistogramMap(const RtcHistogramMap&) = delete;
114 RtcHistogramMap& operator=(const RtcHistogramMap&) = delete;
115
Ali Tofigh969c13562022-05-13 08:26:58116 Histogram* GetCountsHistogram(absl::string_view name,
asapersson01d70a32016-05-20 13:29:46117 int min,
118 int max,
119 int bucket_count) {
Markus Handell85585f42020-07-08 21:04:37120 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:46121 const auto& it = map_.find(name);
122 if (it != map_.end())
123 return reinterpret_cast<Histogram*>(it->second.get());
124
125 RtcHistogram* hist = new RtcHistogram(name, min, max, bucket_count);
Ali Tofigh969c13562022-05-13 08:26:58126 map_.emplace(name, hist);
asapersson01d70a32016-05-20 13:29:46127 return reinterpret_cast<Histogram*>(hist);
128 }
129
Ali Tofigh969c13562022-05-13 08:26:58130 Histogram* GetEnumerationHistogram(absl::string_view name, int boundary) {
Markus Handell85585f42020-07-08 21:04:37131 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:46132 const auto& it = map_.find(name);
133 if (it != map_.end())
134 return reinterpret_cast<Histogram*>(it->second.get());
135
136 RtcHistogram* hist = new RtcHistogram(name, 1, boundary, boundary + 1);
Ali Tofigh969c13562022-05-13 08:26:58137 map_.emplace(name, hist);
asapersson01d70a32016-05-20 13:29:46138 return reinterpret_cast<Histogram*>(hist);
139 }
140
Ali Tofigh969c13562022-05-13 08:26:58141 void GetAndReset(std::map<std::string,
142 std::unique_ptr<SampleInfo>,
143 rtc::AbslStringViewCmp>* histograms) {
Markus Handell85585f42020-07-08 21:04:37144 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:46145 for (const auto& kv : map_) {
146 std::unique_ptr<SampleInfo> info = kv.second->GetAndReset();
147 if (info)
148 histograms->insert(std::make_pair(kv.first, std::move(info)));
149 }
150 }
151
152 // Functions only for testing.
153 void Reset() {
Markus Handell85585f42020-07-08 21:04:37154 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:46155 for (const auto& kv : map_)
156 kv.second->Reset();
157 }
158
Ali Tofigh969c13562022-05-13 08:26:58159 int NumEvents(absl::string_view name, int sample) const {
Markus Handell85585f42020-07-08 21:04:37160 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:46161 const auto& it = map_.find(name);
162 return (it == map_.end()) ? 0 : it->second->NumEvents(sample);
163 }
164
Ali Tofigh969c13562022-05-13 08:26:58165 int NumSamples(absl::string_view name) const {
Markus Handell85585f42020-07-08 21:04:37166 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:46167 const auto& it = map_.find(name);
168 return (it == map_.end()) ? 0 : it->second->NumSamples();
169 }
170
Ali Tofigh969c13562022-05-13 08:26:58171 int MinSample(absl::string_view name) const {
Markus Handell85585f42020-07-08 21:04:37172 MutexLock lock(&mutex_);
asapersson01d70a32016-05-20 13:29:46173 const auto& it = map_.find(name);
174 return (it == map_.end()) ? -1 : it->second->MinSample();
175 }
176
Ali Tofigh969c13562022-05-13 08:26:58177 std::map<int, int> Samples(absl::string_view name) const {
Markus Handell85585f42020-07-08 21:04:37178 MutexLock lock(&mutex_);
Steve Antonc1e6e862019-03-04 22:43:44179 const auto& it = map_.find(name);
180 return (it == map_.end()) ? std::map<int, int>() : it->second->Samples();
181 }
182
asapersson01d70a32016-05-20 13:29:46183 private:
Markus Handell85585f42020-07-08 21:04:37184 mutable Mutex mutex_;
Ali Tofigh969c13562022-05-13 08:26:58185 std::map<std::string, std::unique_ptr<RtcHistogram>, rtc::AbslStringViewCmp>
186 map_ RTC_GUARDED_BY(mutex_);
asapersson01d70a32016-05-20 13:29:46187};
188
189// RtcHistogramMap is allocated upon call to Enable().
190// The histogram getter functions, which return pointer values to the histograms
191// in the map, are cached in WebRTC. Therefore, this memory is not freed by the
192// application (the memory will be reclaimed by the OS).
Niels Möller7a669002022-06-27 07:47:02193static std::atomic<RtcHistogramMap*> g_rtc_histogram_map(nullptr);
asapersson01d70a32016-05-20 13:29:46194
195void CreateMap() {
Niels Möller7a669002022-06-27 07:47:02196 RtcHistogramMap* map = g_rtc_histogram_map.load(std::memory_order_acquire);
asapersson01d70a32016-05-20 13:29:46197 if (map == nullptr) {
198 RtcHistogramMap* new_map = new RtcHistogramMap();
Niels Möller7a669002022-06-27 07:47:02199 if (!g_rtc_histogram_map.compare_exchange_strong(map, new_map))
asapersson01d70a32016-05-20 13:29:46200 delete new_map;
201 }
202}
203
204// Set the first time we start using histograms. Used to make sure Enable() is
205// not called thereafter.
206#if RTC_DCHECK_IS_ON
Niels Möller7a669002022-06-27 07:47:02207static std::atomic<int> g_rtc_histogram_called(0);
asapersson01d70a32016-05-20 13:29:46208#endif
209
210// Gets the map (or nullptr).
211RtcHistogramMap* GetMap() {
212#if RTC_DCHECK_IS_ON
Niels Möller7a669002022-06-27 07:47:02213 g_rtc_histogram_called.store(1, std::memory_order_release);
asapersson01d70a32016-05-20 13:29:46214#endif
Niels Möller7a669002022-06-27 07:47:02215 return g_rtc_histogram_map.load();
asapersson01d70a32016-05-20 13:29:46216}
217} // namespace
218
Mirko Bonadeic1c2a882018-09-06 11:34:51219#ifndef WEBRTC_EXCLUDE_METRICS_DEFAULT
asapersson01d70a32016-05-20 13:29:46220// Implementation of histogram methods in
221// webrtc/system_wrappers/interface/metrics.h.
222
223// Histogram with exponentially spaced buckets.
224// Creates (or finds) histogram.
225// The returned histogram pointer is cached (and used for adding samples in
226// subsequent calls).
Ali Tofigh969c13562022-05-13 08:26:58227Histogram* HistogramFactoryGetCounts(absl::string_view name,
asapersson01d70a32016-05-20 13:29:46228 int min,
229 int max,
230 int bucket_count) {
henrik.lundinf29e05d2016-12-01 17:58:45231 // TODO(asapersson): Alternative implementation will be needed if this
232 // histogram type should be truly exponential.
233 return HistogramFactoryGetCountsLinear(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).
Ali Tofigh969c13562022-05-13 08:26:58240Histogram* HistogramFactoryGetCountsLinear(absl::string_view name,
henrik.lundinf29e05d2016-12-01 17:58:45241 int min,
242 int max,
243 int bucket_count) {
asapersson01d70a32016-05-20 13:29:46244 RtcHistogramMap* map = GetMap();
245 if (!map)
246 return nullptr;
247
248 return map->GetCountsHistogram(name, min, max, bucket_count);
249}
250
251// Histogram with linearly spaced buckets.
252// Creates (or finds) histogram.
253// The returned histogram pointer is cached (and used for adding samples in
254// subsequent calls).
Ali Tofigh969c13562022-05-13 08:26:58255Histogram* HistogramFactoryGetEnumeration(absl::string_view name,
asapersson01d70a32016-05-20 13:29:46256 int boundary) {
257 RtcHistogramMap* map = GetMap();
258 if (!map)
259 return nullptr;
asapersson@webrtc.org580d3672014-10-23 12:57:56260
asapersson01d70a32016-05-20 13:29:46261 return map->GetEnumerationHistogram(name, boundary);
262}
263
Qingsi Wangd6eb71e2018-06-26 19:30:04264// Our default implementation reuses the non-sparse histogram.
Ali Tofigh969c13562022-05-13 08:26:58265Histogram* SparseHistogramFactoryGetEnumeration(absl::string_view name,
Qingsi Wangd6eb71e2018-06-26 19:30:04266 int boundary) {
267 return HistogramFactoryGetEnumeration(name, boundary);
268}
269
Artem Titovf0671922021-07-27 10:40:17270// Fast path. Adds `sample` to cached `histogram_pointer`.
sakal2a5f3712016-09-09 07:11:48271void HistogramAdd(Histogram* histogram_pointer, int sample) {
sakal2a5f3712016-09-09 07:11:48272 RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer);
273 ptr->Add(sample);
274}
275
Mirko Bonadeic1c2a882018-09-06 11:34:51276#endif // WEBRTC_EXCLUDE_METRICS_DEFAULT
277
Ali Tofigh969c13562022-05-13 08:26:58278SampleInfo::SampleInfo(absl::string_view name,
asapersson01d70a32016-05-20 13:29:46279 int min,
280 int max,
281 size_t bucket_count)
282 : name(name), min(min), max(max), bucket_count(bucket_count) {}
283
284SampleInfo::~SampleInfo() {}
285
Mirko Bonadei17f48782018-09-28 06:51:10286// Implementation of global functions in metrics.h.
asapersson01d70a32016-05-20 13:29:46287void Enable() {
Niels Möller7a669002022-06-27 07:47:02288 RTC_DCHECK(g_rtc_histogram_map.load() == nullptr);
asapersson01d70a32016-05-20 13:29:46289#if RTC_DCHECK_IS_ON
Niels Möller7a669002022-06-27 07:47:02290 RTC_DCHECK_EQ(0, g_rtc_histogram_called.load(std::memory_order_acquire));
asapersson01d70a32016-05-20 13:29:46291#endif
292 CreateMap();
293}
294
295void GetAndReset(
Ali Tofigh969c13562022-05-13 08:26:58296 std::map<std::string, std::unique_ptr<SampleInfo>, rtc::AbslStringViewCmp>*
297 histograms) {
asapersson01d70a32016-05-20 13:29:46298 histograms->clear();
299 RtcHistogramMap* map = GetMap();
300 if (map)
301 map->GetAndReset(histograms);
302}
303
304void Reset() {
305 RtcHistogramMap* map = GetMap();
306 if (map)
307 map->Reset();
308}
309
Ali Tofigh969c13562022-05-13 08:26:58310int NumEvents(absl::string_view name, int sample) {
asapersson01d70a32016-05-20 13:29:46311 RtcHistogramMap* map = GetMap();
312 return map ? map->NumEvents(name, sample) : 0;
313}
314
Ali Tofigh969c13562022-05-13 08:26:58315int NumSamples(absl::string_view name) {
asapersson01d70a32016-05-20 13:29:46316 RtcHistogramMap* map = GetMap();
317 return map ? map->NumSamples(name) : 0;
318}
319
Ali Tofigh969c13562022-05-13 08:26:58320int MinSample(absl::string_view name) {
asapersson01d70a32016-05-20 13:29:46321 RtcHistogramMap* map = GetMap();
322 return map ? map->MinSample(name) : -1;
323}
asapersson@webrtc.org580d3672014-10-23 12:57:56324
Ali Tofigh969c13562022-05-13 08:26:58325std::map<int, int> Samples(absl::string_view name) {
Steve Antonc1e6e862019-03-04 22:43:44326 RtcHistogramMap* map = GetMap();
327 return map ? map->Samples(name) : std::map<int, int>();
328}
329
asapersson@webrtc.org580d3672014-10-23 12:57:56330} // namespace metrics
331} // namespace webrtc