OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/statistics_recorder.h" | 5 #include "base/metrics/statistics_recorder.h" |
6 | 6 |
7 #include "base/at_exit.h" | 7 #include "base/at_exit.h" |
8 #include "base/debug/leak_annotations.h" | 8 #include "base/debug/leak_annotations.h" |
9 #include "base/json/string_escape.h" | 9 #include "base/json/string_escape.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "base/stl_util.h" |
13 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
14 #include "base/synchronization/lock.h" | 15 #include "base/synchronization/lock.h" |
15 #include "base/values.h" | 16 #include "base/values.h" |
16 | 17 |
17 namespace { | 18 namespace { |
18 // Initialize histogram statistics gathering system. | 19 // Initialize histogram statistics gathering system. |
19 base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ = | 20 base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ = |
20 LAZY_INSTANCE_INITIALIZER; | 21 LAZY_INSTANCE_INITIALIZER; |
21 } // namespace | 22 } // namespace |
22 | 23 |
(...skipping 27 matching lines...) Expand all Loading... |
50 } | 51 } |
51 | 52 |
52 HistogramBase* histogram_to_delete = NULL; | 53 HistogramBase* histogram_to_delete = NULL; |
53 HistogramBase* histogram_to_return = NULL; | 54 HistogramBase* histogram_to_return = NULL; |
54 { | 55 { |
55 base::AutoLock auto_lock(*lock_); | 56 base::AutoLock auto_lock(*lock_); |
56 if (histograms_ == NULL) { | 57 if (histograms_ == NULL) { |
57 histogram_to_return = histogram; | 58 histogram_to_return = histogram; |
58 } else { | 59 } else { |
59 const std::string& name = histogram->histogram_name(); | 60 const std::string& name = histogram->histogram_name(); |
60 HistogramMap::iterator it = histograms_->find(name); | 61 HistogramMap::iterator it = histograms_->find(HistogramNameRef(name)); |
61 if (histograms_->end() == it) { | 62 if (histograms_->end() == it) { |
62 (*histograms_)[name] = histogram; | 63 (*histograms_)[HistogramNameRef(name)] = histogram; |
63 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 | 64 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 |
| 65 // If there are callbacks for this histogram, we set the kCallbackExists |
| 66 // flag. |
| 67 auto callback_iterator = callbacks_->find(name); |
| 68 if (callback_iterator != callbacks_->end()) { |
| 69 if (!callback_iterator->second.is_null()) |
| 70 histogram->SetFlags(HistogramBase::kCallbackExists); |
| 71 else |
| 72 histogram->ClearFlags(HistogramBase::kCallbackExists); |
| 73 } |
64 histogram_to_return = histogram; | 74 histogram_to_return = histogram; |
65 } else if (histogram == it->second) { | 75 } else if (histogram == it->second) { |
66 // The histogram was registered before. | 76 // The histogram was registered before. |
67 histogram_to_return = histogram; | 77 histogram_to_return = histogram; |
68 } else { | 78 } else { |
69 // We already have one histogram with this name. | 79 // We already have one histogram with this name. |
70 histogram_to_return = it->second; | 80 histogram_to_return = it->second; |
71 histogram_to_delete = histogram; | 81 histogram_to_delete = histogram; |
72 } | 82 } |
73 } | 83 } |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
183 | 193 |
184 // static | 194 // static |
185 void StatisticsRecorder::GetHistograms(Histograms* output) { | 195 void StatisticsRecorder::GetHistograms(Histograms* output) { |
186 if (lock_ == NULL) | 196 if (lock_ == NULL) |
187 return; | 197 return; |
188 base::AutoLock auto_lock(*lock_); | 198 base::AutoLock auto_lock(*lock_); |
189 if (histograms_ == NULL) | 199 if (histograms_ == NULL) |
190 return; | 200 return; |
191 | 201 |
192 for (const auto& entry : *histograms_) { | 202 for (const auto& entry : *histograms_) { |
193 DCHECK_EQ(entry.first, entry.second->histogram_name()); | 203 DCHECK_EQ(entry.first.name_, entry.second->histogram_name()); |
194 output->push_back(entry.second); | 204 output->push_back(entry.second); |
195 } | 205 } |
196 } | 206 } |
197 | 207 |
198 // static | 208 // static |
199 void StatisticsRecorder::GetBucketRanges( | 209 void StatisticsRecorder::GetBucketRanges( |
200 std::vector<const BucketRanges*>* output) { | 210 std::vector<const BucketRanges*>* output) { |
201 if (lock_ == NULL) | 211 if (lock_ == NULL) |
202 return; | 212 return; |
203 base::AutoLock auto_lock(*lock_); | 213 base::AutoLock auto_lock(*lock_); |
204 if (ranges_ == NULL) | 214 if (ranges_ == NULL) |
205 return; | 215 return; |
206 | 216 |
207 for (const auto& entry : *ranges_) { | 217 for (const auto& entry : *ranges_) { |
208 for (const auto& range_entry : *entry.second) { | 218 for (const auto& range_entry : *entry.second) { |
209 output->push_back(range_entry); | 219 output->push_back(range_entry); |
210 } | 220 } |
211 } | 221 } |
212 } | 222 } |
213 | 223 |
214 // static | 224 // static |
215 HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) { | 225 HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) { |
216 if (lock_ == NULL) | 226 if (lock_ == NULL) |
217 return NULL; | 227 return NULL; |
218 base::AutoLock auto_lock(*lock_); | 228 base::AutoLock auto_lock(*lock_); |
219 if (histograms_ == NULL) | 229 if (histograms_ == NULL) |
220 return NULL; | 230 return NULL; |
221 | 231 |
222 HistogramMap::iterator it = histograms_->find(name); | 232 HistogramMap::iterator it = histograms_->find(HistogramNameRef(name)); |
223 if (histograms_->end() == it) | 233 if (histograms_->end() == it) |
224 return NULL; | 234 return NULL; |
225 return it->second; | 235 return it->second; |
226 } | 236 } |
227 | 237 |
| 238 // static |
| 239 bool StatisticsRecorder::SetCallback( |
| 240 const std::string& name, |
| 241 const StatisticsRecorder::OnSampleCallback& cb) { |
| 242 DCHECK(!cb.is_null()); |
| 243 if (lock_ == NULL) |
| 244 return false; |
| 245 base::AutoLock auto_lock(*lock_); |
| 246 if (histograms_ == NULL) |
| 247 return false; |
| 248 |
| 249 if (ContainsKey(*callbacks_, name)) |
| 250 return false; |
| 251 callbacks_->insert(std::make_pair(name, cb)); |
| 252 |
| 253 auto histogram_iterator = histograms_->find(HistogramNameRef(name)); |
| 254 if (histogram_iterator != histograms_->end()) |
| 255 histogram_iterator->second->SetFlags(HistogramBase::kCallbackExists); |
| 256 |
| 257 return true; |
| 258 } |
| 259 |
| 260 // static |
| 261 void StatisticsRecorder::ClearCallback(const std::string& name) { |
| 262 if (lock_ == NULL) |
| 263 return; |
| 264 base::AutoLock auto_lock(*lock_); |
| 265 if (histograms_ == NULL) |
| 266 return; |
| 267 |
| 268 callbacks_->erase(name); |
| 269 |
| 270 // We also clear the flag from the histogram (if it exists). |
| 271 auto histogram_iterator = histograms_->find(HistogramNameRef(name)); |
| 272 if (histogram_iterator != histograms_->end()) |
| 273 histogram_iterator->second->ClearFlags(HistogramBase::kCallbackExists); |
| 274 } |
| 275 |
| 276 // static |
| 277 StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback( |
| 278 const std::string& name) { |
| 279 if (lock_ == NULL) |
| 280 return OnSampleCallback(); |
| 281 base::AutoLock auto_lock(*lock_); |
| 282 if (histograms_ == NULL) |
| 283 return OnSampleCallback(); |
| 284 |
| 285 auto callback_iterator = callbacks_->find(name); |
| 286 return callback_iterator != callbacks_->end() ? callback_iterator->second |
| 287 : OnSampleCallback(); |
| 288 } |
| 289 |
228 // private static | 290 // private static |
229 void StatisticsRecorder::GetSnapshot(const std::string& query, | 291 void StatisticsRecorder::GetSnapshot(const std::string& query, |
230 Histograms* snapshot) { | 292 Histograms* snapshot) { |
231 if (lock_ == NULL) | 293 if (lock_ == NULL) |
232 return; | 294 return; |
233 base::AutoLock auto_lock(*lock_); | 295 base::AutoLock auto_lock(*lock_); |
234 if (histograms_ == NULL) | 296 if (histograms_ == NULL) |
235 return; | 297 return; |
236 | 298 |
237 for (const auto& entry : *histograms_) { | 299 for (const auto& entry : *histograms_) { |
238 if (entry.first.find(query) != std::string::npos) | 300 if (entry.first.name_.find(query) != std::string::npos) |
239 snapshot->push_back(entry.second); | 301 snapshot->push_back(entry.second); |
240 } | 302 } |
241 } | 303 } |
242 | 304 |
243 // This singleton instance should be started during the single threaded portion | 305 // This singleton instance should be started during the single threaded portion |
244 // of main(), and hence it is not thread safe. It initializes globals to | 306 // of main(), and hence it is not thread safe. It initializes globals to |
245 // provide support for all future calls. | 307 // provide support for all future calls. |
246 StatisticsRecorder::StatisticsRecorder() { | 308 StatisticsRecorder::StatisticsRecorder() { |
247 DCHECK(!histograms_); | 309 DCHECK(!histograms_); |
248 if (lock_ == NULL) { | 310 if (lock_ == NULL) { |
249 // This will leak on purpose. It's the only way to make sure we won't race | 311 // This will leak on purpose. It's the only way to make sure we won't race |
250 // against the static uninitialization of the module while one of our | 312 // against the static uninitialization of the module while one of our |
251 // static methods relying on the lock get called at an inappropriate time | 313 // static methods relying on the lock get called at an inappropriate time |
252 // during the termination phase. Since it's a static data member, we will | 314 // during the termination phase. Since it's a static data member, we will |
253 // leak one per process, which would be similar to the instance allocated | 315 // leak one per process, which would be similar to the instance allocated |
254 // during static initialization and released only on process termination. | 316 // during static initialization and released only on process termination. |
255 lock_ = new base::Lock; | 317 lock_ = new base::Lock; |
256 } | 318 } |
257 base::AutoLock auto_lock(*lock_); | 319 base::AutoLock auto_lock(*lock_); |
258 histograms_ = new HistogramMap; | 320 histograms_ = new HistogramMap; |
| 321 callbacks_ = new CallbackMap; |
259 ranges_ = new RangesMap; | 322 ranges_ = new RangesMap; |
260 | 323 |
261 if (VLOG_IS_ON(1)) | 324 if (VLOG_IS_ON(1)) |
262 AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this); | 325 AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this); |
263 } | 326 } |
264 | 327 |
265 // static | 328 // static |
266 void StatisticsRecorder::DumpHistogramsToVlog(void* instance) { | 329 void StatisticsRecorder::DumpHistogramsToVlog(void* instance) { |
267 std::string output; | 330 std::string output; |
268 StatisticsRecorder::WriteGraph(std::string(), &output); | 331 StatisticsRecorder::WriteGraph(std::string(), &output); |
269 VLOG(1) << output; | 332 VLOG(1) << output; |
270 } | 333 } |
271 | 334 |
272 StatisticsRecorder::~StatisticsRecorder() { | 335 StatisticsRecorder::~StatisticsRecorder() { |
273 DCHECK(histograms_ && ranges_ && lock_); | 336 DCHECK(histograms_ && ranges_ && lock_); |
274 | 337 |
275 // Clean up. | 338 // Clean up. |
276 scoped_ptr<HistogramMap> histograms_deleter; | 339 scoped_ptr<HistogramMap> histograms_deleter; |
| 340 scoped_ptr<CallbackMap> callbacks_deleter; |
277 scoped_ptr<RangesMap> ranges_deleter; | 341 scoped_ptr<RangesMap> ranges_deleter; |
278 // We don't delete lock_ on purpose to avoid having to properly protect | 342 // We don't delete lock_ on purpose to avoid having to properly protect |
279 // against it going away after we checked for NULL in the static methods. | 343 // against it going away after we checked for NULL in the static methods. |
280 { | 344 { |
281 base::AutoLock auto_lock(*lock_); | 345 base::AutoLock auto_lock(*lock_); |
282 histograms_deleter.reset(histograms_); | 346 histograms_deleter.reset(histograms_); |
| 347 callbacks_deleter.reset(callbacks_); |
283 ranges_deleter.reset(ranges_); | 348 ranges_deleter.reset(ranges_); |
284 histograms_ = NULL; | 349 histograms_ = NULL; |
| 350 callbacks_ = NULL; |
285 ranges_ = NULL; | 351 ranges_ = NULL; |
286 } | 352 } |
287 // We are going to leak the histograms and the ranges. | 353 // We are going to leak the histograms and the ranges. |
288 } | 354 } |
289 | 355 |
290 | 356 |
291 // static | 357 // static |
292 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; | 358 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; |
293 // static | 359 // static |
| 360 StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL; |
| 361 // static |
294 StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL; | 362 StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL; |
295 // static | 363 // static |
296 base::Lock* StatisticsRecorder::lock_ = NULL; | 364 base::Lock* StatisticsRecorder::lock_ = NULL; |
297 | 365 |
298 } // namespace base | 366 } // namespace base |
OLD | NEW |