| 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 | 
|---|