Fix some JS style nits.
[chromium-blink-merge.git] / base / metrics / statistics_recorder.cc
blob85408e1fa496dec8dae7574213a3f3b21a1b123d
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
3 // found in the LICENSE file.
5 #include "base/metrics/statistics_recorder.h"
7 #include "base/at_exit.h"
8 #include "base/debug/leak_annotations.h"
9 #include "base/json/string_escape.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/metrics/histogram.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/synchronization/lock.h"
15 #include "base/values.h"
17 namespace {
18 // Initialize histogram statistics gathering system.
19 base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ =
20 LAZY_INSTANCE_INITIALIZER;
21 } // namespace
23 namespace base {
25 // static
26 void StatisticsRecorder::Initialize() {
27 // Ensure that an instance of the StatisticsRecorder object is created.
28 g_statistics_recorder_.Get();
31 // static
32 bool StatisticsRecorder::IsActive() {
33 if (lock_ == NULL)
34 return false;
35 base::AutoLock auto_lock(*lock_);
36 return NULL != histograms_;
39 // static
40 HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
41 HistogramBase* histogram) {
42 // As per crbug.com/79322 the histograms are intentionally leaked, so we need
43 // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once
44 // for an object, the duplicates should not be annotated.
45 // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
46 // twice if (lock_ == NULL) || (!histograms_).
47 if (lock_ == NULL) {
48 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
49 return histogram;
52 HistogramBase* histogram_to_delete = NULL;
53 HistogramBase* histogram_to_return = NULL;
55 base::AutoLock auto_lock(*lock_);
56 if (histograms_ == NULL) {
57 histogram_to_return = histogram;
58 } else {
59 const std::string& name = histogram->histogram_name();
60 HistogramMap::iterator it = histograms_->find(name);
61 if (histograms_->end() == it) {
62 (*histograms_)[name] = histogram;
63 ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
64 histogram_to_return = histogram;
65 } else if (histogram == it->second) {
66 // The histogram was registered before.
67 histogram_to_return = histogram;
68 } else {
69 // We already have one histogram with this name.
70 histogram_to_return = it->second;
71 histogram_to_delete = histogram;
75 delete histogram_to_delete;
76 return histogram_to_return;
79 // static
80 const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
81 const BucketRanges* ranges) {
82 DCHECK(ranges->HasValidChecksum());
83 scoped_ptr<const BucketRanges> ranges_deleter;
85 if (lock_ == NULL) {
86 ANNOTATE_LEAKING_OBJECT_PTR(ranges);
87 return ranges;
90 base::AutoLock auto_lock(*lock_);
91 if (ranges_ == NULL) {
92 ANNOTATE_LEAKING_OBJECT_PTR(ranges);
93 return ranges;
96 std::list<const BucketRanges*>* checksum_matching_list;
97 RangesMap::iterator ranges_it = ranges_->find(ranges->checksum());
98 if (ranges_->end() == ranges_it) {
99 // Add a new matching list to map.
100 checksum_matching_list = new std::list<const BucketRanges*>();
101 ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
102 (*ranges_)[ranges->checksum()] = checksum_matching_list;
103 } else {
104 checksum_matching_list = ranges_it->second;
107 for (const BucketRanges* existing_ranges : *checksum_matching_list) {
108 if (existing_ranges->Equals(ranges)) {
109 if (existing_ranges == ranges) {
110 return ranges;
111 } else {
112 ranges_deleter.reset(ranges);
113 return existing_ranges;
117 // We haven't found a BucketRanges which has the same ranges. Register the
118 // new BucketRanges.
119 checksum_matching_list->push_front(ranges);
120 return ranges;
123 // static
124 void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
125 std::string* output) {
126 if (!IsActive())
127 return;
129 Histograms snapshot;
130 GetSnapshot(query, &snapshot);
131 for (const HistogramBase* histogram : snapshot) {
132 histogram->WriteHTMLGraph(output);
133 output->append("<br><hr><br>");
137 // static
138 void StatisticsRecorder::WriteGraph(const std::string& query,
139 std::string* output) {
140 if (!IsActive())
141 return;
142 if (query.length())
143 StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
144 else
145 output->append("Collections of all histograms\n");
147 Histograms snapshot;
148 GetSnapshot(query, &snapshot);
149 for (const HistogramBase* histogram : snapshot) {
150 histogram->WriteAscii(output);
151 output->append("\n");
155 // static
156 std::string StatisticsRecorder::ToJSON(const std::string& query) {
157 if (!IsActive())
158 return std::string();
160 std::string output("{");
161 if (!query.empty()) {
162 output += "\"query\":";
163 EscapeJSONString(query, true, &output);
164 output += ",";
167 Histograms snapshot;
168 GetSnapshot(query, &snapshot);
169 output += "\"histograms\":[";
170 bool first_histogram = true;
171 for (const HistogramBase* histogram : snapshot) {
172 if (first_histogram)
173 first_histogram = false;
174 else
175 output += ",";
176 std::string json;
177 histogram->WriteJSON(&json);
178 output += json;
180 output += "]}";
181 return output;
184 // static
185 void StatisticsRecorder::GetHistograms(Histograms* output) {
186 if (lock_ == NULL)
187 return;
188 base::AutoLock auto_lock(*lock_);
189 if (histograms_ == NULL)
190 return;
192 for (const auto& entry : *histograms_) {
193 DCHECK_EQ(entry.first, entry.second->histogram_name());
194 output->push_back(entry.second);
198 // static
199 void StatisticsRecorder::GetBucketRanges(
200 std::vector<const BucketRanges*>* output) {
201 if (lock_ == NULL)
202 return;
203 base::AutoLock auto_lock(*lock_);
204 if (ranges_ == NULL)
205 return;
207 for (const auto& entry : *ranges_) {
208 for (const auto& range_entry : *entry.second) {
209 output->push_back(range_entry);
214 // static
215 HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) {
216 if (lock_ == NULL)
217 return NULL;
218 base::AutoLock auto_lock(*lock_);
219 if (histograms_ == NULL)
220 return NULL;
222 HistogramMap::iterator it = histograms_->find(name);
223 if (histograms_->end() == it)
224 return NULL;
225 return it->second;
228 // private static
229 void StatisticsRecorder::GetSnapshot(const std::string& query,
230 Histograms* snapshot) {
231 if (lock_ == NULL)
232 return;
233 base::AutoLock auto_lock(*lock_);
234 if (histograms_ == NULL)
235 return;
237 for (const auto& entry : *histograms_) {
238 if (entry.first.find(query) != std::string::npos)
239 snapshot->push_back(entry.second);
243 // 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
245 // provide support for all future calls.
246 StatisticsRecorder::StatisticsRecorder() {
247 DCHECK(!histograms_);
248 if (lock_ == NULL) {
249 // 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
251 // 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
253 // leak one per process, which would be similar to the instance allocated
254 // during static initialization and released only on process termination.
255 lock_ = new base::Lock;
257 base::AutoLock auto_lock(*lock_);
258 histograms_ = new HistogramMap;
259 ranges_ = new RangesMap;
261 if (VLOG_IS_ON(1))
262 AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this);
265 // static
266 void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
267 std::string output;
268 StatisticsRecorder::WriteGraph(std::string(), &output);
269 VLOG(1) << output;
272 StatisticsRecorder::~StatisticsRecorder() {
273 DCHECK(histograms_ && ranges_ && lock_);
275 // Clean up.
276 scoped_ptr<HistogramMap> histograms_deleter;
277 scoped_ptr<RangesMap> ranges_deleter;
278 // 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.
281 base::AutoLock auto_lock(*lock_);
282 histograms_deleter.reset(histograms_);
283 ranges_deleter.reset(ranges_);
284 histograms_ = NULL;
285 ranges_ = NULL;
287 // We are going to leak the histograms and the ranges.
291 // static
292 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
293 // static
294 StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
295 // static
296 base::Lock* StatisticsRecorder::lock_ = NULL;
298 } // namespace base