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