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.
4
5 #include "base/metrics/sparse_histogram.h"
6
7 #include <utility>
8
9 #include "base/metrics/metrics_hashes.h"
10 #include "base/metrics/sample_map.h"
11 #include "base/metrics/statistics_recorder.h"
12 #include "base/pickle.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/synchronization/lock.h"
15
16 namespace base {
17
18 typedef HistogramBase::Count Count;
19 typedef HistogramBase::Sample Sample;
20
21 // static
FactoryGet(const std::string & name,int32_t flags)22 HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
23 int32_t flags) {
24 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
25
26 if (!histogram) {
27 // To avoid racy destruction at shutdown, the following will be leaked.
28 HistogramBase* tentative_histogram = new SparseHistogram(name);
29 tentative_histogram->SetFlags(flags);
30 histogram =
31 StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
32 }
33 DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
34 return histogram;
35 }
36
~SparseHistogram()37 SparseHistogram::~SparseHistogram() {}
38
name_hash() const39 uint64_t SparseHistogram::name_hash() const {
40 return samples_.id();
41 }
42
GetHistogramType() const43 HistogramType SparseHistogram::GetHistogramType() const {
44 return SPARSE_HISTOGRAM;
45 }
46
HasConstructionArguments(Sample,Sample,size_t) const47 bool SparseHistogram::HasConstructionArguments(
48 Sample /* expected_minimum */,
49 Sample /* expected_maximum */,
50 size_t /* expected_bucket_count */) const {
51 // SparseHistogram never has min/max/bucket_count limit.
52 return false;
53 }
54
Add(Sample value)55 void SparseHistogram::Add(Sample value) {
56 AddCount(value, 1);
57 }
58
AddCount(Sample value,int count)59 void SparseHistogram::AddCount(Sample value, int count) {
60 if (count <= 0) {
61 NOTREACHED();
62 return;
63 }
64 {
65 base::AutoLock auto_lock(lock_);
66 samples_.Accumulate(value, count);
67 }
68
69 FindAndRunCallback(value);
70 }
71
SnapshotSamples() const72 scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
73 scoped_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
74
75 base::AutoLock auto_lock(lock_);
76 snapshot->Add(samples_);
77 return std::move(snapshot);
78 }
79
AddSamples(const HistogramSamples & samples)80 void SparseHistogram::AddSamples(const HistogramSamples& samples) {
81 base::AutoLock auto_lock(lock_);
82 samples_.Add(samples);
83 }
84
AddSamplesFromPickle(PickleIterator * iter)85 bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
86 base::AutoLock auto_lock(lock_);
87 return samples_.AddFromPickle(iter);
88 }
89
WriteHTMLGraph(std::string * output) const90 void SparseHistogram::WriteHTMLGraph(std::string* output) const {
91 output->append("<PRE>");
92 WriteAsciiImpl(true, "<br>", output);
93 output->append("</PRE>");
94 }
95
WriteAscii(std::string * output) const96 void SparseHistogram::WriteAscii(std::string* output) const {
97 WriteAsciiImpl(true, "\n", output);
98 }
99
SerializeInfoImpl(Pickle * pickle) const100 bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
101 return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags());
102 }
103
SparseHistogram(const std::string & name)104 SparseHistogram::SparseHistogram(const std::string& name)
105 : HistogramBase(name),
106 samples_(HashMetricName(name)) {}
107
DeserializeInfoImpl(PickleIterator * iter)108 HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
109 std::string histogram_name;
110 int flags;
111 if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
112 DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
113 return NULL;
114 }
115
116 DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag);
117 flags &= ~HistogramBase::kIPCSerializationSourceFlag;
118
119 return SparseHistogram::FactoryGet(histogram_name, flags);
120 }
121
GetParameters(DictionaryValue *) const122 void SparseHistogram::GetParameters(DictionaryValue* /* params */) const {
123 // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
124 }
125
GetCountAndBucketData(Count *,int64_t *,ListValue *) const126 void SparseHistogram::GetCountAndBucketData(Count* /* count */,
127 int64_t* /* sum */,
128 ListValue* /* buckets */) const {
129 // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
130 }
131
WriteAsciiImpl(bool graph_it,const std::string & newline,std::string * output) const132 void SparseHistogram::WriteAsciiImpl(bool graph_it,
133 const std::string& newline,
134 std::string* output) const {
135 // Get a local copy of the data so we are consistent.
136 scoped_ptr<HistogramSamples> snapshot = SnapshotSamples();
137 Count total_count = snapshot->TotalCount();
138 double scaled_total_count = total_count / 100.0;
139
140 WriteAsciiHeader(total_count, output);
141 output->append(newline);
142
143 // Determine how wide the largest bucket range is (how many digits to print),
144 // so that we'll be able to right-align starts for the graphical bars.
145 // Determine which bucket has the largest sample count so that we can
146 // normalize the graphical bar-width relative to that sample count.
147 Count largest_count = 0;
148 Sample largest_sample = 0;
149 scoped_ptr<SampleCountIterator> it = snapshot->Iterator();
150 while (!it->Done()) {
151 Sample min;
152 Sample max;
153 Count count;
154 it->Get(&min, &max, &count);
155 if (min > largest_sample)
156 largest_sample = min;
157 if (count > largest_count)
158 largest_count = count;
159 it->Next();
160 }
161 size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1;
162
163 // iterate over each item and display them
164 it = snapshot->Iterator();
165 while (!it->Done()) {
166 Sample min;
167 Sample max;
168 Count count;
169 it->Get(&min, &max, &count);
170
171 // value is min, so display it
172 std::string range = GetSimpleAsciiBucketRange(min);
173 output->append(range);
174 for (size_t j = 0; range.size() + j < print_width + 1; ++j)
175 output->push_back(' ');
176
177 if (graph_it)
178 WriteAsciiBucketGraph(count, largest_count, output);
179 WriteAsciiBucketValue(count, scaled_total_count, output);
180 output->append(newline);
181 it->Next();
182 }
183 }
184
WriteAsciiHeader(const Count total_count,std::string * output) const185 void SparseHistogram::WriteAsciiHeader(const Count total_count,
186 std::string* output) const {
187 StringAppendF(output,
188 "Histogram: %s recorded %d samples",
189 histogram_name().c_str(),
190 total_count);
191 if (flags() & ~kHexRangePrintingFlag)
192 StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
193 }
194
195 } // namespace base
196