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