blob: 716a02de805050caecc75e71a977ae1651d21717 [file] [log] [blame]
[email protected]a93721e22012-01-06 02:13:281// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
5// Histogram is an object that aggregates statistics, and can summarize them in
6// various forms, including ASCII graphical, HTML, and numerically (as a
7// vector of numbers corresponding to each of the aggregating buckets).
8// See header file for details and examples.
9
[email protected]835d7c82010-10-14 04:38:3810#include "base/metrics/histogram.h"
initial.commitd7cae122008-07-26 21:49:3811
Alexei Svitkinee73f80a02017-07-18 00:08:3912#include <inttypes.h>
avi9b6f42932015-12-26 22:15:1413#include <limits.h>
initial.commitd7cae122008-07-26 21:49:3814#include <math.h>
[email protected]f1633932010-08-17 23:05:2815
16#include <algorithm>
initial.commitd7cae122008-07-26 21:49:3817#include <string>
jdoerrief1e72e32017-04-26 16:23:5518#include <utility>
initial.commitd7cae122008-07-26 21:49:3819
[email protected]ec0c0aa2012-08-14 02:02:0020#include "base/compiler_specific.h"
21#include "base/debug/alias.h"
initial.commitd7cae122008-07-26 21:49:3822#include "base/logging.h"
dcheng093de9b2016-04-04 21:25:5123#include "base/memory/ptr_util.h"
Gayane Petrosyan5745ac62018-03-23 01:45:2424#include "base/metrics/dummy_histogram.h"
Ilya Sherman16d5d5f42017-12-08 00:32:4425#include "base/metrics/histogram_functions.h"
bcwhiteb036e4322015-12-10 18:36:3426#include "base/metrics/metrics_hashes.h"
bcwhite33d95806a2016-03-16 02:37:4527#include "base/metrics/persistent_histogram_allocator.h"
bcwhite5cb99eb2016-02-01 21:07:5628#include "base/metrics/persistent_memory_allocator.h"
[email protected]877ef562012-10-20 02:56:1829#include "base/metrics/sample_vector.h"
[email protected]567d30e2012-07-13 21:48:2930#include "base/metrics/statistics_recorder.h"
[email protected]3f383852009-04-03 18:18:5531#include "base/pickle.h"
[email protected]d529cb02013-06-10 19:06:5732#include "base/strings/string_util.h"
33#include "base/strings/stringprintf.h"
[email protected]bc581a682011-01-01 23:16:2034#include "base/synchronization/lock.h"
Brian White4eb39392018-05-09 12:49:2235#include "base/sys_info.h"
[email protected]24a7ec52012-10-08 10:31:5036#include "base/values.h"
Alexei Svitkinee73f80a02017-07-18 00:08:3937#include "build/build_config.h"
initial.commitd7cae122008-07-26 21:49:3838
[email protected]835d7c82010-10-14 04:38:3839namespace base {
[email protected]e1acf6f2008-10-27 20:43:3340
[email protected]c50c21d2013-01-11 21:52:4441namespace {
42
43bool ReadHistogramArguments(PickleIterator* iter,
asvitkine24d3e9a2015-05-27 05:22:1444 std::string* histogram_name,
[email protected]c50c21d2013-01-11 21:52:4445 int* flags,
46 int* declared_min,
47 int* declared_max,
jam1eacd7e2016-02-08 22:48:1648 uint32_t* bucket_count,
avi9b6f42932015-12-26 22:15:1449 uint32_t* range_checksum) {
[email protected]c50c21d2013-01-11 21:52:4450 if (!iter->ReadString(histogram_name) ||
51 !iter->ReadInt(flags) ||
52 !iter->ReadInt(declared_min) ||
53 !iter->ReadInt(declared_max) ||
jam1eacd7e2016-02-08 22:48:1654 !iter->ReadUInt32(bucket_count) ||
[email protected]c50c21d2013-01-11 21:52:4455 !iter->ReadUInt32(range_checksum)) {
56 DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
57 return false;
58 }
59
60 // Since these fields may have come from an untrusted renderer, do additional
61 // checks above and beyond those in Histogram::Initialize()
62 if (*declared_max <= 0 ||
63 *declared_min <= 0 ||
64 *declared_max < *declared_min ||
65 INT_MAX / sizeof(HistogramBase::Count) <= *bucket_count ||
66 *bucket_count < 2) {
67 DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
68 return false;
69 }
70
71 // We use the arguments to find or create the local version of the histogram
bcwhite05dc0922016-06-03 04:59:4472 // in this process, so we need to clear any IPC flag.
[email protected]c50c21d2013-01-11 21:52:4473 *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
74
75 return true;
76}
77
78bool ValidateRangeChecksum(const HistogramBase& histogram,
avi9b6f42932015-12-26 22:15:1479 uint32_t range_checksum) {
Gayane Petrosyan5745ac62018-03-23 01:45:2480 // Normally, |histogram| should have type HISTOGRAM or be inherited from it.
81 // However, if it's expired, it will actually be a DUMMY_HISTOGRAM.
82 // Skip the checks in that case.
83 if (histogram.GetHistogramType() == DUMMY_HISTOGRAM)
84 return true;
[email protected]c50c21d2013-01-11 21:52:4485 const Histogram& casted_histogram =
86 static_cast<const Histogram&>(histogram);
87
88 return casted_histogram.bucket_ranges()->checksum() == range_checksum;
89}
90
91} // namespace
92
[email protected]34d062322012-08-01 21:34:0893typedef HistogramBase::Count Count;
94typedef HistogramBase::Sample Sample;
initial.commitd7cae122008-07-26 21:49:3895
[email protected]b122c0c2011-02-23 22:31:1896// static
jam1eacd7e2016-02-08 22:48:1697const uint32_t Histogram::kBucketCount_MAX = 16384u;
[email protected]b122c0c2011-02-23 22:31:1898
bcwhite5cb99eb2016-02-01 21:07:5699class Histogram::Factory {
100 public:
101 Factory(const std::string& name,
102 HistogramBase::Sample minimum,
103 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16104 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56105 int32_t flags)
106 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
107
108 // Create histogram based on construction parameters. Caller takes
109 // ownership of the returned object.
110 HistogramBase* Build();
111
112 protected:
113 Factory(const std::string& name,
114 HistogramType histogram_type,
115 HistogramBase::Sample minimum,
116 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16117 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56118 int32_t flags)
119 : name_(name),
120 histogram_type_(histogram_type),
121 minimum_(minimum),
122 maximum_(maximum),
123 bucket_count_(bucket_count),
124 flags_(flags) {}
125
126 // Create a BucketRanges structure appropriate for this histogram.
127 virtual BucketRanges* CreateRanges() {
128 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
129 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges);
130 return ranges;
131 }
132
133 // Allocate the correct Histogram object off the heap (in case persistent
134 // memory is not available).
dcheng093de9b2016-04-04 21:25:51135 virtual std::unique_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) {
Brian Whited1c91082017-11-03 14:46:42136 return WrapUnique(
137 new Histogram(GetPermanentName(name_), minimum_, maximum_, ranges));
bcwhite5cb99eb2016-02-01 21:07:56138 }
139
140 // Perform any required datafill on the just-created histogram. If
bcwhite3dd85c4f2016-03-17 13:21:56141 // overridden, be sure to call the "super" version -- this method may not
142 // always remain empty.
143 virtual void FillHistogram(HistogramBase* histogram) {}
bcwhite5cb99eb2016-02-01 21:07:56144
145 // These values are protected (instead of private) because they need to
146 // be accessible to methods of sub-classes in order to avoid passing
147 // unnecessary parameters everywhere.
148 const std::string& name_;
149 const HistogramType histogram_type_;
150 HistogramBase::Sample minimum_;
151 HistogramBase::Sample maximum_;
jam1eacd7e2016-02-08 22:48:16152 uint32_t bucket_count_;
bcwhite5cb99eb2016-02-01 21:07:56153 int32_t flags_;
154
155 private:
156 DISALLOW_COPY_AND_ASSIGN(Factory);
157};
158
159HistogramBase* Histogram::Factory::Build() {
bcwhite5cb99eb2016-02-01 21:07:56160 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
161 if (!histogram) {
Gayane Petrosyan5745ac62018-03-23 01:45:24162 // TODO(gayane): |HashMetricName()| is called again in Histogram
163 // constructor. Refactor code to avoid the additional call.
164 bool should_record =
165 StatisticsRecorder::ShouldRecordHistogram(HashMetricName(name_));
166 if (!should_record)
167 return DummyHistogram::GetInstance();
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();
170 const BucketRanges* registered_ranges =
bcwhite5cb99eb2016-02-01 21:07:56171 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
172
173 // In most cases, the bucket-count, minimum, and maximum values are known
174 // when the code is written and so are passed in explicitly. In other
175 // cases (such as with a CustomHistogram), they are calculated dynamically
176 // at run-time. In the latter case, those ctor parameters are zero and
177 // the results extracted from the result of CreateRanges().
178 if (bucket_count_ == 0) {
jam1eacd7e2016-02-08 22:48:16179 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count());
bcwhite5cb99eb2016-02-01 21:07:56180 minimum_ = registered_ranges->range(1);
181 maximum_ = registered_ranges->range(bucket_count_ - 1);
182 }
bcwhitef1dec482017-07-06 14:39:11183 DCHECK_EQ(minimum_, registered_ranges->range(1));
184 DCHECK_EQ(maximum_, registered_ranges->range(bucket_count_ - 1));
bcwhite5cb99eb2016-02-01 21:07:56185
186 // Try to create the histogram using a "persistent" allocator. As of
bcwhite3dd85c4f2016-03-17 13:21:56187 // 2016-02-25, the availability of such is controlled by a base::Feature
bcwhite5cb99eb2016-02-01 21:07:56188 // that is off by default. If the allocator doesn't exist or if
189 // allocating from it fails, code below will allocate the histogram from
190 // the process heap.
bcwhite4ebd7272016-03-22 19:14:38191 PersistentHistogramAllocator::Reference histogram_ref = 0;
dcheng093de9b2016-04-04 21:25:51192 std::unique_ptr<HistogramBase> tentative_histogram;
bcwhite5e748c62016-04-06 02:03:53193 PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
bcwhite5cb99eb2016-02-01 21:07:56194 if (allocator) {
bcwhite33d95806a2016-03-16 02:37:45195 tentative_histogram = allocator->AllocateHistogram(
bcwhite5cb99eb2016-02-01 21:07:56196 histogram_type_,
197 name_,
198 minimum_,
199 maximum_,
200 registered_ranges,
201 flags_,
202 &histogram_ref);
203 }
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.
209 DCHECK(!allocator); // Shouldn't have failed.
bcwhite5cb99eb2016-02-01 21:07:56210 flags_ &= ~HistogramBase::kIsPersistent;
211 tentative_histogram = HeapAlloc(registered_ranges);
bcwhite3dd85c4f2016-03-17 13:21:56212 tentative_histogram->SetFlags(flags_);
bcwhite5cb99eb2016-02-01 21:07:56213 }
214
bcwhite33d95806a2016-03-16 02:37:45215 FillHistogram(tentative_histogram.get());
216
217 // Register this histogram with the StatisticsRecorder. Keep a copy of
218 // the pointer value to tell later whether the locally created histogram
219 // was registered or deleted. The type is "void" because it could point
220 // to released memory after the following line.
221 const void* tentative_histogram_ptr = tentative_histogram.get();
222 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
223 tentative_histogram.release());
bcwhite5cb99eb2016-02-01 21:07:56224
225 // Persistent histograms need some follow-up processing.
bcwhite4ebd7272016-03-22 19:14:38226 if (histogram_ref) {
bcwhite33d95806a2016-03-16 02:37:45227 allocator->FinalizeHistogram(histogram_ref,
228 histogram == tentative_histogram_ptr);
bcwhite5cb99eb2016-02-01 21:07:56229 }
230 }
231
Brian Whitea958cc72018-04-19 18:24:16232 if (histogram_type_ != histogram->GetHistogramType() ||
233 (bucket_count_ != 0 && !histogram->HasConstructionArguments(
234 minimum_, maximum_, bucket_count_))) {
bcwhite5cb99eb2016-02-01 21:07:56235 // The construction arguments do not match the existing histogram. This can
236 // come about if an extension updates in the middle of a chrome run and has
Brian Whitea958cc72018-04-19 18:24:16237 // changed one of them, or simply by bad code within Chrome itself. A NULL
238 // return would cause Chrome to crash; better to just record it for later
239 // analysis.
240 UmaHistogramSparse("Histogram.MismatchedConstructionArguments",
241 static_cast<Sample>(HashMetricName(name_)));
242 DLOG(ERROR) << "Histogram " << name_
243 << " has mismatched construction arguments";
244 return DummyHistogram::GetInstance();
bcwhite5cb99eb2016-02-01 21:07:56245 }
246 return histogram;
247}
248
asvitkine24d3e9a2015-05-27 05:22:14249HistogramBase* Histogram::FactoryGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17250 Sample minimum,
251 Sample maximum,
jam1eacd7e2016-02-08 22:48:16252 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14253 int32_t flags) {
[email protected]e184be902012-08-07 04:49:24254 bool valid_arguments =
255 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
256 DCHECK(valid_arguments);
[email protected]a93721e22012-01-06 02:13:28257
bcwhite5cb99eb2016-02-01 21:07:56258 return Factory(name, minimum, maximum, bucket_count, flags).Build();
[email protected]e8829a192009-12-06 00:09:37259}
260
asvitkine24d3e9a2015-05-27 05:22:14261HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17262 TimeDelta minimum,
263 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16264 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14265 int32_t flags) {
pkasting9cf9b94a2014-10-01 22:18:43266 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
267 static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
268 flags);
[email protected]34d062322012-08-01 21:34:08269}
270
Gabriel Charette5ec205882018-05-22 18:07:31271HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const std::string& name,
272 TimeDelta minimum,
273 TimeDelta maximum,
274 uint32_t bucket_count,
275 int32_t flags) {
276 return FactoryGet(name, static_cast<Sample>(minimum.InMicroseconds()),
277 static_cast<Sample>(maximum.InMicroseconds()), bucket_count,
278 flags);
279}
280
asvitkine5c2d5022015-06-19 00:37:50281HistogramBase* Histogram::FactoryGet(const char* name,
282 Sample minimum,
283 Sample maximum,
jam1eacd7e2016-02-08 22:48:16284 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14285 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50286 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
287}
288
289HistogramBase* Histogram::FactoryTimeGet(const char* name,
290 TimeDelta minimum,
291 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16292 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14293 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50294 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
295 flags);
296}
297
Gabriel Charette5ec205882018-05-22 18:07:31298HistogramBase* Histogram::FactoryMicrosecondsTimeGet(const char* name,
299 TimeDelta minimum,
300 TimeDelta maximum,
301 uint32_t bucket_count,
302 int32_t flags) {
303 return FactoryMicrosecondsTimeGet(std::string(name), minimum, maximum,
304 bucket_count, flags);
305}
306
dcheng093de9b2016-04-04 21:25:51307std::unique_ptr<HistogramBase> Histogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:42308 const char* name,
bcwhitec85a1f822016-02-18 21:22:14309 Sample minimum,
310 Sample maximum,
311 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25312 const DelayedPersistentAllocation& counts,
313 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14314 HistogramSamples::Metadata* meta,
315 HistogramSamples::Metadata* logged_meta) {
dcheng093de9b2016-04-04 21:25:51316 return WrapUnique(new Histogram(name, minimum, maximum, ranges, counts,
bcwhitefa8485b2017-05-01 16:43:25317 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56318}
319
[email protected]34d062322012-08-01 21:34:08320// Calculate what range of values are held in each bucket.
321// We have to be careful that we don't pick a ratio between starting points in
322// consecutive buckets that is sooo small, that the integer bounds are the same
323// (effectively making one bucket get no values). We need to avoid:
324// ranges(i) == ranges(i + 1)
325// To avoid that, we just do a fine-grained bucket width as far as we need to
326// until we get a ratio that moves us along at least 2 units at a time. From
327// that bucket onward we do use the exponential growth of buckets.
328//
329// static
330void Histogram::InitializeBucketRanges(Sample minimum,
331 Sample maximum,
[email protected]34d062322012-08-01 21:34:08332 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08333 double log_max = log(static_cast<double>(maximum));
334 double log_ratio;
335 double log_next;
336 size_t bucket_index = 1;
337 Sample current = minimum;
338 ranges->set_range(bucket_index, current);
[email protected]15ce3842013-06-27 14:38:45339 size_t bucket_count = ranges->bucket_count();
[email protected]34d062322012-08-01 21:34:08340 while (bucket_count > ++bucket_index) {
341 double log_current;
342 log_current = log(static_cast<double>(current));
343 // Calculate the count'th root of the range.
344 log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
345 // See where the next bucket would start.
346 log_next = log_current + log_ratio;
347 Sample next;
Peter Kasting8c3adfb2017-09-13 08:07:39348 next = static_cast<int>(std::round(exp(log_next)));
[email protected]34d062322012-08-01 21:34:08349 if (next > current)
350 current = next;
351 else
352 ++current; // Just do a narrow bucket, and keep trying.
353 ranges->set_range(bucket_index, current);
354 }
[email protected]15ce3842013-06-27 14:38:45355 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08356 ranges->ResetChecksum();
357}
358
[email protected]2f7d9cd2012-09-22 03:42:12359// static
360const int Histogram::kCommonRaceBasedCountMismatch = 5;
[email protected]34d062322012-08-01 21:34:08361
bcwhitec85a1f822016-02-18 21:22:14362uint32_t Histogram::FindCorruption(const HistogramSamples& samples) const {
[email protected]34d062322012-08-01 21:34:08363 int inconsistencies = NO_INCONSISTENCIES;
364 Sample previous_range = -1; // Bottom range is always 0.
jam1eacd7e2016-02-08 22:48:16365 for (uint32_t index = 0; index < bucket_count(); ++index) {
[email protected]34d062322012-08-01 21:34:08366 int new_range = ranges(index);
367 if (previous_range >= new_range)
368 inconsistencies |= BUCKET_ORDER_ERROR;
369 previous_range = new_range;
370 }
371
372 if (!bucket_ranges()->HasValidChecksum())
373 inconsistencies |= RANGE_CHECKSUM_ERROR;
374
avi9b6f42932015-12-26 22:15:14375 int64_t delta64 = samples.redundant_count() - samples.TotalCount();
[email protected]34d062322012-08-01 21:34:08376 if (delta64 != 0) {
377 int delta = static_cast<int>(delta64);
378 if (delta != delta64)
379 delta = INT_MAX; // Flag all giant errors as INT_MAX.
[email protected]34d062322012-08-01 21:34:08380 if (delta > 0) {
[email protected]34d062322012-08-01 21:34:08381 if (delta > kCommonRaceBasedCountMismatch)
382 inconsistencies |= COUNT_HIGH_ERROR;
383 } else {
384 DCHECK_GT(0, delta);
[email protected]34d062322012-08-01 21:34:08385 if (-delta > kCommonRaceBasedCountMismatch)
386 inconsistencies |= COUNT_LOW_ERROR;
387 }
388 }
[email protected]cc7dec212013-03-01 03:53:25389 return inconsistencies;
[email protected]34d062322012-08-01 21:34:08390}
391
Brian White32052d5b2017-08-07 16:46:57392const BucketRanges* Histogram::bucket_ranges() const {
393 return unlogged_samples_->bucket_ranges();
394}
395
bcwhitef1dec482017-07-06 14:39:11396Sample Histogram::declared_min() const {
Brian White32052d5b2017-08-07 16:46:57397 const BucketRanges* ranges = bucket_ranges();
398 if (ranges->bucket_count() < 2)
bcwhitef1dec482017-07-06 14:39:11399 return -1;
Brian White32052d5b2017-08-07 16:46:57400 return ranges->range(1);
bcwhitef1dec482017-07-06 14:39:11401}
402
403Sample Histogram::declared_max() const {
Brian White32052d5b2017-08-07 16:46:57404 const BucketRanges* ranges = bucket_ranges();
405 if (ranges->bucket_count() < 2)
bcwhitef1dec482017-07-06 14:39:11406 return -1;
Brian White32052d5b2017-08-07 16:46:57407 return ranges->range(ranges->bucket_count() - 1);
bcwhitef1dec482017-07-06 14:39:11408}
409
jam1eacd7e2016-02-08 22:48:16410Sample Histogram::ranges(uint32_t i) const {
Brian White32052d5b2017-08-07 16:46:57411 return bucket_ranges()->range(i);
[email protected]34d062322012-08-01 21:34:08412}
413
jam1eacd7e2016-02-08 22:48:16414uint32_t Histogram::bucket_count() const {
Brian White32052d5b2017-08-07 16:46:57415 return static_cast<uint32_t>(bucket_ranges()->bucket_count());
[email protected]34d062322012-08-01 21:34:08416}
417
[email protected]34d062322012-08-01 21:34:08418// static
Brian Whited1c91082017-11-03 14:46:42419bool Histogram::InspectConstructionArguments(StringPiece name,
[email protected]34d062322012-08-01 21:34:08420 Sample* minimum,
421 Sample* maximum,
jam1eacd7e2016-02-08 22:48:16422 uint32_t* bucket_count) {
[email protected]34d062322012-08-01 21:34:08423 // Defensive code for backward compatibility.
424 if (*minimum < 1) {
[email protected]a5c7bd792012-08-02 00:29:04425 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
[email protected]34d062322012-08-01 21:34:08426 *minimum = 1;
427 }
428 if (*maximum >= kSampleType_MAX) {
[email protected]a5c7bd792012-08-02 00:29:04429 DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
430 *maximum = kSampleType_MAX - 1;
[email protected]34d062322012-08-01 21:34:08431 }
[email protected]e184be902012-08-07 04:49:24432 if (*bucket_count >= kBucketCount_MAX) {
433 DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
434 << *bucket_count;
435 *bucket_count = kBucketCount_MAX - 1;
436 }
[email protected]34d062322012-08-01 21:34:08437
bcwhiteaaf2d3452017-04-26 19:17:47438 bool check_okay = true;
439
440 if (*minimum > *maximum) {
441 check_okay = false;
442 std::swap(*minimum, *maximum);
443 }
444 if (*maximum == *minimum) {
445 check_okay = false;
446 *maximum = *minimum + 1;
447 }
448 if (*bucket_count < 3) {
449 check_okay = false;
450 *bucket_count = 3;
451 }
asvitkinec49943d2017-05-25 19:29:47452 // Very high bucket counts are wasteful. Use a sparse histogram instead.
453 // Value of 10002 equals a user-supplied value of 10k + 2 overflow buckets.
454 constexpr uint32_t kMaxBucketCount = 10002;
455 if (*bucket_count > kMaxBucketCount) {
456 check_okay = false;
457 *bucket_count = kMaxBucketCount;
458 }
bcwhiteaaf2d3452017-04-26 19:17:47459 if (*bucket_count > static_cast<uint32_t>(*maximum - *minimum + 2)) {
460 check_okay = false;
461 *bucket_count = static_cast<uint32_t>(*maximum - *minimum + 2);
462 }
463
464 if (!check_okay) {
Ilya Sherman16d5d5f42017-12-08 00:32:44465 UmaHistogramSparse("Histogram.BadConstructionArguments",
466 static_cast<Sample>(HashMetricName(name)));
bcwhiteaaf2d3452017-04-26 19:17:47467 }
468
469 return check_okay;
[email protected]34d062322012-08-01 21:34:08470}
471
bcwhiteb036e4322015-12-10 18:36:34472uint64_t Histogram::name_hash() const {
altimin498c8382017-05-12 17:49:18473 return unlogged_samples_->id();
bcwhiteb036e4322015-12-10 18:36:34474}
475
[email protected]07c02402012-10-31 06:20:25476HistogramType Histogram::GetHistogramType() const {
477 return HISTOGRAM;
478}
479
[email protected]15ce3842013-06-27 14:38:45480bool Histogram::HasConstructionArguments(Sample expected_minimum,
481 Sample expected_maximum,
jam1eacd7e2016-02-08 22:48:16482 uint32_t expected_bucket_count) const {
bcwhitef1dec482017-07-06 14:39:11483 return (expected_bucket_count == bucket_count() &&
484 expected_minimum == declared_min() &&
485 expected_maximum == declared_max());
[email protected]abae9b022012-10-24 08:18:52486}
487
488void Histogram::Add(int value) {
amohammadkhan6779b5c32015-08-05 20:31:11489 AddCount(value, 1);
490}
491
492void Histogram::AddCount(int value, int count) {
[email protected]abae9b022012-10-24 08:18:52493 DCHECK_EQ(0, ranges(0));
[email protected]15ce3842013-06-27 14:38:45494 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
[email protected]abae9b022012-10-24 08:18:52495
496 if (value > kSampleType_MAX - 1)
497 value = kSampleType_MAX - 1;
498 if (value < 0)
499 value = 0;
amohammadkhan6779b5c32015-08-05 20:31:11500 if (count <= 0) {
501 NOTREACHED();
502 return;
503 }
altimin498c8382017-05-12 17:49:18504 unlogged_samples_->Accumulate(value, count);
simonhatchdf5a8142015-07-15 22:22:57505
506 FindAndRunCallback(value);
[email protected]abae9b022012-10-24 08:18:52507}
508
dcheng093de9b2016-04-04 21:25:51509std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
altimin498c8382017-05-12 17:49:18510 return SnapshotAllSamples();
[email protected]abae9b022012-10-24 08:18:52511}
512
dcheng093de9b2016-04-04 21:25:51513std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() {
bcwhitef1dec482017-07-06 14:39:11514#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40515 DCHECK(!final_delta_created_);
bcwhitef1dec482017-07-06 14:39:11516#endif
517
altimin498c8382017-05-12 17:49:18518 // The code below has subtle thread-safety guarantees! All changes to
519 // the underlying SampleVectors use atomic integer operations, which guarantee
520 // eventual consistency, but do not guarantee full synchronization between
521 // different entries in the SampleVector. In particular, this means that
522 // concurrent updates to the histogram might result in the reported sum not
523 // matching the individual bucket counts; or there being some buckets that are
524 // logically updated "together", but end up being only partially updated when
525 // a snapshot is captured. Note that this is why it's important to subtract
526 // exactly the snapshotted unlogged samples, rather than simply resetting the
527 // vector: this way, the next snapshot will include any concurrent updates
528 // missed by the current snapshot.
bcwhite65e57d02016-05-13 14:39:40529
altimin498c8382017-05-12 17:49:18530 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples();
531 unlogged_samples_->Subtract(*snapshot);
bcwhitec85a1f822016-02-18 21:22:14532 logged_samples_->Add(*snapshot);
altimin498c8382017-05-12 17:49:18533
bcwhitec85a1f822016-02-18 21:22:14534 return snapshot;
535}
536
bcwhite65e57d02016-05-13 14:39:40537std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
bcwhitef1dec482017-07-06 14:39:11538#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40539 DCHECK(!final_delta_created_);
540 final_delta_created_ = true;
bcwhitef1dec482017-07-06 14:39:11541#endif
bcwhite65e57d02016-05-13 14:39:40542
altimin498c8382017-05-12 17:49:18543 return SnapshotUnloggedSamples();
bcwhite65e57d02016-05-13 14:39:40544}
545
[email protected]c50c21d2013-01-11 21:52:44546void Histogram::AddSamples(const HistogramSamples& samples) {
altimin498c8382017-05-12 17:49:18547 unlogged_samples_->Add(samples);
[email protected]c50c21d2013-01-11 21:52:44548}
549
550bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
altimin498c8382017-05-12 17:49:18551 return unlogged_samples_->AddFromPickle(iter);
[email protected]c50c21d2013-01-11 21:52:44552}
553
[email protected]abae9b022012-10-24 08:18:52554// The following methods provide a graphical histogram display.
asvitkine24d3e9a2015-05-27 05:22:14555void Histogram::WriteHTMLGraph(std::string* output) const {
[email protected]abae9b022012-10-24 08:18:52556 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
557 output->append("<PRE>");
558 WriteAsciiImpl(true, "<br>", output);
559 output->append("</PRE>");
560}
561
asvitkine24d3e9a2015-05-27 05:22:14562void Histogram::WriteAscii(std::string* output) const {
[email protected]abae9b022012-10-24 08:18:52563 WriteAsciiImpl(true, "\n", output);
564}
565
Brian White1a3a225c2018-04-27 00:40:07566void Histogram::ValidateHistogramContents() const {
567 CHECK(unlogged_samples_);
568 CHECK(unlogged_samples_->bucket_ranges());
569 CHECK(logged_samples_);
570 CHECK(logged_samples_->bucket_ranges());
Brian White4eb39392018-05-09 12:49:22571#if !defined(OS_NACL)
572 if (0U == logged_samples_->id() && (flags() & kIsPersistent)) {
573 // ID should never be zero. If it is, then it's probably because the
574 // entire memory page was cleared. Check that this is true.
575 // TODO(bcwhite): Remove this.
576 // https://bugs.chromium.org/p/chromium/issues/detail?id=836875
Brian White9114be5d2018-05-16 17:01:26577 size_t page_size = SysInfo::VMAllocationGranularity();
578 if (page_size == 0)
579 page_size = 1024;
Brian White4eb39392018-05-09 12:49:22580 const int* address = reinterpret_cast<const int*>(
581 reinterpret_cast<uintptr_t>(logged_samples_->meta()) &
582 ~(page_size - 1));
583 // Check a couple places so there is evidence in a crash report as to
584 // where it was non-zero.
585 CHECK_EQ(0, address[0]);
586 CHECK_EQ(0, address[1]);
587 CHECK_EQ(0, address[2]);
588 CHECK_EQ(0, address[4]);
589 CHECK_EQ(0, address[8]);
590 CHECK_EQ(0, address[16]);
591 CHECK_EQ(0, address[32]);
592 CHECK_EQ(0, address[64]);
593 CHECK_EQ(0, address[128]);
594 CHECK_EQ(0, address[256]);
595 CHECK_EQ(0, address[512]);
596 // Now check every address.
597 for (size_t i = 0; i < page_size / sizeof(int); ++i)
598 CHECK_EQ(0, address[i]);
599 }
600#endif
Brian White1a3a225c2018-04-27 00:40:07601 CHECK_NE(0U, logged_samples_->id());
602}
603
Daniel Cheng0d89f9222017-09-22 05:05:07604void Histogram::SerializeInfoImpl(Pickle* pickle) const {
[email protected]c50c21d2013-01-11 21:52:44605 DCHECK(bucket_ranges()->HasValidChecksum());
Daniel Cheng0d89f9222017-09-22 05:05:07606 pickle->WriteString(histogram_name());
607 pickle->WriteInt(flags());
608 pickle->WriteInt(declared_min());
609 pickle->WriteInt(declared_max());
610 pickle->WriteUInt32(bucket_count());
611 pickle->WriteUInt32(bucket_ranges()->checksum());
[email protected]c50c21d2013-01-11 21:52:44612}
613
bcwhitef1dec482017-07-06 14:39:11614// TODO(bcwhite): Remove minimum/maximum parameters from here and call chain.
Brian Whited1c91082017-11-03 14:46:42615Histogram::Histogram(const char* name,
[email protected]abae9b022012-10-24 08:18:52616 Sample minimum,
617 Sample maximum,
[email protected]abae9b022012-10-24 08:18:52618 const BucketRanges* ranges)
Brian Whitecaef6e12018-03-12 22:06:11619 : HistogramBase(name) {
Brian White7463677b2018-04-09 21:51:40620 DCHECK(ranges) << name << ": " << minimum << "-" << maximum;
bcwhiteb7bde182017-06-19 20:00:44621 unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges));
622 logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges));
[email protected]abae9b022012-10-24 08:18:52623}
624
Brian Whited1c91082017-11-03 14:46:42625Histogram::Histogram(const char* name,
bcwhite5cb99eb2016-02-01 21:07:56626 Sample minimum,
627 Sample maximum,
628 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25629 const DelayedPersistentAllocation& counts,
630 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14631 HistogramSamples::Metadata* meta,
632 HistogramSamples::Metadata* logged_meta)
Brian Whitecaef6e12018-03-12 22:06:11633 : HistogramBase(name) {
Brian White7463677b2018-04-09 21:51:40634 DCHECK(ranges) << name << ": " << minimum << "-" << maximum;
bcwhiteb7bde182017-06-19 20:00:44635 unlogged_samples_.reset(
636 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts));
637 logged_samples_.reset(new PersistentSampleVector(
638 unlogged_samples_->id(), ranges, logged_meta, logged_counts));
bcwhite5cb99eb2016-02-01 21:07:56639}
640
Chris Watkinsbb7211c2017-11-29 07:16:38641Histogram::~Histogram() = default;
[email protected]abae9b022012-10-24 08:18:52642
jam1eacd7e2016-02-08 22:48:16643bool Histogram::PrintEmptyBucket(uint32_t index) const {
[email protected]34d062322012-08-01 21:34:08644 return true;
645}
646
[email protected]34d062322012-08-01 21:34:08647// Use the actual bucket widths (like a linear histogram) until the widths get
648// over some transition value, and then use that transition width. Exponentials
649// get so big so fast (and we don't expect to see a lot of entries in the large
650// buckets), so we need this to make it possible to see what is going on and
651// not have 0-graphical-height buckets.
jam1eacd7e2016-02-08 22:48:16652double Histogram::GetBucketSize(Count current, uint32_t i) const {
[email protected]34d062322012-08-01 21:34:08653 DCHECK_GT(ranges(i + 1), ranges(i));
654 static const double kTransitionWidth = 5;
655 double denominator = ranges(i + 1) - ranges(i);
656 if (denominator > kTransitionWidth)
657 denominator = kTransitionWidth; // Stop trying to normalize.
658 return current/denominator;
659}
660
jam1eacd7e2016-02-08 22:48:16661const std::string Histogram::GetAsciiBucketRange(uint32_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;
jam1eacd7e2016-02-08 22:48:16674 uint32_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);
Brian White7eb91482017-08-09 19:54:45685 if (!histogram)
686 return nullptr;
[email protected]c50c21d2013-01-11 21:52:44687
Brian White7eb91482017-08-09 19:54:45688 // The serialized histogram might be corrupted.
689 if (!ValidateRangeChecksum(*histogram, range_checksum))
690 return nullptr;
691
[email protected]c50c21d2013-01-11 21:52:44692 return histogram;
693}
694
altimin498c8382017-05-12 17:49:18695std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const {
696 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamples();
697 samples->Add(*logged_samples_);
698 return samples;
699}
700
701std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const {
dcheng093de9b2016-04-04 21:25:51702 std::unique_ptr<SampleVector> samples(
altimin498c8382017-05-12 17:49:18703 new SampleVector(unlogged_samples_->id(), bucket_ranges()));
704 samples->Add(*unlogged_samples_);
danakj0c8d4aa2015-11-25 05:29:58705 return samples;
[email protected]877ef562012-10-20 02:56:18706}
707
[email protected]34d062322012-08-01 21:34:08708void Histogram::WriteAsciiImpl(bool graph_it,
asvitkine24d3e9a2015-05-27 05:22:14709 const std::string& newline,
710 std::string* output) const {
[email protected]34d062322012-08-01 21:34:08711 // Get local (stack) copies of all effectively volatile class data so that we
712 // are consistent across our output activities.
altimin498c8382017-05-12 17:49:18713 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
[email protected]2f7d9cd2012-09-22 03:42:12714 Count sample_count = snapshot->TotalCount();
[email protected]34d062322012-08-01 21:34:08715
[email protected]2f7d9cd2012-09-22 03:42:12716 WriteAsciiHeader(*snapshot, sample_count, output);
[email protected]34d062322012-08-01 21:34:08717 output->append(newline);
718
719 // Prepare to normalize graphical rendering of bucket contents.
720 double max_size = 0;
721 if (graph_it)
[email protected]2f7d9cd2012-09-22 03:42:12722 max_size = GetPeakBucketSize(*snapshot);
[email protected]34d062322012-08-01 21:34:08723
724 // Calculate space needed to print bucket range numbers. Leave room to print
725 // nearly the largest bucket range without sliding over the histogram.
jam1eacd7e2016-02-08 22:48:16726 uint32_t largest_non_empty_bucket = bucket_count() - 1;
[email protected]2f7d9cd2012-09-22 03:42:12727 while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) {
[email protected]34d062322012-08-01 21:34:08728 if (0 == largest_non_empty_bucket)
729 break; // All buckets are empty.
730 --largest_non_empty_bucket;
731 }
732
733 // Calculate largest print width needed for any of our bucket range displays.
734 size_t print_width = 1;
jam1eacd7e2016-02-08 22:48:16735 for (uint32_t i = 0; i < bucket_count(); ++i) {
[email protected]2f7d9cd2012-09-22 03:42:12736 if (snapshot->GetCountAtIndex(i)) {
[email protected]34d062322012-08-01 21:34:08737 size_t width = GetAsciiBucketRange(i).size() + 1;
738 if (width > print_width)
739 print_width = width;
740 }
741 }
742
avi9b6f42932015-12-26 22:15:14743 int64_t remaining = sample_count;
744 int64_t past = 0;
[email protected]34d062322012-08-01 21:34:08745 // Output the actual histogram graph.
jam1eacd7e2016-02-08 22:48:16746 for (uint32_t i = 0; i < bucket_count(); ++i) {
[email protected]2f7d9cd2012-09-22 03:42:12747 Count current = snapshot->GetCountAtIndex(i);
[email protected]34d062322012-08-01 21:34:08748 if (!current && !PrintEmptyBucket(i))
749 continue;
750 remaining -= current;
asvitkine24d3e9a2015-05-27 05:22:14751 std::string range = GetAsciiBucketRange(i);
[email protected]34d062322012-08-01 21:34:08752 output->append(range);
753 for (size_t j = 0; range.size() + j < print_width + 1; ++j)
754 output->push_back(' ');
[email protected]2f7d9cd2012-09-22 03:42:12755 if (0 == current && i < bucket_count() - 1 &&
756 0 == snapshot->GetCountAtIndex(i + 1)) {
757 while (i < bucket_count() - 1 &&
758 0 == snapshot->GetCountAtIndex(i + 1)) {
[email protected]34d062322012-08-01 21:34:08759 ++i;
[email protected]2f7d9cd2012-09-22 03:42:12760 }
[email protected]34d062322012-08-01 21:34:08761 output->append("... ");
762 output->append(newline);
763 continue; // No reason to plot emptiness.
764 }
765 double current_size = GetBucketSize(current, i);
766 if (graph_it)
767 WriteAsciiBucketGraph(current_size, max_size, output);
768 WriteAsciiBucketContext(past, current, remaining, i, output);
769 output->append(newline);
770 past += current;
771 }
772 DCHECK_EQ(sample_count, past);
773}
774
bcwhitefa8485b2017-05-01 16:43:25775double Histogram::GetPeakBucketSize(const SampleVectorBase& samples) const {
[email protected]34d062322012-08-01 21:34:08776 double max = 0;
jam1eacd7e2016-02-08 22:48:16777 for (uint32_t i = 0; i < bucket_count() ; ++i) {
[email protected]2f7d9cd2012-09-22 03:42:12778 double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
[email protected]34d062322012-08-01 21:34:08779 if (current_size > max)
780 max = current_size;
781 }
782 return max;
783}
784
bcwhitefa8485b2017-05-01 16:43:25785void Histogram::WriteAsciiHeader(const SampleVectorBase& samples,
[email protected]34d062322012-08-01 21:34:08786 Count sample_count,
asvitkine24d3e9a2015-05-27 05:22:14787 std::string* output) const {
Brian Whited1c91082017-11-03 14:46:42788 StringAppendF(output, "Histogram: %s recorded %d samples", histogram_name(),
[email protected]34d062322012-08-01 21:34:08789 sample_count);
rkaplow035eb122016-09-28 21:48:36790 if (sample_count == 0) {
[email protected]2f7d9cd2012-09-22 03:42:12791 DCHECK_EQ(samples.sum(), 0);
[email protected]34d062322012-08-01 21:34:08792 } else {
rkaplow035eb122016-09-28 21:48:36793 double mean = static_cast<float>(samples.sum()) / sample_count;
794 StringAppendF(output, ", mean = %.1f", mean);
[email protected]34d062322012-08-01 21:34:08795 }
rkaplow035eb122016-09-28 21:48:36796 if (flags())
797 StringAppendF(output, " (flags = 0x%x)", flags());
[email protected]34d062322012-08-01 21:34:08798}
799
avi9b6f42932015-12-26 22:15:14800void Histogram::WriteAsciiBucketContext(const int64_t past,
[email protected]34d062322012-08-01 21:34:08801 const Count current,
avi9b6f42932015-12-26 22:15:14802 const int64_t remaining,
jam1eacd7e2016-02-08 22:48:16803 const uint32_t i,
asvitkine24d3e9a2015-05-27 05:22:14804 std::string* output) const {
[email protected]34d062322012-08-01 21:34:08805 double scaled_sum = (past + current + remaining) / 100.0;
806 WriteAsciiBucketValue(current, scaled_sum, output);
807 if (0 < i) {
808 double percentage = past / scaled_sum;
809 StringAppendF(output, " {%3.1f%%}", percentage);
810 }
811}
812
[email protected]24a7ec52012-10-08 10:31:50813void Histogram::GetParameters(DictionaryValue* params) const {
[email protected]07c02402012-10-31 06:20:25814 params->SetString("type", HistogramTypeToString(GetHistogramType()));
[email protected]24a7ec52012-10-08 10:31:50815 params->SetInteger("min", declared_min());
816 params->SetInteger("max", declared_max());
817 params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
818}
819
[email protected]cdd98fc2013-05-10 09:32:58820void Histogram::GetCountAndBucketData(Count* count,
avi9b6f42932015-12-26 22:15:14821 int64_t* sum,
[email protected]cdd98fc2013-05-10 09:32:58822 ListValue* buckets) const {
altimin498c8382017-05-12 17:49:18823 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
[email protected]24a7ec52012-10-08 10:31:50824 *count = snapshot->TotalCount();
[email protected]cdd98fc2013-05-10 09:32:58825 *sum = snapshot->sum();
jam1eacd7e2016-02-08 22:48:16826 uint32_t index = 0;
827 for (uint32_t i = 0; i < bucket_count(); ++i) {
scottmgdcc933d2015-01-27 21:37:55828 Sample count_at_index = snapshot->GetCountAtIndex(i);
829 if (count_at_index > 0) {
dcheng093de9b2016-04-04 21:25:51830 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue());
[email protected]24a7ec52012-10-08 10:31:50831 bucket_value->SetInteger("low", ranges(i));
832 if (i != bucket_count() - 1)
833 bucket_value->SetInteger("high", ranges(i + 1));
scottmgdcc933d2015-01-27 21:37:55834 bucket_value->SetInteger("count", count_at_index);
jdoerrief1e72e32017-04-26 16:23:55835 buckets->Set(index, std::move(bucket_value));
[email protected]24a7ec52012-10-08 10:31:50836 ++index;
837 }
838 }
839}
840
[email protected]34d062322012-08-01 21:34:08841//------------------------------------------------------------------------------
842// LinearHistogram: This histogram uses a traditional set of evenly spaced
843// buckets.
844//------------------------------------------------------------------------------
845
bcwhite5cb99eb2016-02-01 21:07:56846class LinearHistogram::Factory : public Histogram::Factory {
847 public:
848 Factory(const std::string& name,
849 HistogramBase::Sample minimum,
850 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16851 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56852 int32_t flags,
853 const DescriptionPair* descriptions)
854 : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum,
855 bucket_count, flags) {
856 descriptions_ = descriptions;
857 }
858
859 protected:
860 BucketRanges* CreateRanges() override {
861 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
862 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
863 return ranges;
864 }
865
dcheng093de9b2016-04-04 21:25:51866 std::unique_ptr<HistogramBase> HeapAlloc(
867 const BucketRanges* ranges) override {
Brian Whited1c91082017-11-03 14:46:42868 return WrapUnique(new LinearHistogram(GetPermanentName(name_), minimum_,
869 maximum_, ranges));
bcwhite5cb99eb2016-02-01 21:07:56870 }
871
872 void FillHistogram(HistogramBase* base_histogram) override {
873 Histogram::Factory::FillHistogram(base_histogram);
Gayane Petrosyan5745ac62018-03-23 01:45:24874 // Normally, |base_histogram| should have type LINEAR_HISTOGRAM or be
875 // inherited from it. However, if it's expired, it will actually be a
876 // DUMMY_HISTOGRAM. Skip filling in that case.
877 if (base_histogram->GetHistogramType() == DUMMY_HISTOGRAM)
878 return;
bcwhite5cb99eb2016-02-01 21:07:56879 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
880 // Set range descriptions.
881 if (descriptions_) {
882 for (int i = 0; descriptions_[i].description; ++i) {
883 histogram->bucket_description_[descriptions_[i].sample] =
884 descriptions_[i].description;
885 }
886 }
887 }
888
889 private:
890 const DescriptionPair* descriptions_;
891
892 DISALLOW_COPY_AND_ASSIGN(Factory);
893};
894
Chris Watkinsbb7211c2017-11-29 07:16:38895LinearHistogram::~LinearHistogram() = default;
[email protected]34d062322012-08-01 21:34:08896
asvitkine24d3e9a2015-05-27 05:22:14897HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17898 Sample minimum,
899 Sample maximum,
jam1eacd7e2016-02-08 22:48:16900 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14901 int32_t flags) {
Brian White7eb91482017-08-09 19:54:45902 return FactoryGetWithRangeDescription(name, minimum, maximum, bucket_count,
Brian Whited1c91082017-11-03 14:46:42903 flags, NULL);
[email protected]07c02402012-10-31 06:20:25904}
905
asvitkine24d3e9a2015-05-27 05:22:14906HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17907 TimeDelta minimum,
908 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16909 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14910 int32_t flags) {
pkasting9cf9b94a2014-10-01 22:18:43911 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
912 static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
913 flags);
[email protected]07c02402012-10-31 06:20:25914}
915
asvitkine5c2d5022015-06-19 00:37:50916HistogramBase* LinearHistogram::FactoryGet(const char* name,
917 Sample minimum,
918 Sample maximum,
jam1eacd7e2016-02-08 22:48:16919 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14920 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50921 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
922}
923
924HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
925 TimeDelta minimum,
926 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16927 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14928 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50929 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
930 flags);
931}
932
dcheng093de9b2016-04-04 21:25:51933std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:42934 const char* name,
bcwhite5cb99eb2016-02-01 21:07:56935 Sample minimum,
936 Sample maximum,
937 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25938 const DelayedPersistentAllocation& counts,
939 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14940 HistogramSamples::Metadata* meta,
941 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:25942 return WrapUnique(new LinearHistogram(name, minimum, maximum, ranges, counts,
943 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56944}
945
[email protected]de415552013-01-23 04:12:17946HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
avi9b6f42932015-12-26 22:15:14947 const std::string& name,
948 Sample minimum,
949 Sample maximum,
jam1eacd7e2016-02-08 22:48:16950 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14951 int32_t flags,
952 const DescriptionPair descriptions[]) {
[email protected]e184be902012-08-07 04:49:24953 bool valid_arguments = Histogram::InspectConstructionArguments(
954 name, &minimum, &maximum, &bucket_count);
955 DCHECK(valid_arguments);
[email protected]34d062322012-08-01 21:34:08956
bcwhite5cb99eb2016-02-01 21:07:56957 return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
958 .Build();
[email protected]34d062322012-08-01 21:34:08959}
960
[email protected]07c02402012-10-31 06:20:25961HistogramType LinearHistogram::GetHistogramType() const {
[email protected]b7d08202011-01-25 17:29:39962 return LINEAR_HISTOGRAM;
963}
964
Brian Whited1c91082017-11-03 14:46:42965LinearHistogram::LinearHistogram(const char* name,
[email protected]835d7c82010-10-14 04:38:38966 Sample minimum,
967 Sample maximum,
[email protected]34d062322012-08-01 21:34:08968 const BucketRanges* ranges)
Brian Whited1c91082017-11-03 14:46:42969 : Histogram(name, minimum, maximum, ranges) {}
initial.commitd7cae122008-07-26 21:49:38970
bcwhitefa8485b2017-05-01 16:43:25971LinearHistogram::LinearHistogram(
Brian Whited1c91082017-11-03 14:46:42972 const char* name,
bcwhitefa8485b2017-05-01 16:43:25973 Sample minimum,
974 Sample maximum,
975 const BucketRanges* ranges,
976 const DelayedPersistentAllocation& counts,
977 const DelayedPersistentAllocation& logged_counts,
978 HistogramSamples::Metadata* meta,
979 HistogramSamples::Metadata* logged_meta)
980 : Histogram(name,
981 minimum,
982 maximum,
983 ranges,
984 counts,
985 logged_counts,
986 meta,
987 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:56988
jam1eacd7e2016-02-08 22:48:16989double LinearHistogram::GetBucketSize(Count current, uint32_t i) const {
[email protected]2ef3748f2010-10-19 17:33:28990 DCHECK_GT(ranges(i + 1), ranges(i));
initial.commitd7cae122008-07-26 21:49:38991 // Adjacent buckets with different widths would have "surprisingly" many (few)
992 // samples in a histogram if we didn't normalize this way.
993 double denominator = ranges(i + 1) - ranges(i);
994 return current/denominator;
995}
996
jam1eacd7e2016-02-08 22:48:16997const std::string LinearHistogram::GetAsciiBucketRange(uint32_t i) const {
[email protected]b7d08202011-01-25 17:29:39998 int range = ranges(i);
999 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
1000 if (it == bucket_description_.end())
1001 return Histogram::GetAsciiBucketRange(i);
1002 return it->second;
1003}
1004
jam1eacd7e2016-02-08 22:48:161005bool LinearHistogram::PrintEmptyBucket(uint32_t index) const {
[email protected]b7d08202011-01-25 17:29:391006 return bucket_description_.find(ranges(index)) == bucket_description_.end();
1007}
1008
[email protected]34d062322012-08-01 21:34:081009// static
1010void LinearHistogram::InitializeBucketRanges(Sample minimum,
1011 Sample maximum,
[email protected]34d062322012-08-01 21:34:081012 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:081013 double min = minimum;
1014 double max = maximum;
[email protected]15ce3842013-06-27 14:38:451015 size_t bucket_count = ranges->bucket_count();
1016 for (size_t i = 1; i < bucket_count; ++i) {
[email protected]34d062322012-08-01 21:34:081017 double linear_range =
[email protected]15ce3842013-06-27 14:38:451018 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
[email protected]34d062322012-08-01 21:34:081019 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5));
1020 }
[email protected]15ce3842013-06-27 14:38:451021 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:081022 ranges->ResetChecksum();
1023}
[email protected]b7d08202011-01-25 17:29:391024
[email protected]c50c21d2013-01-11 21:52:441025// static
1026HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141027 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441028 int flags;
1029 int declared_min;
1030 int declared_max;
jam1eacd7e2016-02-08 22:48:161031 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:141032 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441033
1034 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1035 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451036 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441037 }
1038
1039 HistogramBase* histogram = LinearHistogram::FactoryGet(
1040 histogram_name, declared_min, declared_max, bucket_count, flags);
Brian White82027ff5d2017-08-21 19:50:221041 if (!histogram)
1042 return nullptr;
1043
[email protected]c50c21d2013-01-11 21:52:441044 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1045 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451046 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441047 }
1048 return histogram;
1049}
1050
initial.commitd7cae122008-07-26 21:49:381051//------------------------------------------------------------------------------
Brian Whitefffb3582018-05-24 21:17:011052// ScaledLinearHistogram: This is a wrapper around a LinearHistogram that
1053// scales input counts.
1054//------------------------------------------------------------------------------
1055
1056ScaledLinearHistogram::ScaledLinearHistogram(const char* name,
1057 Sample minimum,
1058 Sample maximum,
1059 uint32_t bucket_count,
1060 int32_t scale,
1061 int32_t flags)
1062 : histogram_(static_cast<LinearHistogram*>(
1063 LinearHistogram::FactoryGet(name,
1064 minimum,
1065 maximum,
1066 bucket_count,
1067 flags))),
1068 scale_(scale) {
1069 DCHECK(histogram_);
1070 DCHECK_LT(1, scale);
1071 DCHECK_EQ(1, minimum);
1072 CHECK_EQ(static_cast<Sample>(bucket_count), maximum - minimum + 2)
1073 << " ScaledLinearHistogram requires buckets of size 1";
1074
1075 remainders_.resize(histogram_->bucket_count(), 0);
1076}
1077
1078ScaledLinearHistogram::~ScaledLinearHistogram() = default;
1079
1080void ScaledLinearHistogram::AddScaledCount(Sample value, int count) {
Farah Charabb114f862018-06-12 11:53:571081 if (count == 0)
1082 return;
1083 if (count < 0) {
1084 NOTREACHED();
1085 return;
1086 }
Brian Whitefffb3582018-05-24 21:17:011087 const int32_t max_value =
1088 static_cast<int32_t>(histogram_->bucket_count() - 1);
1089 if (value > max_value)
1090 value = max_value;
1091 if (value < 0)
1092 value = 0;
Brian Whitefffb3582018-05-24 21:17:011093
1094 int scaled_count = count / scale_;
1095 subtle::Atomic32 remainder = count - scaled_count * scale_;
1096
1097 // ScaledLinearHistogram currently requires 1-to-1 mappings between value
1098 // and bucket which alleviates the need to do a bucket lookup here (something
1099 // that is internal to the HistogramSamples object).
1100 if (remainder > 0) {
1101 remainder =
1102 subtle::NoBarrier_AtomicIncrement(&remainders_[value], remainder);
1103 // If remainder passes 1/2 scale, increment main count (thus rounding up).
1104 // The remainder is decremented by the full scale, though, which will
1105 // cause it to go negative and thus requrire another increase by the full
1106 // scale amount before another bump of the scaled count.
1107 if (remainder >= scale_ / 2) {
1108 scaled_count += 1;
1109 subtle::NoBarrier_AtomicIncrement(&remainders_[value], -scale_);
1110 }
1111 }
1112
1113 if (scaled_count > 0)
1114 histogram_->AddCount(value, scaled_count);
1115}
1116
1117//------------------------------------------------------------------------------
[email protected]e8829a192009-12-06 00:09:371118// This section provides implementation for BooleanHistogram.
1119//------------------------------------------------------------------------------
1120
bcwhite5cb99eb2016-02-01 21:07:561121class BooleanHistogram::Factory : public Histogram::Factory {
1122 public:
1123 Factory(const std::string& name, int32_t flags)
1124 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
1125
1126 protected:
1127 BucketRanges* CreateRanges() override {
1128 BucketRanges* ranges = new BucketRanges(3 + 1);
[email protected]15ce3842013-06-27 14:38:451129 LinearHistogram::InitializeBucketRanges(1, 2, ranges);
bcwhite5cb99eb2016-02-01 21:07:561130 return ranges;
[email protected]e8829a192009-12-06 00:09:371131 }
1132
dcheng093de9b2016-04-04 21:25:511133 std::unique_ptr<HistogramBase> HeapAlloc(
1134 const BucketRanges* ranges) override {
Brian Whited1c91082017-11-03 14:46:421135 return WrapUnique(new BooleanHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561136 }
1137
1138 private:
1139 DISALLOW_COPY_AND_ASSIGN(Factory);
1140};
1141
1142HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
1143 int32_t flags) {
1144 return Factory(name, flags).Build();
[email protected]e8829a192009-12-06 00:09:371145}
1146
avi9b6f42932015-12-26 22:15:141147HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:501148 return FactoryGet(std::string(name), flags);
1149}
1150
dcheng093de9b2016-04-04 21:25:511151std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:421152 const char* name,
bcwhite5cb99eb2016-02-01 21:07:561153 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251154 const DelayedPersistentAllocation& counts,
1155 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141156 HistogramSamples::Metadata* meta,
1157 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:251158 return WrapUnique(new BooleanHistogram(name, ranges, counts, logged_counts,
1159 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561160}
1161
[email protected]07c02402012-10-31 06:20:251162HistogramType BooleanHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281163 return BOOLEAN_HISTOGRAM;
1164}
1165
Brian Whited1c91082017-11-03 14:46:421166BooleanHistogram::BooleanHistogram(const char* name, const BucketRanges* ranges)
[email protected]15ce3842013-06-27 14:38:451167 : LinearHistogram(name, 1, 2, ranges) {}
initial.commitd7cae122008-07-26 21:49:381168
bcwhitefa8485b2017-05-01 16:43:251169BooleanHistogram::BooleanHistogram(
Brian Whited1c91082017-11-03 14:46:421170 const char* name,
bcwhitefa8485b2017-05-01 16:43:251171 const BucketRanges* ranges,
1172 const DelayedPersistentAllocation& counts,
1173 const DelayedPersistentAllocation& logged_counts,
1174 HistogramSamples::Metadata* meta,
1175 HistogramSamples::Metadata* logged_meta)
1176 : LinearHistogram(name,
1177 1,
1178 2,
1179 ranges,
1180 counts,
1181 logged_counts,
1182 meta,
bcwhitec85a1f822016-02-18 21:22:141183 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561184
[email protected]c50c21d2013-01-11 21:52:441185HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141186 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441187 int flags;
1188 int declared_min;
1189 int declared_max;
jam1eacd7e2016-02-08 22:48:161190 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:141191 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441192
1193 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1194 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451195 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441196 }
1197
1198 HistogramBase* histogram = BooleanHistogram::FactoryGet(
1199 histogram_name, flags);
Brian White82027ff5d2017-08-21 19:50:221200 if (!histogram)
1201 return nullptr;
1202
[email protected]c50c21d2013-01-11 21:52:441203 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1204 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451205 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441206 }
1207 return histogram;
1208}
1209
initial.commitd7cae122008-07-26 21:49:381210//------------------------------------------------------------------------------
[email protected]70cc56e42010-04-29 22:39:551211// CustomHistogram:
1212//------------------------------------------------------------------------------
1213
bcwhite5cb99eb2016-02-01 21:07:561214class CustomHistogram::Factory : public Histogram::Factory {
1215 public:
1216 Factory(const std::string& name,
1217 const std::vector<Sample>* custom_ranges,
1218 int32_t flags)
1219 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
1220 custom_ranges_ = custom_ranges;
1221 }
1222
1223 protected:
1224 BucketRanges* CreateRanges() override {
1225 // Remove the duplicates in the custom ranges array.
1226 std::vector<int> ranges = *custom_ranges_;
1227 ranges.push_back(0); // Ensure we have a zero value.
1228 ranges.push_back(HistogramBase::kSampleType_MAX);
1229 std::sort(ranges.begin(), ranges.end());
1230 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
1231
1232 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
jam1eacd7e2016-02-08 22:48:161233 for (uint32_t i = 0; i < ranges.size(); i++) {
bcwhite5cb99eb2016-02-01 21:07:561234 bucket_ranges->set_range(i, ranges[i]);
1235 }
1236 bucket_ranges->ResetChecksum();
1237 return bucket_ranges;
1238 }
1239
dcheng093de9b2016-04-04 21:25:511240 std::unique_ptr<HistogramBase> HeapAlloc(
1241 const BucketRanges* ranges) override {
Brian Whited1c91082017-11-03 14:46:421242 return WrapUnique(new CustomHistogram(GetPermanentName(name_), ranges));
bcwhite5cb99eb2016-02-01 21:07:561243 }
1244
1245 private:
1246 const std::vector<Sample>* custom_ranges_;
1247
1248 DISALLOW_COPY_AND_ASSIGN(Factory);
1249};
1250
asvitkine24d3e9a2015-05-27 05:22:141251HistogramBase* CustomHistogram::FactoryGet(
1252 const std::string& name,
1253 const std::vector<Sample>& custom_ranges,
avi9b6f42932015-12-26 22:15:141254 int32_t flags) {
[email protected]34d062322012-08-01 21:34:081255 CHECK(ValidateCustomRanges(custom_ranges));
[email protected]70cc56e42010-04-29 22:39:551256
bcwhite5cb99eb2016-02-01 21:07:561257 return Factory(name, &custom_ranges, flags).Build();
[email protected]70cc56e42010-04-29 22:39:551258}
1259
asvitkine5c2d5022015-06-19 00:37:501260HistogramBase* CustomHistogram::FactoryGet(
1261 const char* name,
1262 const std::vector<Sample>& custom_ranges,
avi9b6f42932015-12-26 22:15:141263 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:501264 return FactoryGet(std::string(name), custom_ranges, flags);
1265}
1266
dcheng093de9b2016-04-04 21:25:511267std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
Brian Whited1c91082017-11-03 14:46:421268 const char* name,
bcwhite5cb99eb2016-02-01 21:07:561269 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251270 const DelayedPersistentAllocation& counts,
1271 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141272 HistogramSamples::Metadata* meta,
1273 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:251274 return WrapUnique(new CustomHistogram(name, ranges, counts, logged_counts,
1275 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561276}
1277
[email protected]07c02402012-10-31 06:20:251278HistogramType CustomHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281279 return CUSTOM_HISTOGRAM;
1280}
1281
[email protected]961fefb2011-05-24 13:59:581282// static
Ryan Sleevi9c79c3542018-05-12 01:38:091283std::vector<Sample> CustomHistogram::ArrayToCustomEnumRanges(
1284 base::span<const Sample> values) {
asvitkine24d3e9a2015-05-27 05:22:141285 std::vector<Sample> all_values;
Ryan Sleevi9c79c3542018-05-12 01:38:091286 for (Sample value : values) {
[email protected]961fefb2011-05-24 13:59:581287 all_values.push_back(value);
1288
1289 // Ensure that a guard bucket is added. If we end up with duplicate
1290 // values, FactoryGet will take care of removing them.
1291 all_values.push_back(value + 1);
1292 }
1293 return all_values;
1294}
1295
Brian Whited1c91082017-11-03 14:46:421296CustomHistogram::CustomHistogram(const char* name, const BucketRanges* ranges)
[email protected]34d062322012-08-01 21:34:081297 : Histogram(name,
1298 ranges->range(1),
[email protected]15ce3842013-06-27 14:38:451299 ranges->range(ranges->bucket_count() - 1),
[email protected]34d062322012-08-01 21:34:081300 ranges) {}
[email protected]70cc56e42010-04-29 22:39:551301
bcwhitefa8485b2017-05-01 16:43:251302CustomHistogram::CustomHistogram(
Brian Whited1c91082017-11-03 14:46:421303 const char* name,
bcwhitefa8485b2017-05-01 16:43:251304 const BucketRanges* ranges,
1305 const DelayedPersistentAllocation& counts,
1306 const DelayedPersistentAllocation& logged_counts,
1307 HistogramSamples::Metadata* meta,
1308 HistogramSamples::Metadata* logged_meta)
bcwhite5cb99eb2016-02-01 21:07:561309 : Histogram(name,
1310 ranges->range(1),
1311 ranges->range(ranges->bucket_count() - 1),
1312 ranges,
1313 counts,
bcwhitec85a1f822016-02-18 21:22:141314 logged_counts,
bcwhitec85a1f822016-02-18 21:22:141315 meta,
1316 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561317
Daniel Cheng0d89f9222017-09-22 05:05:071318void CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
1319 Histogram::SerializeInfoImpl(pickle);
[email protected]cd56dff2011-11-13 04:19:151320
[email protected]c50c21d2013-01-11 21:52:441321 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't
1322 // write them.
Daniel Cheng0d89f9222017-09-22 05:05:071323 for (uint32_t i = 1; i < bucket_ranges()->bucket_count(); ++i)
1324 pickle->WriteInt(bucket_ranges()->range(i));
[email protected]cd56dff2011-11-13 04:19:151325}
1326
jam1eacd7e2016-02-08 22:48:161327double CustomHistogram::GetBucketSize(Count current, uint32_t i) const {
brianderson7406e5c2016-06-23 21:34:471328 // If this is a histogram of enum values, normalizing the bucket count
1329 // by the bucket range is not helpful, so just return the bucket count.
1330 return current;
[email protected]70cc56e42010-04-29 22:39:551331}
1332
[email protected]34d062322012-08-01 21:34:081333// static
[email protected]c50c21d2013-01-11 21:52:441334HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141335 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441336 int flags;
1337 int declared_min;
1338 int declared_max;
jam1eacd7e2016-02-08 22:48:161339 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:141340 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441341
1342 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1343 &declared_max, &bucket_count, &range_checksum)) {
Brian White7eb91482017-08-09 19:54:451344 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441345 }
1346
1347 // First and last ranges are not serialized.
asvitkine24d3e9a2015-05-27 05:22:141348 std::vector<Sample> sample_ranges(bucket_count - 1);
[email protected]c50c21d2013-01-11 21:52:441349
jam1eacd7e2016-02-08 22:48:161350 for (uint32_t i = 0; i < sample_ranges.size(); ++i) {
[email protected]c50c21d2013-01-11 21:52:441351 if (!iter->ReadInt(&sample_ranges[i]))
Brian White7eb91482017-08-09 19:54:451352 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441353 }
1354
1355 HistogramBase* histogram = CustomHistogram::FactoryGet(
1356 histogram_name, sample_ranges, flags);
Brian White82027ff5d2017-08-21 19:50:221357 if (!histogram)
1358 return nullptr;
1359
[email protected]c50c21d2013-01-11 21:52:441360 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1361 // The serialized histogram might be corrupted.
Brian White7eb91482017-08-09 19:54:451362 return nullptr;
[email protected]c50c21d2013-01-11 21:52:441363 }
1364 return histogram;
1365}
1366
1367// static
[email protected]34d062322012-08-01 21:34:081368bool CustomHistogram::ValidateCustomRanges(
asvitkine24d3e9a2015-05-27 05:22:141369 const std::vector<Sample>& custom_ranges) {
[email protected]640d95ef2012-08-04 06:23:031370 bool has_valid_range = false;
jam1eacd7e2016-02-08 22:48:161371 for (uint32_t i = 0; i < custom_ranges.size(); i++) {
[email protected]640d95ef2012-08-04 06:23:031372 Sample sample = custom_ranges[i];
1373 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
[email protected]34d062322012-08-01 21:34:081374 return false;
[email protected]640d95ef2012-08-04 06:23:031375 if (sample != 0)
1376 has_valid_range = true;
[email protected]34d062322012-08-01 21:34:081377 }
[email protected]640d95ef2012-08-04 06:23:031378 return has_valid_range;
[email protected]34d062322012-08-01 21:34:081379}
1380
[email protected]835d7c82010-10-14 04:38:381381} // namespace base