blob: 3c8e7b3d8258d246f2274c95bf05096033996c59 [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) {
642 DCHECK(ranges) << histogram_name();
Peter Boströmfd851232021-03-31 17:05:33643 unlogged_samples_ = std::make_unique<PersistentSampleVector>(
Roger McFarlane89528592025-02-20 20:50:27644 HashMetricName(histogram_name()), ranges, meta, counts);
Peter Boströmfd851232021-03-31 17:05:33645 logged_samples_ = std::make_unique<PersistentSampleVector>(
646 unlogged_samples_->id(), ranges, logged_meta, logged_counts);
bcwhite5cb99eb2016-02-01 21:07:56647}
648
Chris Watkinsbb7211c2017-11-29 07:16:38649Histogram::~Histogram() = default;
[email protected]abae9b022012-10-24 08:18:52650
Tom Sepeze9a541c52024-10-23 22:47:51651std::string Histogram::GetAsciiBucketRange(size_t i) const {
[email protected]f2bb3202013-04-05 21:21:54652 return GetSimpleAsciiBucketRange(ranges(i));
[email protected]34d062322012-08-01 21:34:08653}
654
[email protected]34d062322012-08-01 21:34:08655//------------------------------------------------------------------------------
656// Private methods
657
[email protected]c50c21d2013-01-11 21:52:44658// static
659HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14660 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44661 int flags;
662 int declared_min;
663 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:45664 size_t bucket_count;
avi9b6f42932015-12-26 22:15:14665 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44666
667 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
668 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45669 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44670 }
671
672 // Find or create the local version of the histogram in this process.
673 HistogramBase* histogram = Histogram::FactoryGet(
674 histogram_name, declared_min, declared_max, bucket_count, flags);
Peter Kasting134ef9af2024-12-28 02:30:09675 if (!histogram) {
Brian White7eb91482017-08-09 19:54:45676 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09677 }
[email protected]c50c21d2013-01-11 21:52:44678
Brian White7eb91482017-08-09 19:54:45679 // The serialized histogram might be corrupted.
Peter Kasting134ef9af2024-12-28 02:30:09680 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
Brian White7eb91482017-08-09 19:54:45681 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09682 }
Brian White7eb91482017-08-09 19:54:45683
[email protected]c50c21d2013-01-11 21:52:44684 return histogram;
685}
686
Alex Ilin84f845b2024-01-15 19:51:04687// static
688HistogramBase* Histogram::FactoryGetInternal(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17689 Sample32 minimum,
690 Sample32 maximum,
Alex Ilin84f845b2024-01-15 19:51:04691 size_t bucket_count,
692 int32_t flags) {
693 bool valid_arguments =
694 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
695 DCHECK(valid_arguments) << name;
696 if (!valid_arguments) {
697 DLOG(ERROR) << "Histogram " << name << " dropped for invalid parameters.";
698 return DummyHistogram::GetInstance();
699 }
700
701 return Factory(name, minimum, maximum, bucket_count, flags).Build();
702}
703
704// static
705HistogramBase* Histogram::FactoryTimeGetInternal(std::string_view name,
706 TimeDelta minimum,
707 TimeDelta maximum,
708 size_t bucket_count,
709 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17710 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample32>::max());
711 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample32>::max());
712 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMilliseconds()),
713 static_cast<Sample32>(maximum.InMilliseconds()),
Alex Ilin84f845b2024-01-15 19:51:04714 bucket_count, flags);
715}
716
717// static
718HistogramBase* Histogram::FactoryMicrosecondsTimeGetInternal(
719 std::string_view name,
720 TimeDelta minimum,
721 TimeDelta maximum,
722 size_t bucket_count,
723 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17724 DCHECK_LT(minimum.InMicroseconds(), std::numeric_limits<Sample32>::max());
725 DCHECK_LT(maximum.InMicroseconds(), std::numeric_limits<Sample32>::max());
726 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMicroseconds()),
727 static_cast<Sample32>(maximum.InMicroseconds()),
Alex Ilin84f845b2024-01-15 19:51:04728 bucket_count, flags);
729}
730
altimin498c8382017-05-12 17:49:18731std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const {
Luc Nguyene01c6752022-12-01 18:40:15732 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamplesImpl();
altimin498c8382017-05-12 17:49:18733 samples->Add(*logged_samples_);
734 return samples;
735}
736
Luc Nguyene01c6752022-12-01 18:40:15737std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamplesImpl() const {
dcheng093de9b2016-04-04 21:25:51738 std::unique_ptr<SampleVector> samples(
altimin498c8382017-05-12 17:49:18739 new SampleVector(unlogged_samples_->id(), bucket_ranges()));
740 samples->Add(*unlogged_samples_);
danakj0c8d4aa2015-11-25 05:29:58741 return samples;
[email protected]877ef562012-10-20 02:56:18742}
743
Nathan Memmottc034fa4e2022-07-15 23:59:43744Value::Dict Histogram::GetParameters() const {
745 Value::Dict params;
746 params.Set("type", HistogramTypeToString(GetHistogramType()));
747 params.Set("min", declared_min());
748 params.Set("max", declared_max());
749 params.Set("bucket_count", static_cast<int>(bucket_count()));
Sylvain Defresne0348ecfd2021-06-23 08:27:34750 return params;
[email protected]24a7ec52012-10-08 10:31:50751}
752
[email protected]34d062322012-08-01 21:34:08753//------------------------------------------------------------------------------
754// LinearHistogram: This histogram uses a traditional set of evenly spaced
755// buckets.
756//------------------------------------------------------------------------------
757
bcwhite5cb99eb2016-02-01 21:07:56758class LinearHistogram::Factory : public Histogram::Factory {
759 public:
Alex Ilin84f845b2024-01-15 19:51:04760 Factory(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22761 Sample32 minimum,
762 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45763 size_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56764 int32_t flags,
765 const DescriptionPair* descriptions)
Peter Kastingfc94f5062022-06-08 16:41:45766 : Histogram::Factory(name,
767 LINEAR_HISTOGRAM,
768 minimum,
769 maximum,
770 bucket_count,
771 flags) {
bcwhite5cb99eb2016-02-01 21:07:56772 descriptions_ = descriptions;
773 }
774
Peter Boström75cd3c02021-09-28 15:23:18775 Factory(const Factory&) = delete;
776 Factory& operator=(const Factory&) = delete;
777
bcwhite5cb99eb2016-02-01 21:07:56778 protected:
779 BucketRanges* CreateRanges() override {
780 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
781 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
782 return ranges;
783 }
784
dcheng093de9b2016-04-04 21:25:51785 std::unique_ptr<HistogramBase> HeapAlloc(
786 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:04787 return WrapUnique(new LinearHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:56788 }
789
790 void FillHistogram(HistogramBase* base_histogram) override {
791 Histogram::Factory::FillHistogram(base_histogram);
Gayane Petrosyan5745ac62018-03-23 01:45:24792 // Normally, |base_histogram| should have type LINEAR_HISTOGRAM or be
793 // inherited from it. However, if it's expired, it will actually be a
794 // DUMMY_HISTOGRAM. Skip filling in that case.
Peter Kasting134ef9af2024-12-28 02:30:09795 if (base_histogram->GetHistogramType() == DUMMY_HISTOGRAM) {
Gayane Petrosyan5745ac62018-03-23 01:45:24796 return;
Peter Kasting134ef9af2024-12-28 02:30:09797 }
bcwhite5cb99eb2016-02-01 21:07:56798 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
799 // Set range descriptions.
800 if (descriptions_) {
801 for (int i = 0; descriptions_[i].description; ++i) {
802 histogram->bucket_description_[descriptions_[i].sample] =
803 descriptions_[i].description;
804 }
805 }
806 }
807
808 private:
Tom Sepezd83ed1b2023-09-19 00:10:00809 raw_ptr<const DescriptionPair, AllowPtrArithmetic> descriptions_;
bcwhite5cb99eb2016-02-01 21:07:56810};
811
Chris Watkinsbb7211c2017-11-29 07:16:38812LinearHistogram::~LinearHistogram() = default;
[email protected]34d062322012-08-01 21:34:08813
Alex Turnerbb5cb56e2024-08-12 17:12:42814HistogramBase* LinearHistogram::FactoryGet(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17815 Sample32 minimum,
816 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:42817 size_t bucket_count,
818 int32_t flags) {
819 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
820}
821
822HistogramBase* LinearHistogram::FactoryTimeGet(std::string_view name,
823 TimeDelta minimum,
824 TimeDelta maximum,
825 size_t bucket_count,
826 int32_t flags) {
827 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
828}
829
asvitkine24d3e9a2015-05-27 05:22:14830HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17831 Sample32 minimum,
832 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45833 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14834 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04835 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]07c02402012-10-31 06:20:25836}
837
asvitkine24d3e9a2015-05-27 05:22:14838HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17839 TimeDelta minimum,
840 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45841 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14842 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04843 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]07c02402012-10-31 06:20:25844}
845
asvitkine5c2d5022015-06-19 00:37:50846HistogramBase* LinearHistogram::FactoryGet(const char* name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17847 Sample32 minimum,
848 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45849 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14850 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04851 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50852}
853
854HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
855 TimeDelta minimum,
856 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45857 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14858 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04859 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50860}
861
dcheng093de9b2016-04-04 21:25:51862std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:27863 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:56864 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25865 const DelayedPersistentAllocation& counts,
866 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14867 HistogramSamples::Metadata* meta,
868 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:27869 return WrapUnique(new LinearHistogram(durable_name, ranges, counts,
870 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56871}
872
[email protected]de415552013-01-23 04:12:17873HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
Alex Ilin84f845b2024-01-15 19:51:04874 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17875 Sample32 minimum,
876 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45877 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14878 int32_t flags,
879 const DescriptionPair descriptions[]) {
Brian White564cedf2018-11-15 20:26:00880 // Originally, histograms were required to have at least one sample value
881 // plus underflow and overflow buckets. For single-entry enumerations,
882 // that one value is usually zero (which IS the underflow bucket)
883 // resulting in a |maximum| value of 1 (the exclusive upper-bound) and only
884 // the two outlier buckets. Handle this by making max==2 and buckets==3.
885 // This usually won't have any cost since the single-value-optimization
886 // will be used until the count exceeds 16 bits.
887 if (maximum == 1 && bucket_count == 2) {
888 maximum = 2;
889 bucket_count = 3;
890 }
891
[email protected]e184be902012-08-07 04:49:24892 bool valid_arguments = Histogram::InspectConstructionArguments(
893 name, &minimum, &maximum, &bucket_count);
Brian White226244e2018-12-20 23:11:39894 DCHECK(valid_arguments) << name;
Brian Whitea254ab842022-02-16 16:34:53895 if (!valid_arguments) {
896 DLOG(ERROR) << "Histogram " << name << " dropped for invalid parameters.";
897 return DummyHistogram::GetInstance();
898 }
[email protected]34d062322012-08-01 21:34:08899
bcwhite5cb99eb2016-02-01 21:07:56900 return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
901 .Build();
[email protected]34d062322012-08-01 21:34:08902}
903
[email protected]07c02402012-10-31 06:20:25904HistogramType LinearHistogram::GetHistogramType() const {
[email protected]b7d08202011-01-25 17:29:39905 return LINEAR_HISTOGRAM;
906}
907
Roger McFarlane89528592025-02-20 20:50:27908LinearHistogram::LinearHistogram(DurableStringView durable_name,
909 const BucketRanges* ranges)
910 : Histogram(durable_name, ranges) {}
initial.commitd7cae122008-07-26 21:49:38911
bcwhitefa8485b2017-05-01 16:43:25912LinearHistogram::LinearHistogram(
Roger McFarlane89528592025-02-20 20:50:27913 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:25914 const BucketRanges* ranges,
915 const DelayedPersistentAllocation& counts,
916 const DelayedPersistentAllocation& logged_counts,
917 HistogramSamples::Metadata* meta,
918 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:27919 : Histogram(durable_name,
920 ranges,
921 counts,
922 logged_counts,
923 meta,
924 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:56925
Tom Sepeze9a541c52024-10-23 22:47:51926std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
[email protected]b7d08202011-01-25 17:29:39927 int range = ranges(i);
Brian White61b84b22018-10-05 18:03:18928 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
Peter Kasting134ef9af2024-12-28 02:30:09929 if (it == bucket_description_.end()) {
[email protected]b7d08202011-01-25 17:29:39930 return Histogram::GetAsciiBucketRange(i);
Peter Kasting134ef9af2024-12-28 02:30:09931 }
[email protected]b7d08202011-01-25 17:29:39932 return it->second;
933}
934
[email protected]34d062322012-08-01 21:34:08935// static
Ramon Cano Aparicio4a39d122025-01-20 13:00:17936void LinearHistogram::InitializeBucketRanges(Sample32 minimum,
937 Sample32 maximum,
[email protected]34d062322012-08-01 21:34:08938 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08939 double min = minimum;
940 double max = maximum;
[email protected]15ce3842013-06-27 14:38:45941 size_t bucket_count = ranges->bucket_count();
Brian White61b84b22018-10-05 18:03:18942
[email protected]15ce3842013-06-27 14:38:45943 for (size_t i = 1; i < bucket_count; ++i) {
[email protected]34d062322012-08-01 21:34:08944 double linear_range =
[email protected]15ce3842013-06-27 14:38:45945 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
Ramon Cano Aparicio4a39d122025-01-20 13:00:17946 auto range = static_cast<Sample32>(linear_range + 0.5);
Brian White61b84b22018-10-05 18:03:18947 ranges->set_range(i, range);
[email protected]34d062322012-08-01 21:34:08948 }
[email protected]15ce3842013-06-27 14:38:45949 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08950 ranges->ResetChecksum();
951}
[email protected]b7d08202011-01-25 17:29:39952
[email protected]c50c21d2013-01-11 21:52:44953// static
Alex Ilin84f845b2024-01-15 19:51:04954HistogramBase* LinearHistogram::FactoryGetInternal(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17955 Sample32 minimum,
956 Sample32 maximum,
Alex Ilin84f845b2024-01-15 19:51:04957 size_t bucket_count,
958 int32_t flags) {
959 return FactoryGetWithRangeDescription(name, minimum, maximum, bucket_count,
960 flags, nullptr);
961}
962
963// static
964HistogramBase* LinearHistogram::FactoryTimeGetInternal(std::string_view name,
965 TimeDelta minimum,
966 TimeDelta maximum,
967 size_t bucket_count,
968 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17969 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample32>::max());
970 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample32>::max());
971 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMilliseconds()),
972 static_cast<Sample32>(maximum.InMilliseconds()),
Alex Ilin84f845b2024-01-15 19:51:04973 bucket_count, flags);
974}
975
976// static
[email protected]c50c21d2013-01-11 21:52:44977HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14978 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44979 int flags;
980 int declared_min;
981 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:45982 size_t bucket_count;
avi9b6f42932015-12-26 22:15:14983 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44984
985 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
986 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45987 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44988 }
989
990 HistogramBase* histogram = LinearHistogram::FactoryGet(
991 histogram_name, declared_min, declared_max, bucket_count, flags);
Peter Kasting134ef9af2024-12-28 02:30:09992 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:22993 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09994 }
Brian White82027ff5d2017-08-21 19:50:22995
[email protected]c50c21d2013-01-11 21:52:44996 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
997 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:45998 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44999 }
1000 return histogram;
1001}
1002
initial.commitd7cae122008-07-26 21:49:381003//------------------------------------------------------------------------------
Brian Whitefffb3582018-05-24 21:17:011004// ScaledLinearHistogram: This is a wrapper around a LinearHistogram that
1005// scales input counts.
1006//------------------------------------------------------------------------------
1007
Alex Turnerbb5cb56e2024-08-12 17:12:421008ScaledLinearHistogram::ScaledLinearHistogram(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221009 Sample32 minimum,
1010 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:451011 size_t bucket_count,
Eric Seckler21a69f42020-07-10 14:18:171012 int32_t scale,
1013 int32_t flags)
Joshua Berenhaus9c88c1a22020-07-16 16:37:341014 : histogram_(LinearHistogram::FactoryGet(name,
1015 minimum,
1016 maximum,
1017 bucket_count,
1018 flags)),
Brian Whitefffb3582018-05-24 21:17:011019 scale_(scale) {
1020 DCHECK(histogram_);
1021 DCHECK_LT(1, scale);
1022 DCHECK_EQ(1, minimum);
Ramon Cano Aparicio79e06642025-01-09 19:10:221023 CHECK_EQ(static_cast<Sample32>(bucket_count), maximum - minimum + 2)
Brian Whitefffb3582018-05-24 21:17:011024 << " ScaledLinearHistogram requires buckets of size 1";
1025
Joshua Berenhaus9c88c1a22020-07-16 16:37:341026 // Normally, |histogram_| should have type LINEAR_HISTOGRAM or be
1027 // inherited from it. However, if it's expired, it will be DUMMY_HISTOGRAM.
Peter Kasting134ef9af2024-12-28 02:30:091028 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM) {
Joshua Berenhaus9c88c1a22020-07-16 16:37:341029 return;
Peter Kasting134ef9af2024-12-28 02:30:091030 }
Joshua Berenhaus9c88c1a22020-07-16 16:37:341031
1032 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
1033 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
1034 remainders_.resize(histogram->bucket_count(), 0);
Brian Whitefffb3582018-05-24 21:17:011035}
1036
Alex Turnerbb5cb56e2024-08-12 17:12:421037ScaledLinearHistogram::ScaledLinearHistogram(const std::string& name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221038 Sample32 minimum,
1039 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:421040 size_t bucket_count,
1041 int32_t scale,
1042 int32_t flags)
1043 : ScaledLinearHistogram(std::string_view(name),
1044 minimum,
1045 maximum,
1046 bucket_count,
1047 scale,
1048 flags) {}
1049
1050ScaledLinearHistogram::ScaledLinearHistogram(const char* name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221051 Sample32 minimum,
1052 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:421053 size_t bucket_count,
1054 int32_t scale,
1055 int32_t flags)
1056 : ScaledLinearHistogram(std::string_view(name),
1057 minimum,
1058 maximum,
1059 bucket_count,
1060 scale,
1061 flags) {}
1062
Brian Whitefffb3582018-05-24 21:17:011063ScaledLinearHistogram::~ScaledLinearHistogram() = default;
1064
Ramon Cano Aparicio79e06642025-01-09 19:10:221065void ScaledLinearHistogram::AddScaledCount(Sample32 value, int64_t count) {
Peter Kasting134ef9af2024-12-28 02:30:091066 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM) {
Joshua Berenhaus9c88c1a22020-07-16 16:37:341067 return;
Peter Kasting134ef9af2024-12-28 02:30:091068 }
1069 if (count == 0) {
Farah Charabb114f862018-06-12 11:53:571070 return;
Peter Kasting134ef9af2024-12-28 02:30:091071 }
Farah Charabb114f862018-06-12 11:53:571072 if (count < 0) {
Peter Boströmcb0d53062024-06-04 18:45:311073 DUMP_WILL_BE_NOTREACHED();
Farah Charabb114f862018-06-12 11:53:571074 return;
1075 }
Joshua Berenhaus9c88c1a22020-07-16 16:37:341076
1077 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
1078 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
Ramon Cano Aparicio79e06642025-01-09 19:10:221079 const auto max_value = static_cast<Sample32>(histogram->bucket_count() - 1);
Ho Cheung3f166bc2023-05-08 16:07:471080 value = std::clamp(value, 0, max_value);
Brian Whitefffb3582018-05-24 21:17:011081
Mikhail Khokhlovaa896052023-01-25 11:41:481082 int64_t scaled_count = count / scale_;
1083 subtle::Atomic32 remainder = static_cast<int>(count - scaled_count * scale_);
Brian Whitefffb3582018-05-24 21:17:011084
1085 // ScaledLinearHistogram currently requires 1-to-1 mappings between value
1086 // and bucket which alleviates the need to do a bucket lookup here (something
1087 // that is internal to the HistogramSamples object).
1088 if (remainder > 0) {
Peter Kastingfc94f5062022-06-08 16:41:451089 remainder = subtle::NoBarrier_AtomicIncrement(
1090 &remainders_[static_cast<size_t>(value)], remainder);
Brian Whitefffb3582018-05-24 21:17:011091 // If remainder passes 1/2 scale, increment main count (thus rounding up).
1092 // The remainder is decremented by the full scale, though, which will
Ramon Cano Apariciob2cba0f2025-01-22 21:26:101093 // cause it to go negative and thus require another increase by the full
Brian Whitefffb3582018-05-24 21:17:011094 // scale amount before another bump of the scaled count.
1095 if (remainder >= scale_ / 2) {
1096 scaled_count += 1;
Peter Kastingfc94f5062022-06-08 16:41:451097 subtle::NoBarrier_AtomicIncrement(
1098 &remainders_[static_cast<size_t>(value)], -scale_);
Brian Whitefffb3582018-05-24 21:17:011099 }
1100 }
1101
Mikhail Khokhlovaa896052023-01-25 11:41:481102 if (scaled_count > 0) {
wuguobin0914ace2024-12-20 10:50:451103 int capped_scaled_count = scaled_count > std::numeric_limits<int>::max()
1104 ? std::numeric_limits<int>::max()
1105 : static_cast<int>(scaled_count);
1106 histogram->AddCount(value, capped_scaled_count);
Mikhail Khokhlovaa896052023-01-25 11:41:481107 }
Brian Whitefffb3582018-05-24 21:17:011108}
1109
1110//------------------------------------------------------------------------------
[email protected]e8829a192009-12-06 00:09:371111// This section provides implementation for BooleanHistogram.
1112//------------------------------------------------------------------------------
1113
bcwhite5cb99eb2016-02-01 21:07:561114class BooleanHistogram::Factory : public Histogram::Factory {
1115 public:
Alex Ilin84f845b2024-01-15 19:51:041116 Factory(std::string_view name, int32_t flags)
1117 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
bcwhite5cb99eb2016-02-01 21:07:561118
Peter Boström75cd3c02021-09-28 15:23:181119 Factory(const Factory&) = delete;
1120 Factory& operator=(const Factory&) = delete;
1121
bcwhite5cb99eb2016-02-01 21:07:561122 protected:
1123 BucketRanges* CreateRanges() override {
1124 BucketRanges* ranges = new BucketRanges(3 + 1);
[email protected]15ce3842013-06-27 14:38:451125 LinearHistogram::InitializeBucketRanges(1, 2, ranges);
bcwhite5cb99eb2016-02-01 21:07:561126 return ranges;
[email protected]e8829a192009-12-06 00:09:371127 }
1128
dcheng093de9b2016-04-04 21:25:511129 std::unique_ptr<HistogramBase> HeapAlloc(
1130 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:041131 return WrapUnique(new BooleanHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561132 }
bcwhite5cb99eb2016-02-01 21:07:561133};
1134
Alex Turnerbb5cb56e2024-08-12 17:12:421135HistogramBase* BooleanHistogram::FactoryGet(std::string_view name,
1136 int32_t flags) {
1137 return FactoryGetInternal(name, flags);
1138}
1139
bcwhite5cb99eb2016-02-01 21:07:561140HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
1141 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041142 return FactoryGetInternal(name, flags);
[email protected]e8829a192009-12-06 00:09:371143}
1144
avi9b6f42932015-12-26 22:15:141145HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041146 return FactoryGetInternal(name, flags);
asvitkine5c2d5022015-06-19 00:37:501147}
1148
dcheng093de9b2016-04-04 21:25:511149std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:271150 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:561151 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251152 const DelayedPersistentAllocation& counts,
1153 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141154 HistogramSamples::Metadata* meta,
1155 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:271156 return WrapUnique(new BooleanHistogram(durable_name, ranges, counts,
1157 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561158}
1159
[email protected]07c02402012-10-31 06:20:251160HistogramType BooleanHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281161 return BOOLEAN_HISTOGRAM;
1162}
1163
Alex Ilin84f845b2024-01-15 19:51:041164// static
1165HistogramBase* BooleanHistogram::FactoryGetInternal(std::string_view name,
1166 int32_t flags) {
1167 return Factory(name, flags).Build();
1168}
1169
Roger McFarlane89528592025-02-20 20:50:271170BooleanHistogram::BooleanHistogram(DurableStringView durable_name,
1171 const BucketRanges* ranges)
1172 : LinearHistogram(durable_name, ranges) {}
initial.commitd7cae122008-07-26 21:49:381173
bcwhitefa8485b2017-05-01 16:43:251174BooleanHistogram::BooleanHistogram(
Roger McFarlane89528592025-02-20 20:50:271175 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:251176 const BucketRanges* ranges,
1177 const DelayedPersistentAllocation& counts,
1178 const DelayedPersistentAllocation& logged_counts,
1179 HistogramSamples::Metadata* meta,
1180 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:271181 : LinearHistogram(durable_name,
1182 ranges,
1183 counts,
1184 logged_counts,
1185 meta,
1186 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561187
[email protected]c50c21d2013-01-11 21:52:441188HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141189 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441190 int flags;
1191 int declared_min;
1192 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:451193 size_t bucket_count;
avi9b6f42932015-12-26 22:15:141194 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441195
1196 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1197 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451198 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441199 }
1200
Peter Kasting134ef9af2024-12-28 02:30:091201 HistogramBase* histogram =
1202 BooleanHistogram::FactoryGet(histogram_name, flags);
1203 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:221204 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091205 }
Brian White82027ff5d2017-08-21 19:50:221206
[email protected]c50c21d2013-01-11 21:52:441207 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1208 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451209 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441210 }
1211 return histogram;
1212}
1213
initial.commitd7cae122008-07-26 21:49:381214//------------------------------------------------------------------------------
[email protected]70cc56e42010-04-29 22:39:551215// CustomHistogram:
1216//------------------------------------------------------------------------------
1217
bcwhite5cb99eb2016-02-01 21:07:561218class CustomHistogram::Factory : public Histogram::Factory {
1219 public:
Alex Ilin84f845b2024-01-15 19:51:041220 Factory(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171221 const std::vector<Sample32>* custom_ranges,
bcwhite5cb99eb2016-02-01 21:07:561222 int32_t flags)
Alex Ilin84f845b2024-01-15 19:51:041223 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
bcwhite5cb99eb2016-02-01 21:07:561224 custom_ranges_ = custom_ranges;
1225 }
1226
Peter Boström75cd3c02021-09-28 15:23:181227 Factory(const Factory&) = delete;
1228 Factory& operator=(const Factory&) = delete;
1229
bcwhite5cb99eb2016-02-01 21:07:561230 protected:
1231 BucketRanges* CreateRanges() override {
1232 // Remove the duplicates in the custom ranges array.
1233 std::vector<int> ranges = *custom_ranges_;
1234 ranges.push_back(0); // Ensure we have a zero value.
1235 ranges.push_back(HistogramBase::kSampleType_MAX);
Peter Kasting025a94252025-01-29 21:28:371236 std::ranges::sort(ranges);
Peter Kastingbd9dde5c2025-01-08 12:48:221237 auto removed = std::ranges::unique(ranges);
1238 ranges.erase(removed.begin(), removed.end());
bcwhite5cb99eb2016-02-01 21:07:561239
1240 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
Peter Kastingfc94f5062022-06-08 16:41:451241 for (size_t i = 0; i < ranges.size(); i++) {
bcwhite5cb99eb2016-02-01 21:07:561242 bucket_ranges->set_range(i, ranges[i]);
1243 }
1244 bucket_ranges->ResetChecksum();
1245 return bucket_ranges;
1246 }
1247
dcheng093de9b2016-04-04 21:25:511248 std::unique_ptr<HistogramBase> HeapAlloc(
1249 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:041250 return WrapUnique(new CustomHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561251 }
1252
1253 private:
Ramon Cano Aparicio4a39d122025-01-20 13:00:171254 raw_ptr<const std::vector<Sample32>> custom_ranges_;
bcwhite5cb99eb2016-02-01 21:07:561255};
1256
asvitkine24d3e9a2015-05-27 05:22:141257HistogramBase* CustomHistogram::FactoryGet(
Alex Turnerbb5cb56e2024-08-12 17:12:421258 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171259 const std::vector<Sample32>& custom_ranges,
Alex Turnerbb5cb56e2024-08-12 17:12:421260 int32_t flags) {
1261 return FactoryGetInternal(name, custom_ranges, flags);
1262}
1263
1264HistogramBase* CustomHistogram::FactoryGet(
asvitkine24d3e9a2015-05-27 05:22:141265 const std::string& name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171266 const std::vector<Sample32>& custom_ranges,
avi9b6f42932015-12-26 22:15:141267 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041268 return FactoryGetInternal(name, custom_ranges, flags);
[email protected]70cc56e42010-04-29 22:39:551269}
1270
asvitkine5c2d5022015-06-19 00:37:501271HistogramBase* CustomHistogram::FactoryGet(
1272 const char* name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171273 const std::vector<Sample32>& custom_ranges,
avi9b6f42932015-12-26 22:15:141274 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041275 return FactoryGetInternal(name, custom_ranges, flags);
asvitkine5c2d5022015-06-19 00:37:501276}
1277
dcheng093de9b2016-04-04 21:25:511278std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:271279 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:561280 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251281 const DelayedPersistentAllocation& counts,
1282 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141283 HistogramSamples::Metadata* meta,
1284 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:271285 return WrapUnique(new CustomHistogram(durable_name, ranges, counts,
1286 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561287}
1288
[email protected]07c02402012-10-31 06:20:251289HistogramType CustomHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281290 return CUSTOM_HISTOGRAM;
1291}
1292
[email protected]961fefb2011-05-24 13:59:581293// static
Ramon Cano Aparicio79e06642025-01-09 19:10:221294std::vector<Sample32> CustomHistogram::ArrayToCustomEnumRanges(
Ramon Cano Aparicio4a39d122025-01-20 13:00:171295 base::span<const Sample32> values) {
1296 std::vector<Sample32> all_values;
1297 for (Sample32 value : values) {
[email protected]961fefb2011-05-24 13:59:581298 all_values.push_back(value);
1299
1300 // Ensure that a guard bucket is added. If we end up with duplicate
1301 // values, FactoryGet will take care of removing them.
1302 all_values.push_back(value + 1);
1303 }
1304 return all_values;
1305}
1306
Roger McFarlane89528592025-02-20 20:50:271307CustomHistogram::CustomHistogram(DurableStringView durable_name,
1308 const BucketRanges* ranges)
1309 : Histogram(durable_name, ranges) {}
[email protected]70cc56e42010-04-29 22:39:551310
bcwhitefa8485b2017-05-01 16:43:251311CustomHistogram::CustomHistogram(
Roger McFarlane89528592025-02-20 20:50:271312 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:251313 const BucketRanges* ranges,
1314 const DelayedPersistentAllocation& counts,
1315 const DelayedPersistentAllocation& logged_counts,
1316 HistogramSamples::Metadata* meta,
1317 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:271318 : Histogram(durable_name,
1319 ranges,
1320 counts,
1321 logged_counts,
1322 meta,
1323 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561324
Daniel Cheng0d89f9222017-09-22 05:05:071325void CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
1326 Histogram::SerializeInfoImpl(pickle);
[email protected]cd56dff2011-11-13 04:19:151327
Ramon Cano Apariciob2cba0f2025-01-22 21:26:101328 // Serialize ranges. First and last ranges are always 0 and INT_MAX, so don't
[email protected]c50c21d2013-01-11 21:52:441329 // write them.
Peter Kasting134ef9af2024-12-28 02:30:091330 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) {
Daniel Cheng0d89f9222017-09-22 05:05:071331 pickle->WriteInt(bucket_ranges()->range(i));
Peter Kasting134ef9af2024-12-28 02:30:091332 }
[email protected]cd56dff2011-11-13 04:19:151333}
1334
[email protected]34d062322012-08-01 21:34:081335// static
[email protected]c50c21d2013-01-11 21:52:441336HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141337 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441338 int flags;
1339 int declared_min;
1340 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:451341 size_t bucket_count;
avi9b6f42932015-12-26 22:15:141342 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441343
1344 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1345 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451346 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441347 }
1348
1349 // First and last ranges are not serialized.
Ramon Cano Aparicio4a39d122025-01-20 13:00:171350 std::vector<Sample32> sample_ranges(bucket_count - 1);
[email protected]c50c21d2013-01-11 21:52:441351
Ramon Cano Aparicio4a39d122025-01-20 13:00:171352 for (Sample32& sample : sample_ranges) {
Peter Kasting134ef9af2024-12-28 02:30:091353 if (!iter->ReadInt(&sample)) {
Brian White7eb91482017-08-09 19:54:451354 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091355 }
[email protected]c50c21d2013-01-11 21:52:441356 }
1357
Peter Kasting134ef9af2024-12-28 02:30:091358 HistogramBase* histogram =
1359 CustomHistogram::FactoryGet(histogram_name, sample_ranges, flags);
1360 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:221361 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091362 }
Brian White82027ff5d2017-08-21 19:50:221363
[email protected]c50c21d2013-01-11 21:52:441364 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1365 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451366 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441367 }
1368 return histogram;
1369}
1370
1371// static
Alex Ilin84f845b2024-01-15 19:51:041372HistogramBase* CustomHistogram::FactoryGetInternal(
1373 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171374 const std::vector<Sample32>& custom_ranges,
Alex Ilin84f845b2024-01-15 19:51:041375 int32_t flags) {
1376 CHECK(ValidateCustomRanges(custom_ranges));
1377
1378 return Factory(name, &custom_ranges, flags).Build();
1379}
1380
1381// static
[email protected]34d062322012-08-01 21:34:081382bool CustomHistogram::ValidateCustomRanges(
Ramon Cano Aparicio4a39d122025-01-20 13:00:171383 const std::vector<Sample32>& custom_ranges) {
[email protected]640d95ef2012-08-04 06:23:031384 bool has_valid_range = false;
Ramon Cano Aparicio4a39d122025-01-20 13:00:171385 for (Sample32 sample : custom_ranges) {
Peter Kasting134ef9af2024-12-28 02:30:091386 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) {
[email protected]34d062322012-08-01 21:34:081387 return false;
Peter Kasting134ef9af2024-12-28 02:30:091388 }
1389 if (sample != 0) {
[email protected]640d95ef2012-08-04 06:23:031390 has_valid_range = true;
Peter Kasting134ef9af2024-12-28 02:30:091391 }
[email protected]34d062322012-08-01 21:34:081392 }
[email protected]640d95ef2012-08-04 06:23:031393 return has_valid_range;
[email protected]34d062322012-08-01 21:34:081394}
1395
Gabriel Charette8becf3e2024-06-07 00:47:201396namespace internal {
1397
1398namespace {
1399// The pointer to the atomic const-pointer also needs to be atomic as some
1400// threads might already be alive when it's set. It requires acquire-release
1401// semantics to ensure the memory it points to is seen in its initialized state.
1402constinit std::atomic<const std::atomic<TimeTicks>*> g_last_foreground_time_ref;
1403} // namespace
1404
1405void SetSharedLastForegroundTimeForMetrics(
1406 const std::atomic<TimeTicks>* last_foreground_time_ref) {
1407 g_last_foreground_time_ref.store(last_foreground_time_ref,
1408 std::memory_order_release);
1409}
1410
Joe Mason0c9a90a2024-09-25 16:41:381411const std::atomic<TimeTicks>*
1412GetSharedLastForegroundTimeForMetricsForTesting() {
1413 return g_last_foreground_time_ref.load(std::memory_order_acquire);
1414}
1415
Gabriel Charette8becf3e2024-06-07 00:47:201416bool OverlapsBestEffortRange(TimeTicks sample_time, TimeDelta sample_interval) {
1417 // std::memory_order_acquire semantics required as documented above to make
1418 // sure the memory pointed to by the stored `const std::atomic<TimeTicks>*`
1419 // is initialized from this thread's POV.
1420 auto last_foreground_time_ref =
1421 g_last_foreground_time_ref.load(std::memory_order_acquire);
1422 if (!last_foreground_time_ref) {
1423 return false;
1424 }
1425
1426 // std::memory_order_relaxed is sufficient here as we care about the stored
1427 // TimeTicks value but don't assume the state of any other shared memory based
1428 // on the result.
1429 auto last_foreground_time =
1430 last_foreground_time_ref->load(std::memory_order_relaxed);
1431 // `last_foreground_time.is_null()` indicates we're currently under
1432 // best-effort priority and thus assume overlap. Otherwise we compare whether
1433 // the range of interest is fully contained within the last time this process
1434 // was running at a foreground priority.
1435 return last_foreground_time.is_null() ||
1436 (sample_time - sample_interval) < last_foreground_time;
1437}
1438
1439} // namespace internal
1440
[email protected]835d7c82010-10-14 04:38:381441} // namespace base