blob: 33a6f9f8d117a32776bbefb51bff6d6075328b73 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
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
Ho Cheung3f166bc2023-05-08 16:07:4716#include <algorithm>
Gabriel Charette8becf3e2024-06-07 00:47:2017#include <atomic>
Peter Boströmfd851232021-03-31 17:05:3318#include <memory>
initial.commitd7cae122008-07-26 21:49:3819#include <string>
Helmut Januschka274c3802024-03-12 23:31:2920#include <string_view>
jdoerrief1e72e32017-04-26 16:23:5521#include <utility>
initial.commitd7cae122008-07-26 21:49:3822
[email protected]ec0c0aa2012-08-14 02:02:0023#include "base/compiler_specific.h"
24#include "base/debug/alias.h"
initial.commitd7cae122008-07-26 21:49:3825#include "base/logging.h"
dcheng093de9b2016-04-04 21:25:5126#include "base/memory/ptr_util.h"
Keishi Hattori0e45c022021-11-27 09:25:5227#include "base/memory/raw_ptr.h"
Ali Hijazia8877892022-11-10 20:51:0328#include "base/memory/raw_ref.h"
Gayane Petrosyan5745ac62018-03-23 01:45:2429#include "base/metrics/dummy_histogram.h"
Ilya Sherman16d5d5f42017-12-08 00:32:4430#include "base/metrics/histogram_functions.h"
bcwhiteb036e4322015-12-10 18:36:3431#include "base/metrics/metrics_hashes.h"
bcwhite33d95806a2016-03-16 02:37:4532#include "base/metrics/persistent_histogram_allocator.h"
bcwhite5cb99eb2016-02-01 21:07:5633#include "base/metrics/persistent_memory_allocator.h"
[email protected]877ef562012-10-20 02:56:1834#include "base/metrics/sample_vector.h"
[email protected]567d30e2012-07-13 21:48:2935#include "base/metrics/statistics_recorder.h"
David Sanders83f8ae42022-04-04 23:15:3936#include "base/notreached.h"
[email protected]3f383852009-04-03 18:18:5537#include "base/pickle.h"
[email protected]d529cb02013-06-10 19:06:5738#include "base/strings/string_util.h"
Jun Kokatsu505af9f2020-05-05 11:59:4739#include "base/strings/utf_string_conversions.h"
[email protected]bc581a682011-01-01 23:16:2040#include "base/synchronization/lock.h"
[email protected]24a7ec52012-10-08 10:31:5041#include "base/values.h"
Alexei Svitkinee73f80a02017-07-18 00:08:3942#include "build/build_config.h"
initial.commitd7cae122008-07-26 21:49:3843
[email protected]835d7c82010-10-14 04:38:3844namespace base {
[email protected]e1acf6f2008-10-27 20:43:3345
[email protected]c50c21d2013-01-11 21:52:4446namespace {
47
48bool ReadHistogramArguments(PickleIterator* iter,
asvitkine24d3e9a2015-05-27 05:22:1449 std::string* histogram_name,
[email protected]c50c21d2013-01-11 21:52:4450 int* flags,
51 int* declared_min,
52 int* declared_max,
Peter Kastingfc94f5062022-06-08 16:41:4553 size_t* bucket_count,
avi9b6f42932015-12-26 22:15:1454 uint32_t* range_checksum) {
Peter Kastingfc94f5062022-06-08 16:41:4555 uint32_t bucket_count_u32;
56 if (!iter->ReadString(histogram_name) || !iter->ReadInt(flags) ||
57 !iter->ReadInt(declared_min) || !iter->ReadInt(declared_max) ||
58 !iter->ReadUInt32(&bucket_count_u32) ||
[email protected]c50c21d2013-01-11 21:52:4459 !iter->ReadUInt32(range_checksum)) {
60 DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
61 return false;
62 }
Peter Kastingfc94f5062022-06-08 16:41:4563 *bucket_count = bucket_count_u32;
[email protected]c50c21d2013-01-11 21:52:4464
65 // Since these fields may have come from an untrusted renderer, do additional
66 // checks above and beyond those in Histogram::Initialize()
Peter Kasting134ef9af2024-12-28 02:30:0967 if (*declared_max <= 0 || *declared_min <= 0 ||
[email protected]c50c21d2013-01-11 21:52:4468 *declared_max < *declared_min ||
Ramon Cano Apariciob2cba0f2025-01-22 21:26:1069 INT_MAX / sizeof(HistogramBase::Count32) <= *bucket_count ||
[email protected]c50c21d2013-01-11 21:52:4470 *bucket_count < 2) {
71 DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
72 return false;
73 }
74
75 // We use the arguments to find or create the local version of the histogram
bcwhite05dc0922016-06-03 04:59:4476 // in this process, so we need to clear any IPC flag.
[email protected]c50c21d2013-01-11 21:52:4477 *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
78
79 return true;
80}
81
82bool ValidateRangeChecksum(const HistogramBase& histogram,
avi9b6f42932015-12-26 22:15:1483 uint32_t range_checksum) {
Gayane Petrosyan5745ac62018-03-23 01:45:2484 // Normally, |histogram| should have type HISTOGRAM or be inherited from it.
85 // However, if it's expired, it will actually be a DUMMY_HISTOGRAM.
86 // Skip the checks in that case.
Peter Kasting134ef9af2024-12-28 02:30:0987 if (histogram.GetHistogramType() == DUMMY_HISTOGRAM) {
Gayane Petrosyan5745ac62018-03-23 01:45:2488 return true;
Peter Kasting134ef9af2024-12-28 02:30:0989 }
90 const Histogram& casted_histogram = static_cast<const Histogram&>(histogram);
[email protected]c50c21d2013-01-11 21:52:4491
92 return casted_histogram.bucket_ranges()->checksum() == range_checksum;
93}
94
95} // namespace
96
Ramon Cano Apariciob2cba0f2025-01-22 21:26:1097typedef HistogramBase::Count32 Count32;
Ramon Cano Aparicio79e06642025-01-09 19:10:2298typedef HistogramBase::Sample32 Sample32;
initial.commitd7cae122008-07-26 21:49:3899
bcwhite5cb99eb2016-02-01 21:07:56100class Histogram::Factory {
101 public:
Alex Ilin84f845b2024-01-15 19:51:04102 Factory(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22103 Sample32 minimum,
104 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45105 size_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56106 int32_t flags)
Peter Kastingfc94f5062022-06-08 16:41:45107 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
bcwhite5cb99eb2016-02-01 21:07:56108
Peter Boström75cd3c02021-09-28 15:23:18109 Factory(const Factory&) = delete;
110 Factory& operator=(const Factory&) = delete;
111
bcwhite5cb99eb2016-02-01 21:07:56112 // Create histogram based on construction parameters. Caller takes
113 // ownership of the returned object.
114 HistogramBase* Build();
115
116 protected:
Alex Ilin84f845b2024-01-15 19:51:04117 Factory(std::string_view name,
bcwhite5cb99eb2016-02-01 21:07:56118 HistogramType histogram_type,
Ramon Cano Aparicio79e06642025-01-09 19:10:22119 Sample32 minimum,
120 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45121 size_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56122 int32_t flags)
Peter Kastingfc94f5062022-06-08 16:41:45123 : name_(name),
124 histogram_type_(histogram_type),
125 minimum_(minimum),
126 maximum_(maximum),
127 bucket_count_(bucket_count),
128 flags_(flags) {}
bcwhite5cb99eb2016-02-01 21:07:56129
130 // Create a BucketRanges structure appropriate for this histogram.
131 virtual BucketRanges* CreateRanges() {
132 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
133 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges);
134 return ranges;
135 }
136
137 // Allocate the correct Histogram object off the heap (in case persistent
138 // memory is not available).
dcheng093de9b2016-04-04 21:25:51139 virtual std::unique_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) {
Alex Ilin84f845b2024-01-15 19:51:04140 return WrapUnique(new Histogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:56141 }
142
143 // Perform any required datafill on the just-created histogram. If
bcwhite3dd85c4f2016-03-17 13:21:56144 // overridden, be sure to call the "super" version -- this method may not
145 // always remain empty.
146 virtual void FillHistogram(HistogramBase* histogram) {}
bcwhite5cb99eb2016-02-01 21:07:56147
148 // These values are protected (instead of private) because they need to
149 // be accessible to methods of sub-classes in order to avoid passing
150 // unnecessary parameters everywhere.
Alex Ilin84f845b2024-01-15 19:51:04151 const std::string_view name_;
bcwhite5cb99eb2016-02-01 21:07:56152 const HistogramType histogram_type_;
Ramon Cano Aparicio79e06642025-01-09 19:10:22153 Sample32 minimum_;
154 Sample32 maximum_;
Peter Kastingfc94f5062022-06-08 16:41:45155 size_t bucket_count_;
bcwhite5cb99eb2016-02-01 21:07:56156 int32_t flags_;
bcwhite5cb99eb2016-02-01 21:07:56157};
158
159HistogramBase* Histogram::Factory::Build() {
Alex Ilin84f845b2024-01-15 19:51:04160 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
bcwhite5cb99eb2016-02-01 21:07:56161 if (!histogram) {
Gayane Petrosyan5745ac62018-03-23 01:45:24162 // constructor. Refactor code to avoid the additional call.
Toshiaki Tanakad917f462021-05-10 17:24:04163 bool should_record = StatisticsRecorder::ShouldRecordHistogram(
Alex Ilin84f845b2024-01-15 19:51:04164 HashMetricNameAs32Bits(name_));
Peter Kasting134ef9af2024-12-28 02:30:09165 if (!should_record) {
Gayane Petrosyan5745ac62018-03-23 01:45:24166 return DummyHistogram::GetInstance();
Peter Kasting134ef9af2024-12-28 02:30:09167 }
bcwhite5cb99eb2016-02-01 21:07:56168 // To avoid racy destruction at shutdown, the following will be leaked.
bcwhite4ebd7272016-03-22 19:14:38169 const BucketRanges* created_ranges = CreateRanges();
Brian Whitee716f6e2018-09-27 21:01:46170
171 const BucketRanges* registered_ranges =
172 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
173
bcwhite5cb99eb2016-02-01 21:07:56174 // In most cases, the bucket-count, minimum, and maximum values are known
175 // when the code is written and so are passed in explicitly. In other
176 // cases (such as with a CustomHistogram), they are calculated dynamically
177 // at run-time. In the latter case, those ctor parameters are zero and
178 // the results extracted from the result of CreateRanges().
179 if (bucket_count_ == 0) {
Peter Kastingfc94f5062022-06-08 16:41:45180 bucket_count_ = registered_ranges->bucket_count();
bcwhite5cb99eb2016-02-01 21:07:56181 minimum_ = registered_ranges->range(1);
182 maximum_ = registered_ranges->range(bucket_count_ - 1);
183 }
bcwhitef1dec482017-07-06 14:39:11184 DCHECK_EQ(minimum_, registered_ranges->range(1));
185 DCHECK_EQ(maximum_, registered_ranges->range(bucket_count_ - 1));
bcwhite5cb99eb2016-02-01 21:07:56186
187 // Try to create the histogram using a "persistent" allocator. As of
bcwhite3dd85c4f2016-03-17 13:21:56188 // 2016-02-25, the availability of such is controlled by a base::Feature
bcwhite5cb99eb2016-02-01 21:07:56189 // that is off by default. If the allocator doesn't exist or if
190 // allocating from it fails, code below will allocate the histogram from
191 // the process heap.
bcwhite4ebd7272016-03-22 19:14:38192 PersistentHistogramAllocator::Reference histogram_ref = 0;
dcheng093de9b2016-04-04 21:25:51193 std::unique_ptr<HistogramBase> tentative_histogram;
bcwhite5e748c62016-04-06 02:03:53194 PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
bcwhite5cb99eb2016-02-01 21:07:56195 if (allocator) {
bcwhite33d95806a2016-03-16 02:37:45196 tentative_histogram = allocator->AllocateHistogram(
Alex Ilin84f845b2024-01-15 19:51:04197 histogram_type_, name_, minimum_, maximum_, registered_ranges, flags_,
198 &histogram_ref);
bcwhite5cb99eb2016-02-01 21:07:56199 }
200
201 // Handle the case where no persistent allocator is present or the
202 // persistent allocation fails (perhaps because it is full).
203 if (!tentative_histogram) {
bcwhite4ebd7272016-03-22 19:14:38204 DCHECK(!histogram_ref); // Should never have been set.
bcwhite5cb99eb2016-02-01 21:07:56205 flags_ &= ~HistogramBase::kIsPersistent;
206 tentative_histogram = HeapAlloc(registered_ranges);
bcwhite3dd85c4f2016-03-17 13:21:56207 tentative_histogram->SetFlags(flags_);
bcwhite5cb99eb2016-02-01 21:07:56208 }
209
bcwhite33d95806a2016-03-16 02:37:45210 FillHistogram(tentative_histogram.get());
211
212 // Register this histogram with the StatisticsRecorder. Keep a copy of
213 // the pointer value to tell later whether the locally created histogram
214 // was registered or deleted. The type is "void" because it could point
215 // to released memory after the following line.
216 const void* tentative_histogram_ptr = tentative_histogram.get();
217 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
218 tentative_histogram.release());
bcwhite5cb99eb2016-02-01 21:07:56219
220 // Persistent histograms need some follow-up processing.
bcwhite4ebd7272016-03-22 19:14:38221 if (histogram_ref) {
bcwhite33d95806a2016-03-16 02:37:45222 allocator->FinalizeHistogram(histogram_ref,
223 histogram == tentative_histogram_ptr);
bcwhite5cb99eb2016-02-01 21:07:56224 }
225 }
226
Brian Whitea958cc72018-04-19 18:24:16227 if (histogram_type_ != histogram->GetHistogramType() ||
228 (bucket_count_ != 0 && !histogram->HasConstructionArguments(
229 minimum_, maximum_, bucket_count_))) {
bcwhite5cb99eb2016-02-01 21:07:56230 // The construction arguments do not match the existing histogram. This can
231 // come about if an extension updates in the middle of a chrome run and has
Brian Whitea958cc72018-04-19 18:24:16232 // changed one of them, or simply by bad code within Chrome itself. A NULL
233 // return would cause Chrome to crash; better to just record it for later
234 // analysis.
235 UmaHistogramSparse("Histogram.MismatchedConstructionArguments",
Ramon Cano Aparicio79e06642025-01-09 19:10:22236 static_cast<Sample32>(HashMetricName(name_)));
Alex Ilin84f845b2024-01-15 19:51:04237 DLOG(ERROR) << "Histogram " << name_
Brian Whitea958cc72018-04-19 18:24:16238 << " has mismatched construction arguments";
239 return DummyHistogram::GetInstance();
bcwhite5cb99eb2016-02-01 21:07:56240 }
241 return histogram;
242}
243
Alex Turnerbb5cb56e2024-08-12 17:12:42244HistogramBase* Histogram::FactoryGet(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22245 Sample32 minimum,
246 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:42247 size_t bucket_count,
248 int32_t flags) {
249 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
250}
251
252HistogramBase* Histogram::FactoryTimeGet(std::string_view name,
253 TimeDelta minimum,
254 TimeDelta maximum,
255 size_t bucket_count,
256 int32_t flags) {
257 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
258}
259
260HistogramBase* Histogram::FactoryMicrosecondsTimeGet(std::string_view name,
261 TimeDelta minimum,
262 TimeDelta maximum,
263 size_t bucket_count,
264 int32_t flags) {
265 return FactoryMicrosecondsTimeGetInternal(name, minimum, maximum,
266 bucket_count, flags);
267}
268
asvitkine24d3e9a2015-05-27 05:22:14269HistogramBase* Histogram::FactoryGet(const std::string& name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22270 Sample32 minimum,
271 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45272 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14273 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04274 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]e8829a192009-12-06 00:09:37275}
276
asvitkine24d3e9a2015-05-27 05:22:14277HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17278 TimeDelta minimum,
279 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45280 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14281 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04282 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]34d062322012-08-01 21:34:08283}
284
Gabriel Charette5ec205882018-05-22 18:07:31285HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const std::string& name,
286 TimeDelta minimum,
287 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45288 size_t bucket_count,
Gabriel Charette5ec205882018-05-22 18:07:31289 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04290 return FactoryMicrosecondsTimeGetInternal(name, minimum, maximum,
291 bucket_count, flags);
Gabriel Charette5ec205882018-05-22 18:07:31292}
293
asvitkine5c2d5022015-06-19 00:37:50294HistogramBase* Histogram::FactoryGet(const char* name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22295 Sample32 minimum,
296 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45297 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14298 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04299 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50300}
301
302HistogramBase* Histogram::FactoryTimeGet(const char* name,
303 TimeDelta minimum,
304 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45305 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14306 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04307 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50308}
309
Gabriel Charette5ec205882018-05-22 18:07:31310HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const char* name,
311 TimeDelta minimum,
312 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45313 size_t bucket_count,
Gabriel Charette5ec205882018-05-22 18:07:31314 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04315 return FactoryMicrosecondsTimeGetInternal(name, minimum, maximum,
316 bucket_count, flags);
Gabriel Charette5ec205882018-05-22 18:07:31317}
318
dcheng093de9b2016-04-04 21:25:51319std::unique_ptr<HistogramBase> Histogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:27320 DurableStringView durable_name,
bcwhitec85a1f822016-02-18 21:22:14321 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25322 const DelayedPersistentAllocation& counts,
323 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14324 HistogramSamples::Metadata* meta,
325 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:27326 return WrapUnique(new Histogram(durable_name, ranges, counts, logged_counts,
327 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56328}
329
[email protected]34d062322012-08-01 21:34:08330// Calculate what range of values are held in each bucket.
331// We have to be careful that we don't pick a ratio between starting points in
332// consecutive buckets that is sooo small, that the integer bounds are the same
333// (effectively making one bucket get no values). We need to avoid:
334// ranges(i) == ranges(i + 1)
335// To avoid that, we just do a fine-grained bucket width as far as we need to
336// until we get a ratio that moves us along at least 2 units at a time. From
337// that bucket onward we do use the exponential growth of buckets.
338//
339// static
Ramon Cano Aparicio79e06642025-01-09 19:10:22340void Histogram::InitializeBucketRanges(Sample32 minimum,
341 Sample32 maximum,
[email protected]34d062322012-08-01 21:34:08342 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08343 double log_max = log(static_cast<double>(maximum));
344 double log_ratio;
345 double log_next;
346 size_t bucket_index = 1;
Ramon Cano Aparicio79e06642025-01-09 19:10:22347 Sample32 current = minimum;
[email protected]34d062322012-08-01 21:34:08348 ranges->set_range(bucket_index, current);
[email protected]15ce3842013-06-27 14:38:45349 size_t bucket_count = ranges->bucket_count();
Brian White61b84b22018-10-05 18:03:18350
[email protected]34d062322012-08-01 21:34:08351 while (bucket_count > ++bucket_index) {
352 double log_current;
353 log_current = log(static_cast<double>(current));
Brian White2aaa8b01a2018-11-13 23:24:56354 debug::Alias(&log_current);
[email protected]34d062322012-08-01 21:34:08355 // Calculate the count'th root of the range.
356 log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
357 // See where the next bucket would start.
358 log_next = log_current + log_ratio;
Ramon Cano Aparicio79e06642025-01-09 19:10:22359 Sample32 next;
Peter Kasting8c3adfb2017-09-13 08:07:39360 next = static_cast<int>(std::round(exp(log_next)));
Peter Kasting134ef9af2024-12-28 02:30:09361 if (next > current) {
[email protected]34d062322012-08-01 21:34:08362 current = next;
Peter Kasting134ef9af2024-12-28 02:30:09363 } else {
[email protected]34d062322012-08-01 21:34:08364 ++current; // Just do a narrow bucket, and keep trying.
Peter Kasting134ef9af2024-12-28 02:30:09365 }
[email protected]34d062322012-08-01 21:34:08366 ranges->set_range(bucket_index, current);
367 }
[email protected]15ce3842013-06-27 14:38:45368 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08369 ranges->ResetChecksum();
370}
371
[email protected]2f7d9cd2012-09-22 03:42:12372// static
373const int Histogram::kCommonRaceBasedCountMismatch = 5;
[email protected]34d062322012-08-01 21:34:08374
bcwhitec85a1f822016-02-18 21:22:14375uint32_t Histogram::FindCorruption(const HistogramSamples& samples) const {
Peter Kastingfc94f5062022-06-08 16:41:45376 uint32_t inconsistencies = NO_INCONSISTENCIES;
Ramon Cano Aparicio79e06642025-01-09 19:10:22377 Sample32 previous_range = -1; // Bottom range is always 0.
Peter Kastingfc94f5062022-06-08 16:41:45378 for (size_t index = 0; index < bucket_count(); ++index) {
[email protected]34d062322012-08-01 21:34:08379 int new_range = ranges(index);
Peter Kasting134ef9af2024-12-28 02:30:09380 if (previous_range >= new_range) {
[email protected]34d062322012-08-01 21:34:08381 inconsistencies |= BUCKET_ORDER_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09382 }
[email protected]34d062322012-08-01 21:34:08383 previous_range = new_range;
384 }
385
Peter Kasting134ef9af2024-12-28 02:30:09386 if (!bucket_ranges()->HasValidChecksum()) {
[email protected]34d062322012-08-01 21:34:08387 inconsistencies |= RANGE_CHECKSUM_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09388 }
[email protected]34d062322012-08-01 21:34:08389
avi9b6f42932015-12-26 22:15:14390 int64_t delta64 = samples.redundant_count() - samples.TotalCount();
[email protected]34d062322012-08-01 21:34:08391 if (delta64 != 0) {
392 int delta = static_cast<int>(delta64);
Peter Kasting134ef9af2024-12-28 02:30:09393 if (delta != delta64) {
[email protected]34d062322012-08-01 21:34:08394 delta = INT_MAX; // Flag all giant errors as INT_MAX.
Peter Kasting134ef9af2024-12-28 02:30:09395 }
[email protected]34d062322012-08-01 21:34:08396 if (delta > 0) {
Peter Kasting134ef9af2024-12-28 02:30:09397 if (delta > kCommonRaceBasedCountMismatch) {
[email protected]34d062322012-08-01 21:34:08398 inconsistencies |= COUNT_HIGH_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09399 }
[email protected]34d062322012-08-01 21:34:08400 } else {
401 DCHECK_GT(0, delta);
Peter Kasting134ef9af2024-12-28 02:30:09402 if (-delta > kCommonRaceBasedCountMismatch) {
[email protected]34d062322012-08-01 21:34:08403 inconsistencies |= COUNT_LOW_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09404 }
[email protected]34d062322012-08-01 21:34:08405 }
406 }
[email protected]cc7dec212013-03-01 03:53:25407 return inconsistencies;
[email protected]34d062322012-08-01 21:34:08408}
409
Brian White32052d5b2017-08-07 16:46:57410const BucketRanges* Histogram::bucket_ranges() const {
411 return unlogged_samples_->bucket_ranges();
412}
413
Ramon Cano Aparicio79e06642025-01-09 19:10:22414Sample32 Histogram::declared_min() const {
Brian White32052d5b2017-08-07 16:46:57415 const BucketRanges* ranges = bucket_ranges();
Peter Kasting134ef9af2024-12-28 02:30:09416 if (ranges->bucket_count() < 2) {
bcwhitef1dec482017-07-06 14:39:11417 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09418 }
Brian White32052d5b2017-08-07 16:46:57419 return ranges->range(1);
bcwhitef1dec482017-07-06 14:39:11420}
421
Ramon Cano Aparicio79e06642025-01-09 19:10:22422Sample32 Histogram::declared_max() const {
Brian White32052d5b2017-08-07 16:46:57423 const BucketRanges* ranges = bucket_ranges();
Peter Kasting134ef9af2024-12-28 02:30:09424 if (ranges->bucket_count() < 2) {
bcwhitef1dec482017-07-06 14:39:11425 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09426 }
Brian White32052d5b2017-08-07 16:46:57427 return ranges->range(ranges->bucket_count() - 1);
bcwhitef1dec482017-07-06 14:39:11428}
429
Ramon Cano Aparicio79e06642025-01-09 19:10:22430Sample32 Histogram::ranges(size_t i) const {
Brian White32052d5b2017-08-07 16:46:57431 return bucket_ranges()->range(i);
[email protected]34d062322012-08-01 21:34:08432}
433
Peter Kastingfc94f5062022-06-08 16:41:45434size_t Histogram::bucket_count() const {
435 return bucket_ranges()->bucket_count();
[email protected]34d062322012-08-01 21:34:08436}
437
[email protected]34d062322012-08-01 21:34:08438// static
Helmut Januschka274c3802024-03-12 23:31:29439bool Histogram::InspectConstructionArguments(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17440 Sample32* minimum,
441 Sample32* maximum,
Peter Kastingfc94f5062022-06-08 16:41:45442 size_t* bucket_count) {
Brian White7cfaffb12018-11-15 16:51:31443 bool check_okay = true;
444
445 // Checks below must be done after any min/max swap.
446 if (*minimum > *maximum) {
Brian Whitea254ab842022-02-16 16:34:53447 DLOG(ERROR) << "Histogram: " << name << " has swapped minimum/maximum";
Brian White7cfaffb12018-11-15 16:51:31448 check_okay = false;
449 std::swap(*minimum, *maximum);
450 }
451
[email protected]34d062322012-08-01 21:34:08452 // Defensive code for backward compatibility.
453 if (*minimum < 1) {
Alison Gale59c007a2024-04-20 03:05:40454 // TODO(crbug.com/40211696): Temporarily disabled during cleanup.
Brian White9c8bb642022-02-22 18:19:12455 // DLOG(ERROR) << "Histogram: " << name << " has bad minimum: " << *minimum;
[email protected]34d062322012-08-01 21:34:08456 *minimum = 1;
Peter Kasting134ef9af2024-12-28 02:30:09457 if (*maximum < 1) {
Brian White7cfaffb12018-11-15 16:51:31458 *maximum = 1;
Peter Kasting134ef9af2024-12-28 02:30:09459 }
[email protected]34d062322012-08-01 21:34:08460 }
461 if (*maximum >= kSampleType_MAX) {
Brian Whitea254ab842022-02-16 16:34:53462 DLOG(ERROR) << "Histogram: " << name << " has bad maximum: " << *maximum;
[email protected]a5c7bd792012-08-02 00:29:04463 *maximum = kSampleType_MAX - 1;
[email protected]34d062322012-08-01 21:34:08464 }
Brian Whiteabfa2702019-04-03 17:00:54465 if (*bucket_count > kBucketCount_MAX) {
Brian White7cfaffb12018-11-15 16:51:31466 UmaHistogramSparse("Histogram.TooManyBuckets.1000",
Ramon Cano Aparicio4a39d122025-01-20 13:00:17467 static_cast<Sample32>(HashMetricName(name)));
Brian White226244e2018-12-20 23:11:39468
Brian White226244e2018-12-20 23:11:39469 // Blink.UseCounter legitimately has more than 1000 entries in its enum.
Alexei Svitkined67a4432020-10-13 22:31:21470 if (!StartsWith(name, "Blink.UseCounter")) {
Brian Whitea254ab842022-02-16 16:34:53471 DLOG(ERROR) << "Histogram: " << name
472 << " has bad bucket_count: " << *bucket_count << " (limit "
473 << kBucketCount_MAX << ")";
Brian Whiteabfa2702019-04-03 17:00:54474
Brian White226244e2018-12-20 23:11:39475 // Assume it's a mistake and limit to 100 buckets, plus under and over.
476 // If the DCHECK doesn't alert the user then hopefully the small number
477 // will be obvious on the dashboard. If not, then it probably wasn't
478 // important.
479 *bucket_count = 102;
480 check_okay = false;
481 }
bcwhiteaaf2d3452017-04-26 19:17:47482 }
Brian White7cfaffb12018-11-15 16:51:31483
484 // Ensure parameters are sane.
bcwhiteaaf2d3452017-04-26 19:17:47485 if (*maximum == *minimum) {
486 check_okay = false;
487 *maximum = *minimum + 1;
488 }
489 if (*bucket_count < 3) {
490 check_okay = false;
491 *bucket_count = 3;
492 }
Peter Kastingfc94f5062022-06-08 16:41:45493 // The swap at the top of the function guarantees this cast is safe.
494 const size_t max_buckets = static_cast<size_t>(*maximum - *minimum + 2);
495 if (*bucket_count > max_buckets) {
bcwhiteaaf2d3452017-04-26 19:17:47496 check_okay = false;
Peter Kastingfc94f5062022-06-08 16:41:45497 *bucket_count = max_buckets;
bcwhiteaaf2d3452017-04-26 19:17:47498 }
499
500 if (!check_okay) {
Ilya Sherman16d5d5f42017-12-08 00:32:44501 UmaHistogramSparse("Histogram.BadConstructionArguments",
Ramon Cano Aparicio4a39d122025-01-20 13:00:17502 static_cast<Sample32>(HashMetricName(name)));
bcwhiteaaf2d3452017-04-26 19:17:47503 }
504
505 return check_okay;
[email protected]34d062322012-08-01 21:34:08506}
507
bcwhiteb036e4322015-12-10 18:36:34508uint64_t Histogram::name_hash() const {
altimin498c8382017-05-12 17:49:18509 return unlogged_samples_->id();
bcwhiteb036e4322015-12-10 18:36:34510}
511
[email protected]07c02402012-10-31 06:20:25512HistogramType Histogram::GetHistogramType() const {
513 return HISTOGRAM;
514}
515
Ramon Cano Aparicio4a39d122025-01-20 13:00:17516bool Histogram::HasConstructionArguments(Sample32 expected_minimum,
517 Sample32 expected_maximum,
Peter Kastingfc94f5062022-06-08 16:41:45518 size_t expected_bucket_count) const {
bcwhitef1dec482017-07-06 14:39:11519 return (expected_bucket_count == bucket_count() &&
520 expected_minimum == declared_min() &&
521 expected_maximum == declared_max());
[email protected]abae9b022012-10-24 08:18:52522}
523
524void Histogram::Add(int value) {
amohammadkhan6779b5c32015-08-05 20:31:11525 AddCount(value, 1);
526}
527
528void Histogram::AddCount(int value, int count) {
[email protected]abae9b022012-10-24 08:18:52529 DCHECK_EQ(0, ranges(0));
[email protected]15ce3842013-06-27 14:38:45530 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
[email protected]abae9b022012-10-24 08:18:52531
Peter Kasting134ef9af2024-12-28 02:30:09532 if (value > kSampleType_MAX - 1) {
[email protected]abae9b022012-10-24 08:18:52533 value = kSampleType_MAX - 1;
Peter Kasting134ef9af2024-12-28 02:30:09534 }
535 if (value < 0) {
[email protected]abae9b022012-10-24 08:18:52536 value = 0;
Peter Kasting134ef9af2024-12-28 02:30:09537 }
amohammadkhan6779b5c32015-08-05 20:31:11538 if (count <= 0) {
Peter Boströmde573332024-08-26 20:42:45539 NOTREACHED();
amohammadkhan6779b5c32015-08-05 20:31:11540 }
altimin498c8382017-05-12 17:49:18541 unlogged_samples_->Accumulate(value, count);
simonhatchdf5a8142015-07-15 22:22:57542
Peter Kastingfa488992024-08-06 07:48:14543 if (StatisticsRecorder::have_active_callbacks()) [[unlikely]] {
Shakti Sahue0e07a0e2021-06-06 00:07:52544 FindAndRunCallbacks(value);
Peter Kastingfa488992024-08-06 07:48:14545 }
[email protected]abae9b022012-10-24 08:18:52546}
547
dcheng093de9b2016-04-04 21:25:51548std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
altimin498c8382017-05-12 17:49:18549 return SnapshotAllSamples();
[email protected]abae9b022012-10-24 08:18:52550}
551
Luc Nguyene01c6752022-12-01 18:40:15552std::unique_ptr<HistogramSamples> Histogram::SnapshotUnloggedSamples() const {
553 return SnapshotUnloggedSamplesImpl();
554}
555
556void Histogram::MarkSamplesAsLogged(const HistogramSamples& samples) {
557 // |final_delta_created_| only exists when DCHECK is on.
558#if DCHECK_IS_ON()
559 DCHECK(!final_delta_created_);
560#endif
561
562 unlogged_samples_->Subtract(samples);
563 logged_samples_->Add(samples);
564}
565
dcheng093de9b2016-04-04 21:25:51566std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() {
Luc Nguyene01c6752022-12-01 18:40:15567 // |final_delta_created_| only exists when DCHECK is on.
bcwhitef1dec482017-07-06 14:39:11568#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40569 DCHECK(!final_delta_created_);
bcwhitef1dec482017-07-06 14:39:11570#endif
571
altimin498c8382017-05-12 17:49:18572 // The code below has subtle thread-safety guarantees! All changes to
573 // the underlying SampleVectors use atomic integer operations, which guarantee
574 // eventual consistency, but do not guarantee full synchronization between
575 // different entries in the SampleVector. In particular, this means that
576 // concurrent updates to the histogram might result in the reported sum not
577 // matching the individual bucket counts; or there being some buckets that are
578 // logically updated "together", but end up being only partially updated when
579 // a snapshot is captured. Note that this is why it's important to subtract
580 // exactly the snapshotted unlogged samples, rather than simply resetting the
581 // vector: this way, the next snapshot will include any concurrent updates
582 // missed by the current snapshot.
bcwhite65e57d02016-05-13 14:39:40583
Luc Nguyen257ecb02023-04-11 21:09:41584 std::unique_ptr<HistogramSamples> snapshot =
585 std::make_unique<SampleVector>(unlogged_samples_->id(), bucket_ranges());
586 snapshot->Extract(*unlogged_samples_);
587 logged_samples_->Add(*snapshot);
altimin498c8382017-05-12 17:49:18588
bcwhitec85a1f822016-02-18 21:22:14589 return snapshot;
590}
591
bcwhite65e57d02016-05-13 14:39:40592std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
Luc Nguyene01c6752022-12-01 18:40:15593 // |final_delta_created_| only exists when DCHECK is on.
bcwhitef1dec482017-07-06 14:39:11594#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40595 DCHECK(!final_delta_created_);
596 final_delta_created_ = true;
bcwhitef1dec482017-07-06 14:39:11597#endif
bcwhite65e57d02016-05-13 14:39:40598
altimin498c8382017-05-12 17:49:18599 return SnapshotUnloggedSamples();
bcwhite65e57d02016-05-13 14:39:40600}
601
Alexei Svitkine1e86b0c892024-10-02 21:02:03602bool Histogram::AddSamples(const HistogramSamples& samples) {
603 return unlogged_samples_->Add(samples);
[email protected]c50c21d2013-01-11 21:52:44604}
605
606bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
altimin498c8382017-05-12 17:49:18607 return unlogged_samples_->AddFromPickle(iter);
[email protected]c50c21d2013-01-11 21:52:44608}
609
Nathan Memmottc034fa4e2022-07-15 23:59:43610base::Value::Dict Histogram::ToGraphDict() const {
Jun Kokatsu505af9f2020-05-05 11:59:47611 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
Quang Minh Tuan Nguyen39b1fed2021-03-16 00:49:38612 return snapshot->ToGraphDict(histogram_name(), flags());
Jun Kokatsu505af9f2020-05-05 11:59:47613}
614
Daniel Cheng0d89f9222017-09-22 05:05:07615void Histogram::SerializeInfoImpl(Pickle* pickle) const {
[email protected]c50c21d2013-01-11 21:52:44616 DCHECK(bucket_ranges()->HasValidChecksum());
Daniel Cheng0d89f9222017-09-22 05:05:07617 pickle->WriteString(histogram_name());
618 pickle->WriteInt(flags());
619 pickle->WriteInt(declared_min());
620 pickle->WriteInt(declared_max());
Peter Kastingfc94f5062022-06-08 16:41:45621 // Limited to kBucketCount_MAX, which fits in a uint32_t.
622 pickle->WriteUInt32(static_cast<uint32_t>(bucket_count()));
Daniel Cheng0d89f9222017-09-22 05:05:07623 pickle->WriteUInt32(bucket_ranges()->checksum());
[email protected]c50c21d2013-01-11 21:52:44624}
625
Roger McFarlane89528592025-02-20 20:50:27626Histogram::Histogram(DurableStringView durable_name, const BucketRanges* ranges)
627 : HistogramBase(durable_name) {
628 DCHECK(ranges) << histogram_name();
Peter Boströmfd851232021-03-31 17:05:33629 unlogged_samples_ =
Roger McFarlane89528592025-02-20 20:50:27630 std::make_unique<SampleVector>(HashMetricName(histogram_name()), ranges);
Peter Boströmfd851232021-03-31 17:05:33631 logged_samples_ =
632 std::make_unique<SampleVector>(unlogged_samples_->id(), ranges);
[email protected]abae9b022012-10-24 08:18:52633}
634
Roger McFarlane89528592025-02-20 20:50:27635Histogram::Histogram(DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:56636 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25637 const DelayedPersistentAllocation& counts,
638 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14639 HistogramSamples::Metadata* meta,
640 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:27641 : HistogramBase(durable_name) {
Roger McFarlaned9048a02025-04-14 16:22:01642 const auto name = histogram_name();
643 const auto id = HashMetricName(name);
644 DCHECK(ranges) << name;
645 unlogged_samples_ =
646 std::make_unique<PersistentSampleVector>(name, id, ranges, meta, counts);
Peter Boströmfd851232021-03-31 17:05:33647 logged_samples_ = std::make_unique<PersistentSampleVector>(
Roger McFarlaned9048a02025-04-14 16:22:01648 name, id, ranges, logged_meta, logged_counts);
bcwhite5cb99eb2016-02-01 21:07:56649}
650
Chris Watkinsbb7211c2017-11-29 07:16:38651Histogram::~Histogram() = default;
[email protected]abae9b022012-10-24 08:18:52652
Tom Sepeze9a541c52024-10-23 22:47:51653std::string Histogram::GetAsciiBucketRange(size_t i) const {
[email protected]f2bb3202013-04-05 21:21:54654 return GetSimpleAsciiBucketRange(ranges(i));
[email protected]34d062322012-08-01 21:34:08655}
656
[email protected]34d062322012-08-01 21:34:08657//------------------------------------------------------------------------------
658// Private methods
659
[email protected]c50c21d2013-01-11 21:52:44660// static
661HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14662 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44663 int flags;
664 int declared_min;
665 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:45666 size_t bucket_count;
avi9b6f42932015-12-26 22:15:14667 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44668
669 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
670 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45671 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44672 }
673
674 // Find or create the local version of the histogram in this process.
675 HistogramBase* histogram = Histogram::FactoryGet(
676 histogram_name, declared_min, declared_max, bucket_count, flags);
Peter Kasting134ef9af2024-12-28 02:30:09677 if (!histogram) {
Brian White7eb91482017-08-09 19:54:45678 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09679 }
[email protected]c50c21d2013-01-11 21:52:44680
Brian White7eb91482017-08-09 19:54:45681 // The serialized histogram might be corrupted.
Peter Kasting134ef9af2024-12-28 02:30:09682 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
Brian White7eb91482017-08-09 19:54:45683 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09684 }
Brian White7eb91482017-08-09 19:54:45685
[email protected]c50c21d2013-01-11 21:52:44686 return histogram;
687}
688
Alex Ilin84f845b2024-01-15 19:51:04689// static
690HistogramBase* Histogram::FactoryGetInternal(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17691 Sample32 minimum,
692 Sample32 maximum,
Alex Ilin84f845b2024-01-15 19:51:04693 size_t bucket_count,
694 int32_t flags) {
695 bool valid_arguments =
696 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
697 DCHECK(valid_arguments) << name;
698 if (!valid_arguments) {
699 DLOG(ERROR) << "Histogram " << name << " dropped for invalid parameters.";
700 return DummyHistogram::GetInstance();
701 }
702
703 return Factory(name, minimum, maximum, bucket_count, flags).Build();
704}
705
706// static
707HistogramBase* Histogram::FactoryTimeGetInternal(std::string_view name,
708 TimeDelta minimum,
709 TimeDelta maximum,
710 size_t bucket_count,
711 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17712 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample32>::max());
713 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample32>::max());
714 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMilliseconds()),
715 static_cast<Sample32>(maximum.InMilliseconds()),
Alex Ilin84f845b2024-01-15 19:51:04716 bucket_count, flags);
717}
718
719// static
720HistogramBase* Histogram::FactoryMicrosecondsTimeGetInternal(
721 std::string_view name,
722 TimeDelta minimum,
723 TimeDelta maximum,
724 size_t bucket_count,
725 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17726 DCHECK_LT(minimum.InMicroseconds(), std::numeric_limits<Sample32>::max());
727 DCHECK_LT(maximum.InMicroseconds(), std::numeric_limits<Sample32>::max());
728 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMicroseconds()),
729 static_cast<Sample32>(maximum.InMicroseconds()),
Alex Ilin84f845b2024-01-15 19:51:04730 bucket_count, flags);
731}
732
altimin498c8382017-05-12 17:49:18733std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const {
Luc Nguyene01c6752022-12-01 18:40:15734 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamplesImpl();
altimin498c8382017-05-12 17:49:18735 samples->Add(*logged_samples_);
736 return samples;
737}
738
Luc Nguyene01c6752022-12-01 18:40:15739std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamplesImpl() const {
dcheng093de9b2016-04-04 21:25:51740 std::unique_ptr<SampleVector> samples(
altimin498c8382017-05-12 17:49:18741 new SampleVector(unlogged_samples_->id(), bucket_ranges()));
742 samples->Add(*unlogged_samples_);
danakj0c8d4aa2015-11-25 05:29:58743 return samples;
[email protected]877ef562012-10-20 02:56:18744}
745
Nathan Memmottc034fa4e2022-07-15 23:59:43746Value::Dict Histogram::GetParameters() const {
747 Value::Dict params;
748 params.Set("type", HistogramTypeToString(GetHistogramType()));
749 params.Set("min", declared_min());
750 params.Set("max", declared_max());
751 params.Set("bucket_count", static_cast<int>(bucket_count()));
Sylvain Defresne0348ecfd2021-06-23 08:27:34752 return params;
[email protected]24a7ec52012-10-08 10:31:50753}
754
[email protected]34d062322012-08-01 21:34:08755//------------------------------------------------------------------------------
756// LinearHistogram: This histogram uses a traditional set of evenly spaced
757// buckets.
758//------------------------------------------------------------------------------
759
bcwhite5cb99eb2016-02-01 21:07:56760class LinearHistogram::Factory : public Histogram::Factory {
761 public:
Alex Ilin84f845b2024-01-15 19:51:04762 Factory(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22763 Sample32 minimum,
764 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45765 size_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56766 int32_t flags,
767 const DescriptionPair* descriptions)
Peter Kastingfc94f5062022-06-08 16:41:45768 : Histogram::Factory(name,
769 LINEAR_HISTOGRAM,
770 minimum,
771 maximum,
772 bucket_count,
773 flags) {
bcwhite5cb99eb2016-02-01 21:07:56774 descriptions_ = descriptions;
775 }
776
Peter Boström75cd3c02021-09-28 15:23:18777 Factory(const Factory&) = delete;
778 Factory& operator=(const Factory&) = delete;
779
bcwhite5cb99eb2016-02-01 21:07:56780 protected:
781 BucketRanges* CreateRanges() override {
782 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
783 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
784 return ranges;
785 }
786
dcheng093de9b2016-04-04 21:25:51787 std::unique_ptr<HistogramBase> HeapAlloc(
788 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:04789 return WrapUnique(new LinearHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:56790 }
791
792 void FillHistogram(HistogramBase* base_histogram) override {
793 Histogram::Factory::FillHistogram(base_histogram);
Gayane Petrosyan5745ac62018-03-23 01:45:24794 // Normally, |base_histogram| should have type LINEAR_HISTOGRAM or be
795 // inherited from it. However, if it's expired, it will actually be a
796 // DUMMY_HISTOGRAM. Skip filling in that case.
Peter Kasting134ef9af2024-12-28 02:30:09797 if (base_histogram->GetHistogramType() == DUMMY_HISTOGRAM) {
Gayane Petrosyan5745ac62018-03-23 01:45:24798 return;
Peter Kasting134ef9af2024-12-28 02:30:09799 }
bcwhite5cb99eb2016-02-01 21:07:56800 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
801 // Set range descriptions.
802 if (descriptions_) {
803 for (int i = 0; descriptions_[i].description; ++i) {
804 histogram->bucket_description_[descriptions_[i].sample] =
805 descriptions_[i].description;
806 }
807 }
808 }
809
810 private:
Tom Sepezd83ed1b2023-09-19 00:10:00811 raw_ptr<const DescriptionPair, AllowPtrArithmetic> descriptions_;
bcwhite5cb99eb2016-02-01 21:07:56812};
813
Chris Watkinsbb7211c2017-11-29 07:16:38814LinearHistogram::~LinearHistogram() = default;
[email protected]34d062322012-08-01 21:34:08815
Alex Turnerbb5cb56e2024-08-12 17:12:42816HistogramBase* LinearHistogram::FactoryGet(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17817 Sample32 minimum,
818 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:42819 size_t bucket_count,
820 int32_t flags) {
821 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
822}
823
824HistogramBase* LinearHistogram::FactoryTimeGet(std::string_view name,
825 TimeDelta minimum,
826 TimeDelta maximum,
827 size_t bucket_count,
828 int32_t flags) {
829 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
830}
831
asvitkine24d3e9a2015-05-27 05:22:14832HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17833 Sample32 minimum,
834 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45835 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14836 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04837 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]07c02402012-10-31 06:20:25838}
839
asvitkine24d3e9a2015-05-27 05:22:14840HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17841 TimeDelta minimum,
842 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45843 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14844 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04845 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]07c02402012-10-31 06:20:25846}
847
asvitkine5c2d5022015-06-19 00:37:50848HistogramBase* LinearHistogram::FactoryGet(const char* name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17849 Sample32 minimum,
850 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45851 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14852 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04853 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50854}
855
856HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
857 TimeDelta minimum,
858 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45859 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14860 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04861 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50862}
863
dcheng093de9b2016-04-04 21:25:51864std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:27865 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:56866 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25867 const DelayedPersistentAllocation& counts,
868 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14869 HistogramSamples::Metadata* meta,
870 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:27871 return WrapUnique(new LinearHistogram(durable_name, ranges, counts,
872 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56873}
874
[email protected]de415552013-01-23 04:12:17875HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
Alex Ilin84f845b2024-01-15 19:51:04876 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17877 Sample32 minimum,
878 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45879 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14880 int32_t flags,
881 const DescriptionPair descriptions[]) {
Brian White564cedf2018-11-15 20:26:00882 // Originally, histograms were required to have at least one sample value
883 // plus underflow and overflow buckets. For single-entry enumerations,
884 // that one value is usually zero (which IS the underflow bucket)
885 // resulting in a |maximum| value of 1 (the exclusive upper-bound) and only
886 // the two outlier buckets. Handle this by making max==2 and buckets==3.
887 // This usually won't have any cost since the single-value-optimization
888 // will be used until the count exceeds 16 bits.
889 if (maximum == 1 && bucket_count == 2) {
890 maximum = 2;
891 bucket_count = 3;
892 }
893
[email protected]e184be902012-08-07 04:49:24894 bool valid_arguments = Histogram::InspectConstructionArguments(
895 name, &minimum, &maximum, &bucket_count);
Brian White226244e2018-12-20 23:11:39896 DCHECK(valid_arguments) << name;
Brian Whitea254ab842022-02-16 16:34:53897 if (!valid_arguments) {
898 DLOG(ERROR) << "Histogram " << name << " dropped for invalid parameters.";
899 return DummyHistogram::GetInstance();
900 }
[email protected]34d062322012-08-01 21:34:08901
bcwhite5cb99eb2016-02-01 21:07:56902 return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
903 .Build();
[email protected]34d062322012-08-01 21:34:08904}
905
[email protected]07c02402012-10-31 06:20:25906HistogramType LinearHistogram::GetHistogramType() const {
[email protected]b7d08202011-01-25 17:29:39907 return LINEAR_HISTOGRAM;
908}
909
Roger McFarlane89528592025-02-20 20:50:27910LinearHistogram::LinearHistogram(DurableStringView durable_name,
911 const BucketRanges* ranges)
912 : Histogram(durable_name, ranges) {}
initial.commitd7cae122008-07-26 21:49:38913
bcwhitefa8485b2017-05-01 16:43:25914LinearHistogram::LinearHistogram(
Roger McFarlane89528592025-02-20 20:50:27915 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:25916 const BucketRanges* ranges,
917 const DelayedPersistentAllocation& counts,
918 const DelayedPersistentAllocation& logged_counts,
919 HistogramSamples::Metadata* meta,
920 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:27921 : Histogram(durable_name,
922 ranges,
923 counts,
924 logged_counts,
925 meta,
926 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:56927
Tom Sepeze9a541c52024-10-23 22:47:51928std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
[email protected]b7d08202011-01-25 17:29:39929 int range = ranges(i);
Brian White61b84b22018-10-05 18:03:18930 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
Peter Kasting134ef9af2024-12-28 02:30:09931 if (it == bucket_description_.end()) {
[email protected]b7d08202011-01-25 17:29:39932 return Histogram::GetAsciiBucketRange(i);
Peter Kasting134ef9af2024-12-28 02:30:09933 }
[email protected]b7d08202011-01-25 17:29:39934 return it->second;
935}
936
[email protected]34d062322012-08-01 21:34:08937// static
Ramon Cano Aparicio4a39d122025-01-20 13:00:17938void LinearHistogram::InitializeBucketRanges(Sample32 minimum,
939 Sample32 maximum,
[email protected]34d062322012-08-01 21:34:08940 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08941 double min = minimum;
942 double max = maximum;
[email protected]15ce3842013-06-27 14:38:45943 size_t bucket_count = ranges->bucket_count();
Brian White61b84b22018-10-05 18:03:18944
[email protected]15ce3842013-06-27 14:38:45945 for (size_t i = 1; i < bucket_count; ++i) {
[email protected]34d062322012-08-01 21:34:08946 double linear_range =
[email protected]15ce3842013-06-27 14:38:45947 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
Ramon Cano Aparicio4a39d122025-01-20 13:00:17948 auto range = static_cast<Sample32>(linear_range + 0.5);
Brian White61b84b22018-10-05 18:03:18949 ranges->set_range(i, range);
[email protected]34d062322012-08-01 21:34:08950 }
[email protected]15ce3842013-06-27 14:38:45951 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08952 ranges->ResetChecksum();
953}
[email protected]b7d08202011-01-25 17:29:39954
[email protected]c50c21d2013-01-11 21:52:44955// static
Alex Ilin84f845b2024-01-15 19:51:04956HistogramBase* LinearHistogram::FactoryGetInternal(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17957 Sample32 minimum,
958 Sample32 maximum,
Alex Ilin84f845b2024-01-15 19:51:04959 size_t bucket_count,
960 int32_t flags) {
961 return FactoryGetWithRangeDescription(name, minimum, maximum, bucket_count,
962 flags, nullptr);
963}
964
965// static
966HistogramBase* LinearHistogram::FactoryTimeGetInternal(std::string_view name,
967 TimeDelta minimum,
968 TimeDelta maximum,
969 size_t bucket_count,
970 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17971 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample32>::max());
972 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample32>::max());
973 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMilliseconds()),
974 static_cast<Sample32>(maximum.InMilliseconds()),
Alex Ilin84f845b2024-01-15 19:51:04975 bucket_count, flags);
976}
977
978// static
[email protected]c50c21d2013-01-11 21:52:44979HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14980 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44981 int flags;
982 int declared_min;
983 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:45984 size_t bucket_count;
avi9b6f42932015-12-26 22:15:14985 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44986
987 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
988 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45989 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44990 }
991
992 HistogramBase* histogram = LinearHistogram::FactoryGet(
993 histogram_name, declared_min, declared_max, bucket_count, flags);
Peter Kasting134ef9af2024-12-28 02:30:09994 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:22995 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09996 }
Brian White82027ff5d2017-08-21 19:50:22997
[email protected]c50c21d2013-01-11 21:52:44998 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
999 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451000 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441001 }
1002 return histogram;
1003}
1004
initial.commitd7cae122008-07-26 21:49:381005//------------------------------------------------------------------------------
Brian Whitefffb3582018-05-24 21:17:011006// ScaledLinearHistogram: This is a wrapper around a LinearHistogram that
1007// scales input counts.
1008//------------------------------------------------------------------------------
1009
Alex Turnerbb5cb56e2024-08-12 17:12:421010ScaledLinearHistogram::ScaledLinearHistogram(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221011 Sample32 minimum,
1012 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:451013 size_t bucket_count,
Eric Seckler21a69f42020-07-10 14:18:171014 int32_t scale,
1015 int32_t flags)
Joshua Berenhaus9c88c1a22020-07-16 16:37:341016 : histogram_(LinearHistogram::FactoryGet(name,
1017 minimum,
1018 maximum,
1019 bucket_count,
1020 flags)),
Brian Whitefffb3582018-05-24 21:17:011021 scale_(scale) {
1022 DCHECK(histogram_);
1023 DCHECK_LT(1, scale);
1024 DCHECK_EQ(1, minimum);
Ramon Cano Aparicio79e06642025-01-09 19:10:221025 CHECK_EQ(static_cast<Sample32>(bucket_count), maximum - minimum + 2)
Brian Whitefffb3582018-05-24 21:17:011026 << " ScaledLinearHistogram requires buckets of size 1";
1027
Joshua Berenhaus9c88c1a22020-07-16 16:37:341028 // Normally, |histogram_| should have type LINEAR_HISTOGRAM or be
1029 // inherited from it. However, if it's expired, it will be DUMMY_HISTOGRAM.
Peter Kasting134ef9af2024-12-28 02:30:091030 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM) {
Joshua Berenhaus9c88c1a22020-07-16 16:37:341031 return;
Peter Kasting134ef9af2024-12-28 02:30:091032 }
Joshua Berenhaus9c88c1a22020-07-16 16:37:341033
1034 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
1035 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
1036 remainders_.resize(histogram->bucket_count(), 0);
Brian Whitefffb3582018-05-24 21:17:011037}
1038
Alex Turnerbb5cb56e2024-08-12 17:12:421039ScaledLinearHistogram::ScaledLinearHistogram(const std::string& name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221040 Sample32 minimum,
1041 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:421042 size_t bucket_count,
1043 int32_t scale,
1044 int32_t flags)
1045 : ScaledLinearHistogram(std::string_view(name),
1046 minimum,
1047 maximum,
1048 bucket_count,
1049 scale,
1050 flags) {}
1051
1052ScaledLinearHistogram::ScaledLinearHistogram(const char* name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221053 Sample32 minimum,
1054 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:421055 size_t bucket_count,
1056 int32_t scale,
1057 int32_t flags)
1058 : ScaledLinearHistogram(std::string_view(name),
1059 minimum,
1060 maximum,
1061 bucket_count,
1062 scale,
1063 flags) {}
1064
Brian Whitefffb3582018-05-24 21:17:011065ScaledLinearHistogram::~ScaledLinearHistogram() = default;
1066
Ramon Cano Aparicio79e06642025-01-09 19:10:221067void ScaledLinearHistogram::AddScaledCount(Sample32 value, int64_t count) {
Peter Kasting134ef9af2024-12-28 02:30:091068 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM) {
Joshua Berenhaus9c88c1a22020-07-16 16:37:341069 return;
Peter Kasting134ef9af2024-12-28 02:30:091070 }
1071 if (count == 0) {
Farah Charabb114f862018-06-12 11:53:571072 return;
Peter Kasting134ef9af2024-12-28 02:30:091073 }
Farah Charabb114f862018-06-12 11:53:571074 if (count < 0) {
Peter Boströmcb0d53062024-06-04 18:45:311075 DUMP_WILL_BE_NOTREACHED();
Farah Charabb114f862018-06-12 11:53:571076 return;
1077 }
Joshua Berenhaus9c88c1a22020-07-16 16:37:341078
1079 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
1080 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
Ramon Cano Aparicio79e06642025-01-09 19:10:221081 const auto max_value = static_cast<Sample32>(histogram->bucket_count() - 1);
Ho Cheung3f166bc2023-05-08 16:07:471082 value = std::clamp(value, 0, max_value);
Brian Whitefffb3582018-05-24 21:17:011083
Mikhail Khokhlovaa896052023-01-25 11:41:481084 int64_t scaled_count = count / scale_;
1085 subtle::Atomic32 remainder = static_cast<int>(count - scaled_count * scale_);
Brian Whitefffb3582018-05-24 21:17:011086
1087 // ScaledLinearHistogram currently requires 1-to-1 mappings between value
1088 // and bucket which alleviates the need to do a bucket lookup here (something
1089 // that is internal to the HistogramSamples object).
1090 if (remainder > 0) {
Peter Kastingfc94f5062022-06-08 16:41:451091 remainder = subtle::NoBarrier_AtomicIncrement(
1092 &remainders_[static_cast<size_t>(value)], remainder);
Brian Whitefffb3582018-05-24 21:17:011093 // If remainder passes 1/2 scale, increment main count (thus rounding up).
1094 // The remainder is decremented by the full scale, though, which will
Ramon Cano Apariciob2cba0f2025-01-22 21:26:101095 // cause it to go negative and thus require another increase by the full
Brian Whitefffb3582018-05-24 21:17:011096 // scale amount before another bump of the scaled count.
1097 if (remainder >= scale_ / 2) {
1098 scaled_count += 1;
Peter Kastingfc94f5062022-06-08 16:41:451099 subtle::NoBarrier_AtomicIncrement(
1100 &remainders_[static_cast<size_t>(value)], -scale_);
Brian Whitefffb3582018-05-24 21:17:011101 }
1102 }
1103
Mikhail Khokhlovaa896052023-01-25 11:41:481104 if (scaled_count > 0) {
wuguobin0914ace2024-12-20 10:50:451105 int capped_scaled_count = scaled_count > std::numeric_limits<int>::max()
1106 ? std::numeric_limits<int>::max()
1107 : static_cast<int>(scaled_count);
1108 histogram->AddCount(value, capped_scaled_count);
Mikhail Khokhlovaa896052023-01-25 11:41:481109 }
Brian Whitefffb3582018-05-24 21:17:011110}
1111
1112//------------------------------------------------------------------------------
[email protected]e8829a192009-12-06 00:09:371113// This section provides implementation for BooleanHistogram.
1114//------------------------------------------------------------------------------
1115
bcwhite5cb99eb2016-02-01 21:07:561116class BooleanHistogram::Factory : public Histogram::Factory {
1117 public:
Alex Ilin84f845b2024-01-15 19:51:041118 Factory(std::string_view name, int32_t flags)
1119 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
bcwhite5cb99eb2016-02-01 21:07:561120
Peter Boström75cd3c02021-09-28 15:23:181121 Factory(const Factory&) = delete;
1122 Factory& operator=(const Factory&) = delete;
1123
bcwhite5cb99eb2016-02-01 21:07:561124 protected:
1125 BucketRanges* CreateRanges() override {
1126 BucketRanges* ranges = new BucketRanges(3 + 1);
[email protected]15ce3842013-06-27 14:38:451127 LinearHistogram::InitializeBucketRanges(1, 2, ranges);
bcwhite5cb99eb2016-02-01 21:07:561128 return ranges;
[email protected]e8829a192009-12-06 00:09:371129 }
1130
dcheng093de9b2016-04-04 21:25:511131 std::unique_ptr<HistogramBase> HeapAlloc(
1132 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:041133 return WrapUnique(new BooleanHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561134 }
bcwhite5cb99eb2016-02-01 21:07:561135};
1136
Alex Turnerbb5cb56e2024-08-12 17:12:421137HistogramBase* BooleanHistogram::FactoryGet(std::string_view name,
1138 int32_t flags) {
1139 return FactoryGetInternal(name, flags);
1140}
1141
bcwhite5cb99eb2016-02-01 21:07:561142HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
1143 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041144 return FactoryGetInternal(name, flags);
[email protected]e8829a192009-12-06 00:09:371145}
1146
avi9b6f42932015-12-26 22:15:141147HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041148 return FactoryGetInternal(name, flags);
asvitkine5c2d5022015-06-19 00:37:501149}
1150
dcheng093de9b2016-04-04 21:25:511151std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:271152 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:561153 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251154 const DelayedPersistentAllocation& counts,
1155 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141156 HistogramSamples::Metadata* meta,
1157 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:271158 return WrapUnique(new BooleanHistogram(durable_name, ranges, counts,
1159 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561160}
1161
[email protected]07c02402012-10-31 06:20:251162HistogramType BooleanHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281163 return BOOLEAN_HISTOGRAM;
1164}
1165
Alex Ilin84f845b2024-01-15 19:51:041166// static
1167HistogramBase* BooleanHistogram::FactoryGetInternal(std::string_view name,
1168 int32_t flags) {
1169 return Factory(name, flags).Build();
1170}
1171
Roger McFarlane89528592025-02-20 20:50:271172BooleanHistogram::BooleanHistogram(DurableStringView durable_name,
1173 const BucketRanges* ranges)
1174 : LinearHistogram(durable_name, ranges) {}
initial.commitd7cae122008-07-26 21:49:381175
bcwhitefa8485b2017-05-01 16:43:251176BooleanHistogram::BooleanHistogram(
Roger McFarlane89528592025-02-20 20:50:271177 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:251178 const BucketRanges* ranges,
1179 const DelayedPersistentAllocation& counts,
1180 const DelayedPersistentAllocation& logged_counts,
1181 HistogramSamples::Metadata* meta,
1182 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:271183 : LinearHistogram(durable_name,
1184 ranges,
1185 counts,
1186 logged_counts,
1187 meta,
1188 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561189
[email protected]c50c21d2013-01-11 21:52:441190HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141191 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441192 int flags;
1193 int declared_min;
1194 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:451195 size_t bucket_count;
avi9b6f42932015-12-26 22:15:141196 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441197
1198 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1199 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451200 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441201 }
1202
Peter Kasting134ef9af2024-12-28 02:30:091203 HistogramBase* histogram =
1204 BooleanHistogram::FactoryGet(histogram_name, flags);
1205 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:221206 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091207 }
Brian White82027ff5d2017-08-21 19:50:221208
[email protected]c50c21d2013-01-11 21:52:441209 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1210 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451211 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441212 }
1213 return histogram;
1214}
1215
initial.commitd7cae122008-07-26 21:49:381216//------------------------------------------------------------------------------
[email protected]70cc56e42010-04-29 22:39:551217// CustomHistogram:
1218//------------------------------------------------------------------------------
1219
bcwhite5cb99eb2016-02-01 21:07:561220class CustomHistogram::Factory : public Histogram::Factory {
1221 public:
Alex Ilin84f845b2024-01-15 19:51:041222 Factory(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171223 const std::vector<Sample32>* custom_ranges,
bcwhite5cb99eb2016-02-01 21:07:561224 int32_t flags)
Alex Ilin84f845b2024-01-15 19:51:041225 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
bcwhite5cb99eb2016-02-01 21:07:561226 custom_ranges_ = custom_ranges;
1227 }
1228
Peter Boström75cd3c02021-09-28 15:23:181229 Factory(const Factory&) = delete;
1230 Factory& operator=(const Factory&) = delete;
1231
bcwhite5cb99eb2016-02-01 21:07:561232 protected:
1233 BucketRanges* CreateRanges() override {
1234 // Remove the duplicates in the custom ranges array.
1235 std::vector<int> ranges = *custom_ranges_;
1236 ranges.push_back(0); // Ensure we have a zero value.
1237 ranges.push_back(HistogramBase::kSampleType_MAX);
Peter Kasting025a94252025-01-29 21:28:371238 std::ranges::sort(ranges);
Peter Kastingbd9dde5c2025-01-08 12:48:221239 auto removed = std::ranges::unique(ranges);
1240 ranges.erase(removed.begin(), removed.end());
bcwhite5cb99eb2016-02-01 21:07:561241
1242 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
Peter Kastingfc94f5062022-06-08 16:41:451243 for (size_t i = 0; i < ranges.size(); i++) {
bcwhite5cb99eb2016-02-01 21:07:561244 bucket_ranges->set_range(i, ranges[i]);
1245 }
1246 bucket_ranges->ResetChecksum();
1247 return bucket_ranges;
1248 }
1249
dcheng093de9b2016-04-04 21:25:511250 std::unique_ptr<HistogramBase> HeapAlloc(
1251 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:041252 return WrapUnique(new CustomHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561253 }
1254
1255 private:
Ramon Cano Aparicio4a39d122025-01-20 13:00:171256 raw_ptr<const std::vector<Sample32>> custom_ranges_;
bcwhite5cb99eb2016-02-01 21:07:561257};
1258
asvitkine24d3e9a2015-05-27 05:22:141259HistogramBase* CustomHistogram::FactoryGet(
Alex Turnerbb5cb56e2024-08-12 17:12:421260 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171261 const std::vector<Sample32>& custom_ranges,
Alex Turnerbb5cb56e2024-08-12 17:12:421262 int32_t flags) {
1263 return FactoryGetInternal(name, custom_ranges, flags);
1264}
1265
1266HistogramBase* CustomHistogram::FactoryGet(
asvitkine24d3e9a2015-05-27 05:22:141267 const std::string& name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171268 const std::vector<Sample32>& custom_ranges,
avi9b6f42932015-12-26 22:15:141269 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041270 return FactoryGetInternal(name, custom_ranges, flags);
[email protected]70cc56e42010-04-29 22:39:551271}
1272
asvitkine5c2d5022015-06-19 00:37:501273HistogramBase* CustomHistogram::FactoryGet(
1274 const char* name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171275 const std::vector<Sample32>& custom_ranges,
avi9b6f42932015-12-26 22:15:141276 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041277 return FactoryGetInternal(name, custom_ranges, flags);
asvitkine5c2d5022015-06-19 00:37:501278}
1279
dcheng093de9b2016-04-04 21:25:511280std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:271281 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:561282 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251283 const DelayedPersistentAllocation& counts,
1284 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141285 HistogramSamples::Metadata* meta,
1286 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:271287 return WrapUnique(new CustomHistogram(durable_name, ranges, counts,
1288 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561289}
1290
[email protected]07c02402012-10-31 06:20:251291HistogramType CustomHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281292 return CUSTOM_HISTOGRAM;
1293}
1294
[email protected]961fefb2011-05-24 13:59:581295// static
Ramon Cano Aparicio79e06642025-01-09 19:10:221296std::vector<Sample32> CustomHistogram::ArrayToCustomEnumRanges(
Ramon Cano Aparicio4a39d122025-01-20 13:00:171297 base::span<const Sample32> values) {
1298 std::vector<Sample32> all_values;
1299 for (Sample32 value : values) {
[email protected]961fefb2011-05-24 13:59:581300 all_values.push_back(value);
1301
1302 // Ensure that a guard bucket is added. If we end up with duplicate
1303 // values, FactoryGet will take care of removing them.
1304 all_values.push_back(value + 1);
1305 }
1306 return all_values;
1307}
1308
Roger McFarlane89528592025-02-20 20:50:271309CustomHistogram::CustomHistogram(DurableStringView durable_name,
1310 const BucketRanges* ranges)
1311 : Histogram(durable_name, ranges) {}
[email protected]70cc56e42010-04-29 22:39:551312
bcwhitefa8485b2017-05-01 16:43:251313CustomHistogram::CustomHistogram(
Roger McFarlane89528592025-02-20 20:50:271314 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:251315 const BucketRanges* ranges,
1316 const DelayedPersistentAllocation& counts,
1317 const DelayedPersistentAllocation& logged_counts,
1318 HistogramSamples::Metadata* meta,
1319 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:271320 : Histogram(durable_name,
1321 ranges,
1322 counts,
1323 logged_counts,
1324 meta,
1325 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561326
Daniel Cheng0d89f9222017-09-22 05:05:071327void CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
1328 Histogram::SerializeInfoImpl(pickle);
[email protected]cd56dff2011-11-13 04:19:151329
Ramon Cano Apariciob2cba0f2025-01-22 21:26:101330 // Serialize ranges. First and last ranges are always 0 and INT_MAX, so don't
[email protected]c50c21d2013-01-11 21:52:441331 // write them.
Peter Kasting134ef9af2024-12-28 02:30:091332 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) {
Daniel Cheng0d89f9222017-09-22 05:05:071333 pickle->WriteInt(bucket_ranges()->range(i));
Peter Kasting134ef9af2024-12-28 02:30:091334 }
[email protected]cd56dff2011-11-13 04:19:151335}
1336
[email protected]34d062322012-08-01 21:34:081337// static
[email protected]c50c21d2013-01-11 21:52:441338HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141339 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441340 int flags;
1341 int declared_min;
1342 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:451343 size_t bucket_count;
avi9b6f42932015-12-26 22:15:141344 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441345
1346 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1347 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451348 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441349 }
1350
1351 // First and last ranges are not serialized.
Ramon Cano Aparicio4a39d122025-01-20 13:00:171352 std::vector<Sample32> sample_ranges(bucket_count - 1);
[email protected]c50c21d2013-01-11 21:52:441353
Ramon Cano Aparicio4a39d122025-01-20 13:00:171354 for (Sample32& sample : sample_ranges) {
Peter Kasting134ef9af2024-12-28 02:30:091355 if (!iter->ReadInt(&sample)) {
Brian White7eb91482017-08-09 19:54:451356 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091357 }
[email protected]c50c21d2013-01-11 21:52:441358 }
1359
Peter Kasting134ef9af2024-12-28 02:30:091360 HistogramBase* histogram =
1361 CustomHistogram::FactoryGet(histogram_name, sample_ranges, flags);
1362 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:221363 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091364 }
Brian White82027ff5d2017-08-21 19:50:221365
[email protected]c50c21d2013-01-11 21:52:441366 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1367 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451368 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441369 }
1370 return histogram;
1371}
1372
1373// static
Alex Ilin84f845b2024-01-15 19:51:041374HistogramBase* CustomHistogram::FactoryGetInternal(
1375 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171376 const std::vector<Sample32>& custom_ranges,
Alex Ilin84f845b2024-01-15 19:51:041377 int32_t flags) {
1378 CHECK(ValidateCustomRanges(custom_ranges));
1379
1380 return Factory(name, &custom_ranges, flags).Build();
1381}
1382
1383// static
[email protected]34d062322012-08-01 21:34:081384bool CustomHistogram::ValidateCustomRanges(
Ramon Cano Aparicio4a39d122025-01-20 13:00:171385 const std::vector<Sample32>& custom_ranges) {
[email protected]640d95e2012-08-04 06:23:031386 bool has_valid_range = false;
Ramon Cano Aparicio4a39d122025-01-20 13:00:171387 for (Sample32 sample : custom_ranges) {
Peter Kasting134ef9af2024-12-28 02:30:091388 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) {
[email protected]34d062322012-08-01 21:34:081389 return false;
Peter Kasting134ef9af2024-12-28 02:30:091390 }
1391 if (sample != 0) {
[email protected]640d95e2012-08-04 06:23:031392 has_valid_range = true;
Peter Kasting134ef9af2024-12-28 02:30:091393 }
[email protected]34d062322012-08-01 21:34:081394 }
[email protected]640d95e2012-08-04 06:23:031395 return has_valid_range;
[email protected]34d062322012-08-01 21:34:081396}
1397
Gabriel Charette8becf3e2024-06-07 00:47:201398namespace internal {
1399
1400namespace {
1401// The pointer to the atomic const-pointer also needs to be atomic as some
1402// threads might already be alive when it's set. It requires acquire-release
1403// semantics to ensure the memory it points to is seen in its initialized state.
1404constinit std::atomic<const std::atomic<TimeTicks>*> g_last_foreground_time_ref;
1405} // namespace
1406
1407void SetSharedLastForegroundTimeForMetrics(
1408 const std::atomic<TimeTicks>* last_foreground_time_ref) {
1409 g_last_foreground_time_ref.store(last_foreground_time_ref,
1410 std::memory_order_release);
1411}
1412
Joe Mason0c9a90a2024-09-25 16:41:381413const std::atomic<TimeTicks>*
1414GetSharedLastForegroundTimeForMetricsForTesting() {
1415 return g_last_foreground_time_ref.load(std::memory_order_acquire);
1416}
1417
Gabriel Charette8becf3e2024-06-07 00:47:201418bool OverlapsBestEffortRange(TimeTicks sample_time, TimeDelta sample_interval) {
1419 // std::memory_order_acquire semantics required as documented above to make
1420 // sure the memory pointed to by the stored `const std::atomic<TimeTicks>*`
1421 // is initialized from this thread's POV.
1422 auto last_foreground_time_ref =
1423 g_last_foreground_time_ref.load(std::memory_order_acquire);
1424 if (!last_foreground_time_ref) {
1425 return false;
1426 }
1427
1428 // std::memory_order_relaxed is sufficient here as we care about the stored
1429 // TimeTicks value but don't assume the state of any other shared memory based
1430 // on the result.
1431 auto last_foreground_time =
1432 last_foreground_time_ref->load(std::memory_order_relaxed);
1433 // `last_foreground_time.is_null()` indicates we're currently under
1434 // best-effort priority and thus assume overlap. Otherwise we compare whether
1435 // the range of interest is fully contained within the last time this process
1436 // was running at a foreground priority.
1437 return last_foreground_time.is_null() ||
1438 (sample_time - sample_interval) < last_foreground_time;
1439}
1440
1441} // namespace internal
1442
[email protected]835d7c82010-10-14 04:38:381443} // namespace base