1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be
3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file.
4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/metrics/statistics_recorder.h"
6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include <memory>
894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/at_exit.h"
1094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include "base/debug/leak_annotations.h"
11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/json/string_escape.h"
12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h"
130c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez#include "base/memory/ptr_util.h"
14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/metrics/histogram.h"
150d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/metrics/metrics_hashes.h"
1694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez#include "base/metrics/persistent_histogram_allocator.h"
170d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko#include "base/stl_util.h"
18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/strings/stringprintf.h"
19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/synchronization/lock.h"
20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/values.h"
21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace {
2345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Initialize histogram statistics gathering system.
25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ =
26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    LAZY_INSTANCE_INITIALIZER;
2745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
2845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkobool HistogramNameLesser(const base::HistogramBase* a,
2945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                         const base::HistogramBase* b) {
3045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  return a->histogram_name() < b->histogram_name();
3145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
3245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace
34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base {
36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
3745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::HistogramIterator::HistogramIterator(
3845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const HistogramMap::iterator& iter, bool include_persistent)
3945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    : iter_(iter),
4045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      include_persistent_(include_persistent) {
4194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // The starting location could point to a persistent histogram when such
4294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // is not wanted. If so, skip it.
4394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (!include_persistent_ && iter_ != histograms_->end() &&
4494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      (iter_->second->flags() & HistogramBase::kIsPersistent)) {
4594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    // This operator will continue to skip until a non-persistent histogram
4694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    // is found.
4794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    operator++();
4894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  }
4945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
5045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
5145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::HistogramIterator::HistogramIterator(
5245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    const HistogramIterator& rhs)
5345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    : iter_(rhs.iter_),
5445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      include_persistent_(rhs.include_persistent_) {
5545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
5645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
5745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::HistogramIterator::~HistogramIterator() {}
5845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
5945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::HistogramIterator&
6045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::HistogramIterator::operator++() {
6145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  const HistogramMap::iterator histograms_end = histograms_->end();
6245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (iter_ == histograms_end || lock_ == NULL)
6345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return *this;
6445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
6545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  base::AutoLock auto_lock(*lock_);
6645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
6745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  for (;;) {
6845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    ++iter_;
6945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    if (iter_ == histograms_end)
7045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      break;
7145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    if (!include_persistent_ && (iter_->second->flags() &
7245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                 HistogramBase::kIsPersistent)) {
7345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      continue;
7445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    }
7545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    break;
7645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
7745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
7845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  return *this;
7945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
8045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
8145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::~StatisticsRecorder() {
8245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(lock_);
8345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(histograms_);
8445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  DCHECK(ranges_);
8545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
8694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Clean out what this object created and then restore what existed before.
8745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  Reset();
8894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  base::AutoLock auto_lock(*lock_);
8994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  histograms_ = existing_histograms_.release();
9094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  callbacks_ = existing_callbacks_.release();
9194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  ranges_ = existing_ranges_.release();
9245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
9345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid StatisticsRecorder::Initialize() {
96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // Ensure that an instance of the StatisticsRecorder object is created.
97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  g_statistics_recorder_.Get();
98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbool StatisticsRecorder::IsActive() {
102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (lock_ == NULL)
103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return false;
104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::AutoLock auto_lock(*lock_);
105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return NULL != histograms_;
106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratHistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    HistogramBase* histogram) {
11194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // As per crbug.com/79322 the histograms are intentionally leaked, so we need
11294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once
11394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // for an object, the duplicates should not be annotated.
11494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
11594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // twice if (lock_ == NULL) || (!histograms_).
116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (lock_ == NULL) {
11794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return histogram;
119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  HistogramBase* histogram_to_delete = NULL;
122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  HistogramBase* histogram_to_return = NULL;
123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  {
124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    base::AutoLock auto_lock(*lock_);
125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (histograms_ == NULL) {
126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      histogram_to_return = histogram;
127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    } else {
128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      const std::string& name = histogram->histogram_name();
12994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez      HistogramMap::iterator it = histograms_->find(name);
130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (histograms_->end() == it) {
13194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez        // The StringKey references the name within |histogram| rather than
13294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez        // making a copy.
13394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez        (*histograms_)[name] = histogram;
13494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez        ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
1350d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko        // If there are callbacks for this histogram, we set the kCallbackExists
1360d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko        // flag.
1370d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko        auto callback_iterator = callbacks_->find(name);
1380d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko        if (callback_iterator != callbacks_->end()) {
1390d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko          if (!callback_iterator->second.is_null())
1400d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko            histogram->SetFlags(HistogramBase::kCallbackExists);
1410d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko          else
1420d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko            histogram->ClearFlags(HistogramBase::kCallbackExists);
1430d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko        }
144b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        histogram_to_return = histogram;
145b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      } else if (histogram == it->second) {
146b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        // The histogram was registered before.
147b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        histogram_to_return = histogram;
148b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      } else {
149b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        // We already have one histogram with this name.
1500d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko        DCHECK_EQ(histogram->histogram_name(),
1510d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko                  it->second->histogram_name()) << "hash collision";
152b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        histogram_to_return = it->second;
153b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        histogram_to_delete = histogram;
154b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
155b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
156b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
157b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  delete histogram_to_delete;
158b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return histogram_to_return;
159b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
160b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
161b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
162b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratconst BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
163b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    const BucketRanges* ranges) {
164b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  DCHECK(ranges->HasValidChecksum());
16594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<const BucketRanges> ranges_deleter;
166b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
167b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (lock_ == NULL) {
16894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
169b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return ranges;
170b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
171b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
172b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::AutoLock auto_lock(*lock_);
173b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (ranges_ == NULL) {
17494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
175b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return ranges;
176b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
177b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
178b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  std::list<const BucketRanges*>* checksum_matching_list;
179b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  RangesMap::iterator ranges_it = ranges_->find(ranges->checksum());
180b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (ranges_->end() == ranges_it) {
181b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // Add a new matching list to map.
182b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    checksum_matching_list = new std::list<const BucketRanges*>();
18394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
184b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    (*ranges_)[ranges->checksum()] = checksum_matching_list;
185b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  } else {
186b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    checksum_matching_list = ranges_it->second;
187b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
188b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
189b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const BucketRanges* existing_ranges : *checksum_matching_list) {
190b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (existing_ranges->Equals(ranges)) {
191b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      if (existing_ranges == ranges) {
192b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        return ranges;
193b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      } else {
194b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        ranges_deleter.reset(ranges);
195b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat        return existing_ranges;
196b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      }
197b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
198b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
199b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // We haven't found a BucketRanges which has the same ranges. Register the
200b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // new BucketRanges.
201b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  checksum_matching_list->push_front(ranges);
202b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return ranges;
203b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
204b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
205b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
206b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid StatisticsRecorder::WriteHTMLGraph(const std::string& query,
207b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                        std::string* output) {
208b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!IsActive())
209b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
210b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
211b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Histograms snapshot;
212b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  GetSnapshot(query, &snapshot);
21345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
214b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const HistogramBase* histogram : snapshot) {
215b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    histogram->WriteHTMLGraph(output);
216b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    output->append("<br><hr><br>");
217b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
218b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
219b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
220b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
221b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid StatisticsRecorder::WriteGraph(const std::string& query,
222b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat                                    std::string* output) {
223b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!IsActive())
224b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
225b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (query.length())
226b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
227b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  else
228b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    output->append("Collections of all histograms\n");
229b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
230b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Histograms snapshot;
231b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  GetSnapshot(query, &snapshot);
23245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
233b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const HistogramBase* histogram : snapshot) {
234b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    histogram->WriteAscii(output);
235b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    output->append("\n");
236b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
237b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
238b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
239b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
240b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstd::string StatisticsRecorder::ToJSON(const std::string& query) {
241b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!IsActive())
242b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return std::string();
243b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
244b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  std::string output("{");
245b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (!query.empty()) {
246b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    output += "\"query\":";
247b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    EscapeJSONString(query, true, &output);
248b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    output += ",";
249b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
250b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
251b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  Histograms snapshot;
252b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  GetSnapshot(query, &snapshot);
253b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  output += "\"histograms\":[";
254b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  bool first_histogram = true;
255b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const HistogramBase* histogram : snapshot) {
256b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    if (first_histogram)
257b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      first_histogram = false;
258b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    else
259b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      output += ",";
260b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    std::string json;
261b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    histogram->WriteJSON(&json);
262b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    output += json;
263b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
264b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  output += "]}";
265b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return output;
266b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
267b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
268b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
269b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid StatisticsRecorder::GetHistograms(Histograms* output) {
270b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (lock_ == NULL)
271b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
272b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::AutoLock auto_lock(*lock_);
273b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (histograms_ == NULL)
274b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
275b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
276b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const auto& entry : *histograms_) {
277b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    output->push_back(entry.second);
278b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
279b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
280b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
281b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
282b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid StatisticsRecorder::GetBucketRanges(
283b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    std::vector<const BucketRanges*>* output) {
284b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (lock_ == NULL)
285b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
286b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::AutoLock auto_lock(*lock_);
287b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (ranges_ == NULL)
288b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return;
289b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
290b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  for (const auto& entry : *ranges_) {
2910c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez    for (auto* range_entry : *entry.second) {
292b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat      output->push_back(range_entry);
293b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    }
294b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
295b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
296b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
297b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
29845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoHistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
29994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // This must be called *before* the lock is acquired below because it will
30094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // call back into this object to register histograms. Those called methods
30194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // will acquire the lock at that time.
30294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  ImportGlobalPersistentHistograms();
30394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
304b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (lock_ == NULL)
305b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return NULL;
306b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::AutoLock auto_lock(*lock_);
307b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (histograms_ == NULL)
308b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return NULL;
309b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
31094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  HistogramMap::iterator it = histograms_->find(name);
311b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (histograms_->end() == it)
312b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    return NULL;
313b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  return it->second;
314b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
315b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
3160d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// static
31745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::HistogramIterator StatisticsRecorder::begin(
31845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    bool include_persistent) {
31994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  DCHECK(histograms_);
32094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  ImportGlobalPersistentHistograms();
32194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
32294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  HistogramMap::iterator iter_begin;
32394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  {
32494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    base::AutoLock auto_lock(*lock_);
32594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    iter_begin = histograms_->begin();
32694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  }
32794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  return HistogramIterator(iter_begin, include_persistent);
32845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
32945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
33045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
33145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex VakulenkoStatisticsRecorder::HistogramIterator StatisticsRecorder::end() {
33294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  HistogramMap::iterator iter_end;
33394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  {
33494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    base::AutoLock auto_lock(*lock_);
33594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    iter_end = histograms_->end();
33694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  }
33794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  return HistogramIterator(iter_end, true);
33845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
33945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
34045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
3410c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavezvoid StatisticsRecorder::InitLogOnShutdown() {
3420c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  if (lock_ == nullptr)
3430c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez    return;
3440c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  base::AutoLock auto_lock(*lock_);
3450c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock();
3460c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez}
3470c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez
3480c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez// static
34945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid StatisticsRecorder::GetSnapshot(const std::string& query,
35045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko                                     Histograms* snapshot) {
35145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (lock_ == NULL)
35245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return;
35345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  base::AutoLock auto_lock(*lock_);
35445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (histograms_ == NULL)
35545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return;
35645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
35745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  for (const auto& entry : *histograms_) {
35845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    if (entry.second->histogram_name().find(query) != std::string::npos)
35945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko      snapshot->push_back(entry.second);
36045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  }
36145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
36245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
36345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
3640d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkobool StatisticsRecorder::SetCallback(
3650d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    const std::string& name,
3660d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    const StatisticsRecorder::OnSampleCallback& cb) {
3670d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  DCHECK(!cb.is_null());
3680d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (lock_ == NULL)
3690d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return false;
3700d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  base::AutoLock auto_lock(*lock_);
3710d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (histograms_ == NULL)
3720d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return false;
3730d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
3740d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (ContainsKey(*callbacks_, name))
3750d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return false;
3760d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  callbacks_->insert(std::make_pair(name, cb));
3770d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
37894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  auto it = histograms_->find(name);
37994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (it != histograms_->end())
3800d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    it->second->SetFlags(HistogramBase::kCallbackExists);
3810d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
3820d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  return true;
3830d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko}
3840d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
3850d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// static
3860d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenkovoid StatisticsRecorder::ClearCallback(const std::string& name) {
3870d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (lock_ == NULL)
3880d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return;
3890d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  base::AutoLock auto_lock(*lock_);
3900d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (histograms_ == NULL)
3910d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return;
3920d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
3930d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  callbacks_->erase(name);
3940d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
3950d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  // We also clear the flag from the histogram (if it exists).
39694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  auto it = histograms_->find(name);
39794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (it != histograms_->end())
3980d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    it->second->ClearFlags(HistogramBase::kCallbackExists);
3990d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko}
4000d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
4010d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// static
4020d205d712abd16eeed2f5d5b1052a367d23a223fAlex VakulenkoStatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
4030d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    const std::string& name) {
4040d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (lock_ == NULL)
4050d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return OnSampleCallback();
4060d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  base::AutoLock auto_lock(*lock_);
4070d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  if (histograms_ == NULL)
4080d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    return OnSampleCallback();
4090d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
4100d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  auto callback_iterator = callbacks_->find(name);
4110d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  return callback_iterator != callbacks_->end() ? callback_iterator->second
4120d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko                                                : OnSampleCallback();
4130d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko}
4140d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko
41545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
41645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkosize_t StatisticsRecorder::GetHistogramCount() {
41745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (!lock_)
41845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return 0;
41945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
420b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::AutoLock auto_lock(*lock_);
42145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (!histograms_)
42245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return 0;
42345779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  return histograms_->size();
42445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
425b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
42645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
42794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) {
42894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (histograms_)
42994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    histograms_->erase(name);
43045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
43145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
43245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
4330c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavezstd::unique_ptr<StatisticsRecorder>
4340c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector ChavezStatisticsRecorder::CreateTemporaryForTesting() {
4350c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  return WrapUnique(new StatisticsRecorder());
4360c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez}
4370c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez
4380c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez// static
43994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid StatisticsRecorder::UninitializeForTesting() {
44094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Stop now if it's never been initialized.
44194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (lock_ == NULL || histograms_ == NULL)
44294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    return;
44394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
44494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Get the global instance and destruct it. It's held in static memory so
44594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // can't "delete" it; call the destructor explicitly.
44694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  DCHECK(g_statistics_recorder_.private_instance_);
44794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  g_statistics_recorder_.Get().~StatisticsRecorder();
44894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
44994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Now the ugly part. There's no official way to release a LazyInstance once
45094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // created so it's necessary to clear out an internal variable which
45194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // shouldn't be publicly visible but is for initialization reasons.
45294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  g_statistics_recorder_.private_instance_ = 0;
45394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez}
45494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
45594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez// static
45694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid StatisticsRecorder::ImportGlobalPersistentHistograms() {
45794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (lock_ == NULL)
45894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    return;
45994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
46094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // Import histograms from known persistent storage. Histograms could have
46194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // been added by other processes and they must be fetched and recognized
46294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // locally. If the persistent memory segment is not shared between processes,
46394ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  // this call does nothing.
46494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
46594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  if (allocator)
46694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez    allocator->ImportHistogramsToStatisticsRecorder();
467b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
468b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
469b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// This singleton instance should be started during the single threaded portion
470b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// of main(), and hence it is not thread safe.  It initializes globals to
471b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// provide support for all future calls.
472b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratStatisticsRecorder::StatisticsRecorder() {
473b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  if (lock_ == NULL) {
474b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // This will leak on purpose. It's the only way to make sure we won't race
475b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // against the static uninitialization of the module while one of our
476b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // static methods relying on the lock get called at an inappropriate time
477b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // during the termination phase. Since it's a static data member, we will
478b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // leak one per process, which would be similar to the instance allocated
479b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    // during static initialization and released only on  process termination.
480b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    lock_ = new base::Lock;
481b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
48294ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
483b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  base::AutoLock auto_lock(*lock_);
48494ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
48594ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  existing_histograms_.reset(histograms_);
48694ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  existing_callbacks_.reset(callbacks_);
48794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  existing_ranges_.reset(ranges_);
48894ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez
489b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  histograms_ = new HistogramMap;
4900d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko  callbacks_ = new CallbackMap;
491b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  ranges_ = new RangesMap;
492b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
4930c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  InitLogOnShutdownWithoutLock();
4940c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez}
4950c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez
4960c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavezvoid StatisticsRecorder::InitLogOnShutdownWithoutLock() {
4970c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  if (!vlog_initialized_ && VLOG_IS_ON(1)) {
4980c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez    vlog_initialized_ = true;
499b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this);
5000c4f26a46430b8c503c65f5cae1d2b6876d53e30Luis Hector Chavez  }
501b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
502b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
503b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
50445779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenkovoid StatisticsRecorder::Reset() {
50545779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  // If there's no lock then there is nothing to reset.
50645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  if (!lock_)
50745779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko    return;
508b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
50994ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<HistogramMap> histograms_deleter;
51094ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<CallbackMap> callbacks_deleter;
51194ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavez  std::unique_ptr<RangesMap> ranges_deleter;
512b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // We don't delete lock_ on purpose to avoid having to properly protect
513b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // against it going away after we checked for NULL in the static methods.
514b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  {
515b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    base::AutoLock auto_lock(*lock_);
516b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    histograms_deleter.reset(histograms_);
5170d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    callbacks_deleter.reset(callbacks_);
518b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    ranges_deleter.reset(ranges_);
519b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    histograms_ = NULL;
5200d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko    callbacks_ = NULL;
521b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat    ranges_ = NULL;
522b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  }
523b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat  // We are going to leak the histograms and the ranges.
524b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}
525b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
52645779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko// static
52794ffa55491333f3dcc701befd0d2652922916d99Luis Hector Chavezvoid StatisticsRecorder::DumpHistogramsToVlog(void* /*instance*/) {
52845779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  std::string output;
52945779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  StatisticsRecorder::WriteGraph(std::string(), &output);
53045779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko  VLOG(1) << output;
53145779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko}
53245779228f8c9e40851cfd23f727e2bd8ffdd4714Alex Vakulenko
533b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
534b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
535b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratStatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
536b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
5370d205d712abd16eeed2f5d5b1052a367d23a223fAlex VakulenkoStatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = NULL;
5380d205d712abd16eeed2f5d5b1052a367d23a223fAlex Vakulenko// static
539b8cf94937c52feb53b55c39e3f82094d27de464cDaniel EratStatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
540b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// static
541b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratbase::Lock* StatisticsRecorder::lock_ = NULL;
542b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat
543b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}  // namespace base
544