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 : min_(min), max_(max), info_(name, min, max, bucket_count) { |
| 33 RTC_DCHECK_GT(bucket_count, 0); |
| 34 } |
| 35 |
| 36 void Add(int sample) { |
| 37 if (sample < min_) |
| 38 sample = min_ - 1; // Underflow bucket. |
| 39 if (sample > max_) |
| 40 sample = max_; |
| 41 |
| 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); |
| 58 copy->samples = info_.samples; |
| 59 info_.samples.clear(); |
| 60 return std::unique_ptr<SampleInfo>(copy); |
| 61 } |
| 62 |
| 63 const std::string& name() const { return info_.name; } |
| 64 |
| 65 // Functions only for testing. |
| 66 void Reset() { |
| 67 rtc::CritScope cs(&crit_); |
| 68 info_.samples.clear(); |
| 69 } |
| 70 |
| 71 int NumEvents(int sample) const { |
| 72 rtc::CritScope cs(&crit_); |
| 73 const auto it = info_.samples.find(sample); |
| 74 return (it == info_.samples.end()) ? 0 : it->second; |
| 75 } |
| 76 |
| 77 int NumSamples() const { |
| 78 int num_samples = 0; |
| 79 rtc::CritScope cs(&crit_); |
| 80 for (const auto& sample : info_.samples) { |
| 81 num_samples += sample.second; |
| 82 } |
| 83 return num_samples; |
| 84 } |
| 85 |
| 86 int MinSample() const { |
| 87 rtc::CritScope cs(&crit_); |
| 88 return (info_.samples.empty()) ? -1 : info_.samples.begin()->first; |
| 89 } |
| 90 |
| 91 private: |
| 92 rtc::CriticalSection crit_; |
| 93 const int min_; |
| 94 const int max_; |
| 95 SampleInfo info_ GUARDED_BY(crit_); |
| 96 |
| 97 RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogram); |
| 98 }; |
| 99 |
| 100 class RtcHistogramMap { |
| 101 public: |
| 102 RtcHistogramMap() {} |
| 103 ~RtcHistogramMap() {} |
| 104 |
| 105 Histogram* GetCountsHistogram(const std::string& name, |
| 106 int min, |
| 107 int max, |
| 108 int bucket_count) { |
| 109 rtc::CritScope cs(&crit_); |
| 110 const auto& it = map_.find(name); |
| 111 if (it != map_.end()) |
| 112 return reinterpret_cast<Histogram*>(it->second.get()); |
| 113 |
| 114 RtcHistogram* hist = new RtcHistogram(name, min, max, bucket_count); |
| 115 map_[name].reset(hist); |
| 116 return reinterpret_cast<Histogram*>(hist); |
| 117 } |
| 118 |
| 119 Histogram* GetEnumerationHistogram(const std::string& name, int boundary) { |
| 120 rtc::CritScope cs(&crit_); |
| 121 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, 1, boundary, boundary + 1); |
| 126 map_[name].reset(hist); |
| 127 return reinterpret_cast<Histogram*>(hist); |
| 128 } |
| 129 |
| 130 void GetAndReset( |
| 131 std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) { |
| 132 rtc::CritScope cs(&crit_); |
| 133 for (const auto& kv : map_) { |
| 134 std::unique_ptr<SampleInfo> info = kv.second->GetAndReset(); |
| 135 if (info) |
| 136 histograms->insert(std::make_pair(kv.first, std::move(info))); |
| 137 } |
| 138 } |
| 139 |
| 140 // Functions only for testing. |
| 141 void Reset() { |
| 142 rtc::CritScope cs(&crit_); |
| 143 for (const auto& kv : map_) |
| 144 kv.second->Reset(); |
| 145 } |
| 146 |
| 147 int NumEvents(const std::string& name, int sample) const { |
| 148 rtc::CritScope cs(&crit_); |
| 149 const auto& it = map_.find(name); |
| 150 return (it == map_.end()) ? 0 : it->second->NumEvents(sample); |
| 151 } |
| 152 |
| 153 int NumSamples(const std::string& name) const { |
| 154 rtc::CritScope cs(&crit_); |
| 155 const auto& it = map_.find(name); |
| 156 return (it == map_.end()) ? 0 : it->second->NumSamples(); |
| 157 } |
| 158 |
| 159 int MinSample(const std::string& name) const { |
| 160 rtc::CritScope cs(&crit_); |
| 161 const auto& it = map_.find(name); |
| 162 return (it == map_.end()) ? -1 : it->second->MinSample(); |
| 163 } |
| 164 |
| 165 private: |
| 166 rtc::CriticalSection crit_; |
| 167 std::map<std::string, std::unique_ptr<RtcHistogram>> map_ GUARDED_BY(crit_); |
| 168 |
| 169 RTC_DISALLOW_COPY_AND_ASSIGN(RtcHistogramMap); |
| 170 }; |
| 171 |
| 172 // RtcHistogramMap is allocated upon call to Enable(). |
| 173 // The histogram getter functions, which return pointer values to the histograms |
| 174 // in the map, are cached in WebRTC. Therefore, this memory is not freed by the |
| 175 // application (the memory will be reclaimed by the OS). |
| 176 static RtcHistogramMap* volatile g_rtc_histogram_map = nullptr; |
| 177 |
| 178 void CreateMap() { |
| 179 RtcHistogramMap* map = rtc::AtomicOps::AcquireLoadPtr(&g_rtc_histogram_map); |
| 180 if (map == nullptr) { |
| 181 RtcHistogramMap* new_map = new RtcHistogramMap(); |
| 182 RtcHistogramMap* old_map = rtc::AtomicOps::CompareAndSwapPtr( |
| 183 &g_rtc_histogram_map, static_cast<RtcHistogramMap*>(nullptr), new_map); |
| 184 if (old_map != nullptr) |
| 185 delete new_map; |
| 186 } |
| 187 } |
| 188 |
| 189 // Set the first time we start using histograms. Used to make sure Enable() is |
| 190 // not called thereafter. |
| 191 #if RTC_DCHECK_IS_ON |
| 192 static volatile int g_rtc_histogram_called = 0; |
| 193 #endif |
| 194 |
| 195 // Gets the map (or nullptr). |
| 196 RtcHistogramMap* GetMap() { |
| 197 #if RTC_DCHECK_IS_ON |
| 198 rtc::AtomicOps::ReleaseStore(&g_rtc_histogram_called, 1); |
| 199 #endif |
| 200 return g_rtc_histogram_map; |
| 201 } |
| 202 } // namespace |
| 203 |
| 204 // Implementation of histogram methods in |
| 205 // webrtc/system_wrappers/interface/metrics.h. |
| 206 |
| 207 // Histogram with exponentially spaced buckets. |
| 208 // Creates (or finds) histogram. |
| 209 // The returned histogram pointer is cached (and used for adding samples in |
| 210 // subsequent calls). |
| 211 Histogram* HistogramFactoryGetCounts(const std::string& name, |
| 212 int min, |
| 213 int max, |
| 214 int bucket_count) { |
| 215 RtcHistogramMap* map = GetMap(); |
| 216 if (!map) |
| 217 return nullptr; |
| 218 |
| 219 return map->GetCountsHistogram(name, min, max, bucket_count); |
| 220 } |
| 221 |
| 222 // Histogram with linearly spaced buckets. |
| 223 // Creates (or finds) histogram. |
| 224 // The returned histogram pointer is cached (and used for adding samples in |
| 225 // subsequent calls). |
21 Histogram* HistogramFactoryGetEnumeration(const std::string& name, | 226 Histogram* HistogramFactoryGetEnumeration(const std::string& name, |
22 int boundary) { return NULL; } | 227 int boundary) { |
23 | 228 RtcHistogramMap* map = GetMap(); |
24 void HistogramAdd( | 229 if (!map) |
25 Histogram* histogram_pointer, const std::string& name, int sample) {} | 230 return nullptr; |
| 231 |
| 232 return map->GetEnumerationHistogram(name, boundary); |
| 233 } |
| 234 |
| 235 // Fast path. Adds |sample| to cached |histogram_pointer|. |
| 236 void HistogramAdd(Histogram* histogram_pointer, |
| 237 const std::string& name, |
| 238 int sample) { |
| 239 if (!histogram_pointer) |
| 240 return; |
| 241 |
| 242 RtcHistogram* ptr = reinterpret_cast<RtcHistogram*>(histogram_pointer); |
| 243 RTC_DCHECK_EQ(name, ptr->name()) << "The name should not vary."; |
| 244 ptr->Add(sample); |
| 245 } |
| 246 |
| 247 SampleInfo::SampleInfo(const std::string& name, |
| 248 int min, |
| 249 int max, |
| 250 size_t bucket_count) |
| 251 : name(name), min(min), max(max), bucket_count(bucket_count) {} |
| 252 |
| 253 SampleInfo::~SampleInfo() {} |
| 254 |
| 255 // Implementation of global functions in metrics_default.h. |
| 256 void Enable() { |
| 257 RTC_DCHECK(g_rtc_histogram_map == nullptr); |
| 258 #if RTC_DCHECK_IS_ON |
| 259 RTC_DCHECK_EQ(0, rtc::AtomicOps::AcquireLoad(&g_rtc_histogram_called)); |
| 260 #endif |
| 261 CreateMap(); |
| 262 } |
| 263 |
| 264 void GetAndReset( |
| 265 std::map<std::string, std::unique_ptr<SampleInfo>>* histograms) { |
| 266 histograms->clear(); |
| 267 RtcHistogramMap* map = GetMap(); |
| 268 if (map) |
| 269 map->GetAndReset(histograms); |
| 270 } |
| 271 |
| 272 void Reset() { |
| 273 RtcHistogramMap* map = GetMap(); |
| 274 if (map) |
| 275 map->Reset(); |
| 276 } |
| 277 |
| 278 int NumEvents(const std::string& name, int sample) { |
| 279 RtcHistogramMap* map = GetMap(); |
| 280 return map ? map->NumEvents(name, sample) : 0; |
| 281 } |
| 282 |
| 283 int NumSamples(const std::string& name) { |
| 284 RtcHistogramMap* map = GetMap(); |
| 285 return map ? map->NumSamples(name) : 0; |
| 286 } |
| 287 |
| 288 int MinSample(const std::string& name) { |
| 289 RtcHistogramMap* map = GetMap(); |
| 290 return map ? map->MinSample(name) : -1; |
| 291 } |
26 | 292 |
27 } // namespace metrics | 293 } // namespace metrics |
28 } // namespace webrtc | 294 } // namespace webrtc |
29 | |
OLD | NEW |