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