• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Histogram is an object that aggregates statistics, and can summarize them in
6 // various forms, including ASCII graphical, HTML, and numerically (as a
7 // vector of numbers corresponding to each of the aggregating buckets).
8 // See header file for details and examples.
9 
10 #include "base/metrics/histogram.h"
11 
12 #include <limits.h>
13 #include <math.h>
14 
15 #include <algorithm>
16 #include <string>
17 
18 #include "base/compiler_specific.h"
19 #include "base/debug/alias.h"
20 #include "base/logging.h"
21 #include "base/memory/ptr_util.h"
22 #include "base/metrics/histogram_macros.h"
23 #include "base/metrics/metrics_hashes.h"
24 #include "base/metrics/persistent_histogram_allocator.h"
25 #include "base/metrics/persistent_memory_allocator.h"
26 #include "base/metrics/sample_vector.h"
27 #include "base/metrics/statistics_recorder.h"
28 #include "base/pickle.h"
29 #include "base/strings/string_util.h"
30 #include "base/strings/stringprintf.h"
31 #include "base/synchronization/lock.h"
32 #include "base/values.h"
33 
34 namespace base {
35 
36 namespace {
37 
ReadHistogramArguments(PickleIterator * iter,std::string * histogram_name,int * flags,int * declared_min,int * declared_max,uint32_t * bucket_count,uint32_t * range_checksum)38 bool ReadHistogramArguments(PickleIterator* iter,
39                             std::string* histogram_name,
40                             int* flags,
41                             int* declared_min,
42                             int* declared_max,
43                             uint32_t* bucket_count,
44                             uint32_t* range_checksum) {
45   if (!iter->ReadString(histogram_name) ||
46       !iter->ReadInt(flags) ||
47       !iter->ReadInt(declared_min) ||
48       !iter->ReadInt(declared_max) ||
49       !iter->ReadUInt32(bucket_count) ||
50       !iter->ReadUInt32(range_checksum)) {
51     DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
52     return false;
53   }
54 
55   // Since these fields may have come from an untrusted renderer, do additional
56   // checks above and beyond those in Histogram::Initialize()
57   if (*declared_max <= 0 ||
58       *declared_min <= 0 ||
59       *declared_max < *declared_min ||
60       INT_MAX / sizeof(HistogramBase::Count) <= *bucket_count ||
61       *bucket_count < 2) {
62     DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
63     return false;
64   }
65 
66   // We use the arguments to find or create the local version of the histogram
67   // in this process, so we need to clear any IPC flag.
68   *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
69 
70   return true;
71 }
72 
ValidateRangeChecksum(const HistogramBase & histogram,uint32_t range_checksum)73 bool ValidateRangeChecksum(const HistogramBase& histogram,
74                            uint32_t range_checksum) {
75   const Histogram& casted_histogram =
76       static_cast<const Histogram&>(histogram);
77 
78   return casted_histogram.bucket_ranges()->checksum() == range_checksum;
79 }
80 
81 }  // namespace
82 
83 typedef HistogramBase::Count Count;
84 typedef HistogramBase::Sample Sample;
85 
86 // static
87 const uint32_t Histogram::kBucketCount_MAX = 16384u;
88 
89 class Histogram::Factory {
90  public:
Factory(const std::string & name,HistogramBase::Sample minimum,HistogramBase::Sample maximum,uint32_t bucket_count,int32_t flags)91   Factory(const std::string& name,
92           HistogramBase::Sample minimum,
93           HistogramBase::Sample maximum,
94           uint32_t bucket_count,
95           int32_t flags)
96     : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
97   virtual ~Factory() = default;
98 
99   // Create histogram based on construction parameters. Caller takes
100   // ownership of the returned object.
101   HistogramBase* Build();
102 
103  protected:
Factory(const std::string & name,HistogramType histogram_type,HistogramBase::Sample minimum,HistogramBase::Sample maximum,uint32_t bucket_count,int32_t flags)104   Factory(const std::string& name,
105           HistogramType histogram_type,
106           HistogramBase::Sample minimum,
107           HistogramBase::Sample maximum,
108           uint32_t bucket_count,
109           int32_t flags)
110     : name_(name),
111       histogram_type_(histogram_type),
112       minimum_(minimum),
113       maximum_(maximum),
114       bucket_count_(bucket_count),
115       flags_(flags) {}
116 
117   // Create a BucketRanges structure appropriate for this histogram.
CreateRanges()118   virtual BucketRanges* CreateRanges() {
119     BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
120     Histogram::InitializeBucketRanges(minimum_, maximum_, ranges);
121     return ranges;
122   }
123 
124   // Allocate the correct Histogram object off the heap (in case persistent
125   // memory is not available).
HeapAlloc(const BucketRanges * ranges)126   virtual std::unique_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) {
127     return WrapUnique(new Histogram(name_, minimum_, maximum_, ranges));
128   }
129 
130   // Perform any required datafill on the just-created histogram.  If
131   // overridden, be sure to call the "super" version -- this method may not
132   // always remain empty.
FillHistogram(HistogramBase *)133   virtual void FillHistogram(HistogramBase* /*histogram*/) {}
134 
135   // These values are protected (instead of private) because they need to
136   // be accessible to methods of sub-classes in order to avoid passing
137   // unnecessary parameters everywhere.
138   const std::string& name_;
139   const HistogramType histogram_type_;
140   HistogramBase::Sample minimum_;
141   HistogramBase::Sample maximum_;
142   uint32_t bucket_count_;
143   int32_t flags_;
144 
145  private:
146   DISALLOW_COPY_AND_ASSIGN(Factory);
147 };
148 
Build()149 HistogramBase* Histogram::Factory::Build() {
150   HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
151   if (!histogram) {
152     // To avoid racy destruction at shutdown, the following will be leaked.
153     const BucketRanges* created_ranges = CreateRanges();
154     const BucketRanges* registered_ranges =
155         StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
156 
157     // In most cases, the bucket-count, minimum, and maximum values are known
158     // when the code is written and so are passed in explicitly. In other
159     // cases (such as with a CustomHistogram), they are calculated dynamically
160     // at run-time. In the latter case, those ctor parameters are zero and
161     // the results extracted from the result of CreateRanges().
162     if (bucket_count_ == 0) {
163       bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count());
164       minimum_ = registered_ranges->range(1);
165       maximum_ = registered_ranges->range(bucket_count_ - 1);
166     }
167 
168     // Try to create the histogram using a "persistent" allocator. As of
169     // 2016-02-25, the availability of such is controlled by a base::Feature
170     // that is off by default. If the allocator doesn't exist or if
171     // allocating from it fails, code below will allocate the histogram from
172     // the process heap.
173     PersistentHistogramAllocator::Reference histogram_ref = 0;
174     std::unique_ptr<HistogramBase> tentative_histogram;
175     PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
176     if (allocator) {
177       tentative_histogram = allocator->AllocateHistogram(
178           histogram_type_,
179           name_,
180           minimum_,
181           maximum_,
182           registered_ranges,
183           flags_,
184           &histogram_ref);
185     }
186 
187     // Handle the case where no persistent allocator is present or the
188     // persistent allocation fails (perhaps because it is full).
189     if (!tentative_histogram) {
190       DCHECK(!histogram_ref);  // Should never have been set.
191       DCHECK(!allocator);  // Shouldn't have failed.
192       flags_ &= ~HistogramBase::kIsPersistent;
193       tentative_histogram = HeapAlloc(registered_ranges);
194       tentative_histogram->SetFlags(flags_);
195     }
196 
197     FillHistogram(tentative_histogram.get());
198 
199     // Register this histogram with the StatisticsRecorder. Keep a copy of
200     // the pointer value to tell later whether the locally created histogram
201     // was registered or deleted. The type is "void" because it could point
202     // to released memory after the following line.
203     const void* tentative_histogram_ptr = tentative_histogram.get();
204     histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
205         tentative_histogram.release());
206 
207     // Persistent histograms need some follow-up processing.
208     if (histogram_ref) {
209       allocator->FinalizeHistogram(histogram_ref,
210                                    histogram == tentative_histogram_ptr);
211     }
212 
213     // Update report on created histograms.
214     ReportHistogramActivity(*histogram, HISTOGRAM_CREATED);
215   } else {
216     // Update report on lookup histograms.
217     ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP);
218   }
219 
220   DCHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_;
221   if (bucket_count_ != 0 &&
222       !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) {
223     // The construction arguments do not match the existing histogram.  This can
224     // come about if an extension updates in the middle of a chrome run and has
225     // changed one of them, or simply by bad code within Chrome itself.  We
226     // return NULL here with the expectation that bad code in Chrome will crash
227     // on dereference, but extension/Pepper APIs will guard against NULL and not
228     // crash.
229     DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments";
230     return nullptr;
231   }
232   return histogram;
233 }
234 
FactoryGet(const std::string & name,Sample minimum,Sample maximum,uint32_t bucket_count,int32_t flags)235 HistogramBase* Histogram::FactoryGet(const std::string& name,
236                                      Sample minimum,
237                                      Sample maximum,
238                                      uint32_t bucket_count,
239                                      int32_t flags) {
240   bool valid_arguments =
241       InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
242   DCHECK(valid_arguments);
243 
244   return Factory(name, minimum, maximum, bucket_count, flags).Build();
245 }
246 
FactoryTimeGet(const std::string & name,TimeDelta minimum,TimeDelta maximum,uint32_t bucket_count,int32_t flags)247 HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
248                                          TimeDelta minimum,
249                                          TimeDelta maximum,
250                                          uint32_t bucket_count,
251                                          int32_t flags) {
252   return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
253                     static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
254                     flags);
255 }
256 
FactoryGet(const char * name,Sample minimum,Sample maximum,uint32_t bucket_count,int32_t flags)257 HistogramBase* Histogram::FactoryGet(const char* name,
258                                      Sample minimum,
259                                      Sample maximum,
260                                      uint32_t bucket_count,
261                                      int32_t flags) {
262   return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
263 }
264 
FactoryTimeGet(const char * name,TimeDelta minimum,TimeDelta maximum,uint32_t bucket_count,int32_t flags)265 HistogramBase* Histogram::FactoryTimeGet(const char* name,
266                                          TimeDelta minimum,
267                                          TimeDelta maximum,
268                                          uint32_t bucket_count,
269                                          int32_t flags) {
270   return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
271                         flags);
272 }
273 
PersistentCreate(const std::string & name,Sample minimum,Sample maximum,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,uint32_t counts_size,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)274 std::unique_ptr<HistogramBase> Histogram::PersistentCreate(
275     const std::string& name,
276     Sample minimum,
277     Sample maximum,
278     const BucketRanges* ranges,
279     HistogramBase::AtomicCount* counts,
280     HistogramBase::AtomicCount* logged_counts,
281     uint32_t counts_size,
282     HistogramSamples::Metadata* meta,
283     HistogramSamples::Metadata* logged_meta) {
284   return WrapUnique(new Histogram(name, minimum, maximum, ranges, counts,
285                                   logged_counts, counts_size, meta,
286                                   logged_meta));
287 }
288 
289 // Calculate what range of values are held in each bucket.
290 // We have to be careful that we don't pick a ratio between starting points in
291 // consecutive buckets that is sooo small, that the integer bounds are the same
292 // (effectively making one bucket get no values).  We need to avoid:
293 //   ranges(i) == ranges(i + 1)
294 // To avoid that, we just do a fine-grained bucket width as far as we need to
295 // until we get a ratio that moves us along at least 2 units at a time.  From
296 // that bucket onward we do use the exponential growth of buckets.
297 //
298 // static
InitializeBucketRanges(Sample minimum,Sample maximum,BucketRanges * ranges)299 void Histogram::InitializeBucketRanges(Sample minimum,
300                                        Sample maximum,
301                                        BucketRanges* ranges) {
302   double log_max = log(static_cast<double>(maximum));
303   double log_ratio;
304   double log_next;
305   size_t bucket_index = 1;
306   Sample current = minimum;
307   ranges->set_range(bucket_index, current);
308   size_t bucket_count = ranges->bucket_count();
309   while (bucket_count > ++bucket_index) {
310     double log_current;
311     log_current = log(static_cast<double>(current));
312     // Calculate the count'th root of the range.
313     log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
314     // See where the next bucket would start.
315     log_next = log_current + log_ratio;
316     Sample next;
317     next = static_cast<int>(floor(exp(log_next) + 0.5));
318     if (next > current)
319       current = next;
320     else
321       ++current;  // Just do a narrow bucket, and keep trying.
322     ranges->set_range(bucket_index, current);
323   }
324   ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
325   ranges->ResetChecksum();
326 }
327 
328 // static
329 const int Histogram::kCommonRaceBasedCountMismatch = 5;
330 
FindCorruption(const HistogramSamples & samples) const331 uint32_t Histogram::FindCorruption(const HistogramSamples& samples) const {
332   int inconsistencies = NO_INCONSISTENCIES;
333   Sample previous_range = -1;  // Bottom range is always 0.
334   for (uint32_t index = 0; index < bucket_count(); ++index) {
335     int new_range = ranges(index);
336     if (previous_range >= new_range)
337       inconsistencies |= BUCKET_ORDER_ERROR;
338     previous_range = new_range;
339   }
340 
341   if (!bucket_ranges()->HasValidChecksum())
342     inconsistencies |= RANGE_CHECKSUM_ERROR;
343 
344   int64_t delta64 = samples.redundant_count() - samples.TotalCount();
345   if (delta64 != 0) {
346     int delta = static_cast<int>(delta64);
347     if (delta != delta64)
348       delta = INT_MAX;  // Flag all giant errors as INT_MAX.
349     if (delta > 0) {
350       UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
351       if (delta > kCommonRaceBasedCountMismatch)
352         inconsistencies |= COUNT_HIGH_ERROR;
353     } else {
354       DCHECK_GT(0, delta);
355       UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
356       if (-delta > kCommonRaceBasedCountMismatch)
357         inconsistencies |= COUNT_LOW_ERROR;
358     }
359   }
360   return inconsistencies;
361 }
362 
ranges(uint32_t i) const363 Sample Histogram::ranges(uint32_t i) const {
364   return bucket_ranges_->range(i);
365 }
366 
bucket_count() const367 uint32_t Histogram::bucket_count() const {
368   return static_cast<uint32_t>(bucket_ranges_->bucket_count());
369 }
370 
371 // static
InspectConstructionArguments(const std::string & name,Sample * minimum,Sample * maximum,uint32_t * bucket_count)372 bool Histogram::InspectConstructionArguments(const std::string& name,
373                                              Sample* minimum,
374                                              Sample* maximum,
375                                              uint32_t* bucket_count) {
376   // Defensive code for backward compatibility.
377   if (*minimum < 1) {
378     DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
379     *minimum = 1;
380   }
381   if (*maximum >= kSampleType_MAX) {
382     DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
383     *maximum = kSampleType_MAX - 1;
384   }
385   if (*bucket_count >= kBucketCount_MAX) {
386     DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
387              << *bucket_count;
388     *bucket_count = kBucketCount_MAX - 1;
389   }
390 
391   if (*minimum >= *maximum)
392     return false;
393   if (*bucket_count < 3)
394     return false;
395   if (*bucket_count > static_cast<uint32_t>(*maximum - *minimum + 2))
396     return false;
397   return true;
398 }
399 
name_hash() const400 uint64_t Histogram::name_hash() const {
401   return samples_->id();
402 }
403 
GetHistogramType() const404 HistogramType Histogram::GetHistogramType() const {
405   return HISTOGRAM;
406 }
407 
HasConstructionArguments(Sample expected_minimum,Sample expected_maximum,uint32_t expected_bucket_count) const408 bool Histogram::HasConstructionArguments(Sample expected_minimum,
409                                          Sample expected_maximum,
410                                          uint32_t expected_bucket_count) const {
411   return ((expected_minimum == declared_min_) &&
412           (expected_maximum == declared_max_) &&
413           (expected_bucket_count == bucket_count()));
414 }
415 
Add(int value)416 void Histogram::Add(int value) {
417   AddCount(value, 1);
418 }
419 
AddCount(int value,int count)420 void Histogram::AddCount(int value, int count) {
421   DCHECK_EQ(0, ranges(0));
422   DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
423 
424   if (value > kSampleType_MAX - 1)
425     value = kSampleType_MAX - 1;
426   if (value < 0)
427     value = 0;
428   if (count <= 0) {
429     NOTREACHED();
430     return;
431   }
432   samples_->Accumulate(value, count);
433 
434   FindAndRunCallback(value);
435 }
436 
SnapshotSamples() const437 std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
438   return SnapshotSampleVector();
439 }
440 
SnapshotDelta()441 std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() {
442   DCHECK(!final_delta_created_);
443 
444   std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector();
445   if (!logged_samples_) {
446     // If nothing has been previously logged, save this one as
447     // |logged_samples_| and gather another snapshot to return.
448     logged_samples_.swap(snapshot);
449     return SnapshotSampleVector();
450   }
451 
452   // Subtract what was previously logged and update that information.
453   snapshot->Subtract(*logged_samples_);
454   logged_samples_->Add(*snapshot);
455   return snapshot;
456 }
457 
SnapshotFinalDelta() const458 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
459   DCHECK(!final_delta_created_);
460   final_delta_created_ = true;
461 
462   std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector();
463 
464   // Subtract what was previously logged and then return.
465   if (logged_samples_)
466     snapshot->Subtract(*logged_samples_);
467   return snapshot;
468 }
469 
AddSamples(const HistogramSamples & samples)470 void Histogram::AddSamples(const HistogramSamples& samples) {
471   samples_->Add(samples);
472 }
473 
AddSamplesFromPickle(PickleIterator * iter)474 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
475   return samples_->AddFromPickle(iter);
476 }
477 
478 // The following methods provide a graphical histogram display.
WriteHTMLGraph(std::string * output) const479 void Histogram::WriteHTMLGraph(std::string* output) const {
480   // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
481   output->append("<PRE>");
482   WriteAsciiImpl(true, "<br>", output);
483   output->append("</PRE>");
484 }
485 
WriteAscii(std::string * output) const486 void Histogram::WriteAscii(std::string* output) const {
487   WriteAsciiImpl(true, "\n", output);
488 }
489 
SerializeInfoImpl(Pickle * pickle) const490 bool Histogram::SerializeInfoImpl(Pickle* pickle) const {
491   DCHECK(bucket_ranges()->HasValidChecksum());
492   return pickle->WriteString(histogram_name()) &&
493       pickle->WriteInt(flags()) &&
494       pickle->WriteInt(declared_min()) &&
495       pickle->WriteInt(declared_max()) &&
496       pickle->WriteUInt32(bucket_count()) &&
497       pickle->WriteUInt32(bucket_ranges()->checksum());
498 }
499 
Histogram(const std::string & name,Sample minimum,Sample maximum,const BucketRanges * ranges)500 Histogram::Histogram(const std::string& name,
501                      Sample minimum,
502                      Sample maximum,
503                      const BucketRanges* ranges)
504   : HistogramBase(name),
505     bucket_ranges_(ranges),
506     declared_min_(minimum),
507     declared_max_(maximum) {
508   if (ranges)
509     samples_.reset(new SampleVector(HashMetricName(name), ranges));
510 }
511 
Histogram(const std::string & name,Sample minimum,Sample maximum,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,uint32_t counts_size,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)512 Histogram::Histogram(const std::string& name,
513                      Sample minimum,
514                      Sample maximum,
515                      const BucketRanges* ranges,
516                      HistogramBase::AtomicCount* counts,
517                      HistogramBase::AtomicCount* logged_counts,
518                      uint32_t counts_size,
519                      HistogramSamples::Metadata* meta,
520                      HistogramSamples::Metadata* logged_meta)
521   : HistogramBase(name),
522     bucket_ranges_(ranges),
523     declared_min_(minimum),
524     declared_max_(maximum) {
525   if (ranges) {
526     samples_.reset(new SampleVector(HashMetricName(name),
527                                     counts, counts_size, meta, ranges));
528     logged_samples_.reset(new SampleVector(samples_->id(), logged_counts,
529                                            counts_size, logged_meta, ranges));
530   }
531 }
532 
~Histogram()533 Histogram::~Histogram() {
534 }
535 
PrintEmptyBucket(uint32_t) const536 bool Histogram::PrintEmptyBucket(uint32_t /*index*/) const {
537   return true;
538 }
539 
540 // Use the actual bucket widths (like a linear histogram) until the widths get
541 // over some transition value, and then use that transition width.  Exponentials
542 // get so big so fast (and we don't expect to see a lot of entries in the large
543 // buckets), so we need this to make it possible to see what is going on and
544 // not have 0-graphical-height buckets.
GetBucketSize(Count current,uint32_t i) const545 double Histogram::GetBucketSize(Count current, uint32_t i) const {
546   DCHECK_GT(ranges(i + 1), ranges(i));
547   static const double kTransitionWidth = 5;
548   double denominator = ranges(i + 1) - ranges(i);
549   if (denominator > kTransitionWidth)
550     denominator = kTransitionWidth;  // Stop trying to normalize.
551   return current/denominator;
552 }
553 
GetAsciiBucketRange(uint32_t i) const554 const std::string Histogram::GetAsciiBucketRange(uint32_t i) const {
555   return GetSimpleAsciiBucketRange(ranges(i));
556 }
557 
558 //------------------------------------------------------------------------------
559 // Private methods
560 
561 // static
DeserializeInfoImpl(PickleIterator * iter)562 HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
563   std::string histogram_name;
564   int flags;
565   int declared_min;
566   int declared_max;
567   uint32_t bucket_count;
568   uint32_t range_checksum;
569 
570   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
571                               &declared_max, &bucket_count, &range_checksum)) {
572     return NULL;
573   }
574 
575   // Find or create the local version of the histogram in this process.
576   HistogramBase* histogram = Histogram::FactoryGet(
577       histogram_name, declared_min, declared_max, bucket_count, flags);
578 
579   if (!ValidateRangeChecksum(*histogram, range_checksum)) {
580     // The serialized histogram might be corrupted.
581     return NULL;
582   }
583   return histogram;
584 }
585 
SnapshotSampleVector() const586 std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
587   std::unique_ptr<SampleVector> samples(
588       new SampleVector(samples_->id(), bucket_ranges()));
589   samples->Add(*samples_);
590   return samples;
591 }
592 
WriteAsciiImpl(bool graph_it,const std::string & newline,std::string * output) const593 void Histogram::WriteAsciiImpl(bool graph_it,
594                                const std::string& newline,
595                                std::string* output) const {
596   // Get local (stack) copies of all effectively volatile class data so that we
597   // are consistent across our output activities.
598   std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector();
599   Count sample_count = snapshot->TotalCount();
600 
601   WriteAsciiHeader(*snapshot, sample_count, output);
602   output->append(newline);
603 
604   // Prepare to normalize graphical rendering of bucket contents.
605   double max_size = 0;
606   if (graph_it)
607     max_size = GetPeakBucketSize(*snapshot);
608 
609   // Calculate space needed to print bucket range numbers.  Leave room to print
610   // nearly the largest bucket range without sliding over the histogram.
611   uint32_t largest_non_empty_bucket = bucket_count() - 1;
612   while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) {
613     if (0 == largest_non_empty_bucket)
614       break;  // All buckets are empty.
615     --largest_non_empty_bucket;
616   }
617 
618   // Calculate largest print width needed for any of our bucket range displays.
619   size_t print_width = 1;
620   for (uint32_t i = 0; i < bucket_count(); ++i) {
621     if (snapshot->GetCountAtIndex(i)) {
622       size_t width = GetAsciiBucketRange(i).size() + 1;
623       if (width > print_width)
624         print_width = width;
625     }
626   }
627 
628   int64_t remaining = sample_count;
629   int64_t past = 0;
630   // Output the actual histogram graph.
631   for (uint32_t i = 0; i < bucket_count(); ++i) {
632     Count current = snapshot->GetCountAtIndex(i);
633     if (!current && !PrintEmptyBucket(i))
634       continue;
635     remaining -= current;
636     std::string range = GetAsciiBucketRange(i);
637     output->append(range);
638     for (size_t j = 0; range.size() + j < print_width + 1; ++j)
639       output->push_back(' ');
640     if (0 == current && i < bucket_count() - 1 &&
641         0 == snapshot->GetCountAtIndex(i + 1)) {
642       while (i < bucket_count() - 1 &&
643              0 == snapshot->GetCountAtIndex(i + 1)) {
644         ++i;
645       }
646       output->append("... ");
647       output->append(newline);
648       continue;  // No reason to plot emptiness.
649     }
650     double current_size = GetBucketSize(current, i);
651     if (graph_it)
652       WriteAsciiBucketGraph(current_size, max_size, output);
653     WriteAsciiBucketContext(past, current, remaining, i, output);
654     output->append(newline);
655     past += current;
656   }
657   DCHECK_EQ(sample_count, past);
658 }
659 
GetPeakBucketSize(const SampleVector & samples) const660 double Histogram::GetPeakBucketSize(const SampleVector& samples) const {
661   double max = 0;
662   for (uint32_t i = 0; i < bucket_count() ; ++i) {
663     double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
664     if (current_size > max)
665       max = current_size;
666   }
667   return max;
668 }
669 
WriteAsciiHeader(const SampleVector & samples,Count sample_count,std::string * output) const670 void Histogram::WriteAsciiHeader(const SampleVector& samples,
671                                  Count sample_count,
672                                  std::string* output) const {
673   StringAppendF(output,
674                 "Histogram: %s recorded %d samples",
675                 histogram_name().c_str(),
676                 sample_count);
677   if (0 == sample_count) {
678     DCHECK_EQ(samples.sum(), 0);
679   } else {
680     double average = static_cast<float>(samples.sum()) / sample_count;
681 
682     StringAppendF(output, ", average = %.1f", average);
683   }
684   if (flags() & ~kHexRangePrintingFlag)
685     StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
686 }
687 
WriteAsciiBucketContext(const int64_t past,const Count current,const int64_t remaining,const uint32_t i,std::string * output) const688 void Histogram::WriteAsciiBucketContext(const int64_t past,
689                                         const Count current,
690                                         const int64_t remaining,
691                                         const uint32_t i,
692                                         std::string* output) const {
693   double scaled_sum = (past + current + remaining) / 100.0;
694   WriteAsciiBucketValue(current, scaled_sum, output);
695   if (0 < i) {
696     double percentage = past / scaled_sum;
697     StringAppendF(output, " {%3.1f%%}", percentage);
698   }
699 }
700 
GetParameters(DictionaryValue * params) const701 void Histogram::GetParameters(DictionaryValue* params) const {
702   params->SetString("type", HistogramTypeToString(GetHistogramType()));
703   params->SetInteger("min", declared_min());
704   params->SetInteger("max", declared_max());
705   params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
706 }
707 
GetCountAndBucketData(Count * count,int64_t * sum,ListValue * buckets) const708 void Histogram::GetCountAndBucketData(Count* count,
709                                       int64_t* sum,
710                                       ListValue* buckets) const {
711   std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector();
712   *count = snapshot->TotalCount();
713   *sum = snapshot->sum();
714   uint32_t index = 0;
715   for (uint32_t i = 0; i < bucket_count(); ++i) {
716     Sample count_at_index = snapshot->GetCountAtIndex(i);
717     if (count_at_index > 0) {
718       std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue());
719       bucket_value->SetInteger("low", ranges(i));
720       if (i != bucket_count() - 1)
721         bucket_value->SetInteger("high", ranges(i + 1));
722       bucket_value->SetInteger("count", count_at_index);
723       buckets->Set(index, bucket_value.release());
724       ++index;
725     }
726   }
727 }
728 
729 //------------------------------------------------------------------------------
730 // LinearHistogram: This histogram uses a traditional set of evenly spaced
731 // buckets.
732 //------------------------------------------------------------------------------
733 
734 class LinearHistogram::Factory : public Histogram::Factory {
735  public:
Factory(const std::string & name,HistogramBase::Sample minimum,HistogramBase::Sample maximum,uint32_t bucket_count,int32_t flags,const DescriptionPair * descriptions)736   Factory(const std::string& name,
737           HistogramBase::Sample minimum,
738           HistogramBase::Sample maximum,
739           uint32_t bucket_count,
740           int32_t flags,
741           const DescriptionPair* descriptions)
742     : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum,
743                          bucket_count, flags) {
744     descriptions_ = descriptions;
745   }
746   ~Factory() override = default;
747 
748  protected:
CreateRanges()749   BucketRanges* CreateRanges() override {
750     BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
751     LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
752     return ranges;
753   }
754 
HeapAlloc(const BucketRanges * ranges)755   std::unique_ptr<HistogramBase> HeapAlloc(
756       const BucketRanges* ranges) override {
757     return WrapUnique(
758         new LinearHistogram(name_, minimum_, maximum_, ranges));
759   }
760 
FillHistogram(HistogramBase * base_histogram)761   void FillHistogram(HistogramBase* base_histogram) override {
762     Histogram::Factory::FillHistogram(base_histogram);
763     LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
764     // Set range descriptions.
765     if (descriptions_) {
766       for (int i = 0; descriptions_[i].description; ++i) {
767         histogram->bucket_description_[descriptions_[i].sample] =
768             descriptions_[i].description;
769       }
770     }
771   }
772 
773  private:
774   const DescriptionPair* descriptions_;
775 
776   DISALLOW_COPY_AND_ASSIGN(Factory);
777 };
778 
~LinearHistogram()779 LinearHistogram::~LinearHistogram() {}
780 
FactoryGet(const std::string & name,Sample minimum,Sample maximum,uint32_t bucket_count,int32_t flags)781 HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
782                                            Sample minimum,
783                                            Sample maximum,
784                                            uint32_t bucket_count,
785                                            int32_t flags) {
786   return FactoryGetWithRangeDescription(
787       name, minimum, maximum, bucket_count, flags, NULL);
788 }
789 
FactoryTimeGet(const std::string & name,TimeDelta minimum,TimeDelta maximum,uint32_t bucket_count,int32_t flags)790 HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
791                                                TimeDelta minimum,
792                                                TimeDelta maximum,
793                                                uint32_t bucket_count,
794                                                int32_t flags) {
795   return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
796                     static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
797                     flags);
798 }
799 
FactoryGet(const char * name,Sample minimum,Sample maximum,uint32_t bucket_count,int32_t flags)800 HistogramBase* LinearHistogram::FactoryGet(const char* name,
801                                            Sample minimum,
802                                            Sample maximum,
803                                            uint32_t bucket_count,
804                                            int32_t flags) {
805   return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
806 }
807 
FactoryTimeGet(const char * name,TimeDelta minimum,TimeDelta maximum,uint32_t bucket_count,int32_t flags)808 HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
809                                                TimeDelta minimum,
810                                                TimeDelta maximum,
811                                                uint32_t bucket_count,
812                                                int32_t flags) {
813   return FactoryTimeGet(std::string(name),  minimum, maximum, bucket_count,
814                         flags);
815 }
816 
PersistentCreate(const std::string & name,Sample minimum,Sample maximum,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,uint32_t counts_size,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)817 std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
818     const std::string& name,
819     Sample minimum,
820     Sample maximum,
821     const BucketRanges* ranges,
822     HistogramBase::AtomicCount* counts,
823     HistogramBase::AtomicCount* logged_counts,
824     uint32_t counts_size,
825     HistogramSamples::Metadata* meta,
826     HistogramSamples::Metadata* logged_meta) {
827   return WrapUnique(new LinearHistogram(name, minimum, maximum, ranges,
828                                               counts, logged_counts,
829                                               counts_size, meta, logged_meta));
830 }
831 
FactoryGetWithRangeDescription(const std::string & name,Sample minimum,Sample maximum,uint32_t bucket_count,int32_t flags,const DescriptionPair descriptions[])832 HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
833     const std::string& name,
834     Sample minimum,
835     Sample maximum,
836     uint32_t bucket_count,
837     int32_t flags,
838     const DescriptionPair descriptions[]) {
839   bool valid_arguments = Histogram::InspectConstructionArguments(
840       name, &minimum, &maximum, &bucket_count);
841   DCHECK(valid_arguments);
842 
843   return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
844       .Build();
845 }
846 
GetHistogramType() const847 HistogramType LinearHistogram::GetHistogramType() const {
848   return LINEAR_HISTOGRAM;
849 }
850 
LinearHistogram(const std::string & name,Sample minimum,Sample maximum,const BucketRanges * ranges)851 LinearHistogram::LinearHistogram(const std::string& name,
852                                  Sample minimum,
853                                  Sample maximum,
854                                  const BucketRanges* ranges)
855     : Histogram(name, minimum, maximum, ranges) {
856 }
857 
LinearHistogram(const std::string & name,Sample minimum,Sample maximum,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,uint32_t counts_size,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)858 LinearHistogram::LinearHistogram(const std::string& name,
859                                  Sample minimum,
860                                  Sample maximum,
861                                  const BucketRanges* ranges,
862                                  HistogramBase::AtomicCount* counts,
863                                  HistogramBase::AtomicCount* logged_counts,
864                                  uint32_t counts_size,
865                                  HistogramSamples::Metadata* meta,
866                                  HistogramSamples::Metadata* logged_meta)
867     : Histogram(name, minimum, maximum, ranges, counts, logged_counts,
868                 counts_size, meta, logged_meta) {}
869 
GetBucketSize(Count current,uint32_t i) const870 double LinearHistogram::GetBucketSize(Count current, uint32_t i) const {
871   DCHECK_GT(ranges(i + 1), ranges(i));
872   // Adjacent buckets with different widths would have "surprisingly" many (few)
873   // samples in a histogram if we didn't normalize this way.
874   double denominator = ranges(i + 1) - ranges(i);
875   return current/denominator;
876 }
877 
GetAsciiBucketRange(uint32_t i) const878 const std::string LinearHistogram::GetAsciiBucketRange(uint32_t i) const {
879   int range = ranges(i);
880   BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
881   if (it == bucket_description_.end())
882     return Histogram::GetAsciiBucketRange(i);
883   return it->second;
884 }
885 
PrintEmptyBucket(uint32_t index) const886 bool LinearHistogram::PrintEmptyBucket(uint32_t index) const {
887   return bucket_description_.find(ranges(index)) == bucket_description_.end();
888 }
889 
890 // static
InitializeBucketRanges(Sample minimum,Sample maximum,BucketRanges * ranges)891 void LinearHistogram::InitializeBucketRanges(Sample minimum,
892                                              Sample maximum,
893                                              BucketRanges* ranges) {
894   double min = minimum;
895   double max = maximum;
896   size_t bucket_count = ranges->bucket_count();
897   for (size_t i = 1; i < bucket_count; ++i) {
898     double linear_range =
899         (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
900     ranges->set_range(i, static_cast<Sample>(linear_range + 0.5));
901     // TODO(bcwhite): Remove once crbug/586622 is fixed.
902     base::debug::Alias(&linear_range);
903   }
904   ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
905   ranges->ResetChecksum();
906 }
907 
908 // static
DeserializeInfoImpl(PickleIterator * iter)909 HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
910   std::string histogram_name;
911   int flags;
912   int declared_min;
913   int declared_max;
914   uint32_t bucket_count;
915   uint32_t range_checksum;
916 
917   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
918                               &declared_max, &bucket_count, &range_checksum)) {
919     return NULL;
920   }
921 
922   HistogramBase* histogram = LinearHistogram::FactoryGet(
923       histogram_name, declared_min, declared_max, bucket_count, flags);
924   if (!ValidateRangeChecksum(*histogram, range_checksum)) {
925     // The serialized histogram might be corrupted.
926     return NULL;
927   }
928   return histogram;
929 }
930 
931 //------------------------------------------------------------------------------
932 // This section provides implementation for BooleanHistogram.
933 //------------------------------------------------------------------------------
934 
935 class BooleanHistogram::Factory : public Histogram::Factory {
936  public:
Factory(const std::string & name,int32_t flags)937   Factory(const std::string& name, int32_t flags)
938     : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
939   ~Factory() override = default;
940 
941  protected:
CreateRanges()942   BucketRanges* CreateRanges() override {
943     BucketRanges* ranges = new BucketRanges(3 + 1);
944     LinearHistogram::InitializeBucketRanges(1, 2, ranges);
945     return ranges;
946   }
947 
HeapAlloc(const BucketRanges * ranges)948   std::unique_ptr<HistogramBase> HeapAlloc(
949       const BucketRanges* ranges) override {
950     return WrapUnique(new BooleanHistogram(name_, ranges));
951   }
952 
953  private:
954   DISALLOW_COPY_AND_ASSIGN(Factory);
955 };
956 
FactoryGet(const std::string & name,int32_t flags)957 HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
958                                             int32_t flags) {
959   return Factory(name, flags).Build();
960 }
961 
FactoryGet(const char * name,int32_t flags)962 HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
963   return FactoryGet(std::string(name), flags);
964 }
965 
PersistentCreate(const std::string & name,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)966 std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
967     const std::string& name,
968     const BucketRanges* ranges,
969     HistogramBase::AtomicCount* counts,
970     HistogramBase::AtomicCount* logged_counts,
971     HistogramSamples::Metadata* meta,
972     HistogramSamples::Metadata* logged_meta) {
973   return WrapUnique(new BooleanHistogram(
974       name, ranges, counts, logged_counts, meta, logged_meta));
975 }
976 
GetHistogramType() const977 HistogramType BooleanHistogram::GetHistogramType() const {
978   return BOOLEAN_HISTOGRAM;
979 }
980 
BooleanHistogram(const std::string & name,const BucketRanges * ranges)981 BooleanHistogram::BooleanHistogram(const std::string& name,
982                                    const BucketRanges* ranges)
983     : LinearHistogram(name, 1, 2, ranges) {}
984 
BooleanHistogram(const std::string & name,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)985 BooleanHistogram::BooleanHistogram(const std::string& name,
986                                    const BucketRanges* ranges,
987                                    HistogramBase::AtomicCount* counts,
988                                    HistogramBase::AtomicCount* logged_counts,
989                                    HistogramSamples::Metadata* meta,
990                                    HistogramSamples::Metadata* logged_meta)
991     : LinearHistogram(name, 1, 2, ranges, counts, logged_counts, 2, meta,
992                       logged_meta) {}
993 
DeserializeInfoImpl(PickleIterator * iter)994 HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
995   std::string histogram_name;
996   int flags;
997   int declared_min;
998   int declared_max;
999   uint32_t bucket_count;
1000   uint32_t range_checksum;
1001 
1002   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1003                               &declared_max, &bucket_count, &range_checksum)) {
1004     return NULL;
1005   }
1006 
1007   HistogramBase* histogram = BooleanHistogram::FactoryGet(
1008       histogram_name, flags);
1009   if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1010     // The serialized histogram might be corrupted.
1011     return NULL;
1012   }
1013   return histogram;
1014 }
1015 
1016 //------------------------------------------------------------------------------
1017 // CustomHistogram:
1018 //------------------------------------------------------------------------------
1019 
1020 class CustomHistogram::Factory : public Histogram::Factory {
1021  public:
Factory(const std::string & name,const std::vector<Sample> * custom_ranges,int32_t flags)1022   Factory(const std::string& name,
1023           const std::vector<Sample>* custom_ranges,
1024           int32_t flags)
1025     : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
1026     custom_ranges_ = custom_ranges;
1027   }
1028   ~Factory() override = default;
1029 
1030  protected:
CreateRanges()1031   BucketRanges* CreateRanges() override {
1032     // Remove the duplicates in the custom ranges array.
1033     std::vector<int> ranges = *custom_ranges_;
1034     ranges.push_back(0);  // Ensure we have a zero value.
1035     ranges.push_back(HistogramBase::kSampleType_MAX);
1036     std::sort(ranges.begin(), ranges.end());
1037     ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
1038 
1039     BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
1040     for (uint32_t i = 0; i < ranges.size(); i++) {
1041       bucket_ranges->set_range(i, ranges[i]);
1042     }
1043     bucket_ranges->ResetChecksum();
1044     return bucket_ranges;
1045   }
1046 
HeapAlloc(const BucketRanges * ranges)1047   std::unique_ptr<HistogramBase> HeapAlloc(
1048       const BucketRanges* ranges) override {
1049     return WrapUnique(new CustomHistogram(name_, ranges));
1050   }
1051 
1052  private:
1053   const std::vector<Sample>* custom_ranges_;
1054 
1055   DISALLOW_COPY_AND_ASSIGN(Factory);
1056 };
1057 
FactoryGet(const std::string & name,const std::vector<Sample> & custom_ranges,int32_t flags)1058 HistogramBase* CustomHistogram::FactoryGet(
1059     const std::string& name,
1060     const std::vector<Sample>& custom_ranges,
1061     int32_t flags) {
1062   CHECK(ValidateCustomRanges(custom_ranges));
1063 
1064   return Factory(name, &custom_ranges, flags).Build();
1065 }
1066 
FactoryGet(const char * name,const std::vector<Sample> & custom_ranges,int32_t flags)1067 HistogramBase* CustomHistogram::FactoryGet(
1068     const char* name,
1069     const std::vector<Sample>& custom_ranges,
1070     int32_t flags) {
1071   return FactoryGet(std::string(name), custom_ranges, flags);
1072 }
1073 
PersistentCreate(const std::string & name,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,uint32_t counts_size,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)1074 std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
1075     const std::string& name,
1076     const BucketRanges* ranges,
1077     HistogramBase::AtomicCount* counts,
1078     HistogramBase::AtomicCount* logged_counts,
1079     uint32_t counts_size,
1080     HistogramSamples::Metadata* meta,
1081     HistogramSamples::Metadata* logged_meta) {
1082   return WrapUnique(new CustomHistogram(
1083       name, ranges, counts, logged_counts, counts_size, meta, logged_meta));
1084 }
1085 
GetHistogramType() const1086 HistogramType CustomHistogram::GetHistogramType() const {
1087   return CUSTOM_HISTOGRAM;
1088 }
1089 
1090 // static
ArrayToCustomRanges(const Sample * values,uint32_t num_values)1091 std::vector<Sample> CustomHistogram::ArrayToCustomRanges(
1092     const Sample* values, uint32_t num_values) {
1093   std::vector<Sample> all_values;
1094   for (uint32_t i = 0; i < num_values; ++i) {
1095     Sample value = values[i];
1096     all_values.push_back(value);
1097 
1098     // Ensure that a guard bucket is added. If we end up with duplicate
1099     // values, FactoryGet will take care of removing them.
1100     all_values.push_back(value + 1);
1101   }
1102   return all_values;
1103 }
1104 
CustomHistogram(const std::string & name,const BucketRanges * ranges)1105 CustomHistogram::CustomHistogram(const std::string& name,
1106                                  const BucketRanges* ranges)
1107     : Histogram(name,
1108                 ranges->range(1),
1109                 ranges->range(ranges->bucket_count() - 1),
1110                 ranges) {}
1111 
CustomHistogram(const std::string & name,const BucketRanges * ranges,HistogramBase::AtomicCount * counts,HistogramBase::AtomicCount * logged_counts,uint32_t counts_size,HistogramSamples::Metadata * meta,HistogramSamples::Metadata * logged_meta)1112 CustomHistogram::CustomHistogram(const std::string& name,
1113                                  const BucketRanges* ranges,
1114                                  HistogramBase::AtomicCount* counts,
1115                                  HistogramBase::AtomicCount* logged_counts,
1116                                  uint32_t counts_size,
1117                                  HistogramSamples::Metadata* meta,
1118                                  HistogramSamples::Metadata* logged_meta)
1119     : Histogram(name,
1120                 ranges->range(1),
1121                 ranges->range(ranges->bucket_count() - 1),
1122                 ranges,
1123                 counts,
1124                 logged_counts,
1125                 counts_size,
1126                 meta,
1127                 logged_meta) {}
1128 
SerializeInfoImpl(Pickle * pickle) const1129 bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
1130   if (!Histogram::SerializeInfoImpl(pickle))
1131     return false;
1132 
1133   // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't
1134   // write them.
1135   for (uint32_t i = 1; i < bucket_ranges()->bucket_count(); ++i) {
1136     if (!pickle->WriteInt(bucket_ranges()->range(i)))
1137       return false;
1138   }
1139   return true;
1140 }
1141 
GetBucketSize(Count,uint32_t) const1142 double CustomHistogram::GetBucketSize(Count /*current*/, uint32_t /*i*/) const {
1143   return 1;
1144 }
1145 
1146 // static
DeserializeInfoImpl(PickleIterator * iter)1147 HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
1148   std::string histogram_name;
1149   int flags;
1150   int declared_min;
1151   int declared_max;
1152   uint32_t bucket_count;
1153   uint32_t range_checksum;
1154 
1155   if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1156                               &declared_max, &bucket_count, &range_checksum)) {
1157     return NULL;
1158   }
1159 
1160   // First and last ranges are not serialized.
1161   std::vector<Sample> sample_ranges(bucket_count - 1);
1162 
1163   for (uint32_t i = 0; i < sample_ranges.size(); ++i) {
1164     if (!iter->ReadInt(&sample_ranges[i]))
1165       return NULL;
1166   }
1167 
1168   HistogramBase* histogram = CustomHistogram::FactoryGet(
1169       histogram_name, sample_ranges, flags);
1170   if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1171     // The serialized histogram might be corrupted.
1172     return NULL;
1173   }
1174   return histogram;
1175 }
1176 
1177 // static
ValidateCustomRanges(const std::vector<Sample> & custom_ranges)1178 bool CustomHistogram::ValidateCustomRanges(
1179     const std::vector<Sample>& custom_ranges) {
1180   bool has_valid_range = false;
1181   for (uint32_t i = 0; i < custom_ranges.size(); i++) {
1182     Sample sample = custom_ranges[i];
1183     if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
1184       return false;
1185     if (sample != 0)
1186       has_valid_range = true;
1187   }
1188   return has_valid_range;
1189 }
1190 
1191 }  // namespace base
1192