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