1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "base/metrics/sparse_histogram.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <utility>
8*635a8641SAndroid Build Coastguard Worker
9*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/metrics/dummy_histogram.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/metrics/metrics_hashes.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/metrics/persistent_histogram_allocator.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/metrics/persistent_sample_map.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/metrics/sample_map.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/metrics/statistics_recorder.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/pickle.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
19*635a8641SAndroid Build Coastguard Worker
20*635a8641SAndroid Build Coastguard Worker namespace base {
21*635a8641SAndroid Build Coastguard Worker
22*635a8641SAndroid Build Coastguard Worker typedef HistogramBase::Count Count;
23*635a8641SAndroid Build Coastguard Worker typedef HistogramBase::Sample Sample;
24*635a8641SAndroid Build Coastguard Worker
25*635a8641SAndroid Build Coastguard Worker // static
FactoryGet(const std::string & name,int32_t flags)26*635a8641SAndroid Build Coastguard Worker HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
27*635a8641SAndroid Build Coastguard Worker int32_t flags) {
28*635a8641SAndroid Build Coastguard Worker HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
29*635a8641SAndroid Build Coastguard Worker if (!histogram) {
30*635a8641SAndroid Build Coastguard Worker // TODO(gayane): |HashMetricName| is called again in Histogram constructor.
31*635a8641SAndroid Build Coastguard Worker // Refactor code to avoid the additional call.
32*635a8641SAndroid Build Coastguard Worker bool should_record =
33*635a8641SAndroid Build Coastguard Worker StatisticsRecorder::ShouldRecordHistogram(HashMetricName(name));
34*635a8641SAndroid Build Coastguard Worker if (!should_record)
35*635a8641SAndroid Build Coastguard Worker return DummyHistogram::GetInstance();
36*635a8641SAndroid Build Coastguard Worker // Try to create the histogram using a "persistent" allocator. As of
37*635a8641SAndroid Build Coastguard Worker // 2016-02-25, the availability of such is controlled by a base::Feature
38*635a8641SAndroid Build Coastguard Worker // that is off by default. If the allocator doesn't exist or if
39*635a8641SAndroid Build Coastguard Worker // allocating from it fails, code below will allocate the histogram from
40*635a8641SAndroid Build Coastguard Worker // the process heap.
41*635a8641SAndroid Build Coastguard Worker PersistentMemoryAllocator::Reference histogram_ref = 0;
42*635a8641SAndroid Build Coastguard Worker std::unique_ptr<HistogramBase> tentative_histogram;
43*635a8641SAndroid Build Coastguard Worker PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
44*635a8641SAndroid Build Coastguard Worker if (allocator) {
45*635a8641SAndroid Build Coastguard Worker tentative_histogram = allocator->AllocateHistogram(
46*635a8641SAndroid Build Coastguard Worker SPARSE_HISTOGRAM, name, 0, 0, nullptr, flags, &histogram_ref);
47*635a8641SAndroid Build Coastguard Worker }
48*635a8641SAndroid Build Coastguard Worker
49*635a8641SAndroid Build Coastguard Worker // Handle the case where no persistent allocator is present or the
50*635a8641SAndroid Build Coastguard Worker // persistent allocation fails (perhaps because it is full).
51*635a8641SAndroid Build Coastguard Worker if (!tentative_histogram) {
52*635a8641SAndroid Build Coastguard Worker DCHECK(!histogram_ref); // Should never have been set.
53*635a8641SAndroid Build Coastguard Worker DCHECK(!allocator); // Shouldn't have failed.
54*635a8641SAndroid Build Coastguard Worker flags &= ~HistogramBase::kIsPersistent;
55*635a8641SAndroid Build Coastguard Worker tentative_histogram.reset(new SparseHistogram(GetPermanentName(name)));
56*635a8641SAndroid Build Coastguard Worker tentative_histogram->SetFlags(flags);
57*635a8641SAndroid Build Coastguard Worker }
58*635a8641SAndroid Build Coastguard Worker
59*635a8641SAndroid Build Coastguard Worker // Register this histogram with the StatisticsRecorder. Keep a copy of
60*635a8641SAndroid Build Coastguard Worker // the pointer value to tell later whether the locally created histogram
61*635a8641SAndroid Build Coastguard Worker // was registered or deleted. The type is "void" because it could point
62*635a8641SAndroid Build Coastguard Worker // to released memory after the following line.
63*635a8641SAndroid Build Coastguard Worker const void* tentative_histogram_ptr = tentative_histogram.get();
64*635a8641SAndroid Build Coastguard Worker histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
65*635a8641SAndroid Build Coastguard Worker tentative_histogram.release());
66*635a8641SAndroid Build Coastguard Worker
67*635a8641SAndroid Build Coastguard Worker // Persistent histograms need some follow-up processing.
68*635a8641SAndroid Build Coastguard Worker if (histogram_ref) {
69*635a8641SAndroid Build Coastguard Worker allocator->FinalizeHistogram(histogram_ref,
70*635a8641SAndroid Build Coastguard Worker histogram == tentative_histogram_ptr);
71*635a8641SAndroid Build Coastguard Worker }
72*635a8641SAndroid Build Coastguard Worker }
73*635a8641SAndroid Build Coastguard Worker
74*635a8641SAndroid Build Coastguard Worker CHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
75*635a8641SAndroid Build Coastguard Worker return histogram;
76*635a8641SAndroid Build Coastguard Worker }
77*635a8641SAndroid Build Coastguard Worker
78*635a8641SAndroid Build Coastguard Worker // static
PersistentCreate(PersistentHistogramAllocator * allocator,const char * name,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)79*635a8641SAndroid Build Coastguard Worker std::unique_ptr<HistogramBase> SparseHistogram::PersistentCreate(
80*635a8641SAndroid Build Coastguard Worker PersistentHistogramAllocator* allocator,
81*635a8641SAndroid Build Coastguard Worker const char* name,
82*635a8641SAndroid Build Coastguard Worker HistogramSamples::Metadata* meta,
83*635a8641SAndroid Build Coastguard Worker HistogramSamples::Metadata* logged_meta) {
84*635a8641SAndroid Build Coastguard Worker return WrapUnique(
85*635a8641SAndroid Build Coastguard Worker new SparseHistogram(allocator, name, meta, logged_meta));
86*635a8641SAndroid Build Coastguard Worker }
87*635a8641SAndroid Build Coastguard Worker
88*635a8641SAndroid Build Coastguard Worker SparseHistogram::~SparseHistogram() = default;
89*635a8641SAndroid Build Coastguard Worker
name_hash() const90*635a8641SAndroid Build Coastguard Worker uint64_t SparseHistogram::name_hash() const {
91*635a8641SAndroid Build Coastguard Worker return unlogged_samples_->id();
92*635a8641SAndroid Build Coastguard Worker }
93*635a8641SAndroid Build Coastguard Worker
GetHistogramType() const94*635a8641SAndroid Build Coastguard Worker HistogramType SparseHistogram::GetHistogramType() const {
95*635a8641SAndroid Build Coastguard Worker return SPARSE_HISTOGRAM;
96*635a8641SAndroid Build Coastguard Worker }
97*635a8641SAndroid Build Coastguard Worker
HasConstructionArguments(Sample expected_minimum,Sample expected_maximum,uint32_t expected_bucket_count) const98*635a8641SAndroid Build Coastguard Worker bool SparseHistogram::HasConstructionArguments(
99*635a8641SAndroid Build Coastguard Worker Sample expected_minimum,
100*635a8641SAndroid Build Coastguard Worker Sample expected_maximum,
101*635a8641SAndroid Build Coastguard Worker uint32_t expected_bucket_count) const {
102*635a8641SAndroid Build Coastguard Worker // SparseHistogram never has min/max/bucket_count limit.
103*635a8641SAndroid Build Coastguard Worker return false;
104*635a8641SAndroid Build Coastguard Worker }
105*635a8641SAndroid Build Coastguard Worker
Add(Sample value)106*635a8641SAndroid Build Coastguard Worker void SparseHistogram::Add(Sample value) {
107*635a8641SAndroid Build Coastguard Worker AddCount(value, 1);
108*635a8641SAndroid Build Coastguard Worker }
109*635a8641SAndroid Build Coastguard Worker
AddCount(Sample value,int count)110*635a8641SAndroid Build Coastguard Worker void SparseHistogram::AddCount(Sample value, int count) {
111*635a8641SAndroid Build Coastguard Worker if (count <= 0) {
112*635a8641SAndroid Build Coastguard Worker NOTREACHED();
113*635a8641SAndroid Build Coastguard Worker return;
114*635a8641SAndroid Build Coastguard Worker }
115*635a8641SAndroid Build Coastguard Worker {
116*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
117*635a8641SAndroid Build Coastguard Worker unlogged_samples_->Accumulate(value, count);
118*635a8641SAndroid Build Coastguard Worker }
119*635a8641SAndroid Build Coastguard Worker
120*635a8641SAndroid Build Coastguard Worker FindAndRunCallback(value);
121*635a8641SAndroid Build Coastguard Worker }
122*635a8641SAndroid Build Coastguard Worker
SnapshotSamples() const123*635a8641SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
124*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
125*635a8641SAndroid Build Coastguard Worker
126*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
127*635a8641SAndroid Build Coastguard Worker snapshot->Add(*unlogged_samples_);
128*635a8641SAndroid Build Coastguard Worker snapshot->Add(*logged_samples_);
129*635a8641SAndroid Build Coastguard Worker return std::move(snapshot);
130*635a8641SAndroid Build Coastguard Worker }
131*635a8641SAndroid Build Coastguard Worker
SnapshotDelta()132*635a8641SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotDelta() {
133*635a8641SAndroid Build Coastguard Worker DCHECK(!final_delta_created_);
134*635a8641SAndroid Build Coastguard Worker
135*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
136*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
137*635a8641SAndroid Build Coastguard Worker snapshot->Add(*unlogged_samples_);
138*635a8641SAndroid Build Coastguard Worker
139*635a8641SAndroid Build Coastguard Worker unlogged_samples_->Subtract(*snapshot);
140*635a8641SAndroid Build Coastguard Worker logged_samples_->Add(*snapshot);
141*635a8641SAndroid Build Coastguard Worker return std::move(snapshot);
142*635a8641SAndroid Build Coastguard Worker }
143*635a8641SAndroid Build Coastguard Worker
SnapshotFinalDelta() const144*635a8641SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> SparseHistogram::SnapshotFinalDelta() const {
145*635a8641SAndroid Build Coastguard Worker DCHECK(!final_delta_created_);
146*635a8641SAndroid Build Coastguard Worker final_delta_created_ = true;
147*635a8641SAndroid Build Coastguard Worker
148*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
149*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
150*635a8641SAndroid Build Coastguard Worker snapshot->Add(*unlogged_samples_);
151*635a8641SAndroid Build Coastguard Worker
152*635a8641SAndroid Build Coastguard Worker return std::move(snapshot);
153*635a8641SAndroid Build Coastguard Worker }
154*635a8641SAndroid Build Coastguard Worker
AddSamples(const HistogramSamples & samples)155*635a8641SAndroid Build Coastguard Worker void SparseHistogram::AddSamples(const HistogramSamples& samples) {
156*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
157*635a8641SAndroid Build Coastguard Worker unlogged_samples_->Add(samples);
158*635a8641SAndroid Build Coastguard Worker }
159*635a8641SAndroid Build Coastguard Worker
AddSamplesFromPickle(PickleIterator * iter)160*635a8641SAndroid Build Coastguard Worker bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
161*635a8641SAndroid Build Coastguard Worker base::AutoLock auto_lock(lock_);
162*635a8641SAndroid Build Coastguard Worker return unlogged_samples_->AddFromPickle(iter);
163*635a8641SAndroid Build Coastguard Worker }
164*635a8641SAndroid Build Coastguard Worker
WriteHTMLGraph(std::string * output) const165*635a8641SAndroid Build Coastguard Worker void SparseHistogram::WriteHTMLGraph(std::string* output) const {
166*635a8641SAndroid Build Coastguard Worker output->append("<PRE>");
167*635a8641SAndroid Build Coastguard Worker WriteAsciiImpl(true, "<br>", output);
168*635a8641SAndroid Build Coastguard Worker output->append("</PRE>");
169*635a8641SAndroid Build Coastguard Worker }
170*635a8641SAndroid Build Coastguard Worker
WriteAscii(std::string * output) const171*635a8641SAndroid Build Coastguard Worker void SparseHistogram::WriteAscii(std::string* output) const {
172*635a8641SAndroid Build Coastguard Worker WriteAsciiImpl(true, "\n", output);
173*635a8641SAndroid Build Coastguard Worker }
174*635a8641SAndroid Build Coastguard Worker
SerializeInfoImpl(Pickle * pickle) const175*635a8641SAndroid Build Coastguard Worker void SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
176*635a8641SAndroid Build Coastguard Worker pickle->WriteString(histogram_name());
177*635a8641SAndroid Build Coastguard Worker pickle->WriteInt(flags());
178*635a8641SAndroid Build Coastguard Worker }
179*635a8641SAndroid Build Coastguard Worker
SparseHistogram(const char * name)180*635a8641SAndroid Build Coastguard Worker SparseHistogram::SparseHistogram(const char* name)
181*635a8641SAndroid Build Coastguard Worker : HistogramBase(name),
182*635a8641SAndroid Build Coastguard Worker unlogged_samples_(new SampleMap(HashMetricName(name))),
183*635a8641SAndroid Build Coastguard Worker logged_samples_(new SampleMap(unlogged_samples_->id())) {}
184*635a8641SAndroid Build Coastguard Worker
SparseHistogram(PersistentHistogramAllocator * allocator,const char * name,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)185*635a8641SAndroid Build Coastguard Worker SparseHistogram::SparseHistogram(PersistentHistogramAllocator* allocator,
186*635a8641SAndroid Build Coastguard Worker const char* name,
187*635a8641SAndroid Build Coastguard Worker HistogramSamples::Metadata* meta,
188*635a8641SAndroid Build Coastguard Worker HistogramSamples::Metadata* logged_meta)
189*635a8641SAndroid Build Coastguard Worker : HistogramBase(name),
190*635a8641SAndroid Build Coastguard Worker // While other histogram types maintain a static vector of values with
191*635a8641SAndroid Build Coastguard Worker // sufficient space for both "active" and "logged" samples, with each
192*635a8641SAndroid Build Coastguard Worker // SampleVector being given the appropriate half, sparse histograms
193*635a8641SAndroid Build Coastguard Worker // have no such initial allocation. Each sample has its own record
194*635a8641SAndroid Build Coastguard Worker // attached to a single PersistentSampleMap by a common 64-bit identifier.
195*635a8641SAndroid Build Coastguard Worker // Since a sparse histogram has two sample maps (active and logged),
196*635a8641SAndroid Build Coastguard Worker // there must be two sets of sample records with diffent IDs. The
197*635a8641SAndroid Build Coastguard Worker // "active" samples use, for convenience purposes, an ID matching
198*635a8641SAndroid Build Coastguard Worker // that of the histogram while the "logged" samples use that number
199*635a8641SAndroid Build Coastguard Worker // plus 1.
200*635a8641SAndroid Build Coastguard Worker unlogged_samples_(
201*635a8641SAndroid Build Coastguard Worker new PersistentSampleMap(HashMetricName(name), allocator, meta)),
202*635a8641SAndroid Build Coastguard Worker logged_samples_(new PersistentSampleMap(unlogged_samples_->id() + 1,
203*635a8641SAndroid Build Coastguard Worker allocator,
204*635a8641SAndroid Build Coastguard Worker logged_meta)) {}
205*635a8641SAndroid Build Coastguard Worker
DeserializeInfoImpl(PickleIterator * iter)206*635a8641SAndroid Build Coastguard Worker HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
207*635a8641SAndroid Build Coastguard Worker std::string histogram_name;
208*635a8641SAndroid Build Coastguard Worker int flags;
209*635a8641SAndroid Build Coastguard Worker if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
210*635a8641SAndroid Build Coastguard Worker DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
211*635a8641SAndroid Build Coastguard Worker return nullptr;
212*635a8641SAndroid Build Coastguard Worker }
213*635a8641SAndroid Build Coastguard Worker
214*635a8641SAndroid Build Coastguard Worker flags &= ~HistogramBase::kIPCSerializationSourceFlag;
215*635a8641SAndroid Build Coastguard Worker
216*635a8641SAndroid Build Coastguard Worker return SparseHistogram::FactoryGet(histogram_name, flags);
217*635a8641SAndroid Build Coastguard Worker }
218*635a8641SAndroid Build Coastguard Worker
GetParameters(DictionaryValue * params) const219*635a8641SAndroid Build Coastguard Worker void SparseHistogram::GetParameters(DictionaryValue* params) const {
220*635a8641SAndroid Build Coastguard Worker // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
221*635a8641SAndroid Build Coastguard Worker }
222*635a8641SAndroid Build Coastguard Worker
GetCountAndBucketData(Count * count,int64_t * sum,ListValue * buckets) const223*635a8641SAndroid Build Coastguard Worker void SparseHistogram::GetCountAndBucketData(Count* count,
224*635a8641SAndroid Build Coastguard Worker int64_t* sum,
225*635a8641SAndroid Build Coastguard Worker ListValue* buckets) const {
226*635a8641SAndroid Build Coastguard Worker // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
227*635a8641SAndroid Build Coastguard Worker }
228*635a8641SAndroid Build Coastguard Worker
WriteAsciiImpl(bool graph_it,const std::string & newline,std::string * output) const229*635a8641SAndroid Build Coastguard Worker void SparseHistogram::WriteAsciiImpl(bool graph_it,
230*635a8641SAndroid Build Coastguard Worker const std::string& newline,
231*635a8641SAndroid Build Coastguard Worker std::string* output) const {
232*635a8641SAndroid Build Coastguard Worker // Get a local copy of the data so we are consistent.
233*635a8641SAndroid Build Coastguard Worker std::unique_ptr<HistogramSamples> snapshot = SnapshotSamples();
234*635a8641SAndroid Build Coastguard Worker Count total_count = snapshot->TotalCount();
235*635a8641SAndroid Build Coastguard Worker double scaled_total_count = total_count / 100.0;
236*635a8641SAndroid Build Coastguard Worker
237*635a8641SAndroid Build Coastguard Worker WriteAsciiHeader(total_count, output);
238*635a8641SAndroid Build Coastguard Worker output->append(newline);
239*635a8641SAndroid Build Coastguard Worker
240*635a8641SAndroid Build Coastguard Worker // Determine how wide the largest bucket range is (how many digits to print),
241*635a8641SAndroid Build Coastguard Worker // so that we'll be able to right-align starts for the graphical bars.
242*635a8641SAndroid Build Coastguard Worker // Determine which bucket has the largest sample count so that we can
243*635a8641SAndroid Build Coastguard Worker // normalize the graphical bar-width relative to that sample count.
244*635a8641SAndroid Build Coastguard Worker Count largest_count = 0;
245*635a8641SAndroid Build Coastguard Worker Sample largest_sample = 0;
246*635a8641SAndroid Build Coastguard Worker std::unique_ptr<SampleCountIterator> it = snapshot->Iterator();
247*635a8641SAndroid Build Coastguard Worker while (!it->Done()) {
248*635a8641SAndroid Build Coastguard Worker Sample min;
249*635a8641SAndroid Build Coastguard Worker int64_t max;
250*635a8641SAndroid Build Coastguard Worker Count count;
251*635a8641SAndroid Build Coastguard Worker it->Get(&min, &max, &count);
252*635a8641SAndroid Build Coastguard Worker if (min > largest_sample)
253*635a8641SAndroid Build Coastguard Worker largest_sample = min;
254*635a8641SAndroid Build Coastguard Worker if (count > largest_count)
255*635a8641SAndroid Build Coastguard Worker largest_count = count;
256*635a8641SAndroid Build Coastguard Worker it->Next();
257*635a8641SAndroid Build Coastguard Worker }
258*635a8641SAndroid Build Coastguard Worker size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1;
259*635a8641SAndroid Build Coastguard Worker
260*635a8641SAndroid Build Coastguard Worker // iterate over each item and display them
261*635a8641SAndroid Build Coastguard Worker it = snapshot->Iterator();
262*635a8641SAndroid Build Coastguard Worker while (!it->Done()) {
263*635a8641SAndroid Build Coastguard Worker Sample min;
264*635a8641SAndroid Build Coastguard Worker int64_t max;
265*635a8641SAndroid Build Coastguard Worker Count count;
266*635a8641SAndroid Build Coastguard Worker it->Get(&min, &max, &count);
267*635a8641SAndroid Build Coastguard Worker
268*635a8641SAndroid Build Coastguard Worker // value is min, so display it
269*635a8641SAndroid Build Coastguard Worker std::string range = GetSimpleAsciiBucketRange(min);
270*635a8641SAndroid Build Coastguard Worker output->append(range);
271*635a8641SAndroid Build Coastguard Worker for (size_t j = 0; range.size() + j < print_width + 1; ++j)
272*635a8641SAndroid Build Coastguard Worker output->push_back(' ');
273*635a8641SAndroid Build Coastguard Worker
274*635a8641SAndroid Build Coastguard Worker if (graph_it)
275*635a8641SAndroid Build Coastguard Worker WriteAsciiBucketGraph(count, largest_count, output);
276*635a8641SAndroid Build Coastguard Worker WriteAsciiBucketValue(count, scaled_total_count, output);
277*635a8641SAndroid Build Coastguard Worker output->append(newline);
278*635a8641SAndroid Build Coastguard Worker it->Next();
279*635a8641SAndroid Build Coastguard Worker }
280*635a8641SAndroid Build Coastguard Worker }
281*635a8641SAndroid Build Coastguard Worker
WriteAsciiHeader(const Count total_count,std::string * output) const282*635a8641SAndroid Build Coastguard Worker void SparseHistogram::WriteAsciiHeader(const Count total_count,
283*635a8641SAndroid Build Coastguard Worker std::string* output) const {
284*635a8641SAndroid Build Coastguard Worker StringAppendF(output, "Histogram: %s recorded %d samples", histogram_name(),
285*635a8641SAndroid Build Coastguard Worker total_count);
286*635a8641SAndroid Build Coastguard Worker if (flags())
287*635a8641SAndroid Build Coastguard Worker StringAppendF(output, " (flags = 0x%x)", flags());
288*635a8641SAndroid Build Coastguard Worker }
289*635a8641SAndroid Build Coastguard Worker
290*635a8641SAndroid Build Coastguard Worker } // namespace base
291