blob: d49f5ad5d1808c299453c37c8073a74c91eda154 [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() {
Ramon Cano Aparicio901ec6c2025-04-22 14:30:45160 uint64_t name_hash = HashMetricName(name_);
161 HistogramBase* histogram =
162 StatisticsRecorder::FindHistogram(name_hash, name_);
bcwhite5cb99eb2016-02-01 21:07:56163 if (!histogram) {
Toshiaki Tanakad917f462021-05-10 17:24:04164 bool should_record = StatisticsRecorder::ShouldRecordHistogram(
Ramon Cano Aparicio901ec6c2025-04-22 14:30:45165 ParseMetricHashTo32Bits(name_hash));
Peter Kasting134ef9af2024-12-28 02:30:09166 if (!should_record) {
Gayane Petrosyan5745ac62018-03-23 01:45:24167 return DummyHistogram::GetInstance();
Peter Kasting134ef9af2024-12-28 02:30:09168 }
bcwhite5cb99eb2016-02-01 21:07:56169 // To avoid racy destruction at shutdown, the following will be leaked.
bcwhite4ebd7272016-03-22 19:14:38170 const BucketRanges* created_ranges = CreateRanges();
Brian Whitee716f6e2018-09-27 21:01:46171
172 const BucketRanges* registered_ranges =
173 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
174
bcwhite5cb99eb2016-02-01 21:07:56175 // In most cases, the bucket-count, minimum, and maximum values are known
176 // when the code is written and so are passed in explicitly. In other
177 // cases (such as with a CustomHistogram), they are calculated dynamically
178 // at run-time. In the latter case, those ctor parameters are zero and
179 // the results extracted from the result of CreateRanges().
180 if (bucket_count_ == 0) {
Peter Kastingfc94f5062022-06-08 16:41:45181 bucket_count_ = registered_ranges->bucket_count();
bcwhite5cb99eb2016-02-01 21:07:56182 minimum_ = registered_ranges->range(1);
183 maximum_ = registered_ranges->range(bucket_count_ - 1);
184 }
bcwhitef1dec482017-07-06 14:39:11185 DCHECK_EQ(minimum_, registered_ranges->range(1));
186 DCHECK_EQ(maximum_, registered_ranges->range(bucket_count_ - 1));
bcwhite5cb99eb2016-02-01 21:07:56187
188 // Try to create the histogram using a "persistent" allocator. As of
bcwhite3dd85c4f2016-03-17 13:21:56189 // 2016-02-25, the availability of such is controlled by a base::Feature
bcwhite5cb99eb2016-02-01 21:07:56190 // that is off by default. If the allocator doesn't exist or if
191 // allocating from it fails, code below will allocate the histogram from
192 // the process heap.
bcwhite4ebd7272016-03-22 19:14:38193 PersistentHistogramAllocator::Reference histogram_ref = 0;
dcheng093de9b2016-04-04 21:25:51194 std::unique_ptr<HistogramBase> tentative_histogram;
bcwhite5e748c62016-04-06 02:03:53195 PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
bcwhite5cb99eb2016-02-01 21:07:56196 if (allocator) {
Ramon Cano Aparicio901ec6c2025-04-22 14:30:45197 // TODO(crbug.com/394149163): AllocateHistogram ends up calling
198 // CreateHistogram, which calls HashMetricName. We already have the hash,
199 // so we could pass it in.
bcwhite33d95806a2016-03-16 02:37:45200 tentative_histogram = allocator->AllocateHistogram(
Ramon Cano Aparicioeb4e3152025-05-09 14:26:57201 histogram_type_, name_, name_hash, minimum_, maximum_,
202 registered_ranges, flags_, &histogram_ref);
bcwhite5cb99eb2016-02-01 21:07:56203 }
204
205 // Handle the case where no persistent allocator is present or the
206 // persistent allocation fails (perhaps because it is full).
207 if (!tentative_histogram) {
bcwhite4ebd7272016-03-22 19:14:38208 DCHECK(!histogram_ref); // Should never have been set.
bcwhite5cb99eb2016-02-01 21:07:56209 flags_ &= ~HistogramBase::kIsPersistent;
Ramon Cano Aparicio901ec6c2025-04-22 14:30:45210 // TODO(crbug.com/394149163): HeapAlloc creates a new Histogram object,
211 // which calls HashMetricName. We already have the hash, so we could pass
212 // it in. We could also store it so we can use it directly in every
213 // HeapAlloc instead of passing it as a parameter.
bcwhite5cb99eb2016-02-01 21:07:56214 tentative_histogram = HeapAlloc(registered_ranges);
bcwhite3dd85c4f2016-03-17 13:21:56215 tentative_histogram->SetFlags(flags_);
bcwhite5cb99eb2016-02-01 21:07:56216 }
217
bcwhite33d95806a2016-03-16 02:37:45218 FillHistogram(tentative_histogram.get());
219
220 // Register this histogram with the StatisticsRecorder. Keep a copy of
221 // the pointer value to tell later whether the locally created histogram
222 // was registered or deleted. The type is "void" because it could point
223 // to released memory after the following line.
224 const void* tentative_histogram_ptr = tentative_histogram.get();
225 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
226 tentative_histogram.release());
bcwhite5cb99eb2016-02-01 21:07:56227
228 // Persistent histograms need some follow-up processing.
bcwhite4ebd7272016-03-22 19:14:38229 if (histogram_ref) {
bcwhite33d95806a2016-03-16 02:37:45230 allocator->FinalizeHistogram(histogram_ref,
231 histogram == tentative_histogram_ptr);
bcwhite5cb99eb2016-02-01 21:07:56232 }
233 }
234
Brian Whitea958cc72018-04-19 18:24:16235 if (histogram_type_ != histogram->GetHistogramType() ||
236 (bucket_count_ != 0 && !histogram->HasConstructionArguments(
237 minimum_, maximum_, bucket_count_))) {
bcwhite5cb99eb2016-02-01 21:07:56238 // The construction arguments do not match the existing histogram. This can
239 // come about if an extension updates in the middle of a chrome run and has
Brian Whitea958cc72018-04-19 18:24:16240 // changed one of them, or simply by bad code within Chrome itself. A NULL
241 // return would cause Chrome to crash; better to just record it for later
242 // analysis.
243 UmaHistogramSparse("Histogram.MismatchedConstructionArguments",
Ramon Cano Aparicio901ec6c2025-04-22 14:30:45244 static_cast<Sample32>(name_hash));
Alex Ilin84f845b2024-01-15 19:51:04245 DLOG(ERROR) << "Histogram " << name_
Brian Whitea958cc72018-04-19 18:24:16246 << " has mismatched construction arguments";
247 return DummyHistogram::GetInstance();
bcwhite5cb99eb2016-02-01 21:07:56248 }
249 return histogram;
250}
251
Alex Turnerbb5cb56e2024-08-12 17:12:42252HistogramBase* Histogram::FactoryGet(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22253 Sample32 minimum,
254 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:42255 size_t bucket_count,
256 int32_t flags) {
257 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
258}
259
260HistogramBase* Histogram::FactoryTimeGet(std::string_view name,
261 TimeDelta minimum,
262 TimeDelta maximum,
263 size_t bucket_count,
264 int32_t flags) {
265 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
266}
267
268HistogramBase* Histogram::FactoryMicrosecondsTimeGet(std::string_view name,
269 TimeDelta minimum,
270 TimeDelta maximum,
271 size_t bucket_count,
272 int32_t flags) {
273 return FactoryMicrosecondsTimeGetInternal(name, minimum, maximum,
274 bucket_count, flags);
275}
276
asvitkine24d3e9a2015-05-27 05:22:14277HistogramBase* Histogram::FactoryGet(const std::string& name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22278 Sample32 minimum,
279 Sample32 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 FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]e8829a192009-12-06 00:09:37283}
284
asvitkine24d3e9a2015-05-27 05:22:14285HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17286 TimeDelta minimum,
287 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45288 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14289 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04290 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]34d062322012-08-01 21:34:08291}
292
Gabriel Charette5ec205882018-05-22 18:07:31293HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const std::string& name,
294 TimeDelta minimum,
295 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45296 size_t bucket_count,
Gabriel Charette5ec205882018-05-22 18:07:31297 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04298 return FactoryMicrosecondsTimeGetInternal(name, minimum, maximum,
299 bucket_count, flags);
Gabriel Charette5ec205882018-05-22 18:07:31300}
301
asvitkine5c2d5022015-06-19 00:37:50302HistogramBase* Histogram::FactoryGet(const char* name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22303 Sample32 minimum,
304 Sample32 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 FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50308}
309
310HistogramBase* Histogram::FactoryTimeGet(const char* name,
311 TimeDelta minimum,
312 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45313 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14314 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04315 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50316}
317
Gabriel Charette5ec205882018-05-22 18:07:31318HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const char* name,
319 TimeDelta minimum,
320 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45321 size_t bucket_count,
Gabriel Charette5ec205882018-05-22 18:07:31322 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04323 return FactoryMicrosecondsTimeGetInternal(name, minimum, maximum,
324 bucket_count, flags);
Gabriel Charette5ec205882018-05-22 18:07:31325}
326
dcheng093de9b2016-04-04 21:25:51327std::unique_ptr<HistogramBase> Histogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:27328 DurableStringView durable_name,
bcwhitec85a1f822016-02-18 21:22:14329 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25330 const DelayedPersistentAllocation& counts,
331 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14332 HistogramSamples::Metadata* meta,
333 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:27334 return WrapUnique(new Histogram(durable_name, ranges, counts, logged_counts,
335 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56336}
337
[email protected]34d062322012-08-01 21:34:08338// Calculate what range of values are held in each bucket.
339// We have to be careful that we don't pick a ratio between starting points in
340// consecutive buckets that is sooo small, that the integer bounds are the same
341// (effectively making one bucket get no values). We need to avoid:
342// ranges(i) == ranges(i + 1)
343// To avoid that, we just do a fine-grained bucket width as far as we need to
344// until we get a ratio that moves us along at least 2 units at a time. From
345// that bucket onward we do use the exponential growth of buckets.
346//
347// static
Ramon Cano Aparicio79e06642025-01-09 19:10:22348void Histogram::InitializeBucketRanges(Sample32 minimum,
349 Sample32 maximum,
[email protected]34d062322012-08-01 21:34:08350 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08351 double log_max = log(static_cast<double>(maximum));
352 double log_ratio;
353 double log_next;
354 size_t bucket_index = 1;
Ramon Cano Aparicio79e06642025-01-09 19:10:22355 Sample32 current = minimum;
[email protected]34d062322012-08-01 21:34:08356 ranges->set_range(bucket_index, current);
[email protected]15ce3842013-06-27 14:38:45357 size_t bucket_count = ranges->bucket_count();
Brian White61b84b22018-10-05 18:03:18358
[email protected]34d062322012-08-01 21:34:08359 while (bucket_count > ++bucket_index) {
360 double log_current;
361 log_current = log(static_cast<double>(current));
Brian White2aaa8b01a2018-11-13 23:24:56362 debug::Alias(&log_current);
[email protected]34d062322012-08-01 21:34:08363 // Calculate the count'th root of the range.
364 log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
365 // See where the next bucket would start.
366 log_next = log_current + log_ratio;
Ramon Cano Aparicio79e06642025-01-09 19:10:22367 Sample32 next;
Peter Kasting8c3adfb2017-09-13 08:07:39368 next = static_cast<int>(std::round(exp(log_next)));
Peter Kasting134ef9af2024-12-28 02:30:09369 if (next > current) {
[email protected]34d062322012-08-01 21:34:08370 current = next;
Peter Kasting134ef9af2024-12-28 02:30:09371 } else {
[email protected]34d062322012-08-01 21:34:08372 ++current; // Just do a narrow bucket, and keep trying.
Peter Kasting134ef9af2024-12-28 02:30:09373 }
[email protected]34d062322012-08-01 21:34:08374 ranges->set_range(bucket_index, current);
375 }
[email protected]15ce3842013-06-27 14:38:45376 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08377 ranges->ResetChecksum();
378}
379
[email protected]2f7d9cd2012-09-22 03:42:12380// static
381const int Histogram::kCommonRaceBasedCountMismatch = 5;
[email protected]34d062322012-08-01 21:34:08382
bcwhitec85a1f822016-02-18 21:22:14383uint32_t Histogram::FindCorruption(const HistogramSamples& samples) const {
Peter Kastingfc94f5062022-06-08 16:41:45384 uint32_t inconsistencies = NO_INCONSISTENCIES;
Ramon Cano Aparicio79e06642025-01-09 19:10:22385 Sample32 previous_range = -1; // Bottom range is always 0.
Peter Kastingfc94f5062022-06-08 16:41:45386 for (size_t index = 0; index < bucket_count(); ++index) {
[email protected]34d062322012-08-01 21:34:08387 int new_range = ranges(index);
Peter Kasting134ef9af2024-12-28 02:30:09388 if (previous_range >= new_range) {
[email protected]34d062322012-08-01 21:34:08389 inconsistencies |= BUCKET_ORDER_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09390 }
[email protected]34d062322012-08-01 21:34:08391 previous_range = new_range;
392 }
393
Peter Kasting134ef9af2024-12-28 02:30:09394 if (!bucket_ranges()->HasValidChecksum()) {
[email protected]34d062322012-08-01 21:34:08395 inconsistencies |= RANGE_CHECKSUM_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09396 }
[email protected]34d062322012-08-01 21:34:08397
avi9b6f42932015-12-26 22:15:14398 int64_t delta64 = samples.redundant_count() - samples.TotalCount();
[email protected]34d062322012-08-01 21:34:08399 if (delta64 != 0) {
400 int delta = static_cast<int>(delta64);
Peter Kasting134ef9af2024-12-28 02:30:09401 if (delta != delta64) {
[email protected]34d062322012-08-01 21:34:08402 delta = INT_MAX; // Flag all giant errors as INT_MAX.
Peter Kasting134ef9af2024-12-28 02:30:09403 }
[email protected]34d062322012-08-01 21:34:08404 if (delta > 0) {
Peter Kasting134ef9af2024-12-28 02:30:09405 if (delta > kCommonRaceBasedCountMismatch) {
[email protected]34d062322012-08-01 21:34:08406 inconsistencies |= COUNT_HIGH_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09407 }
[email protected]34d062322012-08-01 21:34:08408 } else {
409 DCHECK_GT(0, delta);
Peter Kasting134ef9af2024-12-28 02:30:09410 if (-delta > kCommonRaceBasedCountMismatch) {
[email protected]34d062322012-08-01 21:34:08411 inconsistencies |= COUNT_LOW_ERROR;
Peter Kasting134ef9af2024-12-28 02:30:09412 }
[email protected]34d062322012-08-01 21:34:08413 }
414 }
[email protected]cc7dec212013-03-01 03:53:25415 return inconsistencies;
[email protected]34d062322012-08-01 21:34:08416}
417
Brian White32052d5b2017-08-07 16:46:57418const BucketRanges* Histogram::bucket_ranges() const {
419 return unlogged_samples_->bucket_ranges();
420}
421
Ramon Cano Aparicio79e06642025-01-09 19:10:22422Sample32 Histogram::declared_min() 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(1);
bcwhitef1dec482017-07-06 14:39:11428}
429
Ramon Cano Aparicio79e06642025-01-09 19:10:22430Sample32 Histogram::declared_max() const {
Brian White32052d5b2017-08-07 16:46:57431 const BucketRanges* ranges = bucket_ranges();
Peter Kasting134ef9af2024-12-28 02:30:09432 if (ranges->bucket_count() < 2) {
bcwhitef1dec482017-07-06 14:39:11433 return -1;
Peter Kasting134ef9af2024-12-28 02:30:09434 }
Brian White32052d5b2017-08-07 16:46:57435 return ranges->range(ranges->bucket_count() - 1);
bcwhitef1dec482017-07-06 14:39:11436}
437
Ramon Cano Aparicio79e06642025-01-09 19:10:22438Sample32 Histogram::ranges(size_t i) const {
Brian White32052d5b2017-08-07 16:46:57439 return bucket_ranges()->range(i);
[email protected]34d062322012-08-01 21:34:08440}
441
Peter Kastingfc94f5062022-06-08 16:41:45442size_t Histogram::bucket_count() const {
443 return bucket_ranges()->bucket_count();
[email protected]34d062322012-08-01 21:34:08444}
445
[email protected]34d062322012-08-01 21:34:08446// static
Helmut Januschka274c3802024-03-12 23:31:29447bool Histogram::InspectConstructionArguments(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17448 Sample32* minimum,
449 Sample32* maximum,
Peter Kastingfc94f5062022-06-08 16:41:45450 size_t* bucket_count) {
Brian White7cfaffb12018-11-15 16:51:31451 bool check_okay = true;
452
453 // Checks below must be done after any min/max swap.
454 if (*minimum > *maximum) {
Brian Whitea254ab842022-02-16 16:34:53455 DLOG(ERROR) << "Histogram: " << name << " has swapped minimum/maximum";
Brian White7cfaffb12018-11-15 16:51:31456 check_okay = false;
457 std::swap(*minimum, *maximum);
458 }
459
[email protected]34d062322012-08-01 21:34:08460 // Defensive code for backward compatibility.
461 if (*minimum < 1) {
Alison Gale59c007a2024-04-20 03:05:40462 // TODO(crbug.com/40211696): Temporarily disabled during cleanup.
Brian White9c8bb642022-02-22 18:19:12463 // DLOG(ERROR) << "Histogram: " << name << " has bad minimum: " << *minimum;
[email protected]34d062322012-08-01 21:34:08464 *minimum = 1;
Peter Kasting134ef9af2024-12-28 02:30:09465 if (*maximum < 1) {
Brian White7cfaffb12018-11-15 16:51:31466 *maximum = 1;
Peter Kasting134ef9af2024-12-28 02:30:09467 }
[email protected]34d062322012-08-01 21:34:08468 }
469 if (*maximum >= kSampleType_MAX) {
Brian Whitea254ab842022-02-16 16:34:53470 DLOG(ERROR) << "Histogram: " << name << " has bad maximum: " << *maximum;
[email protected]a5c7bd792012-08-02 00:29:04471 *maximum = kSampleType_MAX - 1;
[email protected]34d062322012-08-01 21:34:08472 }
Brian Whiteabfa2702019-04-03 17:00:54473 if (*bucket_count > kBucketCount_MAX) {
Brian White7cfaffb12018-11-15 16:51:31474 UmaHistogramSparse("Histogram.TooManyBuckets.1000",
Ramon Cano Aparicio4a39d122025-01-20 13:00:17475 static_cast<Sample32>(HashMetricName(name)));
Brian White226244e2018-12-20 23:11:39476
Brian White226244e2018-12-20 23:11:39477 // Blink.UseCounter legitimately has more than 1000 entries in its enum.
Alexei Svitkined67a4432020-10-13 22:31:21478 if (!StartsWith(name, "Blink.UseCounter")) {
Brian Whitea254ab842022-02-16 16:34:53479 DLOG(ERROR) << "Histogram: " << name
480 << " has bad bucket_count: " << *bucket_count << " (limit "
481 << kBucketCount_MAX << ")";
Brian Whiteabfa2702019-04-03 17:00:54482
Brian White226244e2018-12-20 23:11:39483 // Assume it's a mistake and limit to 100 buckets, plus under and over.
484 // If the DCHECK doesn't alert the user then hopefully the small number
485 // will be obvious on the dashboard. If not, then it probably wasn't
486 // important.
487 *bucket_count = 102;
488 check_okay = false;
489 }
bcwhiteaaf2d3452017-04-26 19:17:47490 }
Brian White7cfaffb12018-11-15 16:51:31491
492 // Ensure parameters are sane.
bcwhiteaaf2d3452017-04-26 19:17:47493 if (*maximum == *minimum) {
494 check_okay = false;
495 *maximum = *minimum + 1;
496 }
497 if (*bucket_count < 3) {
498 check_okay = false;
499 *bucket_count = 3;
500 }
Peter Kastingfc94f5062022-06-08 16:41:45501 // The swap at the top of the function guarantees this cast is safe.
502 const size_t max_buckets = static_cast<size_t>(*maximum - *minimum + 2);
503 if (*bucket_count > max_buckets) {
bcwhiteaaf2d3452017-04-26 19:17:47504 check_okay = false;
Peter Kastingfc94f5062022-06-08 16:41:45505 *bucket_count = max_buckets;
bcwhiteaaf2d3452017-04-26 19:17:47506 }
507
508 if (!check_okay) {
Ilya Sherman16d5d5f42017-12-08 00:32:44509 UmaHistogramSparse("Histogram.BadConstructionArguments",
Ramon Cano Aparicio4a39d122025-01-20 13:00:17510 static_cast<Sample32>(HashMetricName(name)));
bcwhiteaaf2d3452017-04-26 19:17:47511 }
512
513 return check_okay;
[email protected]34d062322012-08-01 21:34:08514}
515
bcwhiteb036e4322015-12-10 18:36:34516uint64_t Histogram::name_hash() const {
altimin498c8382017-05-12 17:49:18517 return unlogged_samples_->id();
bcwhiteb036e4322015-12-10 18:36:34518}
519
[email protected]07c02402012-10-31 06:20:25520HistogramType Histogram::GetHistogramType() const {
521 return HISTOGRAM;
522}
523
Ramon Cano Aparicio4a39d122025-01-20 13:00:17524bool Histogram::HasConstructionArguments(Sample32 expected_minimum,
525 Sample32 expected_maximum,
Peter Kastingfc94f5062022-06-08 16:41:45526 size_t expected_bucket_count) const {
bcwhitef1dec482017-07-06 14:39:11527 return (expected_bucket_count == bucket_count() &&
528 expected_minimum == declared_min() &&
529 expected_maximum == declared_max());
[email protected]abae9b022012-10-24 08:18:52530}
531
532void Histogram::Add(int value) {
amohammadkhan6779b5c32015-08-05 20:31:11533 AddCount(value, 1);
534}
535
536void Histogram::AddCount(int value, int count) {
[email protected]abae9b022012-10-24 08:18:52537 DCHECK_EQ(0, ranges(0));
[email protected]15ce3842013-06-27 14:38:45538 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
[email protected]abae9b022012-10-24 08:18:52539
Peter Kasting134ef9af2024-12-28 02:30:09540 if (value > kSampleType_MAX - 1) {
[email protected]abae9b022012-10-24 08:18:52541 value = kSampleType_MAX - 1;
Peter Kasting134ef9af2024-12-28 02:30:09542 }
543 if (value < 0) {
[email protected]abae9b022012-10-24 08:18:52544 value = 0;
Peter Kasting134ef9af2024-12-28 02:30:09545 }
amohammadkhan6779b5c32015-08-05 20:31:11546 if (count <= 0) {
Peter Boströmde573332024-08-26 20:42:45547 NOTREACHED();
amohammadkhan6779b5c32015-08-05 20:31:11548 }
altimin498c8382017-05-12 17:49:18549 unlogged_samples_->Accumulate(value, count);
simonhatchdf5a8142015-07-15 22:22:57550
Peter Kastingfa488992024-08-06 07:48:14551 if (StatisticsRecorder::have_active_callbacks()) [[unlikely]] {
Shakti Sahue0e07a0e2021-06-06 00:07:52552 FindAndRunCallbacks(value);
Peter Kastingfa488992024-08-06 07:48:14553 }
[email protected]abae9b022012-10-24 08:18:52554}
555
dcheng093de9b2016-04-04 21:25:51556std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
altimin498c8382017-05-12 17:49:18557 return SnapshotAllSamples();
[email protected]abae9b022012-10-24 08:18:52558}
559
Luc Nguyene01c6752022-12-01 18:40:15560std::unique_ptr<HistogramSamples> Histogram::SnapshotUnloggedSamples() const {
561 return SnapshotUnloggedSamplesImpl();
562}
563
564void Histogram::MarkSamplesAsLogged(const HistogramSamples& samples) {
565 // |final_delta_created_| only exists when DCHECK is on.
566#if DCHECK_IS_ON()
567 DCHECK(!final_delta_created_);
568#endif
569
570 unlogged_samples_->Subtract(samples);
571 logged_samples_->Add(samples);
572}
573
dcheng093de9b2016-04-04 21:25:51574std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() {
Luc Nguyene01c6752022-12-01 18:40:15575 // |final_delta_created_| only exists when DCHECK is on.
bcwhitef1dec482017-07-06 14:39:11576#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40577 DCHECK(!final_delta_created_);
bcwhitef1dec482017-07-06 14:39:11578#endif
579
altimin498c8382017-05-12 17:49:18580 // The code below has subtle thread-safety guarantees! All changes to
581 // the underlying SampleVectors use atomic integer operations, which guarantee
582 // eventual consistency, but do not guarantee full synchronization between
583 // different entries in the SampleVector. In particular, this means that
584 // concurrent updates to the histogram might result in the reported sum not
585 // matching the individual bucket counts; or there being some buckets that are
586 // logically updated "together", but end up being only partially updated when
587 // a snapshot is captured. Note that this is why it's important to subtract
588 // exactly the snapshotted unlogged samples, rather than simply resetting the
589 // vector: this way, the next snapshot will include any concurrent updates
590 // missed by the current snapshot.
bcwhite65e57d02016-05-13 14:39:40591
Luc Nguyen257ecb02023-04-11 21:09:41592 std::unique_ptr<HistogramSamples> snapshot =
593 std::make_unique<SampleVector>(unlogged_samples_->id(), bucket_ranges());
594 snapshot->Extract(*unlogged_samples_);
595 logged_samples_->Add(*snapshot);
altimin498c8382017-05-12 17:49:18596
bcwhitec85a1f822016-02-18 21:22:14597 return snapshot;
598}
599
bcwhite65e57d02016-05-13 14:39:40600std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
Luc Nguyene01c6752022-12-01 18:40:15601 // |final_delta_created_| only exists when DCHECK is on.
bcwhitef1dec482017-07-06 14:39:11602#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40603 DCHECK(!final_delta_created_);
604 final_delta_created_ = true;
bcwhitef1dec482017-07-06 14:39:11605#endif
bcwhite65e57d02016-05-13 14:39:40606
altimin498c8382017-05-12 17:49:18607 return SnapshotUnloggedSamples();
bcwhite65e57d02016-05-13 14:39:40608}
609
Alexei Svitkine1e86b0c892024-10-02 21:02:03610bool Histogram::AddSamples(const HistogramSamples& samples) {
611 return unlogged_samples_->Add(samples);
[email protected]c50c21d2013-01-11 21:52:44612}
613
614bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
altimin498c8382017-05-12 17:49:18615 return unlogged_samples_->AddFromPickle(iter);
[email protected]c50c21d2013-01-11 21:52:44616}
617
Nathan Memmottc034fa4e2022-07-15 23:59:43618base::Value::Dict Histogram::ToGraphDict() const {
Jun Kokatsu505af9f2020-05-05 11:59:47619 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
Quang Minh Tuan Nguyen39b1fed2021-03-16 00:49:38620 return snapshot->ToGraphDict(histogram_name(), flags());
Jun Kokatsu505af9f2020-05-05 11:59:47621}
622
Daniel Cheng0d89f9222017-09-22 05:05:07623void Histogram::SerializeInfoImpl(Pickle* pickle) const {
[email protected]c50c21d2013-01-11 21:52:44624 DCHECK(bucket_ranges()->HasValidChecksum());
Daniel Cheng0d89f9222017-09-22 05:05:07625 pickle->WriteString(histogram_name());
626 pickle->WriteInt(flags());
627 pickle->WriteInt(declared_min());
628 pickle->WriteInt(declared_max());
Peter Kastingfc94f5062022-06-08 16:41:45629 // Limited to kBucketCount_MAX, which fits in a uint32_t.
630 pickle->WriteUInt32(static_cast<uint32_t>(bucket_count()));
Daniel Cheng0d89f9222017-09-22 05:05:07631 pickle->WriteUInt32(bucket_ranges()->checksum());
[email protected]c50c21d2013-01-11 21:52:44632}
633
Roger McFarlane89528592025-02-20 20:50:27634Histogram::Histogram(DurableStringView durable_name, const BucketRanges* ranges)
635 : HistogramBase(durable_name) {
636 DCHECK(ranges) << histogram_name();
Peter Boströmfd851232021-03-31 17:05:33637 unlogged_samples_ =
Roger McFarlane89528592025-02-20 20:50:27638 std::make_unique<SampleVector>(HashMetricName(histogram_name()), ranges);
Peter Boströmfd851232021-03-31 17:05:33639 logged_samples_ =
640 std::make_unique<SampleVector>(unlogged_samples_->id(), ranges);
[email protected]abae9b022012-10-24 08:18:52641}
642
Roger McFarlane89528592025-02-20 20:50:27643Histogram::Histogram(DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:56644 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25645 const DelayedPersistentAllocation& counts,
646 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14647 HistogramSamples::Metadata* meta,
648 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:27649 : HistogramBase(durable_name) {
Roger McFarlaned9048a02025-04-14 16:22:01650 const auto name = histogram_name();
651 const auto id = HashMetricName(name);
652 DCHECK(ranges) << name;
653 unlogged_samples_ =
654 std::make_unique<PersistentSampleVector>(name, id, ranges, meta, counts);
Peter Boströmfd851232021-03-31 17:05:33655 logged_samples_ = std::make_unique<PersistentSampleVector>(
Roger McFarlaned9048a02025-04-14 16:22:01656 name, id, ranges, logged_meta, logged_counts);
bcwhite5cb99eb2016-02-01 21:07:56657}
658
Chris Watkinsbb7211c2017-11-29 07:16:38659Histogram::~Histogram() = default;
[email protected]abae9b022012-10-24 08:18:52660
Tom Sepeze9a541c52024-10-23 22:47:51661std::string Histogram::GetAsciiBucketRange(size_t i) const {
[email protected]f2bb3202013-04-05 21:21:54662 return GetSimpleAsciiBucketRange(ranges(i));
[email protected]34d062322012-08-01 21:34:08663}
664
[email protected]34d062322012-08-01 21:34:08665//------------------------------------------------------------------------------
666// Private methods
667
[email protected]c50c21d2013-01-11 21:52:44668// static
669HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14670 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44671 int flags;
672 int declared_min;
673 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:45674 size_t bucket_count;
avi9b6f42932015-12-26 22:15:14675 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44676
677 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
678 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45679 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44680 }
681
682 // Find or create the local version of the histogram in this process.
683 HistogramBase* histogram = Histogram::FactoryGet(
684 histogram_name, declared_min, declared_max, bucket_count, flags);
Peter Kasting134ef9af2024-12-28 02:30:09685 if (!histogram) {
Brian White7eb91482017-08-09 19:54:45686 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09687 }
[email protected]c50c21d2013-01-11 21:52:44688
Brian White7eb91482017-08-09 19:54:45689 // The serialized histogram might be corrupted.
Peter Kasting134ef9af2024-12-28 02:30:09690 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
Brian White7eb91482017-08-09 19:54:45691 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:09692 }
Brian White7eb91482017-08-09 19:54:45693
[email protected]c50c21d2013-01-11 21:52:44694 return histogram;
695}
696
Alex Ilin84f845b2024-01-15 19:51:04697// static
698HistogramBase* Histogram::FactoryGetInternal(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17699 Sample32 minimum,
700 Sample32 maximum,
Alex Ilin84f845b2024-01-15 19:51:04701 size_t bucket_count,
702 int32_t flags) {
703 bool valid_arguments =
704 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
705 DCHECK(valid_arguments) << name;
706 if (!valid_arguments) {
707 DLOG(ERROR) << "Histogram " << name << " dropped for invalid parameters.";
708 return DummyHistogram::GetInstance();
709 }
710
711 return Factory(name, minimum, maximum, bucket_count, flags).Build();
712}
713
714// static
715HistogramBase* Histogram::FactoryTimeGetInternal(std::string_view name,
716 TimeDelta minimum,
717 TimeDelta maximum,
718 size_t bucket_count,
719 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17720 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample32>::max());
721 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample32>::max());
722 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMilliseconds()),
723 static_cast<Sample32>(maximum.InMilliseconds()),
Alex Ilin84f845b2024-01-15 19:51:04724 bucket_count, flags);
725}
726
727// static
728HistogramBase* Histogram::FactoryMicrosecondsTimeGetInternal(
729 std::string_view name,
730 TimeDelta minimum,
731 TimeDelta maximum,
732 size_t bucket_count,
733 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17734 DCHECK_LT(minimum.InMicroseconds(), std::numeric_limits<Sample32>::max());
735 DCHECK_LT(maximum.InMicroseconds(), std::numeric_limits<Sample32>::max());
736 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMicroseconds()),
737 static_cast<Sample32>(maximum.InMicroseconds()),
Alex Ilin84f845b2024-01-15 19:51:04738 bucket_count, flags);
739}
740
altimin498c8382017-05-12 17:49:18741std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const {
Luc Nguyene01c6752022-12-01 18:40:15742 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamplesImpl();
altimin498c8382017-05-12 17:49:18743 samples->Add(*logged_samples_);
744 return samples;
745}
746
Luc Nguyene01c6752022-12-01 18:40:15747std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamplesImpl() const {
dcheng093de9b2016-04-04 21:25:51748 std::unique_ptr<SampleVector> samples(
altimin498c8382017-05-12 17:49:18749 new SampleVector(unlogged_samples_->id(), bucket_ranges()));
750 samples->Add(*unlogged_samples_);
danakj0c8d4aa2015-11-25 05:29:58751 return samples;
[email protected]877ef562012-10-20 02:56:18752}
753
Nathan Memmottc034fa4e2022-07-15 23:59:43754Value::Dict Histogram::GetParameters() const {
755 Value::Dict params;
756 params.Set("type", HistogramTypeToString(GetHistogramType()));
757 params.Set("min", declared_min());
758 params.Set("max", declared_max());
759 params.Set("bucket_count", static_cast<int>(bucket_count()));
Sylvain Defresne0348ecfd2021-06-23 08:27:34760 return params;
[email protected]24a7ec52012-10-08 10:31:50761}
762
[email protected]34d062322012-08-01 21:34:08763//------------------------------------------------------------------------------
764// LinearHistogram: This histogram uses a traditional set of evenly spaced
765// buckets.
766//------------------------------------------------------------------------------
767
bcwhite5cb99eb2016-02-01 21:07:56768class LinearHistogram::Factory : public Histogram::Factory {
769 public:
Alex Ilin84f845b2024-01-15 19:51:04770 Factory(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:22771 Sample32 minimum,
772 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45773 size_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56774 int32_t flags,
775 const DescriptionPair* descriptions)
Peter Kastingfc94f5062022-06-08 16:41:45776 : Histogram::Factory(name,
777 LINEAR_HISTOGRAM,
778 minimum,
779 maximum,
780 bucket_count,
781 flags) {
bcwhite5cb99eb2016-02-01 21:07:56782 descriptions_ = descriptions;
783 }
784
Peter Boström75cd3c02021-09-28 15:23:18785 Factory(const Factory&) = delete;
786 Factory& operator=(const Factory&) = delete;
787
bcwhite5cb99eb2016-02-01 21:07:56788 protected:
789 BucketRanges* CreateRanges() override {
790 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
791 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
792 return ranges;
793 }
794
dcheng093de9b2016-04-04 21:25:51795 std::unique_ptr<HistogramBase> HeapAlloc(
796 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:04797 return WrapUnique(new LinearHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:56798 }
799
800 void FillHistogram(HistogramBase* base_histogram) override {
801 Histogram::Factory::FillHistogram(base_histogram);
Gayane Petrosyan5745ac62018-03-23 01:45:24802 // Normally, |base_histogram| should have type LINEAR_HISTOGRAM or be
803 // inherited from it. However, if it's expired, it will actually be a
804 // DUMMY_HISTOGRAM. Skip filling in that case.
Peter Kasting134ef9af2024-12-28 02:30:09805 if (base_histogram->GetHistogramType() == DUMMY_HISTOGRAM) {
Gayane Petrosyan5745ac62018-03-23 01:45:24806 return;
Peter Kasting134ef9af2024-12-28 02:30:09807 }
bcwhite5cb99eb2016-02-01 21:07:56808 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
809 // Set range descriptions.
810 if (descriptions_) {
811 for (int i = 0; descriptions_[i].description; ++i) {
812 histogram->bucket_description_[descriptions_[i].sample] =
813 descriptions_[i].description;
814 }
815 }
816 }
817
818 private:
Tom Sepezd83ed1b2023-09-19 00:10:00819 raw_ptr<const DescriptionPair, AllowPtrArithmetic> descriptions_;
bcwhite5cb99eb2016-02-01 21:07:56820};
821
Chris Watkinsbb7211c2017-11-29 07:16:38822LinearHistogram::~LinearHistogram() = default;
[email protected]34d062322012-08-01 21:34:08823
Alex Turnerbb5cb56e2024-08-12 17:12:42824HistogramBase* LinearHistogram::FactoryGet(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17825 Sample32 minimum,
826 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:42827 size_t bucket_count,
828 int32_t flags) {
829 return FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
830}
831
832HistogramBase* LinearHistogram::FactoryTimeGet(std::string_view name,
833 TimeDelta minimum,
834 TimeDelta maximum,
835 size_t bucket_count,
836 int32_t flags) {
837 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
838}
839
asvitkine24d3e9a2015-05-27 05:22:14840HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17841 Sample32 minimum,
842 Sample32 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 FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]07c02402012-10-31 06:20:25846}
847
asvitkine24d3e9a2015-05-27 05:22:14848HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17849 TimeDelta minimum,
850 TimeDelta 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 FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
[email protected]07c02402012-10-31 06:20:25854}
855
asvitkine5c2d5022015-06-19 00:37:50856HistogramBase* LinearHistogram::FactoryGet(const char* name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17857 Sample32 minimum,
858 Sample32 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 FactoryGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50862}
863
864HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
865 TimeDelta minimum,
866 TimeDelta maximum,
Peter Kastingfc94f5062022-06-08 16:41:45867 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14868 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:04869 return FactoryTimeGetInternal(name, minimum, maximum, bucket_count, flags);
asvitkine5c2d5022015-06-19 00:37:50870}
871
dcheng093de9b2016-04-04 21:25:51872std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:27873 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:56874 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25875 const DelayedPersistentAllocation& counts,
876 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14877 HistogramSamples::Metadata* meta,
878 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:27879 return WrapUnique(new LinearHistogram(durable_name, ranges, counts,
880 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56881}
882
[email protected]de415552013-01-23 04:12:17883HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
Alex Ilin84f845b2024-01-15 19:51:04884 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17885 Sample32 minimum,
886 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:45887 size_t bucket_count,
avi9b6f42932015-12-26 22:15:14888 int32_t flags,
889 const DescriptionPair descriptions[]) {
Brian White564cedf2018-11-15 20:26:00890 // Originally, histograms were required to have at least one sample value
891 // plus underflow and overflow buckets. For single-entry enumerations,
892 // that one value is usually zero (which IS the underflow bucket)
893 // resulting in a |maximum| value of 1 (the exclusive upper-bound) and only
894 // the two outlier buckets. Handle this by making max==2 and buckets==3.
895 // This usually won't have any cost since the single-value-optimization
896 // will be used until the count exceeds 16 bits.
897 if (maximum == 1 && bucket_count == 2) {
898 maximum = 2;
899 bucket_count = 3;
900 }
901
[email protected]e184be902012-08-07 04:49:24902 bool valid_arguments = Histogram::InspectConstructionArguments(
903 name, &minimum, &maximum, &bucket_count);
Brian White226244e2018-12-20 23:11:39904 DCHECK(valid_arguments) << name;
Brian Whitea254ab842022-02-16 16:34:53905 if (!valid_arguments) {
906 DLOG(ERROR) << "Histogram " << name << " dropped for invalid parameters.";
907 return DummyHistogram::GetInstance();
908 }
[email protected]34d062322012-08-01 21:34:08909
bcwhite5cb99eb2016-02-01 21:07:56910 return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
911 .Build();
[email protected]34d062322012-08-01 21:34:08912}
913
[email protected]07c02402012-10-31 06:20:25914HistogramType LinearHistogram::GetHistogramType() const {
[email protected]b7d08202011-01-25 17:29:39915 return LINEAR_HISTOGRAM;
916}
917
Roger McFarlane89528592025-02-20 20:50:27918LinearHistogram::LinearHistogram(DurableStringView durable_name,
919 const BucketRanges* ranges)
920 : Histogram(durable_name, ranges) {}
initial.commitd7cae122008-07-26 21:49:38921
bcwhitefa8485b2017-05-01 16:43:25922LinearHistogram::LinearHistogram(
Roger McFarlane89528592025-02-20 20:50:27923 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:25924 const BucketRanges* ranges,
925 const DelayedPersistentAllocation& counts,
926 const DelayedPersistentAllocation& logged_counts,
927 HistogramSamples::Metadata* meta,
928 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:27929 : Histogram(durable_name,
930 ranges,
931 counts,
932 logged_counts,
933 meta,
934 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:56935
Tom Sepeze9a541c52024-10-23 22:47:51936std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
[email protected]b7d08202011-01-25 17:29:39937 int range = ranges(i);
Brian White61b84b22018-10-05 18:03:18938 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
Peter Kasting134ef9af2024-12-28 02:30:09939 if (it == bucket_description_.end()) {
[email protected]b7d08202011-01-25 17:29:39940 return Histogram::GetAsciiBucketRange(i);
Peter Kasting134ef9af2024-12-28 02:30:09941 }
[email protected]b7d08202011-01-25 17:29:39942 return it->second;
943}
944
[email protected]34d062322012-08-01 21:34:08945// static
Ramon Cano Aparicio4a39d122025-01-20 13:00:17946void LinearHistogram::InitializeBucketRanges(Sample32 minimum,
947 Sample32 maximum,
[email protected]34d062322012-08-01 21:34:08948 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08949 double min = minimum;
950 double max = maximum;
[email protected]15ce3842013-06-27 14:38:45951 size_t bucket_count = ranges->bucket_count();
Brian White61b84b22018-10-05 18:03:18952
[email protected]15ce3842013-06-27 14:38:45953 for (size_t i = 1; i < bucket_count; ++i) {
[email protected]34d062322012-08-01 21:34:08954 double linear_range =
[email protected]15ce3842013-06-27 14:38:45955 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
Ramon Cano Aparicio4a39d122025-01-20 13:00:17956 auto range = static_cast<Sample32>(linear_range + 0.5);
Brian White61b84b22018-10-05 18:03:18957 ranges->set_range(i, range);
[email protected]34d062322012-08-01 21:34:08958 }
[email protected]15ce3842013-06-27 14:38:45959 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08960 ranges->ResetChecksum();
961}
[email protected]b7d08202011-01-25 17:29:39962
[email protected]c50c21d2013-01-11 21:52:44963// static
Alex Ilin84f845b2024-01-15 19:51:04964HistogramBase* LinearHistogram::FactoryGetInternal(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:17965 Sample32 minimum,
966 Sample32 maximum,
Alex Ilin84f845b2024-01-15 19:51:04967 size_t bucket_count,
968 int32_t flags) {
969 return FactoryGetWithRangeDescription(name, minimum, maximum, bucket_count,
970 flags, nullptr);
971}
972
973// static
974HistogramBase* LinearHistogram::FactoryTimeGetInternal(std::string_view name,
975 TimeDelta minimum,
976 TimeDelta maximum,
977 size_t bucket_count,
978 int32_t flags) {
Ramon Cano Aparicio4a39d122025-01-20 13:00:17979 DCHECK_LT(minimum.InMilliseconds(), std::numeric_limits<Sample32>::max());
980 DCHECK_LT(maximum.InMilliseconds(), std::numeric_limits<Sample32>::max());
981 return FactoryGetInternal(name, static_cast<Sample32>(minimum.InMilliseconds()),
982 static_cast<Sample32>(maximum.InMilliseconds()),
Alex Ilin84f845b2024-01-15 19:51:04983 bucket_count, flags);
984}
985
986// static
[email protected]c50c21d2013-01-11 21:52:44987HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14988 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44989 int flags;
990 int declared_min;
991 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:45992 size_t bucket_count;
avi9b6f42932015-12-26 22:15:14993 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44994
995 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
996 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:45997 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44998 }
999
1000 HistogramBase* histogram = LinearHistogram::FactoryGet(
1001 histogram_name, declared_min, declared_max, bucket_count, flags);
Peter Kasting134ef9af2024-12-28 02:30:091002 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:221003 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091004 }
Brian White82027ff5d2017-08-21 19:50:221005
[email protected]c50c21d2013-01-11 21:52:441006 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1007 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451008 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441009 }
1010 return histogram;
1011}
1012
initial.commitd7cae122008-07-26 21:49:381013//------------------------------------------------------------------------------
Brian Whitefffb3582018-05-24 21:17:011014// ScaledLinearHistogram: This is a wrapper around a LinearHistogram that
1015// scales input counts.
1016//------------------------------------------------------------------------------
1017
Alex Turnerbb5cb56e2024-08-12 17:12:421018ScaledLinearHistogram::ScaledLinearHistogram(std::string_view name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221019 Sample32 minimum,
1020 Sample32 maximum,
Peter Kastingfc94f5062022-06-08 16:41:451021 size_t bucket_count,
Eric Seckler21a69f42020-07-10 14:18:171022 int32_t scale,
1023 int32_t flags)
Joshua Berenhaus9c88c1a22020-07-16 16:37:341024 : histogram_(LinearHistogram::FactoryGet(name,
1025 minimum,
1026 maximum,
1027 bucket_count,
1028 flags)),
Brian Whitefffb3582018-05-24 21:17:011029 scale_(scale) {
1030 DCHECK(histogram_);
1031 DCHECK_LT(1, scale);
1032 DCHECK_EQ(1, minimum);
Ramon Cano Aparicio79e06642025-01-09 19:10:221033 CHECK_EQ(static_cast<Sample32>(bucket_count), maximum - minimum + 2)
Brian Whitefffb3582018-05-24 21:17:011034 << " ScaledLinearHistogram requires buckets of size 1";
1035
Joshua Berenhaus9c88c1a22020-07-16 16:37:341036 // Normally, |histogram_| should have type LINEAR_HISTOGRAM or be
1037 // inherited from it. However, if it's expired, it will be DUMMY_HISTOGRAM.
Peter Kasting134ef9af2024-12-28 02:30:091038 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM) {
Joshua Berenhaus9c88c1a22020-07-16 16:37:341039 return;
Peter Kasting134ef9af2024-12-28 02:30:091040 }
Joshua Berenhaus9c88c1a22020-07-16 16:37:341041
1042 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
1043 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
1044 remainders_.resize(histogram->bucket_count(), 0);
Brian Whitefffb3582018-05-24 21:17:011045}
1046
Alex Turnerbb5cb56e2024-08-12 17:12:421047ScaledLinearHistogram::ScaledLinearHistogram(const std::string& name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221048 Sample32 minimum,
1049 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:421050 size_t bucket_count,
1051 int32_t scale,
1052 int32_t flags)
1053 : ScaledLinearHistogram(std::string_view(name),
1054 minimum,
1055 maximum,
1056 bucket_count,
1057 scale,
1058 flags) {}
1059
1060ScaledLinearHistogram::ScaledLinearHistogram(const char* name,
Ramon Cano Aparicio79e06642025-01-09 19:10:221061 Sample32 minimum,
1062 Sample32 maximum,
Alex Turnerbb5cb56e2024-08-12 17:12:421063 size_t bucket_count,
1064 int32_t scale,
1065 int32_t flags)
1066 : ScaledLinearHistogram(std::string_view(name),
1067 minimum,
1068 maximum,
1069 bucket_count,
1070 scale,
1071 flags) {}
1072
Brian Whitefffb3582018-05-24 21:17:011073ScaledLinearHistogram::~ScaledLinearHistogram() = default;
1074
Ramon Cano Aparicio79e06642025-01-09 19:10:221075void ScaledLinearHistogram::AddScaledCount(Sample32 value, int64_t count) {
Peter Kasting134ef9af2024-12-28 02:30:091076 if (histogram_->GetHistogramType() == DUMMY_HISTOGRAM) {
Joshua Berenhaus9c88c1a22020-07-16 16:37:341077 return;
Peter Kasting134ef9af2024-12-28 02:30:091078 }
1079 if (count == 0) {
Farah Charabb114f862018-06-12 11:53:571080 return;
Peter Kasting134ef9af2024-12-28 02:30:091081 }
Farah Charabb114f862018-06-12 11:53:571082 if (count < 0) {
Peter Boströmcb0d53062024-06-04 18:45:311083 DUMP_WILL_BE_NOTREACHED();
Farah Charabb114f862018-06-12 11:53:571084 return;
1085 }
Joshua Berenhaus9c88c1a22020-07-16 16:37:341086
1087 DCHECK_EQ(histogram_->GetHistogramType(), LINEAR_HISTOGRAM);
1088 LinearHistogram* histogram = static_cast<LinearHistogram*>(histogram_);
Ramon Cano Aparicio79e06642025-01-09 19:10:221089 const auto max_value = static_cast<Sample32>(histogram->bucket_count() - 1);
Ho Cheung3f166bc2023-05-08 16:07:471090 value = std::clamp(value, 0, max_value);
Brian Whitefffb3582018-05-24 21:17:011091
Mikhail Khokhlovaa896052023-01-25 11:41:481092 int64_t scaled_count = count / scale_;
1093 subtle::Atomic32 remainder = static_cast<int>(count - scaled_count * scale_);
Brian Whitefffb3582018-05-24 21:17:011094
1095 // ScaledLinearHistogram currently requires 1-to-1 mappings between value
1096 // and bucket which alleviates the need to do a bucket lookup here (something
1097 // that is internal to the HistogramSamples object).
1098 if (remainder > 0) {
Peter Kastingfc94f5062022-06-08 16:41:451099 remainder = subtle::NoBarrier_AtomicIncrement(
1100 &remainders_[static_cast<size_t>(value)], remainder);
Brian Whitefffb3582018-05-24 21:17:011101 // If remainder passes 1/2 scale, increment main count (thus rounding up).
1102 // The remainder is decremented by the full scale, though, which will
Ramon Cano Apariciob2cba0f2025-01-22 21:26:101103 // cause it to go negative and thus require another increase by the full
Brian Whitefffb3582018-05-24 21:17:011104 // scale amount before another bump of the scaled count.
1105 if (remainder >= scale_ / 2) {
1106 scaled_count += 1;
Peter Kastingfc94f5062022-06-08 16:41:451107 subtle::NoBarrier_AtomicIncrement(
1108 &remainders_[static_cast<size_t>(value)], -scale_);
Brian Whitefffb3582018-05-24 21:17:011109 }
1110 }
1111
Mikhail Khokhlovaa896052023-01-25 11:41:481112 if (scaled_count > 0) {
wuguobin0914ace2024-12-20 10:50:451113 int capped_scaled_count = scaled_count > std::numeric_limits<int>::max()
1114 ? std::numeric_limits<int>::max()
1115 : static_cast<int>(scaled_count);
1116 histogram->AddCount(value, capped_scaled_count);
Mikhail Khokhlovaa896052023-01-25 11:41:481117 }
Brian Whitefffb3582018-05-24 21:17:011118}
1119
1120//------------------------------------------------------------------------------
[email protected]e8829a192009-12-06 00:09:371121// This section provides implementation for BooleanHistogram.
1122//------------------------------------------------------------------------------
1123
bcwhite5cb99eb2016-02-01 21:07:561124class BooleanHistogram::Factory : public Histogram::Factory {
1125 public:
Alex Ilin84f845b2024-01-15 19:51:041126 Factory(std::string_view name, int32_t flags)
1127 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
bcwhite5cb99eb2016-02-01 21:07:561128
Peter Boström75cd3c02021-09-28 15:23:181129 Factory(const Factory&) = delete;
1130 Factory& operator=(const Factory&) = delete;
1131
bcwhite5cb99eb2016-02-01 21:07:561132 protected:
1133 BucketRanges* CreateRanges() override {
1134 BucketRanges* ranges = new BucketRanges(3 + 1);
[email protected]15ce3842013-06-27 14:38:451135 LinearHistogram::InitializeBucketRanges(1, 2, ranges);
bcwhite5cb99eb2016-02-01 21:07:561136 return ranges;
[email protected]e8829a192009-12-06 00:09:371137 }
1138
dcheng093de9b2016-04-04 21:25:511139 std::unique_ptr<HistogramBase> HeapAlloc(
1140 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:041141 return WrapUnique(new BooleanHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561142 }
bcwhite5cb99eb2016-02-01 21:07:561143};
1144
Alex Turnerbb5cb56e2024-08-12 17:12:421145HistogramBase* BooleanHistogram::FactoryGet(std::string_view name,
1146 int32_t flags) {
1147 return FactoryGetInternal(name, flags);
1148}
1149
bcwhite5cb99eb2016-02-01 21:07:561150HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
1151 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041152 return FactoryGetInternal(name, flags);
[email protected]e8829a192009-12-06 00:09:371153}
1154
avi9b6f42932015-12-26 22:15:141155HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041156 return FactoryGetInternal(name, flags);
asvitkine5c2d5022015-06-19 00:37:501157}
1158
dcheng093de9b2016-04-04 21:25:511159std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:271160 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:561161 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251162 const DelayedPersistentAllocation& counts,
1163 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141164 HistogramSamples::Metadata* meta,
1165 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:271166 return WrapUnique(new BooleanHistogram(durable_name, ranges, counts,
1167 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561168}
1169
[email protected]07c02402012-10-31 06:20:251170HistogramType BooleanHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281171 return BOOLEAN_HISTOGRAM;
1172}
1173
Alex Ilin84f845b2024-01-15 19:51:041174// static
1175HistogramBase* BooleanHistogram::FactoryGetInternal(std::string_view name,
1176 int32_t flags) {
1177 return Factory(name, flags).Build();
1178}
1179
Roger McFarlane89528592025-02-20 20:50:271180BooleanHistogram::BooleanHistogram(DurableStringView durable_name,
1181 const BucketRanges* ranges)
1182 : LinearHistogram(durable_name, ranges) {}
initial.commitd7cae122008-07-26 21:49:381183
bcwhitefa8485b2017-05-01 16:43:251184BooleanHistogram::BooleanHistogram(
Roger McFarlane89528592025-02-20 20:50:271185 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:251186 const BucketRanges* ranges,
1187 const DelayedPersistentAllocation& counts,
1188 const DelayedPersistentAllocation& logged_counts,
1189 HistogramSamples::Metadata* meta,
1190 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:271191 : LinearHistogram(durable_name,
1192 ranges,
1193 counts,
1194 logged_counts,
1195 meta,
1196 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561197
[email protected]c50c21d2013-01-11 21:52:441198HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141199 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441200 int flags;
1201 int declared_min;
1202 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:451203 size_t bucket_count;
avi9b6f42932015-12-26 22:15:141204 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441205
1206 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1207 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451208 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441209 }
1210
Peter Kasting134ef9af2024-12-28 02:30:091211 HistogramBase* histogram =
1212 BooleanHistogram::FactoryGet(histogram_name, flags);
1213 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:221214 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091215 }
Brian White82027ff5d2017-08-21 19:50:221216
[email protected]c50c21d2013-01-11 21:52:441217 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1218 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451219 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441220 }
1221 return histogram;
1222}
1223
initial.commitd7cae122008-07-26 21:49:381224//------------------------------------------------------------------------------
[email protected]70cc56e42010-04-29 22:39:551225// CustomHistogram:
1226//------------------------------------------------------------------------------
1227
bcwhite5cb99eb2016-02-01 21:07:561228class CustomHistogram::Factory : public Histogram::Factory {
1229 public:
Alex Ilin84f845b2024-01-15 19:51:041230 Factory(std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171231 const std::vector<Sample32>* custom_ranges,
bcwhite5cb99eb2016-02-01 21:07:561232 int32_t flags)
Alex Ilin84f845b2024-01-15 19:51:041233 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
bcwhite5cb99eb2016-02-01 21:07:561234 custom_ranges_ = custom_ranges;
1235 }
1236
Peter Boström75cd3c02021-09-28 15:23:181237 Factory(const Factory&) = delete;
1238 Factory& operator=(const Factory&) = delete;
1239
bcwhite5cb99eb2016-02-01 21:07:561240 protected:
1241 BucketRanges* CreateRanges() override {
1242 // Remove the duplicates in the custom ranges array.
1243 std::vector<int> ranges = *custom_ranges_;
1244 ranges.push_back(0); // Ensure we have a zero value.
1245 ranges.push_back(HistogramBase::kSampleType_MAX);
Peter Kasting025a94252025-01-29 21:28:371246 std::ranges::sort(ranges);
Peter Kastingbd9dde5c2025-01-08 12:48:221247 auto removed = std::ranges::unique(ranges);
1248 ranges.erase(removed.begin(), removed.end());
bcwhite5cb99eb2016-02-01 21:07:561249
1250 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
Peter Kastingfc94f5062022-06-08 16:41:451251 for (size_t i = 0; i < ranges.size(); i++) {
bcwhite5cb99eb2016-02-01 21:07:561252 bucket_ranges->set_range(i, ranges[i]);
1253 }
1254 bucket_ranges->ResetChecksum();
1255 return bucket_ranges;
1256 }
1257
dcheng093de9b2016-04-04 21:25:511258 std::unique_ptr<HistogramBase> HeapAlloc(
1259 const BucketRanges* ranges) override {
Alex Ilin84f845b2024-01-15 19:51:041260 return WrapUnique(new CustomHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561261 }
1262
1263 private:
Ramon Cano Aparicio4a39d122025-01-20 13:00:171264 raw_ptr<const std::vector<Sample32>> custom_ranges_;
bcwhite5cb99eb2016-02-01 21:07:561265};
1266
asvitkine24d3e9a2015-05-27 05:22:141267HistogramBase* CustomHistogram::FactoryGet(
Alex Turnerbb5cb56e2024-08-12 17:12:421268 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171269 const std::vector<Sample32>& custom_ranges,
Alex Turnerbb5cb56e2024-08-12 17:12:421270 int32_t flags) {
1271 return FactoryGetInternal(name, custom_ranges, flags);
1272}
1273
1274HistogramBase* CustomHistogram::FactoryGet(
asvitkine24d3e9a2015-05-27 05:22:141275 const std::string& name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171276 const std::vector<Sample32>& custom_ranges,
avi9b6f42932015-12-26 22:15:141277 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041278 return FactoryGetInternal(name, custom_ranges, flags);
[email protected]70cc56e42010-04-29 22:39:551279}
1280
asvitkine5c2d5022015-06-19 00:37:501281HistogramBase* CustomHistogram::FactoryGet(
1282 const char* name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171283 const std::vector<Sample32>& custom_ranges,
avi9b6f42932015-12-26 22:15:141284 int32_t flags) {
Alex Ilin84f845b2024-01-15 19:51:041285 return FactoryGetInternal(name, custom_ranges, flags);
asvitkine5c2d5022015-06-19 00:37:501286}
1287
dcheng093de9b2016-04-04 21:25:511288std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
Roger McFarlane89528592025-02-20 20:50:271289 DurableStringView durable_name,
bcwhite5cb99eb2016-02-01 21:07:561290 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251291 const DelayedPersistentAllocation& counts,
1292 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141293 HistogramSamples::Metadata* meta,
1294 HistogramSamples::Metadata* logged_meta) {
Roger McFarlane89528592025-02-20 20:50:271295 return WrapUnique(new CustomHistogram(durable_name, ranges, counts,
1296 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561297}
1298
[email protected]07c02402012-10-31 06:20:251299HistogramType CustomHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281300 return CUSTOM_HISTOGRAM;
1301}
1302
[email protected]961fefb2011-05-24 13:59:581303// static
Ramon Cano Aparicio79e06642025-01-09 19:10:221304std::vector<Sample32> CustomHistogram::ArrayToCustomEnumRanges(
Ramon Cano Aparicio4a39d122025-01-20 13:00:171305 base::span<const Sample32> values) {
1306 std::vector<Sample32> all_values;
1307 for (Sample32 value : values) {
[email protected]961fefb2011-05-24 13:59:581308 all_values.push_back(value);
1309
1310 // Ensure that a guard bucket is added. If we end up with duplicate
1311 // values, FactoryGet will take care of removing them.
1312 all_values.push_back(value + 1);
1313 }
1314 return all_values;
1315}
1316
Roger McFarlane89528592025-02-20 20:50:271317CustomHistogram::CustomHistogram(DurableStringView durable_name,
1318 const BucketRanges* ranges)
1319 : Histogram(durable_name, ranges) {}
[email protected]70cc56e42010-04-29 22:39:551320
bcwhitefa8485b2017-05-01 16:43:251321CustomHistogram::CustomHistogram(
Roger McFarlane89528592025-02-20 20:50:271322 DurableStringView durable_name,
bcwhitefa8485b2017-05-01 16:43:251323 const BucketRanges* ranges,
1324 const DelayedPersistentAllocation& counts,
1325 const DelayedPersistentAllocation& logged_counts,
1326 HistogramSamples::Metadata* meta,
1327 HistogramSamples::Metadata* logged_meta)
Roger McFarlane89528592025-02-20 20:50:271328 : Histogram(durable_name,
1329 ranges,
1330 counts,
1331 logged_counts,
1332 meta,
1333 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561334
Daniel Cheng0d89f9222017-09-22 05:05:071335void CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
1336 Histogram::SerializeInfoImpl(pickle);
[email protected]cd56dff2011-11-13 04:19:151337
Ramon Cano Apariciob2cba0f2025-01-22 21:26:101338 // Serialize ranges. First and last ranges are always 0 and INT_MAX, so don't
[email protected]c50c21d2013-01-11 21:52:441339 // write them.
Peter Kasting134ef9af2024-12-28 02:30:091340 for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) {
Daniel Cheng0d89f9222017-09-22 05:05:071341 pickle->WriteInt(bucket_ranges()->range(i));
Peter Kasting134ef9af2024-12-28 02:30:091342 }
[email protected]cd56dff2011-11-13 04:19:151343}
1344
[email protected]34d062322012-08-01 21:34:081345// static
[email protected]c50c21d2013-01-11 21:52:441346HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141347 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441348 int flags;
1349 int declared_min;
1350 int declared_max;
Peter Kastingfc94f5062022-06-08 16:41:451351 size_t bucket_count;
avi9b6f42932015-12-26 22:15:141352 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441353
1354 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1355 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451356 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441357 }
1358
1359 // First and last ranges are not serialized.
Ramon Cano Aparicio4a39d122025-01-20 13:00:171360 std::vector<Sample32> sample_ranges(bucket_count - 1);
[email protected]c50c21d2013-01-11 21:52:441361
Ramon Cano Aparicio4a39d122025-01-20 13:00:171362 for (Sample32& sample : sample_ranges) {
Peter Kasting134ef9af2024-12-28 02:30:091363 if (!iter->ReadInt(&sample)) {
Brian White7eb91482017-08-09 19:54:451364 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091365 }
[email protected]c50c21d2013-01-11 21:52:441366 }
1367
Peter Kasting134ef9af2024-12-28 02:30:091368 HistogramBase* histogram =
1369 CustomHistogram::FactoryGet(histogram_name, sample_ranges, flags);
1370 if (!histogram) {
Brian White82027ff5d2017-08-21 19:50:221371 return nullptr;
Peter Kasting134ef9af2024-12-28 02:30:091372 }
Brian White82027ff5d2017-08-21 19:50:221373
[email protected]c50c21d2013-01-11 21:52:441374 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1375 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451376 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441377 }
1378 return histogram;
1379}
1380
1381// static
Alex Ilin84f845b2024-01-15 19:51:041382HistogramBase* CustomHistogram::FactoryGetInternal(
1383 std::string_view name,
Ramon Cano Aparicio4a39d122025-01-20 13:00:171384 const std::vector<Sample32>& custom_ranges,
Alex Ilin84f845b2024-01-15 19:51:041385 int32_t flags) {
1386 CHECK(ValidateCustomRanges(custom_ranges));
1387
1388 return Factory(name, &custom_ranges, flags).Build();
1389}
1390
1391// static
[email protected]34d062322012-08-01 21:34:081392bool CustomHistogram::ValidateCustomRanges(
Ramon Cano Aparicio4a39d122025-01-20 13:00:171393 const std::vector<Sample32>& custom_ranges) {
[email protected]640d95ef2012-08-04 06:23:031394 bool has_valid_range = false;
Ramon Cano Aparicio4a39d122025-01-20 13:00:171395 for (Sample32 sample : custom_ranges) {
Peter Kasting134ef9af2024-12-28 02:30:091396 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) {
[email protected]34d062322012-08-01 21:34:081397 return false;
Peter Kasting134ef9af2024-12-28 02:30:091398 }
1399 if (sample != 0) {
[email protected]640d95ef2012-08-04 06:23:031400 has_valid_range = true;
Peter Kasting134ef9af2024-12-28 02:30:091401 }
[email protected]34d062322012-08-01 21:34:081402 }
[email protected]640d95ef2012-08-04 06:23:031403 return has_valid_range;
[email protected]34d062322012-08-01 21:34:081404}
1405
Gabriel Charette8becf3e2024-06-07 00:47:201406namespace internal {
1407
1408namespace {
1409// The pointer to the atomic const-pointer also needs to be atomic as some
1410// threads might already be alive when it's set. It requires acquire-release
1411// semantics to ensure the memory it points to is seen in its initialized state.
1412constinit std::atomic<const std::atomic<TimeTicks>*> g_last_foreground_time_ref;
1413} // namespace
1414
1415void SetSharedLastForegroundTimeForMetrics(
1416 const std::atomic<TimeTicks>* last_foreground_time_ref) {
1417 g_last_foreground_time_ref.store(last_foreground_time_ref,
1418 std::memory_order_release);
1419}
1420
Joe Mason0c9a90a2024-09-25 16:41:381421const std::atomic<TimeTicks>*
1422GetSharedLastForegroundTimeForMetricsForTesting() {
1423 return g_last_foreground_time_ref.load(std::memory_order_acquire);
1424}
1425
Gabriel Charette8becf3e2024-06-07 00:47:201426bool OverlapsBestEffortRange(TimeTicks sample_time, TimeDelta sample_interval) {
1427 // std::memory_order_acquire semantics required as documented above to make
1428 // sure the memory pointed to by the stored `const std::atomic<TimeTicks>*`
1429 // is initialized from this thread's POV.
1430 auto last_foreground_time_ref =
1431 g_last_foreground_time_ref.load(std::memory_order_acquire);
1432 if (!last_foreground_time_ref) {
1433 return false;
1434 }
1435
1436 // std::memory_order_relaxed is sufficient here as we care about the stored
1437 // TimeTicks value but don't assume the state of any other shared memory based
1438 // on the result.
1439 auto last_foreground_time =
1440 last_foreground_time_ref->load(std::memory_order_relaxed);
1441 // `last_foreground_time.is_null()` indicates we're currently under
1442 // best-effort priority and thus assume overlap. Otherwise we compare whether
1443 // the range of interest is fully contained within the last time this process
1444 // was running at a foreground priority.
1445 return last_foreground_time.is_null() ||
1446 (sample_time - sample_interval) < last_foreground_time;
1447}
1448
1449} // namespace internal
1450
[email protected]835d7c82010-10-14 04:38:381451} // namespace base