blob: e3f408db48ac97bde5301aa8517bb6570e51240c [file] [log] [blame]
[email protected]a93721e22012-01-06 02:13:281// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
5// Histogram is an object that aggregates statistics, and can summarize them in
6// various forms, including ASCII graphical, HTML, and numerically (as a
7// vector of numbers corresponding to each of the aggregating buckets).
8// See header file for details and examples.
9
[email protected]835d7c82010-10-14 04:38:3810#include "base/metrics/histogram.h"
initial.commitd7cae122008-07-26 21:49:3811
Alexei Svitkinee73f80a02017-07-18 00:08:3912#include <inttypes.h>
avi9b6f42932015-12-26 22:15:1413#include <limits.h>
initial.commitd7cae122008-07-26 21:49:3814#include <math.h>
[email protected]f1633932010-08-17 23:05:2815
Peter Boströmfd851232021-03-31 17:05:3316#include <memory>
initial.commitd7cae122008-07-26 21:49:3817#include <string>
jdoerrief1e72e32017-04-26 16:23:5518#include <utility>
initial.commitd7cae122008-07-26 21:49:3819
[email protected]ec0c0aa2012-08-14 02:02:0020#include "base/compiler_specific.h"
21#include "base/debug/alias.h"
initial.commitd7cae122008-07-26 21:49:3822#include "base/logging.h"
dcheng093de9b2016-04-04 21:25:5123#include "base/memory/ptr_util.h"
Gayane Petrosyan5745ac62018-03-23 01:45:2424#include "base/metrics/dummy_histogram.h"
Ilya Sherman16d5d5f42017-12-08 00:32:4425#include "base/metrics/histogram_functions.h"
bcwhiteb036e4322015-12-10 18:36:3426#include "base/metrics/metrics_hashes.h"
bcwhite33d95806a2016-03-16 02:37:4527#include "base/metrics/persistent_histogram_allocator.h"
bcwhite5cb99eb2016-02-01 21:07:5628#include "base/metrics/persistent_memory_allocator.h"
[email protected]877ef562012-10-20 02:56:1829#include "base/metrics/sample_vector.h"
[email protected]567d30e2012-07-13 21:48:2930#include "base/metrics/statistics_recorder.h"
[email protected]3f383852009-04-03 18:18:5531#include "base/pickle.h"
Anton Bikineeva61fb572020-10-18 08:54:4432#include "base/ranges/algorithm.h"
[email protected]d529cb02013-06-10 19:06:5733#include "base/strings/string_util.h"
34#include "base/strings/stringprintf.h"
Jun Kokatsu505af9f2020-05-05 11:59:4735#include "base/strings/utf_string_conversions.h"
[email protected]bc581a682011-01-01 23:16:2036#include "base/synchronization/lock.h"
[email protected]24a7ec52012-10-08 10:31:5037#include "base/values.h"
Alexei Svitkinee73f80a02017-07-18 00:08:3938#include "build/build_config.h"
initial.commitd7cae122008-07-26 21:49:3839
[email protected]835d7c82010-10-14 04:38:3840namespace base {
[email protected]e1acf6f2008-10-27 20:43:3341
[email protected]c50c21d2013-01-11 21:52:4442namespace {
43
44bool ReadHistogramArguments(PickleIterator* iter,
asvitkine24d3e9a2015-05-27 05:22:1445 std::string* histogram_name,
[email protected]c50c21d2013-01-11 21:52:4446 int* flags,
47 int* declared_min,
48 int* declared_max,
jam1eacd7e2016-02-08 22:48:1649 uint32_t* bucket_count,
avi9b6f42932015-12-26 22:15:1450 uint32_t* range_checksum) {
[email protected]c50c21d2013-01-11 21:52:4451 if (!iter->ReadString(histogram_name) ||
52 !iter->ReadInt(flags) ||
53 !iter->ReadInt(declared_min) ||
54 !iter->ReadInt(declared_max) ||
jam1eacd7e2016-02-08 22:48:1655 !iter->ReadUInt32(bucket_count) ||
[email protected]c50c21d2013-01-11 21:52:4456 !iter->ReadUInt32(range_checksum)) {
57 DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
58 return false;
59 }
60
61 // Since these fields may have come from an untrusted renderer, do additional
62 // checks above and beyond those in Histogram::Initialize()
63 if (*declared_max <= 0 ||
64 *declared_min <= 0 ||
65 *declared_max < *declared_min ||
66 INT_MAX / sizeof(HistogramBase::Count) <= *bucket_count ||
67 *bucket_count < 2) {
68 DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
69 return false;
70 }
71
72 // We use the arguments to find or create the local version of the histogram
bcwhite05dc0922016-06-03 04:59:4473 // in this process, so we need to clear any IPC flag.
[email protected]c50c21d2013-01-11 21:52:4474 *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
75
76 return true;
77}
78
79bool ValidateRangeChecksum(const HistogramBase& histogram,
avi9b6f42932015-12-26 22:15:1480 uint32_t range_checksum) {
Gayane Petrosyan5745ac62018-03-23 01:45:2481 // Normally, |histogram| should have type HISTOGRAM or be inherited from it.
82 // However, if it's expired, it will actually be a DUMMY_HISTOGRAM.
83 // Skip the checks in that case.
84 if (histogram.GetHistogramType() == DUMMY_HISTOGRAM)
85 return true;
[email protected]c50c21d2013-01-11 21:52:4486 const Histogram& casted_histogram =
87 static_cast<const Histogram&>(histogram);
88
89 return casted_histogram.bucket_ranges()->checksum() == range_checksum;
90}
91
92} // namespace
93
[email protected]34d062322012-08-01 21:34:0894typedef HistogramBase::Count Count;
95typedef HistogramBase::Sample Sample;
initial.commitd7cae122008-07-26 21:49:3896
[email protected]b122c0c2011-02-23 22:31:1897// static
Brian Whiteabfa2702019-04-03 17:00:5498const uint32_t Histogram::kBucketCount_MAX = 1002u;
[email protected]b122c0c2011-02-23 22:31:1899
bcwhite5cb99eb2016-02-01 21:07:56100class Histogram::Factory {
101 public:
102 Factory(const std::string& name,
103 HistogramBase::Sample minimum,
104 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16105 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56106 int32_t flags)
107 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
108
109 // Create histogram based on construction parameters. Caller takes
110 // ownership of the returned object.
111 HistogramBase* Build();
112
113 protected:
114 Factory(const std::string& name,
115 HistogramType histogram_type,
116 HistogramBase::Sample minimum,
117 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16118 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56119 int32_t flags)
120 : name_(name),
121 histogram_type_(histogram_type),
122 minimum_(minimum),
123 maximum_(maximum),
124 bucket_count_(bucket_count),
125 flags_(flags) {}
126
127 // Create a BucketRanges structure appropriate for this histogram.
128 virtual BucketRanges* CreateRanges() {
129 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
130 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges);
131 return ranges;
132 }
133
134 // Allocate the correct Histogram object off the heap (in case persistent
135 // memory is not available).
dcheng093de9b2016-04-04 21:25:51136 virtual std::unique_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) {
Brian Whited1c91082017-11-03 14:46:42137 return WrapUnique(
138 new Histogram(GetPermanentName(name_), minimum_, maximum_, ranges));
bcwhite5cb99eb2016-02-01 21:07:56139 }
140
141 // Perform any required datafill on the just-created histogram. If
bcwhite3dd85c4f2016-03-17 13:21:56142 // overridden, be sure to call the "super" version -- this method may not
143 // always remain empty.
144 virtual void FillHistogram(HistogramBase* histogram) {}
bcwhite5cb99eb2016-02-01 21:07:56145
146 // These values are protected (instead of private) because they need to
147 // be accessible to methods of sub-classes in order to avoid passing
148 // unnecessary parameters everywhere.
149 const std::string& name_;
150 const HistogramType histogram_type_;
151 HistogramBase::Sample minimum_;
152 HistogramBase::Sample maximum_;
jam1eacd7e2016-02-08 22:48:16153 uint32_t bucket_count_;
bcwhite5cb99eb2016-02-01 21:07:56154 int32_t flags_;
155
156 private:
157 DISALLOW_COPY_AND_ASSIGN(Factory);
158};
159
160HistogramBase* Histogram::Factory::Build() {
bcwhite5cb99eb2016-02-01 21:07:56161 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
162 if (!histogram) {
Gayane Petrosyan5745ac62018-03-23 01:45:24163 // TODO(gayane): |HashMetricName()| is called again in Histogram
164 // constructor. Refactor code to avoid the additional call.
165 bool should_record =
166 StatisticsRecorder::ShouldRecordHistogram(HashMetricName(name_));
167 if (!should_record)
168 return DummyHistogram::GetInstance();
bcwhite5cb99eb2016-02-01 21:07:56169 // To avoid racy destruction at shutdown, the following will be leaked.
bcwhite4ebd7272016-03-22 19:14:38170 const BucketRanges* created_ranges = CreateRanges();
Brian Whitee716f6e2018-09-27 21:01:46171
172 const BucketRanges* registered_ranges =
173 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
174
bcwhite5cb99eb2016-02-01 21:07:56175 // In most cases, the bucket-count, minimum, and maximum values are known
176 // when the code is written and so are passed in explicitly. In other
177 // cases (such as with a CustomHistogram), they are calculated dynamically
178 // at run-time. In the latter case, those ctor parameters are zero and
179 // the results extracted from the result of CreateRanges().
180 if (bucket_count_ == 0) {
jam1eacd7e2016-02-08 22:48:16181 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count());
bcwhite5cb99eb2016-02-01 21:07:56182 minimum_ = registered_ranges->range(1);
183 maximum_ = registered_ranges->range(bucket_count_ - 1);
184 }
bcwhitef1dec482017-07-06 14:39:11185 DCHECK_EQ(minimum_, registered_ranges->range(1));
186 DCHECK_EQ(maximum_, registered_ranges->range(bucket_count_ - 1));
bcwhite5cb99eb2016-02-01 21:07:56187
188 // Try to create the histogram using a "persistent" allocator. As of
bcwhite3dd85c4f2016-03-17 13:21:56189 // 2016-02-25, the availability of such is controlled by a base::Feature
bcwhite5cb99eb2016-02-01 21:07:56190 // that is off by default. If the allocator doesn't exist or if
191 // allocating from it fails, code below will allocate the histogram from
192 // the process heap.
bcwhite4ebd7272016-03-22 19:14:38193 PersistentHistogramAllocator::Reference histogram_ref = 0;
dcheng093de9b2016-04-04 21:25:51194 std::unique_ptr<HistogramBase> tentative_histogram;
bcwhite5e748c62016-04-06 02:03:53195 PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
bcwhite5cb99eb2016-02-01 21:07:56196 if (allocator) {
bcwhite33d95806a2016-03-16 02:37:45197 tentative_histogram = allocator->AllocateHistogram(
bcwhite5cb99eb2016-02-01 21:07:56198 histogram_type_,
199 name_,
200 minimum_,
201 maximum_,
202 registered_ranges,
203 flags_,
204 &histogram_ref);
205 }
206
207 // Handle the case where no persistent allocator is present or the
208 // persistent allocation fails (perhaps because it is full).
209 if (!tentative_histogram) {
bcwhite4ebd7272016-03-22 19:14:38210 DCHECK(!histogram_ref); // Should never have been set.
211 DCHECK(!allocator); // Shouldn't have failed.
bcwhite5cb99eb2016-02-01 21:07:56212 flags_ &= ~HistogramBase::kIsPersistent;
213 tentative_histogram = HeapAlloc(registered_ranges);
bcwhite3dd85c4f2016-03-17 13:21:56214 tentative_histogram->SetFlags(flags_);
bcwhite5cb99eb2016-02-01 21:07:56215 }
216
bcwhite33d95806a2016-03-16 02:37:45217 FillHistogram(tentative_histogram.get());
218
219 // Register this histogram with the StatisticsRecorder. Keep a copy of
220 // the pointer value to tell later whether the locally created histogram
221 // was registered or deleted. The type is "void" because it could point
222 // to released memory after the following line.
223 const void* tentative_histogram_ptr = tentative_histogram.get();
224 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
225 tentative_histogram.release());
bcwhite5cb99eb2016-02-01 21:07:56226
227 // Persistent histograms need some follow-up processing.
bcwhite4ebd7272016-03-22 19:14:38228 if (histogram_ref) {
bcwhite33d95806a2016-03-16 02:37:45229 allocator->FinalizeHistogram(histogram_ref,
230 histogram == tentative_histogram_ptr);
bcwhite5cb99eb2016-02-01 21:07:56231 }
232 }
233
Brian Whitea958cc72018-04-19 18:24:16234 if (histogram_type_ != histogram->GetHistogramType() ||
235 (bucket_count_ != 0 && !histogram->HasConstructionArguments(
236 minimum_, maximum_, bucket_count_))) {
bcwhite5cb99eb2016-02-01 21:07:56237 // The construction arguments do not match the existing histogram. This can
238 // come about if an extension updates in the middle of a chrome run and has
Brian Whitea958cc72018-04-19 18:24:16239 // changed one of them, or simply by bad code within Chrome itself. A NULL
240 // return would cause Chrome to crash; better to just record it for later
241 // analysis.
242 UmaHistogramSparse("Histogram.MismatchedConstructionArguments",
243 static_cast<Sample>(HashMetricName(name_)));
244 DLOG(ERROR) << "Histogram " << name_
245 << " has mismatched construction arguments";
246 return DummyHistogram::GetInstance();
bcwhite5cb99eb2016-02-01 21:07:56247 }
248 return histogram;
249}
250
asvitkine24d3e9a2015-05-27 05:22:14251HistogramBase* Histogram::FactoryGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17252 Sample minimum,
253 Sample maximum,
jam1eacd7e2016-02-08 22:48:16254 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14255 int32_t flags) {
[email protected]e184be902012-08-07 04:49:24256 bool valid_arguments =
257 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
Brian White226244e2018-12-20 23:11:39258 DCHECK(valid_arguments) << name;
[email protected]a93721e22012-01-06 02:13:28259
bcwhite5cb99eb2016-02-01 21:07:56260 return Factory(name, minimum, maximum, bucket_count, flags).Build();
[email protected]e8829a192009-12-06 00:09:37261}
262
asvitkine24d3e9a2015-05-27 05:22:14263HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17264 TimeDelta minimum,
265 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16266 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14267 int32_t flags) {
Jan Krcal4e553f422019-04-08 12:52:46268 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample>::max());
269 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample>::max());
pkasting9cf9b94a2014-10-01 22:18:43270 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
271 static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
272 flags);
[email protected]34d062322012-08-01 21:34:08273}
274
Gabriel Charette5ec205882018-05-22 18:07:31275HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const std::string& name,
276 TimeDelta minimum,
277 TimeDelta maximum,
278 uint32_t bucket_count,
279 int32_t flags) {
Jan Krcal4e553f422019-04-08 12:52:46280 DCHECK_LT(minimum.InMicroseconds(), std::numeric_limits<Sample>::max());
281 DCHECK_LT(maximum.InMicroseconds(), std::numeric_limits<Sample>::max());
Gabriel Charette5ec205882018-05-22 18:07:31282 return FactoryGet(name, static_cast<Sample>(minimum.InMicroseconds()),
283 static_cast<Sample>(maximum.InMicroseconds()), bucket_count,
284 flags);
285}
286
asvitkine5c2d5022015-06-19 00:37:50287HistogramBase* Histogram::FactoryGet(const char* name,
288 Sample minimum,
289 Sample maximum,
jam1eacd7e2016-02-08 22:48:16290 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14291 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50292 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
293}
294
295HistogramBase* Histogram::FactoryTimeGet(const char* name,
296 TimeDelta minimum,
297 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16298 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14299 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50300 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
301 flags);
302}
303
Gabriel Charette5ec205882018-05-22 18:07:31304HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const char* name,
305 TimeDelta minimum,
306 TimeDelta maximum,
307 uint32_t bucket_count,
308 int32_t flags) {
309 return FactoryMicrosecondsTimeGet(std::string(name), minimum, maximum,
310 bucket_count, flags);
311}
312
dcheng093de9b2016-04-04 21:25:51313std::unique_ptr<HistogramBase> Histogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:42314 const char* name,
bcwhitec85a1f822016-02-18 21:22:14315 Sample minimum,
316 Sample maximum,
317 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25318 const DelayedPersistentAllocation& counts,
319 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14320 HistogramSamples::Metadata* meta,
321 HistogramSamples::Metadata* logged_meta) {
dcheng093de9b2016-04-04 21:25:51322 return WrapUnique(new Histogram(name, minimum, maximum, ranges, counts,
bcwhitefa8485b2017-05-01 16:43:25323 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56324}
325
[email protected]34d062322012-08-01 21:34:08326// Calculate what range of values are held in each bucket.
327// We have to be careful that we don't pick a ratio between starting points in
328// consecutive buckets that is sooo small, that the integer bounds are the same
329// (effectively making one bucket get no values). We need to avoid:
330// ranges(i) == ranges(i + 1)
331// To avoid that, we just do a fine-grained bucket width as far as we need to
332// until we get a ratio that moves us along at least 2 units at a time. From
333// that bucket onward we do use the exponential growth of buckets.
334//
335// static
336void Histogram::InitializeBucketRanges(Sample minimum,
337 Sample maximum,
[email protected]34d062322012-08-01 21:34:08338 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08339 double log_max = log(static_cast<double>(maximum));
340 double log_ratio;
341 double log_next;
342 size_t bucket_index = 1;
343 Sample current = minimum;
344 ranges->set_range(bucket_index, current);
[email protected]15ce3842013-06-27 14:38:45345 size_t bucket_count = ranges->bucket_count();
Brian White61b84b22018-10-05 18:03:18346
[email protected]34d062322012-08-01 21:34:08347 while (bucket_count > ++bucket_index) {
348 double log_current;
349 log_current = log(static_cast<double>(current));
Brian White2aaa8b01a2018-11-13 23:24:56350 debug::Alias(&log_current);
[email protected]34d062322012-08-01 21:34:08351 // Calculate the count'th root of the range.
352 log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
353 // See where the next bucket would start.
354 log_next = log_current + log_ratio;
355 Sample next;
Peter Kasting8c3adfb2017-09-13 08:07:39356 next = static_cast<int>(std::round(exp(log_next)));
[email protected]34d062322012-08-01 21:34:08357 if (next > current)
358 current = next;
359 else
360 ++current; // Just do a narrow bucket, and keep trying.
361 ranges->set_range(bucket_index, current);
362 }
[email protected]15ce3842013-06-27 14:38:45363 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08364 ranges->ResetChecksum();
365}
366
[email protected]2f7d9cd2012-09-22 03:42:12367// static
368const int Histogram::kCommonRaceBasedCountMismatch = 5;
[email protected]34d062322012-08-01 21:34:08369
bcwhitec85a1f822016-02-18 21:22:14370uint32_t Histogram::FindCorruption(const HistogramSamples& samples) const {
[email protected]34d062322012-08-01 21:34:08371 int inconsistencies = NO_INCONSISTENCIES;
372 Sample previous_range = -1; // Bottom range is always 0.
jam1eacd7e2016-02-08 22:48:16373 for (uint32_t index = 0; index < bucket_count(); ++index) {
[email protected]34d062322012-08-01 21:34:08374 int new_range = ranges(index);
375 if (previous_range >= new_range)
376 inconsistencies |= BUCKET_ORDER_ERROR;
377 previous_range = new_range;
378 }
379
380 if (!bucket_ranges()->HasValidChecksum())
381 inconsistencies |= RANGE_CHECKSUM_ERROR;
382
avi9b6f42932015-12-26 22:15:14383 int64_t delta64 = samples.redundant_count() - samples.TotalCount();
[email protected]34d062322012-08-01 21:34:08384 if (delta64 != 0) {
385 int delta = static_cast<int>(delta64);
386 if (delta != delta64)
387 delta = INT_MAX; // Flag all giant errors as INT_MAX.
[email protected]34d062322012-08-01 21:34:08388 if (delta > 0) {
[email protected]34d062322012-08-01 21:34:08389 if (delta > kCommonRaceBasedCountMismatch)
390 inconsistencies |= COUNT_HIGH_ERROR;
391 } else {
392 DCHECK_GT(0, delta);
[email protected]34d062322012-08-01 21:34:08393 if (-delta > kCommonRaceBasedCountMismatch)
394 inconsistencies |= COUNT_LOW_ERROR;
395 }
396 }
[email protected]cc7dec212013-03-01 03:53:25397 return inconsistencies;
[email protected]34d062322012-08-01 21:34:08398}
399
Brian White32052d5b2017-08-07 16:46:57400const BucketRanges* Histogram::bucket_ranges() const {
401 return unlogged_samples_->bucket_ranges();
402}
403
bcwhitef1dec482017-07-06 14:39:11404Sample Histogram::declared_min() const {
Brian White32052d5b2017-08-07 16:46:57405 const BucketRanges* ranges = bucket_ranges();
406 if (ranges->bucket_count() < 2)
bcwhitef1dec482017-07-06 14:39:11407 return -1;
Brian White32052d5b2017-08-07 16:46:57408 return ranges->range(1);
bcwhitef1dec482017-07-06 14:39:11409}
410
411Sample Histogram::declared_max() const {
Brian White32052d5b2017-08-07 16:46:57412 const BucketRanges* ranges = bucket_ranges();
413 if (ranges->bucket_count() < 2)
bcwhitef1dec482017-07-06 14:39:11414 return -1;
Brian White32052d5b2017-08-07 16:46:57415 return ranges->range(ranges->bucket_count() - 1);
bcwhitef1dec482017-07-06 14:39:11416}
417
jam1eacd7e2016-02-08 22:48:16418Sample Histogram::ranges(uint32_t i) const {
Brian White32052d5b2017-08-07 16:46:57419 return bucket_ranges()->range(i);
[email protected]34d062322012-08-01 21:34:08420}
421
jam1eacd7e2016-02-08 22:48:16422uint32_t Histogram::bucket_count() const {
Brian White32052d5b2017-08-07 16:46:57423 return static_cast<uint32_t>(bucket_ranges()->bucket_count());
[email protected]34d062322012-08-01 21:34:08424}
425
[email protected]34d062322012-08-01 21:34:08426// static
Brian Whited1c91082017-11-03 14:46:42427bool Histogram::InspectConstructionArguments(StringPiece name,
[email protected]34d062322012-08-01 21:34:08428 Sample* minimum,
429 Sample* maximum,
jam1eacd7e2016-02-08 22:48:16430 uint32_t* bucket_count) {
Brian White7cfaffb12018-11-15 16:51:31431 bool check_okay = true;
432
433 // Checks below must be done after any min/max swap.
434 if (*minimum > *maximum) {
435 check_okay = false;
436 std::swap(*minimum, *maximum);
437 }
438
[email protected]34d062322012-08-01 21:34:08439 // Defensive code for backward compatibility.
440 if (*minimum < 1) {
[email protected]a5c7bd792012-08-02 00:29:04441 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
[email protected]34d062322012-08-01 21:34:08442 *minimum = 1;
Brian White7cfaffb12018-11-15 16:51:31443 if (*maximum < 1)
444 *maximum = 1;
[email protected]34d062322012-08-01 21:34:08445 }
446 if (*maximum >= kSampleType_MAX) {
[email protected]a5c7bd792012-08-02 00:29:04447 DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
448 *maximum = kSampleType_MAX - 1;
[email protected]34d062322012-08-01 21:34:08449 }
Brian Whiteabfa2702019-04-03 17:00:54450 if (*bucket_count > kBucketCount_MAX) {
Brian White7cfaffb12018-11-15 16:51:31451 UmaHistogramSparse("Histogram.TooManyBuckets.1000",
452 static_cast<Sample>(HashMetricName(name)));
Brian White226244e2018-12-20 23:11:39453
Alexei Svitkined67a4432020-10-13 22:31:21454 // TODO(bcwhite): Look at injecting allowlist (using hashes) from a higher
455 // layer rather than hardcoding them here.
Brian White226244e2018-12-20 23:11:39456 // Blink.UseCounter legitimately has more than 1000 entries in its enum.
Alexei Svitkined67a4432020-10-13 22:31:21457 if (!StartsWith(name, "Blink.UseCounter")) {
Brian Whiteabfa2702019-04-03 17:00:54458 DVLOG(1) << "Histogram: " << name
459 << " has bad bucket_count: " << *bucket_count << " (limit "
460 << kBucketCount_MAX << ")";
461
Brian White226244e2018-12-20 23:11:39462 // Assume it's a mistake and limit to 100 buckets, plus under and over.
463 // If the DCHECK doesn't alert the user then hopefully the small number
464 // will be obvious on the dashboard. If not, then it probably wasn't
465 // important.
466 *bucket_count = 102;
467 check_okay = false;
468 }
bcwhiteaaf2d3452017-04-26 19:17:47469 }
Brian White7cfaffb12018-11-15 16:51:31470
471 // Ensure parameters are sane.
bcwhiteaaf2d3452017-04-26 19:17:47472 if (*maximum == *minimum) {
473 check_okay = false;
474 *maximum = *minimum + 1;
475 }
476 if (*bucket_count < 3) {
477 check_okay = false;
478 *bucket_count = 3;
479 }
480 if (*bucket_count > static_cast<uint32_t>(*maximum - *minimum + 2)) {
481 check_okay = false;
482 *bucket_count = static_cast<uint32_t>(*maximum - *minimum + 2);
483 }
484
485 if (!check_okay) {
Ilya Sherman16d5d5f42017-12-08 00:32:44486 UmaHistogramSparse("Histogram.BadConstructionArguments",
487 static_cast<Sample>(HashMetricName(name)));
bcwhiteaaf2d3452017-04-26 19:17:47488 }
489
490 return check_okay;
[email protected]34d062322012-08-01 21:34:08491}
492
bcwhiteb036e4322015-12-10 18:36:34493uint64_t Histogram::name_hash() const {
altimin498c8382017-05-12 17:49:18494 return unlogged_samples_->id();
bcwhiteb036e4322015-12-10 18:36:34495}
496
[email protected]07c02402012-10-31 06:20:25497HistogramType Histogram::GetHistogramType() const {
498 return HISTOGRAM;
499}
500
[email protected]15ce3842013-06-27 14:38:45501bool Histogram::HasConstructionArguments(Sample expected_minimum,
502 Sample expected_maximum,
jam1eacd7e2016-02-08 22:48:16503 uint32_t expected_bucket_count) const {
bcwhitef1dec482017-07-06 14:39:11504 return (expected_bucket_count == bucket_count() &&
505 expected_minimum == declared_min() &&
506 expected_maximum == declared_max());
[email protected]abae9b022012-10-24 08:18:52507}
508
509void Histogram::Add(int value) {
amohammadkhan6779b5c32015-08-05 20:31:11510 AddCount(value, 1);
511}
512
513void Histogram::AddCount(int value, int count) {
[email protected]abae9b022012-10-24 08:18:52514 DCHECK_EQ(0, ranges(0));
[email protected]15ce3842013-06-27 14:38:45515 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
[email protected]abae9b022012-10-24 08:18:52516
517 if (value > kSampleType_MAX - 1)
518 value = kSampleType_MAX - 1;
519 if (value < 0)
520 value = 0;
amohammadkhan6779b5c32015-08-05 20:31:11521 if (count <= 0) {
522 NOTREACHED();
523 return;
524 }
altimin498c8382017-05-12 17:49:18525 unlogged_samples_->Accumulate(value, count);
simonhatchdf5a8142015-07-15 22:22:57526
Oystein Eftevaag53412eb2019-12-09 20:53:56527 if (UNLIKELY(StatisticsRecorder::have_active_callbacks()))
528 FindAndRunCallback(value);
[email protected]abae9b022012-10-24 08:18:52529}
530
dcheng093de9b2016-04-04 21:25:51531std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
altimin498c8382017-05-12 17:49:18532 return SnapshotAllSamples();
[email protected]abae9b022012-10-24 08:18:52533}
534
dcheng093de9b2016-04-04 21:25:51535std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() {
bcwhitef1dec482017-07-06 14:39:11536#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40537 DCHECK(!final_delta_created_);
bcwhitef1dec482017-07-06 14:39:11538#endif
539
altimin498c8382017-05-12 17:49:18540 // The code below has subtle thread-safety guarantees! All changes to
541 // the underlying SampleVectors use atomic integer operations, which guarantee
542 // eventual consistency, but do not guarantee full synchronization between
543 // different entries in the SampleVector. In particular, this means that
544 // concurrent updates to the histogram might result in the reported sum not
545 // matching the individual bucket counts; or there being some buckets that are
546 // logically updated "together", but end up being only partially updated when
547 // a snapshot is captured. Note that this is why it's important to subtract
548 // exactly the snapshotted unlogged samples, rather than simply resetting the
549 // vector: this way, the next snapshot will include any concurrent updates
550 // missed by the current snapshot.
bcwhite65e57d02016-05-13 14:39:40551
altimin498c8382017-05-12 17:49:18552 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples();
553 unlogged_samples_->Subtract(*snapshot);
bcwhitec85a1f822016-02-18 21:22:14554 logged_samples_->Add(*snapshot);
altimin498c8382017-05-12 17:49:18555
bcwhitec85a1f822016-02-18 21:22:14556 return snapshot;
557}
558
bcwhite65e57d02016-05-13 14:39:40559std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
bcwhitef1dec482017-07-06 14:39:11560#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40561 DCHECK(!final_delta_created_);
562 final_delta_created_ = true;
bcwhitef1dec482017-07-06 14:39:11563#endif
bcwhite65e57d02016-05-13 14:39:40564
altimin498c8382017-05-12 17:49:18565 return SnapshotUnloggedSamples();
bcwhite65e57d02016-05-13 14:39:40566}
567
[email protected]c50c21d2013-01-11 21:52:44568void Histogram::AddSamples(const HistogramSamples& samples) {
altimin498c8382017-05-12 17:49:18569 unlogged_samples_->Add(samples);
[email protected]c50c21d2013-01-11 21:52:44570}
571
572bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
altimin498c8382017-05-12 17:49:18573 return unlogged_samples_->AddFromPickle(iter);
[email protected]c50c21d2013-01-11 21:52:44574}
575
Jun Kokatsu505af9f2020-05-05 11:59:47576base::DictionaryValue Histogram::ToGraphDict() const {
577 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
Quang Minh Tuan Nguyen39b1fed2021-03-16 00:49:38578 return snapshot->ToGraphDict(histogram_name(), flags());
Jun Kokatsu505af9f2020-05-05 11:59:47579}
580
Brian White1a3a225c2018-04-27 00:40:07581void Histogram::ValidateHistogramContents() const {
582 CHECK(unlogged_samples_);
583 CHECK(unlogged_samples_->bucket_ranges());
584 CHECK(logged_samples_);
585 CHECK(logged_samples_->bucket_ranges());
586 CHECK_NE(0U, logged_samples_->id());
587}
588
Daniel Cheng0d89f9222017-09-22 05:05:07589void Histogram::SerializeInfoImpl(Pickle* pickle) const {
[email protected]c50c21d2013-01-11 21:52:44590 DCHECK(bucket_ranges()->HasValidChecksum());
Daniel Cheng0d89f9222017-09-22 05:05:07591 pickle->WriteString(histogram_name());
592 pickle->WriteInt(flags());
593 pickle->WriteInt(declared_min());
594 pickle->WriteInt(declared_max());
595 pickle->WriteUInt32(bucket_count());
596 pickle->WriteUInt32(bucket_ranges()->checksum());
[email protected]c50c21d2013-01-11 21:52:44597}
598
bcwhitef1dec482017-07-06 14:39:11599// TODO(bcwhite): Remove minimum/maximum parameters from here and call chain.
Brian Whited1c91082017-11-03 14:46:42600Histogram::Histogram(const char* name,
[email protected]abae9b022012-10-24 08:18:52601 Sample minimum,
602 Sample maximum,
[email protected]abae9b022012-10-24 08:18:52603 const BucketRanges* ranges)
Brian Whitecaef6e12018-03-12 22:06:11604 : HistogramBase(name) {
Brian White7463677b2018-04-09 21:51:40605 DCHECK(ranges) << name << ": " << minimum << "-" << maximum;
Peter Boströmfd851232021-03-31 17:05:33606 unlogged_samples_ =
607 std::make_unique<SampleVector>(HashMetricName(name), ranges);
608 logged_samples_ =
609 std::make_unique<SampleVector>(unlogged_samples_->id(), ranges);
[email protected]abae9b022012-10-24 08:18:52610}
611
Brian Whited1c91082017-11-03 14:46:42612Histogram::Histogram(const char* name,
bcwhite5cb99eb2016-02-01 21:07:56613 Sample minimum,
614 Sample maximum,
615 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25616 const DelayedPersistentAllocation& counts,
617 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14618 HistogramSamples::Metadata* meta,
619 HistogramSamples::Metadata* logged_meta)
Brian Whitecaef6e12018-03-12 22:06:11620 : HistogramBase(name) {
Brian White7463677b2018-04-09 21:51:40621 DCHECK(ranges) << name << ": " << minimum << "-" << maximum;
Peter Boströmfd851232021-03-31 17:05:33622 unlogged_samples_ = std::make_unique<PersistentSampleVector>(
623 HashMetricName(name), ranges, meta, counts);
624 logged_samples_ = std::make_unique<PersistentSampleVector>(
625 unlogged_samples_->id(), ranges, logged_meta, logged_counts);
bcwhite5cb99eb2016-02-01 21:07:56626}
627
Chris Watkinsbb7211c2017-11-29 07:16:38628Histogram::~Histogram() = default;
[email protected]abae9b022012-10-24 08:18:52629
jam1eacd7e2016-02-08 22:48:16630const std::string Histogram::GetAsciiBucketRange(uint32_t i) const {
[email protected]f2bb3202013-04-05 21:21:54631 return GetSimpleAsciiBucketRange(ranges(i));
[email protected]34d062322012-08-01 21:34:08632}
633
[email protected]34d062322012-08-01 21:34:08634//------------------------------------------------------------------------------
635// Private methods
636
[email protected]c50c21d2013-01-11 21:52:44637// static
638HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14639 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44640 int flags;
641 int declared_min;
642 int declared_max;
jam1eacd7e2016-02-08 22:48:16643 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:14644 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44645
646 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
647 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45648 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44649 }
650
651 // Find or create the local version of the histogram in this process.
652 HistogramBase* histogram = Histogram::FactoryGet(
653 histogram_name, declared_min, declared_max, bucket_count, flags);
Brian White7eb91482017-08-09 19:54:45654 if (!histogram)
655 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44656
Brian White7eb91482017-08-09 19:54:45657 // The serialized histogram might be corrupted.
658 if (!ValidateRangeChecksum(*histogram, range_checksum))
659 return nullptr;
660
[email protected]c50c21d2013-01-11 21:52:44661 return histogram;
662}
663
altimin498c8382017-05-12 17:49:18664std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const {
665 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamples();
666 samples->Add(*logged_samples_);
667 return samples;
668}
669
670std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const {
dcheng093de9b2016-04-04 21:25:51671 std::unique_ptr<SampleVector> samples(
altimin498c8382017-05-12 17:49:18672 new SampleVector(unlogged_samples_->id(), bucket_ranges()));
673 samples->Add(*unlogged_samples_);
danakj0c8d4aa2015-11-25 05:29:58674 return samples;
[email protected]877ef562012-10-20 02:56:18675}
676
[email protected]24a7ec52012-10-08 10:31:50677void Histogram::GetParameters(DictionaryValue* params) const {
[email protected]07c02402012-10-31 06:20:25678 params->SetString("type", HistogramTypeToString(GetHistogramType()));
David 'Digit' Turnere169e6c2019-03-28 22:06:29679 params->SetIntKey("min", declared_min());
680 params->SetIntKey("max", declared_max());
681 params->SetIntKey("bucket_count", static_cast<int>(bucket_count()));
[email protected]24a7ec52012-10-08 10:31:50682}
683
[email protected]34d062322012-08-01 21:34:08684//------------------------------------------------------------------------------
685// LinearHistogram: This histogram uses a traditional set of evenly spaced
686// buckets.
687//------------------------------------------------------------------------------
688
bcwhite5cb99eb2016-02-01 21:07:56689class LinearHistogram::Factory : public Histogram::Factory {
690 public:
691 Factory(const std::string& name,
692 HistogramBase::Sample minimum,
693 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16694 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56695 int32_t flags,
696 const DescriptionPair* descriptions)
697 : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum,
698 bucket_count, flags) {
699 descriptions_ = descriptions;
700 }
701
702 protected:
703 BucketRanges* CreateRanges() override {
704 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
705 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
706 return ranges;
707 }
708
dcheng093de9b2016-04-04 21:25:51709 std::unique_ptr<HistogramBase> HeapAlloc(
710 const BucketRanges* ranges) override {
Brian Whited1c91082017-11-03 14:46:42711 return WrapUnique(new LinearHistogram(GetPermanentName(name_), minimum_,
712 maximum_, ranges));
bcwhite5cb99eb2016-02-01 21:07:56713 }
714
715 void FillHistogram(HistogramBase* base_histogram) override {
716 Histogram::Factory::FillHistogram(base_histogram);
Gayane Petrosyan5745ac62018-03-23 01:45:24717 // Normally, |base_histogram| should have type LINEAR_HISTOGRAM or be
718 // inherited from it. However, if it's expired, it will actually be a
719 // DUMMY_HISTOGRAM. Skip filling in that case.
720 if (base_histogram->GetHistogramType() == DUMMY_HISTOGRAM)
721 return;
bcwhite5cb99eb2016-02-01 21:07:56722 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
723 // Set range descriptions.
724 if (descriptions_) {
725 for (int i = 0; descriptions_[i].description; ++i) {
726 histogram->bucket_description_[descriptions_[i].sample] =
727 descriptions_[i].description;
728 }
729 }
730 }
731
732 private:
733 const DescriptionPair* descriptions_;
734
735 DISALLOW_COPY_AND_ASSIGN(Factory);
736};
737
Chris Watkinsbb7211c2017-11-29 07:16:38738LinearHistogram::~LinearHistogram() = default;
[email protected]34d062322012-08-01 21:34:08739
asvitkine24d3e9a2015-05-27 05:22:14740HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17741 Sample minimum,
742 Sample maximum,
jam1eacd7e2016-02-08 22:48:16743 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14744 int32_t flags) {
Brian White7eb91482017-08-09 19:54:45745 return FactoryGetWithRangeDescription(name, minimum, maximum, bucket_count,
Brian Whited1c91082017-11-03 14:46:42746 flags, NULL);
[email protected]07c02402012-10-31 06:20:25747}
748
asvitkine24d3e9a2015-05-27 05:22:14749HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17750 TimeDelta minimum,
751 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16752 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14753 int32_t flags) {
Jan Krcal4e553f422019-04-08 12:52:46754 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample>::max());
755 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample>::max());
pkasting9cf9b94a2014-10-01 22:18:43756 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
757 static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
758 flags);
[email protected]07c02402012-10-31 06:20:25759}
760
asvitkine5c2d5022015-06-19 00:37:50761HistogramBase* LinearHistogram::FactoryGet(const char* name,
762 Sample minimum,
763 Sample maximum,
jam1eacd7e2016-02-08 22:48:16764 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14765 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50766 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
767}
768
769HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
770 TimeDelta minimum,
771 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16772 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14773 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50774 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
775 flags);
776}
777
dcheng093de9b2016-04-04 21:25:51778std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:42779 const char* name,
bcwhite5cb99eb2016-02-01 21:07:56780 Sample minimum,
781 Sample maximum,
782 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25783 const DelayedPersistentAllocation& counts,
784 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14785 HistogramSamples::Metadata* meta,
786 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:25787 return WrapUnique(new LinearHistogram(name, minimum, maximum, ranges, counts,
788 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56789}
790
[email protected]de415552013-01-23 04:12:17791HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
avi9b6f42932015-12-26 22:15:14792 const std::string& name,
793 Sample minimum,
794 Sample maximum,
jam1eacd7e2016-02-08 22:48:16795 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14796 int32_t flags,
797 const DescriptionPair descriptions[]) {
Brian White564cedf2018-11-15 20:26:00798 // Originally, histograms were required to have at least one sample value
799 // plus underflow and overflow buckets. For single-entry enumerations,
800 // that one value is usually zero (which IS the underflow bucket)
801 // resulting in a |maximum| value of 1 (the exclusive upper-bound) and only
802 // the two outlier buckets. Handle this by making max==2 and buckets==3.
803 // This usually won't have any cost since the single-value-optimization
804 // will be used until the count exceeds 16 bits.
805 if (maximum == 1 && bucket_count == 2) {
806 maximum = 2;
807 bucket_count = 3;
808 }
809
[email protected]e184be902012-08-07 04:49:24810 bool valid_arguments = Histogram::InspectConstructionArguments(
811 name, &minimum, &maximum, &bucket_count);
Brian White226244e2018-12-20 23:11:39812 DCHECK(valid_arguments) << name;
[email protected]34d062322012-08-01 21:34:08813
bcwhite5cb99eb2016-02-01 21:07:56814 return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
815 .Build();
[email protected]34d062322012-08-01 21:34:08816}
817
[email protected]07c02402012-10-31 06:20:25818HistogramType LinearHistogram::GetHistogramType() const {
[email protected]b7d08202011-01-25 17:29:39819 return LINEAR_HISTOGRAM;
820}
821
Brian Whited1c91082017-11-03 14:46:42822LinearHistogram::LinearHistogram(const char* name,
[email protected]835d7c82010-10-14 04:38:38823 Sample minimum,
824 Sample maximum,
[email protected]34d062322012-08-01 21:34:08825 const BucketRanges* ranges)
Brian Whited1c91082017-11-03 14:46:42826 : Histogram(name, minimum, maximum, ranges) {}
initial.commitd7cae122008-07-26 21:49:38827
bcwhitefa8485b2017-05-01 16:43:25828LinearHistogram::LinearHistogram(
Brian Whited1c91082017-11-03 14:46:42829 const char* name,
bcwhitefa8485b2017-05-01 16:43:25830 Sample minimum,
831 Sample maximum,
832 const BucketRanges* ranges,
833 const DelayedPersistentAllocation& counts,
834 const DelayedPersistentAllocation& logged_counts,
835 HistogramSamples::Metadata* meta,
836 HistogramSamples::Metadata* logged_meta)
837 : Histogram(name,
838 minimum,
839 maximum,
840 ranges,
841 counts,
842 logged_counts,
843 meta,
844 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:56845
jam1eacd7e2016-02-08 22:48:16846const std::string LinearHistogram::GetAsciiBucketRange(uint32_t i) const {
[email protected]b7d08202011-01-25 17:29:39847 int range = ranges(i);
Brian White61b84b22018-10-05 18:03:18848 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
[email protected]b7d08202011-01-25 17:29:39849 if (it == bucket_description_.end())
850 return Histogram::GetAsciiBucketRange(i);
851 return it->second;
852}
853
[email protected]34d062322012-08-01 21:34:08854// static
855void LinearHistogram::InitializeBucketRanges(Sample minimum,
856 Sample maximum,
[email protected]34d062322012-08-01 21:34:08857 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08858 double min = minimum;
859 double max = maximum;
[email protected]15ce3842013-06-27 14:38:45860 size_t bucket_count = ranges->bucket_count();
Brian White61b84b22018-10-05 18:03:18861
[email protected]15ce3842013-06-27 14:38:45862 for (size_t i = 1; i < bucket_count; ++i) {
[email protected]34d062322012-08-01 21:34:08863 double linear_range =
[email protected]15ce3842013-06-27 14:38:45864 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
Brian White61b84b22018-10-05 18:03:18865 uint32_t range = static_cast<Sample>(linear_range + 0.5);
Brian White61b84b22018-10-05 18:03:18866 ranges->set_range(i, range);
[email protected]34d062322012-08-01 21:34:08867 }
[email protected]15ce3842013-06-27 14:38:45868 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08869 ranges->ResetChecksum();
870}
[email protected]b7d08202011-01-25 17:29:39871
[email protected]c50c21d2013-01-11 21:52:44872// static
873HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14874 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44875 int flags;
876 int declared_min;
877 int declared_max;
jam1eacd7e2016-02-08 22:48:16878 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:14879 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44880
881 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
882 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45883 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44884 }
885
886 HistogramBase* histogram = LinearHistogram::FactoryGet(
887 histogram_name, declared_min, declared_max, bucket_count, flags);
Brian White82027ff5d2017-08-21 19:50:22888 if (!histogram)
889 return nullptr;
890
[email protected]c50c21d2013-01-11 21:52:44891 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
892 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:45893 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44894 }
895 return histogram;
896}
897
initial.commitd7cae122008-07-26 21:49:38898//------------------------------------------------------------------------------
Brian Whitefffb3582018-05-24 21:17:01899// ScaledLinearHistogram: This is a wrapper around a LinearHistogram that
900// scales input counts.
901//------------------------------------------------------------------------------
902
903ScaledLinearHistogram::ScaledLinearHistogram(const char* name,
904 Sample minimum,
905 Sample maximum,
906 uint32_t bucket_count,
907 int32_t scale,
908 int32_t flags)
Eric Seckler21a69f42020-07-10 14:18:17909 : ScaledLinearHistogram(std::string(name),
910 minimum,
911 maximum,
912 bucket_count,
913 scale,
914 flags) {}
915
916ScaledLinearHistogram::ScaledLinearHistogram(const std::string& name,
917 Sample minimum,
918 Sample maximum,
919 uint32_t bucket_count,
920 int32_t scale,
921 int32_t flags)
Joshua Berenhaus9c88c1a22020-07-16 16:37:34922 : histogram_(LinearHistogram::FactoryGet(name,
923 minimum,
924 maximum,
925 bucket_count,
926 flags)),
Brian Whitefffb3582018-05-24 21:17:01927 scale_(scale) {
928 DCHECK(histogram_);
929 DCHECK_LT(1, scale);
930 DCHECK_EQ(1, minimum);
931 CHECK_EQ(static_cast<Sample>(bucket_count), maximum - minimum + 2)
932 << " ScaledLinearHistogram requires buckets of size 1";
933
Joshua Berenhaus9c88c1a22020-07-16 16:37:34934 // Normally, |histogram_| should have type LINEAR_HISTOGRAM or be
935 // inherited from it. However, if it's expired, it will be DUMMY_HISTOGRAM.
936 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM)
937 return;
938
939 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
940 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
941 remainders_.resize(histogram->bucket_count(), 0);
Brian Whitefffb3582018-05-24 21:17:01942}
943
944ScaledLinearHistogram::~ScaledLinearHistogram() = default;
945
946void ScaledLinearHistogram::AddScaledCount(Sample value, int count) {
Joshua Berenhaus9c88c1a22020-07-16 16:37:34947 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM)
948 return;
Farah Charabb114f862018-06-12 11:53:57949 if (count == 0)
950 return;
951 if (count < 0) {
952 NOTREACHED();
953 return;
954 }
Joshua Berenhaus9c88c1a22020-07-16 16:37:34955
956 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
957 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
958 const int32_t max_value = static_cast<int32_t>(histogram->bucket_count() - 1);
Brian Whitefffb3582018-05-24 21:17:01959 if (value > max_value)
960 value = max_value;
961 if (value < 0)
962 value = 0;
Brian Whitefffb3582018-05-24 21:17:01963
964 int scaled_count = count / scale_;
965 subtle::Atomic32 remainder = count - scaled_count * scale_;
966
967 // ScaledLinearHistogram currently requires 1-to-1 mappings between value
968 // and bucket which alleviates the need to do a bucket lookup here (something
969 // that is internal to the HistogramSamples object).
970 if (remainder > 0) {
971 remainder =
972 subtle::NoBarrier_AtomicIncrement(&remainders_[value], remainder);
973 // If remainder passes 1/2 scale, increment main count (thus rounding up).
974 // The remainder is decremented by the full scale, though, which will
975 // cause it to go negative and thus requrire another increase by the full
976 // scale amount before another bump of the scaled count.
977 if (remainder >= scale_ / 2) {
978 scaled_count += 1;
979 subtle::NoBarrier_AtomicIncrement(&remainders_[value], -scale_);
980 }
981 }
982
983 if (scaled_count > 0)
Joshua Berenhaus9c88c1a22020-07-16 16:37:34984 histogram->AddCount(value, scaled_count);
Brian Whitefffb3582018-05-24 21:17:01985}
986
987//------------------------------------------------------------------------------
[email protected]e8829a192009-12-06 00:09:37988// This section provides implementation for BooleanHistogram.
989//------------------------------------------------------------------------------
990
bcwhite5cb99eb2016-02-01 21:07:56991class BooleanHistogram::Factory : public Histogram::Factory {
992 public:
993 Factory(const std::string& name, int32_t flags)
994 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
995
996 protected:
997 BucketRanges* CreateRanges() override {
998 BucketRanges* ranges = new BucketRanges(3 + 1);
[email protected]15ce3842013-06-27 14:38:45999 LinearHistogram::InitializeBucketRanges(1, 2, ranges);
bcwhite5cb99eb2016-02-01 21:07:561000 return ranges;
[email protected]e8829a192009-12-06 00:09:371001 }
1002
dcheng093de9b2016-04-04 21:25:511003 std::unique_ptr<HistogramBase> HeapAlloc(
1004 const BucketRanges* ranges) override {
Brian Whited1c91082017-11-03 14:46:421005 return WrapUnique(new BooleanHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561006 }
1007
1008 private:
1009 DISALLOW_COPY_AND_ASSIGN(Factory);
1010};
1011
1012HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
1013 int32_t flags) {
1014 return Factory(name, flags).Build();
[email protected]e8829a192009-12-06 00:09:371015}
1016
avi9b6f42932015-12-26 22:15:141017HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:501018 return FactoryGet(std::string(name), flags);
1019}
1020
dcheng093de9b2016-04-04 21:25:511021std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:421022 const char* name,
bcwhite5cb99eb2016-02-01 21:07:561023 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251024 const DelayedPersistentAllocation& counts,
1025 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141026 HistogramSamples::Metadata* meta,
1027 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:251028 return WrapUnique(new BooleanHistogram(name, ranges, counts, logged_counts,
1029 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561030}
1031
[email protected]07c02402012-10-31 06:20:251032HistogramType BooleanHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281033 return BOOLEAN_HISTOGRAM;
1034}
1035
Brian Whited1c91082017-11-03 14:46:421036BooleanHistogram::BooleanHistogram(const char* name, const BucketRanges* ranges)
[email protected]15ce3842013-06-27 14:38:451037 : LinearHistogram(name, 1, 2, ranges) {}
initial.commitd7cae122008-07-26 21:49:381038
bcwhitefa8485b2017-05-01 16:43:251039BooleanHistogram::BooleanHistogram(
Brian Whited1c91082017-11-03 14:46:421040 const char* name,
bcwhitefa8485b2017-05-01 16:43:251041 const BucketRanges* ranges,
1042 const DelayedPersistentAllocation& counts,
1043 const DelayedPersistentAllocation& logged_counts,
1044 HistogramSamples::Metadata* meta,
1045 HistogramSamples::Metadata* logged_meta)
1046 : LinearHistogram(name,
1047 1,
1048 2,
1049 ranges,
1050 counts,
1051 logged_counts,
1052 meta,
bcwhitec85a1f822016-02-18 21:22:141053 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561054
[email protected]c50c21d2013-01-11 21:52:441055HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141056 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441057 int flags;
1058 int declared_min;
1059 int declared_max;
jam1eacd7e2016-02-08 22:48:161060 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:141061 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441062
1063 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1064 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451065 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441066 }
1067
1068 HistogramBase* histogram = BooleanHistogram::FactoryGet(
1069 histogram_name, flags);
Brian White82027ff5d2017-08-21 19:50:221070 if (!histogram)
1071 return nullptr;
1072
[email protected]c50c21d2013-01-11 21:52:441073 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1074 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451075 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441076 }
1077 return histogram;
1078}
1079
initial.commitd7cae122008-07-26 21:49:381080//------------------------------------------------------------------------------
[email protected]70cc56e42010-04-29 22:39:551081// CustomHistogram:
1082//------------------------------------------------------------------------------
1083
bcwhite5cb99eb2016-02-01 21:07:561084class CustomHistogram::Factory : public Histogram::Factory {
1085 public:
1086 Factory(const std::string& name,
1087 const std::vector<Sample>* custom_ranges,
1088 int32_t flags)
1089 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
1090 custom_ranges_ = custom_ranges;
1091 }
1092
1093 protected:
1094 BucketRanges* CreateRanges() override {
1095 // Remove the duplicates in the custom ranges array.
1096 std::vector<int> ranges = *custom_ranges_;
1097 ranges.push_back(0); // Ensure we have a zero value.
1098 ranges.push_back(HistogramBase::kSampleType_MAX);
Anton Bikineeva61fb572020-10-18 08:54:441099 ranges::sort(ranges);
1100 ranges.erase(ranges::unique(ranges), ranges.end());
bcwhite5cb99eb2016-02-01 21:07:561101
1102 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
jam1eacd7e2016-02-08 22:48:161103 for (uint32_t i = 0; i < ranges.size(); i++) {
bcwhite5cb99eb2016-02-01 21:07:561104 bucket_ranges->set_range(i, ranges[i]);
1105 }
1106 bucket_ranges->ResetChecksum();
1107 return bucket_ranges;
1108 }
1109
dcheng093de9b2016-04-04 21:25:511110 std::unique_ptr<HistogramBase> HeapAlloc(
1111 const BucketRanges* ranges) override {
Brian Whited1c91082017-11-03 14:46:421112 return WrapUnique(new CustomHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561113 }
1114
1115 private:
1116 const std::vector<Sample>* custom_ranges_;
1117
1118 DISALLOW_COPY_AND_ASSIGN(Factory);
1119};
1120
asvitkine24d3e9a2015-05-27 05:22:141121HistogramBase* CustomHistogram::FactoryGet(
1122 const std::string& name,
1123 const std::vector<Sample>& custom_ranges,
avi9b6f42932015-12-26 22:15:141124 int32_t flags) {
[email protected]34d062322012-08-01 21:34:081125 CHECK(ValidateCustomRanges(custom_ranges));
[email protected]70cc56e42010-04-29 22:39:551126
bcwhite5cb99eb2016-02-01 21:07:561127 return Factory(name, &custom_ranges, flags).Build();
[email protected]70cc56e42010-04-29 22:39:551128}
1129
asvitkine5c2d5022015-06-19 00:37:501130HistogramBase* CustomHistogram::FactoryGet(
1131 const char* name,
1132 const std::vector<Sample>& custom_ranges,
avi9b6f42932015-12-26 22:15:141133 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:501134 return FactoryGet(std::string(name), custom_ranges, flags);
1135}
1136
dcheng093de9b2016-04-04 21:25:511137std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:421138 const char* name,
bcwhite5cb99eb2016-02-01 21:07:561139 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251140 const DelayedPersistentAllocation& counts,
1141 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141142 HistogramSamples::Metadata* meta,
1143 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:251144 return WrapUnique(new CustomHistogram(name, ranges, counts, logged_counts,
1145 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561146}
1147
[email protected]07c02402012-10-31 06:20:251148HistogramType CustomHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281149 return CUSTOM_HISTOGRAM;
1150}
1151
[email protected]961fefb2011-05-24 13:59:581152// static
Ryan Sleevi9c79c3542018-05-12 01:38:091153std::vector<Sample> CustomHistogram::ArrayToCustomEnumRanges(
1154 base::span<const Sample> values) {
asvitkine24d3e9a2015-05-27 05:22:141155 std::vector<Sample> all_values;
Ryan Sleevi9c79c3542018-05-12 01:38:091156 for (Sample value : values) {
[email protected]961fefb2011-05-24 13:59:581157 all_values.push_back(value);
1158
1159 // Ensure that a guard bucket is added. If we end up with duplicate
1160 // values, FactoryGet will take care of removing them.
1161 all_values.push_back(value + 1);
1162 }
1163 return all_values;
1164}
1165
Brian Whited1c91082017-11-03 14:46:421166CustomHistogram::CustomHistogram(const char* name, const BucketRanges* ranges)
[email protected]34d062322012-08-01 21:34:081167 : Histogram(name,
1168 ranges->range(1),
[email protected]15ce3842013-06-27 14:38:451169 ranges->range(ranges->bucket_count() - 1),
[email protected]34d062322012-08-01 21:34:081170 ranges) {}
[email protected]70cc56e42010-04-29 22:39:551171
bcwhitefa8485b2017-05-01 16:43:251172CustomHistogram::CustomHistogram(
Brian Whited1c91082017-11-03 14:46:421173 const char* name,
bcwhitefa8485b2017-05-01 16:43:251174 const BucketRanges* ranges,
1175 const DelayedPersistentAllocation& counts,
1176 const DelayedPersistentAllocation& logged_counts,
1177 HistogramSamples::Metadata* meta,
1178 HistogramSamples::Metadata* logged_meta)
bcwhite5cb99eb2016-02-01 21:07:561179 : Histogram(name,
1180 ranges->range(1),
1181 ranges->range(ranges->bucket_count() - 1),
1182 ranges,
1183 counts,
bcwhitec85a1f822016-02-18 21:22:141184 logged_counts,
bcwhitec85a1f822016-02-18 21:22:141185 meta,
1186 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561187
Daniel Cheng0d89f9222017-09-22 05:05:071188void CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
1189 Histogram::SerializeInfoImpl(pickle);
[email protected]cd56dff2011-11-13 04:19:151190
[email protected]c50c21d2013-01-11 21:52:441191 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't
1192 // write them.
Daniel Cheng0d89f9222017-09-22 05:05:071193 for (uint32_t i = 1; i < bucket_ranges()->bucket_count(); ++i)
1194 pickle->WriteInt(bucket_ranges()->range(i));
[email protected]cd56dff2011-11-13 04:19:151195}
1196
[email protected]34d062322012-08-01 21:34:081197// static
[email protected]c50c21d2013-01-11 21:52:441198HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141199 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441200 int flags;
1201 int declared_min;
1202 int declared_max;
jam1eacd7e2016-02-08 22:48:161203 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:141204 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441205
1206 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1207 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451208 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441209 }
1210
1211 // First and last ranges are not serialized.
asvitkine24d3e9a2015-05-27 05:22:141212 std::vector<Sample> sample_ranges(bucket_count - 1);
[email protected]c50c21d2013-01-11 21:52:441213
jam1eacd7e2016-02-08 22:48:161214 for (uint32_t i = 0; i < sample_ranges.size(); ++i) {
[email protected]c50c21d2013-01-11 21:52:441215 if (!iter->ReadInt(&sample_ranges[i]))
Brian White7eb91482017-08-09 19:54:451216 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441217 }
1218
1219 HistogramBase* histogram = CustomHistogram::FactoryGet(
1220 histogram_name, sample_ranges, flags);
Brian White82027ff5d2017-08-21 19:50:221221 if (!histogram)
1222 return nullptr;
1223
[email protected]c50c21d2013-01-11 21:52:441224 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1225 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451226 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441227 }
1228 return histogram;
1229}
1230
1231// static
[email protected]34d062322012-08-01 21:34:081232bool CustomHistogram::ValidateCustomRanges(
asvitkine24d3e9a2015-05-27 05:22:141233 const std::vector<Sample>& custom_ranges) {
[email protected]640d95ef2012-08-04 06:23:031234 bool has_valid_range = false;
jam1eacd7e2016-02-08 22:48:161235 for (uint32_t i = 0; i < custom_ranges.size(); i++) {
[email protected]640d95ef2012-08-04 06:23:031236 Sample sample = custom_ranges[i];
1237 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
[email protected]34d062322012-08-01 21:34:081238 return false;
[email protected]640d95ef2012-08-04 06:23:031239 if (sample != 0)
1240 has_valid_range = true;
[email protected]34d062322012-08-01 21:34:081241 }
[email protected]640d95ef2012-08-04 06:23:031242 return has_valid_range;
[email protected]34d062322012-08-01 21:34:081243}
1244
[email protected]835d7c82010-10-14 04:38:381245} // namespace base