blob: df440851db3af159bac424d0526beafdc48fc022 [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
avi9b6f42932015-12-26 22:15:1412#include <limits.h>
initial.commitd7cae122008-07-26 21:49:3813#include <math.h>
[email protected]f1633932010-08-17 23:05:2814
15#include <algorithm>
initial.commitd7cae122008-07-26 21:49:3816#include <string>
jdoerrief1e72e32017-04-26 16:23:5517#include <utility>
initial.commitd7cae122008-07-26 21:49:3818
[email protected]ec0c0aa2012-08-14 02:02:0019#include "base/compiler_specific.h"
20#include "base/debug/alias.h"
initial.commitd7cae122008-07-26 21:49:3821#include "base/logging.h"
dcheng093de9b2016-04-04 21:25:5122#include "base/memory/ptr_util.h"
asvitkine454600f2015-06-16 16:34:5023#include "base/metrics/histogram_macros.h"
bcwhiteb036e4322015-12-10 18:36:3424#include "base/metrics/metrics_hashes.h"
bcwhite33d95806a2016-03-16 02:37:4525#include "base/metrics/persistent_histogram_allocator.h"
bcwhite5cb99eb2016-02-01 21:07:5626#include "base/metrics/persistent_memory_allocator.h"
[email protected]877ef562012-10-20 02:56:1827#include "base/metrics/sample_vector.h"
[email protected]567d30e2012-07-13 21:48:2928#include "base/metrics/statistics_recorder.h"
[email protected]3f383852009-04-03 18:18:5529#include "base/pickle.h"
[email protected]d529cb02013-06-10 19:06:5730#include "base/strings/string_util.h"
31#include "base/strings/stringprintf.h"
[email protected]bc581a682011-01-01 23:16:2032#include "base/synchronization/lock.h"
[email protected]24a7ec52012-10-08 10:31:5033#include "base/values.h"
initial.commitd7cae122008-07-26 21:49:3834
[email protected]835d7c82010-10-14 04:38:3835namespace base {
[email protected]e1acf6f2008-10-27 20:43:3336
[email protected]c50c21d2013-01-11 21:52:4437namespace {
38
39bool ReadHistogramArguments(PickleIterator* iter,
asvitkine24d3e9a2015-05-27 05:22:1440 std::string* histogram_name,
[email protected]c50c21d2013-01-11 21:52:4441 int* flags,
42 int* declared_min,
43 int* declared_max,
jam1eacd7e2016-02-08 22:48:1644 uint32_t* bucket_count,
avi9b6f42932015-12-26 22:15:1445 uint32_t* range_checksum) {
[email protected]c50c21d2013-01-11 21:52:4446 if (!iter->ReadString(histogram_name) ||
47 !iter->ReadInt(flags) ||
48 !iter->ReadInt(declared_min) ||
49 !iter->ReadInt(declared_max) ||
jam1eacd7e2016-02-08 22:48:1650 !iter->ReadUInt32(bucket_count) ||
[email protected]c50c21d2013-01-11 21:52:4451 !iter->ReadUInt32(range_checksum)) {
52 DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
53 return false;
54 }
55
56 // Since these fields may have come from an untrusted renderer, do additional
57 // checks above and beyond those in Histogram::Initialize()
58 if (*declared_max <= 0 ||
59 *declared_min <= 0 ||
60 *declared_max < *declared_min ||
61 INT_MAX / sizeof(HistogramBase::Count) <= *bucket_count ||
62 *bucket_count < 2) {
63 DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
64 return false;
65 }
66
67 // We use the arguments to find or create the local version of the histogram
bcwhite05dc0922016-06-03 04:59:4468 // in this process, so we need to clear any IPC flag.
[email protected]c50c21d2013-01-11 21:52:4469 *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
70
71 return true;
72}
73
74bool ValidateRangeChecksum(const HistogramBase& histogram,
avi9b6f42932015-12-26 22:15:1475 uint32_t range_checksum) {
[email protected]c50c21d2013-01-11 21:52:4476 const Histogram& casted_histogram =
77 static_cast<const Histogram&>(histogram);
78
79 return casted_histogram.bucket_ranges()->checksum() == range_checksum;
80}
81
82} // namespace
83
[email protected]34d062322012-08-01 21:34:0884typedef HistogramBase::Count Count;
85typedef HistogramBase::Sample Sample;
initial.commitd7cae122008-07-26 21:49:3886
[email protected]b122c0c2011-02-23 22:31:1887// static
jam1eacd7e2016-02-08 22:48:1688const uint32_t Histogram::kBucketCount_MAX = 16384u;
[email protected]b122c0c2011-02-23 22:31:1889
bcwhite5cb99eb2016-02-01 21:07:5690class Histogram::Factory {
91 public:
92 Factory(const std::string& name,
93 HistogramBase::Sample minimum,
94 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:1695 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:5696 int32_t flags)
97 : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
98
99 // Create histogram based on construction parameters. Caller takes
100 // ownership of the returned object.
101 HistogramBase* Build();
102
103 protected:
104 Factory(const std::string& name,
105 HistogramType histogram_type,
106 HistogramBase::Sample minimum,
107 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16108 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56109 int32_t flags)
110 : name_(name),
111 histogram_type_(histogram_type),
112 minimum_(minimum),
113 maximum_(maximum),
114 bucket_count_(bucket_count),
115 flags_(flags) {}
116
117 // Create a BucketRanges structure appropriate for this histogram.
118 virtual BucketRanges* CreateRanges() {
119 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
120 Histogram::InitializeBucketRanges(minimum_, maximum_, ranges);
bcwhite4485eb62017-07-04 21:39:07121 base::debug::Alias(&ranges); // TODO(bcwhite): Remove after crbug/586622.
bcwhite5cb99eb2016-02-01 21:07:56122 return ranges;
123 }
124
125 // Allocate the correct Histogram object off the heap (in case persistent
126 // memory is not available).
dcheng093de9b2016-04-04 21:25:51127 virtual std::unique_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) {
128 return WrapUnique(new Histogram(name_, minimum_, maximum_, ranges));
bcwhite5cb99eb2016-02-01 21:07:56129 }
130
131 // Perform any required datafill on the just-created histogram. If
bcwhite3dd85c4f2016-03-17 13:21:56132 // overridden, be sure to call the "super" version -- this method may not
133 // always remain empty.
134 virtual void FillHistogram(HistogramBase* histogram) {}
bcwhite5cb99eb2016-02-01 21:07:56135
136 // These values are protected (instead of private) because they need to
137 // be accessible to methods of sub-classes in order to avoid passing
138 // unnecessary parameters everywhere.
139 const std::string& name_;
140 const HistogramType histogram_type_;
141 HistogramBase::Sample minimum_;
142 HistogramBase::Sample maximum_;
jam1eacd7e2016-02-08 22:48:16143 uint32_t bucket_count_;
bcwhite5cb99eb2016-02-01 21:07:56144 int32_t flags_;
145
146 private:
147 DISALLOW_COPY_AND_ASSIGN(Factory);
148};
149
150HistogramBase* Histogram::Factory::Build() {
bcwhite5cb99eb2016-02-01 21:07:56151 HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
152 if (!histogram) {
153 // To avoid racy destruction at shutdown, the following will be leaked.
bcwhite4ebd7272016-03-22 19:14:38154 const BucketRanges* created_ranges = CreateRanges();
155 const BucketRanges* registered_ranges =
bcwhite5cb99eb2016-02-01 21:07:56156 StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
157
158 // In most cases, the bucket-count, minimum, and maximum values are known
159 // when the code is written and so are passed in explicitly. In other
160 // cases (such as with a CustomHistogram), they are calculated dynamically
161 // at run-time. In the latter case, those ctor parameters are zero and
162 // the results extracted from the result of CreateRanges().
163 if (bucket_count_ == 0) {
jam1eacd7e2016-02-08 22:48:16164 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count());
bcwhite5cb99eb2016-02-01 21:07:56165 minimum_ = registered_ranges->range(1);
166 maximum_ = registered_ranges->range(bucket_count_ - 1);
167 }
bcwhitef1dec482017-07-06 14:39:11168 DCHECK_EQ(minimum_, registered_ranges->range(1));
169 DCHECK_EQ(maximum_, registered_ranges->range(bucket_count_ - 1));
bcwhite5cb99eb2016-02-01 21:07:56170
171 // Try to create the histogram using a "persistent" allocator. As of
bcwhite3dd85c4f2016-03-17 13:21:56172 // 2016-02-25, the availability of such is controlled by a base::Feature
bcwhite5cb99eb2016-02-01 21:07:56173 // that is off by default. If the allocator doesn't exist or if
174 // allocating from it fails, code below will allocate the histogram from
175 // the process heap.
bcwhite4ebd7272016-03-22 19:14:38176 PersistentHistogramAllocator::Reference histogram_ref = 0;
dcheng093de9b2016-04-04 21:25:51177 std::unique_ptr<HistogramBase> tentative_histogram;
bcwhite5e748c62016-04-06 02:03:53178 PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
bcwhite5cb99eb2016-02-01 21:07:56179 if (allocator) {
bcwhite33d95806a2016-03-16 02:37:45180 tentative_histogram = allocator->AllocateHistogram(
bcwhite5cb99eb2016-02-01 21:07:56181 histogram_type_,
182 name_,
183 minimum_,
184 maximum_,
185 registered_ranges,
186 flags_,
187 &histogram_ref);
188 }
189
190 // Handle the case where no persistent allocator is present or the
191 // persistent allocation fails (perhaps because it is full).
192 if (!tentative_histogram) {
bcwhite4ebd7272016-03-22 19:14:38193 DCHECK(!histogram_ref); // Should never have been set.
194 DCHECK(!allocator); // Shouldn't have failed.
bcwhite5cb99eb2016-02-01 21:07:56195 flags_ &= ~HistogramBase::kIsPersistent;
196 tentative_histogram = HeapAlloc(registered_ranges);
bcwhite3dd85c4f2016-03-17 13:21:56197 tentative_histogram->SetFlags(flags_);
bcwhite5cb99eb2016-02-01 21:07:56198 }
199
bcwhite33d95806a2016-03-16 02:37:45200 FillHistogram(tentative_histogram.get());
201
202 // Register this histogram with the StatisticsRecorder. Keep a copy of
203 // the pointer value to tell later whether the locally created histogram
204 // was registered or deleted. The type is "void" because it could point
205 // to released memory after the following line.
206 const void* tentative_histogram_ptr = tentative_histogram.get();
207 histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
208 tentative_histogram.release());
bcwhite5cb99eb2016-02-01 21:07:56209
210 // Persistent histograms need some follow-up processing.
bcwhite4ebd7272016-03-22 19:14:38211 if (histogram_ref) {
bcwhite33d95806a2016-03-16 02:37:45212 allocator->FinalizeHistogram(histogram_ref,
213 histogram == tentative_histogram_ptr);
bcwhite5cb99eb2016-02-01 21:07:56214 }
bcwhited723c252016-03-16 17:25:41215
216 // Update report on created histograms.
217 ReportHistogramActivity(*histogram, HISTOGRAM_CREATED);
218 } else {
219 // Update report on lookup histograms.
220 ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP);
bcwhite5cb99eb2016-02-01 21:07:56221 }
222
kenrb03c2e972016-09-29 20:50:57223 CHECK_EQ(histogram_type_, histogram->GetHistogramType()) << name_;
bcwhite5cb99eb2016-02-01 21:07:56224 if (bucket_count_ != 0 &&
225 !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) {
226 // The construction arguments do not match the existing histogram. This can
227 // come about if an extension updates in the middle of a chrome run and has
228 // changed one of them, or simply by bad code within Chrome itself. We
229 // return NULL here with the expectation that bad code in Chrome will crash
230 // on dereference, but extension/Pepper APIs will guard against NULL and not
231 // crash.
232 DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments";
bcwhite4ebd7272016-03-22 19:14:38233 return nullptr;
bcwhite5cb99eb2016-02-01 21:07:56234 }
235 return histogram;
236}
237
asvitkine24d3e9a2015-05-27 05:22:14238HistogramBase* Histogram::FactoryGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17239 Sample minimum,
240 Sample maximum,
jam1eacd7e2016-02-08 22:48:16241 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14242 int32_t flags) {
[email protected]e184be902012-08-07 04:49:24243 bool valid_arguments =
244 InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
245 DCHECK(valid_arguments);
[email protected]a93721e22012-01-06 02:13:28246
bcwhite5cb99eb2016-02-01 21:07:56247 return Factory(name, minimum, maximum, bucket_count, flags).Build();
[email protected]e8829a192009-12-06 00:09:37248}
249
asvitkine24d3e9a2015-05-27 05:22:14250HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17251 TimeDelta minimum,
252 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16253 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14254 int32_t flags) {
pkasting9cf9b94a2014-10-01 22:18:43255 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
256 static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
257 flags);
[email protected]34d062322012-08-01 21:34:08258}
259
asvitkine5c2d5022015-06-19 00:37:50260HistogramBase* Histogram::FactoryGet(const char* name,
261 Sample minimum,
262 Sample maximum,
jam1eacd7e2016-02-08 22:48:16263 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14264 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50265 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
266}
267
268HistogramBase* Histogram::FactoryTimeGet(const char* name,
269 TimeDelta minimum,
270 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16271 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14272 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50273 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
274 flags);
275}
276
dcheng093de9b2016-04-04 21:25:51277std::unique_ptr<HistogramBase> Histogram::PersistentCreate(
bcwhitec85a1f822016-02-18 21:22:14278 const std::string& name,
279 Sample minimum,
280 Sample maximum,
281 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25282 const DelayedPersistentAllocation& counts,
283 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14284 HistogramSamples::Metadata* meta,
285 HistogramSamples::Metadata* logged_meta) {
dcheng093de9b2016-04-04 21:25:51286 return WrapUnique(new Histogram(name, minimum, maximum, ranges, counts,
bcwhitefa8485b2017-05-01 16:43:25287 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56288}
289
[email protected]34d062322012-08-01 21:34:08290// Calculate what range of values are held in each bucket.
291// We have to be careful that we don't pick a ratio between starting points in
292// consecutive buckets that is sooo small, that the integer bounds are the same
293// (effectively making one bucket get no values). We need to avoid:
294// ranges(i) == ranges(i + 1)
295// To avoid that, we just do a fine-grained bucket width as far as we need to
296// until we get a ratio that moves us along at least 2 units at a time. From
297// that bucket onward we do use the exponential growth of buckets.
298//
299// static
300void Histogram::InitializeBucketRanges(Sample minimum,
301 Sample maximum,
[email protected]34d062322012-08-01 21:34:08302 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08303 double log_max = log(static_cast<double>(maximum));
304 double log_ratio;
305 double log_next;
306 size_t bucket_index = 1;
307 Sample current = minimum;
308 ranges->set_range(bucket_index, current);
[email protected]15ce3842013-06-27 14:38:45309 size_t bucket_count = ranges->bucket_count();
[email protected]34d062322012-08-01 21:34:08310 while (bucket_count > ++bucket_index) {
311 double log_current;
312 log_current = log(static_cast<double>(current));
313 // Calculate the count'th root of the range.
314 log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
315 // See where the next bucket would start.
316 log_next = log_current + log_ratio;
317 Sample next;
318 next = static_cast<int>(floor(exp(log_next) + 0.5));
319 if (next > current)
320 current = next;
321 else
322 ++current; // Just do a narrow bucket, and keep trying.
323 ranges->set_range(bucket_index, current);
324 }
[email protected]15ce3842013-06-27 14:38:45325 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08326 ranges->ResetChecksum();
327}
328
[email protected]2f7d9cd2012-09-22 03:42:12329// static
330const int Histogram::kCommonRaceBasedCountMismatch = 5;
[email protected]34d062322012-08-01 21:34:08331
bcwhitec85a1f822016-02-18 21:22:14332uint32_t Histogram::FindCorruption(const HistogramSamples& samples) const {
[email protected]34d062322012-08-01 21:34:08333 int inconsistencies = NO_INCONSISTENCIES;
334 Sample previous_range = -1; // Bottom range is always 0.
jam1eacd7e2016-02-08 22:48:16335 for (uint32_t index = 0; index < bucket_count(); ++index) {
[email protected]34d062322012-08-01 21:34:08336 int new_range = ranges(index);
337 if (previous_range >= new_range)
338 inconsistencies |= BUCKET_ORDER_ERROR;
339 previous_range = new_range;
340 }
341
342 if (!bucket_ranges()->HasValidChecksum())
343 inconsistencies |= RANGE_CHECKSUM_ERROR;
344
avi9b6f42932015-12-26 22:15:14345 int64_t delta64 = samples.redundant_count() - samples.TotalCount();
[email protected]34d062322012-08-01 21:34:08346 if (delta64 != 0) {
347 int delta = static_cast<int>(delta64);
348 if (delta != delta64)
349 delta = INT_MAX; // Flag all giant errors as INT_MAX.
[email protected]34d062322012-08-01 21:34:08350 if (delta > 0) {
351 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
352 if (delta > kCommonRaceBasedCountMismatch)
353 inconsistencies |= COUNT_HIGH_ERROR;
354 } else {
355 DCHECK_GT(0, delta);
356 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
357 if (-delta > kCommonRaceBasedCountMismatch)
358 inconsistencies |= COUNT_LOW_ERROR;
359 }
360 }
[email protected]cc7dec212013-03-01 03:53:25361 return inconsistencies;
[email protected]34d062322012-08-01 21:34:08362}
363
bcwhitef1dec482017-07-06 14:39:11364Sample Histogram::declared_min() const {
365 if (bucket_ranges_->bucket_count() < 2)
366 return -1;
367 return bucket_ranges_->range(1);
368}
369
370Sample Histogram::declared_max() const {
371 if (bucket_ranges_->bucket_count() < 2)
372 return -1;
373 return bucket_ranges_->range(bucket_ranges_->bucket_count() - 1);
374}
375
jam1eacd7e2016-02-08 22:48:16376Sample Histogram::ranges(uint32_t i) const {
[email protected]34d062322012-08-01 21:34:08377 return bucket_ranges_->range(i);
378}
379
jam1eacd7e2016-02-08 22:48:16380uint32_t Histogram::bucket_count() const {
381 return static_cast<uint32_t>(bucket_ranges_->bucket_count());
[email protected]34d062322012-08-01 21:34:08382}
383
[email protected]34d062322012-08-01 21:34:08384// static
asvitkine24d3e9a2015-05-27 05:22:14385bool Histogram::InspectConstructionArguments(const std::string& name,
[email protected]34d062322012-08-01 21:34:08386 Sample* minimum,
387 Sample* maximum,
jam1eacd7e2016-02-08 22:48:16388 uint32_t* bucket_count) {
[email protected]34d062322012-08-01 21:34:08389 // Defensive code for backward compatibility.
390 if (*minimum < 1) {
[email protected]a5c7bd792012-08-02 00:29:04391 DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
[email protected]34d062322012-08-01 21:34:08392 *minimum = 1;
393 }
394 if (*maximum >= kSampleType_MAX) {
[email protected]a5c7bd792012-08-02 00:29:04395 DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
396 *maximum = kSampleType_MAX - 1;
[email protected]34d062322012-08-01 21:34:08397 }
[email protected]e184be902012-08-07 04:49:24398 if (*bucket_count >= kBucketCount_MAX) {
399 DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
400 << *bucket_count;
401 *bucket_count = kBucketCount_MAX - 1;
402 }
[email protected]34d062322012-08-01 21:34:08403
bcwhiteaaf2d3452017-04-26 19:17:47404 bool check_okay = true;
405
406 if (*minimum > *maximum) {
407 check_okay = false;
408 std::swap(*minimum, *maximum);
409 }
410 if (*maximum == *minimum) {
411 check_okay = false;
412 *maximum = *minimum + 1;
413 }
414 if (*bucket_count < 3) {
415 check_okay = false;
416 *bucket_count = 3;
417 }
asvitkinec49943d2017-05-25 19:29:47418 // Very high bucket counts are wasteful. Use a sparse histogram instead.
419 // Value of 10002 equals a user-supplied value of 10k + 2 overflow buckets.
420 constexpr uint32_t kMaxBucketCount = 10002;
421 if (*bucket_count > kMaxBucketCount) {
422 check_okay = false;
423 *bucket_count = kMaxBucketCount;
424 }
bcwhiteaaf2d3452017-04-26 19:17:47425 if (*bucket_count > static_cast<uint32_t>(*maximum - *minimum + 2)) {
426 check_okay = false;
427 *bucket_count = static_cast<uint32_t>(*maximum - *minimum + 2);
428 }
429
430 if (!check_okay) {
431 UMA_HISTOGRAM_SPARSE_SLOWLY("Histogram.BadConstructionArguments",
432 static_cast<Sample>(HashMetricName(name)));
433 }
434
435 return check_okay;
[email protected]34d062322012-08-01 21:34:08436}
437
bcwhiteb036e4322015-12-10 18:36:34438uint64_t Histogram::name_hash() const {
altimin498c8382017-05-12 17:49:18439 return unlogged_samples_->id();
bcwhiteb036e4322015-12-10 18:36:34440}
441
[email protected]07c02402012-10-31 06:20:25442HistogramType Histogram::GetHistogramType() const {
443 return HISTOGRAM;
444}
445
[email protected]15ce3842013-06-27 14:38:45446bool Histogram::HasConstructionArguments(Sample expected_minimum,
447 Sample expected_maximum,
jam1eacd7e2016-02-08 22:48:16448 uint32_t expected_bucket_count) const {
bcwhitef1dec482017-07-06 14:39:11449 return (expected_bucket_count == bucket_count() &&
450 expected_minimum == declared_min() &&
451 expected_maximum == declared_max());
[email protected]abae9b022012-10-24 08:18:52452}
453
454void Histogram::Add(int value) {
amohammadkhan6779b5c32015-08-05 20:31:11455 AddCount(value, 1);
456}
457
458void Histogram::AddCount(int value, int count) {
[email protected]abae9b022012-10-24 08:18:52459 DCHECK_EQ(0, ranges(0));
[email protected]15ce3842013-06-27 14:38:45460 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
[email protected]abae9b022012-10-24 08:18:52461
462 if (value > kSampleType_MAX - 1)
463 value = kSampleType_MAX - 1;
464 if (value < 0)
465 value = 0;
amohammadkhan6779b5c32015-08-05 20:31:11466 if (count <= 0) {
467 NOTREACHED();
468 return;
469 }
altimin498c8382017-05-12 17:49:18470 unlogged_samples_->Accumulate(value, count);
simonhatchdf5a8142015-07-15 22:22:57471
472 FindAndRunCallback(value);
[email protected]abae9b022012-10-24 08:18:52473}
474
dcheng093de9b2016-04-04 21:25:51475std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
altimin498c8382017-05-12 17:49:18476 return SnapshotAllSamples();
[email protected]abae9b022012-10-24 08:18:52477}
478
dcheng093de9b2016-04-04 21:25:51479std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() {
bcwhitef1dec482017-07-06 14:39:11480#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40481 DCHECK(!final_delta_created_);
bcwhitef1dec482017-07-06 14:39:11482#endif
483
altimin498c8382017-05-12 17:49:18484 // The code below has subtle thread-safety guarantees! All changes to
485 // the underlying SampleVectors use atomic integer operations, which guarantee
486 // eventual consistency, but do not guarantee full synchronization between
487 // different entries in the SampleVector. In particular, this means that
488 // concurrent updates to the histogram might result in the reported sum not
489 // matching the individual bucket counts; or there being some buckets that are
490 // logically updated "together", but end up being only partially updated when
491 // a snapshot is captured. Note that this is why it's important to subtract
492 // exactly the snapshotted unlogged samples, rather than simply resetting the
493 // vector: this way, the next snapshot will include any concurrent updates
494 // missed by the current snapshot.
bcwhite65e57d02016-05-13 14:39:40495
altimin498c8382017-05-12 17:49:18496 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples();
497 unlogged_samples_->Subtract(*snapshot);
bcwhitec85a1f822016-02-18 21:22:14498 logged_samples_->Add(*snapshot);
altimin498c8382017-05-12 17:49:18499
bcwhitec85a1f822016-02-18 21:22:14500 return snapshot;
501}
502
bcwhite65e57d02016-05-13 14:39:40503std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
bcwhitef1dec482017-07-06 14:39:11504#if DCHECK_IS_ON()
bcwhite65e57d02016-05-13 14:39:40505 DCHECK(!final_delta_created_);
506 final_delta_created_ = true;
bcwhitef1dec482017-07-06 14:39:11507#endif
bcwhite65e57d02016-05-13 14:39:40508
altimin498c8382017-05-12 17:49:18509 return SnapshotUnloggedSamples();
bcwhite65e57d02016-05-13 14:39:40510}
511
[email protected]c50c21d2013-01-11 21:52:44512void Histogram::AddSamples(const HistogramSamples& samples) {
altimin498c8382017-05-12 17:49:18513 unlogged_samples_->Add(samples);
[email protected]c50c21d2013-01-11 21:52:44514}
515
516bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
altimin498c8382017-05-12 17:49:18517 return unlogged_samples_->AddFromPickle(iter);
[email protected]c50c21d2013-01-11 21:52:44518}
519
[email protected]abae9b022012-10-24 08:18:52520// The following methods provide a graphical histogram display.
asvitkine24d3e9a2015-05-27 05:22:14521void Histogram::WriteHTMLGraph(std::string* output) const {
[email protected]abae9b022012-10-24 08:18:52522 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
523 output->append("<PRE>");
524 WriteAsciiImpl(true, "<br>", output);
525 output->append("</PRE>");
526}
527
asvitkine24d3e9a2015-05-27 05:22:14528void Histogram::WriteAscii(std::string* output) const {
[email protected]abae9b022012-10-24 08:18:52529 WriteAsciiImpl(true, "\n", output);
530}
531
[email protected]c50c21d2013-01-11 21:52:44532bool Histogram::SerializeInfoImpl(Pickle* pickle) const {
533 DCHECK(bucket_ranges()->HasValidChecksum());
534 return pickle->WriteString(histogram_name()) &&
535 pickle->WriteInt(flags()) &&
536 pickle->WriteInt(declared_min()) &&
537 pickle->WriteInt(declared_max()) &&
jam1eacd7e2016-02-08 22:48:16538 pickle->WriteUInt32(bucket_count()) &&
[email protected]c50c21d2013-01-11 21:52:44539 pickle->WriteUInt32(bucket_ranges()->checksum());
540}
541
bcwhitef1dec482017-07-06 14:39:11542// TODO(bcwhite): Remove minimum/maximum parameters from here and call chain.
asvitkine24d3e9a2015-05-27 05:22:14543Histogram::Histogram(const std::string& name,
[email protected]abae9b022012-10-24 08:18:52544 Sample minimum,
545 Sample maximum,
[email protected]abae9b022012-10-24 08:18:52546 const BucketRanges* ranges)
bcwhitef1dec482017-07-06 14:39:11547 : HistogramBase(name), bucket_ranges_(ranges) {
bcwhiteb7bde182017-06-19 20:00:44548 // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved.
549 CHECK(ranges) << name << ": " << minimum << "-" << maximum;
550 unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges));
551 logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges));
[email protected]abae9b022012-10-24 08:18:52552}
553
bcwhite5cb99eb2016-02-01 21:07:56554Histogram::Histogram(const std::string& name,
555 Sample minimum,
556 Sample maximum,
557 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25558 const DelayedPersistentAllocation& counts,
559 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14560 HistogramSamples::Metadata* meta,
561 HistogramSamples::Metadata* logged_meta)
bcwhitef1dec482017-07-06 14:39:11562 : HistogramBase(name), bucket_ranges_(ranges) {
bcwhiteb7bde182017-06-19 20:00:44563 // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved.
564 CHECK(ranges) << name << ": " << minimum << "-" << maximum;
565 unlogged_samples_.reset(
566 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts));
567 logged_samples_.reset(new PersistentSampleVector(
568 unlogged_samples_->id(), ranges, logged_meta, logged_counts));
bcwhite5cb99eb2016-02-01 21:07:56569}
570
[email protected]abae9b022012-10-24 08:18:52571Histogram::~Histogram() {
[email protected]abae9b022012-10-24 08:18:52572}
573
jam1eacd7e2016-02-08 22:48:16574bool Histogram::PrintEmptyBucket(uint32_t index) const {
[email protected]34d062322012-08-01 21:34:08575 return true;
576}
577
[email protected]34d062322012-08-01 21:34:08578// Use the actual bucket widths (like a linear histogram) until the widths get
579// over some transition value, and then use that transition width. Exponentials
580// get so big so fast (and we don't expect to see a lot of entries in the large
581// buckets), so we need this to make it possible to see what is going on and
582// not have 0-graphical-height buckets.
jam1eacd7e2016-02-08 22:48:16583double Histogram::GetBucketSize(Count current, uint32_t i) const {
[email protected]34d062322012-08-01 21:34:08584 DCHECK_GT(ranges(i + 1), ranges(i));
585 static const double kTransitionWidth = 5;
586 double denominator = ranges(i + 1) - ranges(i);
587 if (denominator > kTransitionWidth)
588 denominator = kTransitionWidth; // Stop trying to normalize.
589 return current/denominator;
590}
591
jam1eacd7e2016-02-08 22:48:16592const std::string Histogram::GetAsciiBucketRange(uint32_t i) const {
[email protected]f2bb3202013-04-05 21:21:54593 return GetSimpleAsciiBucketRange(ranges(i));
[email protected]34d062322012-08-01 21:34:08594}
595
[email protected]34d062322012-08-01 21:34:08596//------------------------------------------------------------------------------
597// Private methods
598
[email protected]c50c21d2013-01-11 21:52:44599// static
600HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14601 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44602 int flags;
603 int declared_min;
604 int declared_max;
jam1eacd7e2016-02-08 22:48:16605 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:14606 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44607
608 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
609 &declared_max, &bucket_count, &range_checksum)) {
610 return NULL;
611 }
612
613 // Find or create the local version of the histogram in this process.
614 HistogramBase* histogram = Histogram::FactoryGet(
615 histogram_name, declared_min, declared_max, bucket_count, flags);
616
617 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
618 // The serialized histogram might be corrupted.
619 return NULL;
620 }
621 return histogram;
622}
623
altimin498c8382017-05-12 17:49:18624std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const {
625 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamples();
626 samples->Add(*logged_samples_);
627 return samples;
628}
629
630std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const {
bcwhite09915232017-06-23 18:51:54631 // TODO(bcwhite): Remove these CHECKs once crbug/734049 is resolved.
bcwhite00537d12017-06-27 17:21:52632 HistogramSamples* unlogged = unlogged_samples_.get();
bcwhite09915232017-06-23 18:51:54633 CHECK(unlogged_samples_);
634 CHECK(unlogged_samples_->id());
635 CHECK(bucket_ranges());
dcheng093de9b2016-04-04 21:25:51636 std::unique_ptr<SampleVector> samples(
altimin498c8382017-05-12 17:49:18637 new SampleVector(unlogged_samples_->id(), bucket_ranges()));
638 samples->Add(*unlogged_samples_);
bcwhite00537d12017-06-27 17:21:52639 debug::Alias(&unlogged);
danakj0c8d4aa2015-11-25 05:29:58640 return samples;
[email protected]877ef562012-10-20 02:56:18641}
642
[email protected]34d062322012-08-01 21:34:08643void Histogram::WriteAsciiImpl(bool graph_it,
asvitkine24d3e9a2015-05-27 05:22:14644 const std::string& newline,
645 std::string* output) const {
[email protected]34d062322012-08-01 21:34:08646 // Get local (stack) copies of all effectively volatile class data so that we
647 // are consistent across our output activities.
altimin498c8382017-05-12 17:49:18648 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
[email protected]2f7d9cd2012-09-22 03:42:12649 Count sample_count = snapshot->TotalCount();
[email protected]34d062322012-08-01 21:34:08650
[email protected]2f7d9cd2012-09-22 03:42:12651 WriteAsciiHeader(*snapshot, sample_count, output);
[email protected]34d062322012-08-01 21:34:08652 output->append(newline);
653
654 // Prepare to normalize graphical rendering of bucket contents.
655 double max_size = 0;
656 if (graph_it)
[email protected]2f7d9cd2012-09-22 03:42:12657 max_size = GetPeakBucketSize(*snapshot);
[email protected]34d062322012-08-01 21:34:08658
659 // Calculate space needed to print bucket range numbers. Leave room to print
660 // nearly the largest bucket range without sliding over the histogram.
jam1eacd7e2016-02-08 22:48:16661 uint32_t largest_non_empty_bucket = bucket_count() - 1;
[email protected]2f7d9cd2012-09-22 03:42:12662 while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) {
[email protected]34d062322012-08-01 21:34:08663 if (0 == largest_non_empty_bucket)
664 break; // All buckets are empty.
665 --largest_non_empty_bucket;
666 }
667
668 // Calculate largest print width needed for any of our bucket range displays.
669 size_t print_width = 1;
jam1eacd7e2016-02-08 22:48:16670 for (uint32_t i = 0; i < bucket_count(); ++i) {
[email protected]2f7d9cd2012-09-22 03:42:12671 if (snapshot->GetCountAtIndex(i)) {
[email protected]34d062322012-08-01 21:34:08672 size_t width = GetAsciiBucketRange(i).size() + 1;
673 if (width > print_width)
674 print_width = width;
675 }
676 }
677
avi9b6f42932015-12-26 22:15:14678 int64_t remaining = sample_count;
679 int64_t past = 0;
[email protected]34d062322012-08-01 21:34:08680 // Output the actual histogram graph.
jam1eacd7e2016-02-08 22:48:16681 for (uint32_t i = 0; i < bucket_count(); ++i) {
[email protected]2f7d9cd2012-09-22 03:42:12682 Count current = snapshot->GetCountAtIndex(i);
[email protected]34d062322012-08-01 21:34:08683 if (!current && !PrintEmptyBucket(i))
684 continue;
685 remaining -= current;
asvitkine24d3e9a2015-05-27 05:22:14686 std::string range = GetAsciiBucketRange(i);
[email protected]34d062322012-08-01 21:34:08687 output->append(range);
688 for (size_t j = 0; range.size() + j < print_width + 1; ++j)
689 output->push_back(' ');
[email protected]2f7d9cd2012-09-22 03:42:12690 if (0 == current && i < bucket_count() - 1 &&
691 0 == snapshot->GetCountAtIndex(i + 1)) {
692 while (i < bucket_count() - 1 &&
693 0 == snapshot->GetCountAtIndex(i + 1)) {
[email protected]34d062322012-08-01 21:34:08694 ++i;
[email protected]2f7d9cd2012-09-22 03:42:12695 }
[email protected]34d062322012-08-01 21:34:08696 output->append("... ");
697 output->append(newline);
698 continue; // No reason to plot emptiness.
699 }
700 double current_size = GetBucketSize(current, i);
701 if (graph_it)
702 WriteAsciiBucketGraph(current_size, max_size, output);
703 WriteAsciiBucketContext(past, current, remaining, i, output);
704 output->append(newline);
705 past += current;
706 }
707 DCHECK_EQ(sample_count, past);
708}
709
bcwhitefa8485b2017-05-01 16:43:25710double Histogram::GetPeakBucketSize(const SampleVectorBase& samples) const {
[email protected]34d062322012-08-01 21:34:08711 double max = 0;
jam1eacd7e2016-02-08 22:48:16712 for (uint32_t i = 0; i < bucket_count() ; ++i) {
[email protected]2f7d9cd2012-09-22 03:42:12713 double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
[email protected]34d062322012-08-01 21:34:08714 if (current_size > max)
715 max = current_size;
716 }
717 return max;
718}
719
bcwhitefa8485b2017-05-01 16:43:25720void Histogram::WriteAsciiHeader(const SampleVectorBase& samples,
[email protected]34d062322012-08-01 21:34:08721 Count sample_count,
asvitkine24d3e9a2015-05-27 05:22:14722 std::string* output) const {
[email protected]34d062322012-08-01 21:34:08723 StringAppendF(output,
724 "Histogram: %s recorded %d samples",
725 histogram_name().c_str(),
726 sample_count);
rkaplow035eb122016-09-28 21:48:36727 if (sample_count == 0) {
[email protected]2f7d9cd2012-09-22 03:42:12728 DCHECK_EQ(samples.sum(), 0);
[email protected]34d062322012-08-01 21:34:08729 } else {
rkaplow035eb122016-09-28 21:48:36730 double mean = static_cast<float>(samples.sum()) / sample_count;
731 StringAppendF(output, ", mean = %.1f", mean);
[email protected]34d062322012-08-01 21:34:08732 }
rkaplow035eb122016-09-28 21:48:36733 if (flags())
734 StringAppendF(output, " (flags = 0x%x)", flags());
[email protected]34d062322012-08-01 21:34:08735}
736
avi9b6f42932015-12-26 22:15:14737void Histogram::WriteAsciiBucketContext(const int64_t past,
[email protected]34d062322012-08-01 21:34:08738 const Count current,
avi9b6f42932015-12-26 22:15:14739 const int64_t remaining,
jam1eacd7e2016-02-08 22:48:16740 const uint32_t i,
asvitkine24d3e9a2015-05-27 05:22:14741 std::string* output) const {
[email protected]34d062322012-08-01 21:34:08742 double scaled_sum = (past + current + remaining) / 100.0;
743 WriteAsciiBucketValue(current, scaled_sum, output);
744 if (0 < i) {
745 double percentage = past / scaled_sum;
746 StringAppendF(output, " {%3.1f%%}", percentage);
747 }
748}
749
[email protected]24a7ec52012-10-08 10:31:50750void Histogram::GetParameters(DictionaryValue* params) const {
[email protected]07c02402012-10-31 06:20:25751 params->SetString("type", HistogramTypeToString(GetHistogramType()));
[email protected]24a7ec52012-10-08 10:31:50752 params->SetInteger("min", declared_min());
753 params->SetInteger("max", declared_max());
754 params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
755}
756
[email protected]cdd98fc2013-05-10 09:32:58757void Histogram::GetCountAndBucketData(Count* count,
avi9b6f42932015-12-26 22:15:14758 int64_t* sum,
[email protected]cdd98fc2013-05-10 09:32:58759 ListValue* buckets) const {
altimin498c8382017-05-12 17:49:18760 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
[email protected]24a7ec52012-10-08 10:31:50761 *count = snapshot->TotalCount();
[email protected]cdd98fc2013-05-10 09:32:58762 *sum = snapshot->sum();
jam1eacd7e2016-02-08 22:48:16763 uint32_t index = 0;
764 for (uint32_t i = 0; i < bucket_count(); ++i) {
scottmgdcc933d2015-01-27 21:37:55765 Sample count_at_index = snapshot->GetCountAtIndex(i);
766 if (count_at_index > 0) {
dcheng093de9b2016-04-04 21:25:51767 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue());
[email protected]24a7ec52012-10-08 10:31:50768 bucket_value->SetInteger("low", ranges(i));
769 if (i != bucket_count() - 1)
770 bucket_value->SetInteger("high", ranges(i + 1));
scottmgdcc933d2015-01-27 21:37:55771 bucket_value->SetInteger("count", count_at_index);
jdoerrief1e72e32017-04-26 16:23:55772 buckets->Set(index, std::move(bucket_value));
[email protected]24a7ec52012-10-08 10:31:50773 ++index;
774 }
775 }
776}
777
[email protected]34d062322012-08-01 21:34:08778//------------------------------------------------------------------------------
779// LinearHistogram: This histogram uses a traditional set of evenly spaced
780// buckets.
781//------------------------------------------------------------------------------
782
bcwhite5cb99eb2016-02-01 21:07:56783class LinearHistogram::Factory : public Histogram::Factory {
784 public:
785 Factory(const std::string& name,
786 HistogramBase::Sample minimum,
787 HistogramBase::Sample maximum,
jam1eacd7e2016-02-08 22:48:16788 uint32_t bucket_count,
bcwhite5cb99eb2016-02-01 21:07:56789 int32_t flags,
790 const DescriptionPair* descriptions)
791 : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum,
792 bucket_count, flags) {
793 descriptions_ = descriptions;
794 }
795
796 protected:
797 BucketRanges* CreateRanges() override {
798 BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
799 LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
bcwhite4485eb62017-07-04 21:39:07800 base::debug::Alias(&ranges); // TODO(bcwhite): Remove after crbug/586622.
bcwhite5cb99eb2016-02-01 21:07:56801 return ranges;
802 }
803
dcheng093de9b2016-04-04 21:25:51804 std::unique_ptr<HistogramBase> HeapAlloc(
805 const BucketRanges* ranges) override {
riceaec7c3997e2016-09-13 04:10:11806 return WrapUnique(new LinearHistogram(name_, minimum_, maximum_, ranges));
bcwhite5cb99eb2016-02-01 21:07:56807 }
808
809 void FillHistogram(HistogramBase* base_histogram) override {
810 Histogram::Factory::FillHistogram(base_histogram);
811 LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
812 // Set range descriptions.
813 if (descriptions_) {
814 for (int i = 0; descriptions_[i].description; ++i) {
815 histogram->bucket_description_[descriptions_[i].sample] =
816 descriptions_[i].description;
817 }
818 }
819 }
820
821 private:
822 const DescriptionPair* descriptions_;
823
824 DISALLOW_COPY_AND_ASSIGN(Factory);
825};
826
[email protected]34d062322012-08-01 21:34:08827LinearHistogram::~LinearHistogram() {}
828
asvitkine24d3e9a2015-05-27 05:22:14829HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17830 Sample minimum,
831 Sample maximum,
jam1eacd7e2016-02-08 22:48:16832 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14833 int32_t flags) {
[email protected]07c02402012-10-31 06:20:25834 return FactoryGetWithRangeDescription(
835 name, minimum, maximum, bucket_count, flags, NULL);
836}
837
asvitkine24d3e9a2015-05-27 05:22:14838HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
[email protected]de415552013-01-23 04:12:17839 TimeDelta minimum,
840 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16841 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14842 int32_t flags) {
pkasting9cf9b94a2014-10-01 22:18:43843 return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
844 static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
845 flags);
[email protected]07c02402012-10-31 06:20:25846}
847
asvitkine5c2d5022015-06-19 00:37:50848HistogramBase* LinearHistogram::FactoryGet(const char* name,
849 Sample minimum,
850 Sample maximum,
jam1eacd7e2016-02-08 22:48:16851 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14852 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50853 return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
854}
855
856HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
857 TimeDelta minimum,
858 TimeDelta maximum,
jam1eacd7e2016-02-08 22:48:16859 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14860 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:50861 return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
862 flags);
863}
864
dcheng093de9b2016-04-04 21:25:51865std::unique_ptr<HistogramBase> LinearHistogram::PersistentCreate(
bcwhite5cb99eb2016-02-01 21:07:56866 const std::string& name,
867 Sample minimum,
868 Sample maximum,
869 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:25870 const DelayedPersistentAllocation& counts,
871 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:14872 HistogramSamples::Metadata* meta,
873 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:25874 return WrapUnique(new LinearHistogram(name, minimum, maximum, ranges, counts,
875 logged_counts, meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:56876}
877
[email protected]de415552013-01-23 04:12:17878HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
avi9b6f42932015-12-26 22:15:14879 const std::string& name,
880 Sample minimum,
881 Sample maximum,
jam1eacd7e2016-02-08 22:48:16882 uint32_t bucket_count,
avi9b6f42932015-12-26 22:15:14883 int32_t flags,
884 const DescriptionPair descriptions[]) {
[email protected]e184be902012-08-07 04:49:24885 bool valid_arguments = Histogram::InspectConstructionArguments(
886 name, &minimum, &maximum, &bucket_count);
887 DCHECK(valid_arguments);
[email protected]34d062322012-08-01 21:34:08888
bcwhite5cb99eb2016-02-01 21:07:56889 return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
890 .Build();
[email protected]34d062322012-08-01 21:34:08891}
892
[email protected]07c02402012-10-31 06:20:25893HistogramType LinearHistogram::GetHistogramType() const {
[email protected]b7d08202011-01-25 17:29:39894 return LINEAR_HISTOGRAM;
895}
896
asvitkine24d3e9a2015-05-27 05:22:14897LinearHistogram::LinearHistogram(const std::string& name,
[email protected]835d7c82010-10-14 04:38:38898 Sample minimum,
899 Sample maximum,
[email protected]34d062322012-08-01 21:34:08900 const BucketRanges* ranges)
[email protected]15ce3842013-06-27 14:38:45901 : Histogram(name, minimum, maximum, ranges) {
initial.commitd7cae122008-07-26 21:49:38902}
903
bcwhitefa8485b2017-05-01 16:43:25904LinearHistogram::LinearHistogram(
905 const std::string& name,
906 Sample minimum,
907 Sample maximum,
908 const BucketRanges* ranges,
909 const DelayedPersistentAllocation& counts,
910 const DelayedPersistentAllocation& logged_counts,
911 HistogramSamples::Metadata* meta,
912 HistogramSamples::Metadata* logged_meta)
913 : Histogram(name,
914 minimum,
915 maximum,
916 ranges,
917 counts,
918 logged_counts,
919 meta,
920 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:56921
jam1eacd7e2016-02-08 22:48:16922double LinearHistogram::GetBucketSize(Count current, uint32_t i) const {
[email protected]2ef3748f2010-10-19 17:33:28923 DCHECK_GT(ranges(i + 1), ranges(i));
initial.commitd7cae122008-07-26 21:49:38924 // Adjacent buckets with different widths would have "surprisingly" many (few)
925 // samples in a histogram if we didn't normalize this way.
926 double denominator = ranges(i + 1) - ranges(i);
927 return current/denominator;
928}
929
jam1eacd7e2016-02-08 22:48:16930const std::string LinearHistogram::GetAsciiBucketRange(uint32_t i) const {
[email protected]b7d08202011-01-25 17:29:39931 int range = ranges(i);
932 BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
933 if (it == bucket_description_.end())
934 return Histogram::GetAsciiBucketRange(i);
935 return it->second;
936}
937
jam1eacd7e2016-02-08 22:48:16938bool LinearHistogram::PrintEmptyBucket(uint32_t index) const {
[email protected]b7d08202011-01-25 17:29:39939 return bucket_description_.find(ranges(index)) == bucket_description_.end();
940}
941
[email protected]34d062322012-08-01 21:34:08942// static
943void LinearHistogram::InitializeBucketRanges(Sample minimum,
944 Sample maximum,
[email protected]34d062322012-08-01 21:34:08945 BucketRanges* ranges) {
[email protected]34d062322012-08-01 21:34:08946 double min = minimum;
947 double max = maximum;
[email protected]15ce3842013-06-27 14:38:45948 size_t bucket_count = ranges->bucket_count();
949 for (size_t i = 1; i < bucket_count; ++i) {
[email protected]34d062322012-08-01 21:34:08950 double linear_range =
[email protected]15ce3842013-06-27 14:38:45951 (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
[email protected]34d062322012-08-01 21:34:08952 ranges->set_range(i, static_cast<Sample>(linear_range + 0.5));
bcwhite76ed19582016-02-19 21:28:54953 // TODO(bcwhite): Remove once crbug/586622 is fixed.
954 base::debug::Alias(&linear_range);
[email protected]34d062322012-08-01 21:34:08955 }
[email protected]15ce3842013-06-27 14:38:45956 ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
[email protected]34d062322012-08-01 21:34:08957 ranges->ResetChecksum();
958}
[email protected]b7d08202011-01-25 17:29:39959
[email protected]c50c21d2013-01-11 21:52:44960// static
961HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:14962 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:44963 int flags;
964 int declared_min;
965 int declared_max;
jam1eacd7e2016-02-08 22:48:16966 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:14967 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:44968
969 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
970 &declared_max, &bucket_count, &range_checksum)) {
971 return NULL;
972 }
973
974 HistogramBase* histogram = LinearHistogram::FactoryGet(
975 histogram_name, declared_min, declared_max, bucket_count, flags);
976 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
977 // The serialized histogram might be corrupted.
978 return NULL;
979 }
980 return histogram;
981}
982
initial.commitd7cae122008-07-26 21:49:38983//------------------------------------------------------------------------------
[email protected]e8829a192009-12-06 00:09:37984// This section provides implementation for BooleanHistogram.
985//------------------------------------------------------------------------------
986
bcwhite5cb99eb2016-02-01 21:07:56987class BooleanHistogram::Factory : public Histogram::Factory {
988 public:
989 Factory(const std::string& name, int32_t flags)
990 : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
991
992 protected:
993 BucketRanges* CreateRanges() override {
994 BucketRanges* ranges = new BucketRanges(3 + 1);
[email protected]15ce3842013-06-27 14:38:45995 LinearHistogram::InitializeBucketRanges(1, 2, ranges);
bcwhite4485eb62017-07-04 21:39:07996 base::debug::Alias(&ranges); // TODO(bcwhite): Remove after crbug/586622.
bcwhite5cb99eb2016-02-01 21:07:56997 return ranges;
[email protected]e8829a192009-12-06 00:09:37998 }
999
dcheng093de9b2016-04-04 21:25:511000 std::unique_ptr<HistogramBase> HeapAlloc(
1001 const BucketRanges* ranges) override {
1002 return WrapUnique(new BooleanHistogram(name_, ranges));
bcwhite5cb99eb2016-02-01 21:07:561003 }
1004
1005 private:
1006 DISALLOW_COPY_AND_ASSIGN(Factory);
1007};
1008
1009HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
1010 int32_t flags) {
1011 return Factory(name, flags).Build();
[email protected]e8829a192009-12-06 00:09:371012}
1013
avi9b6f42932015-12-26 22:15:141014HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:501015 return FactoryGet(std::string(name), flags);
1016}
1017
dcheng093de9b2016-04-04 21:25:511018std::unique_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
bcwhite5cb99eb2016-02-01 21:07:561019 const std::string& name,
1020 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251021 const DelayedPersistentAllocation& counts,
1022 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141023 HistogramSamples::Metadata* meta,
1024 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:251025 return WrapUnique(new BooleanHistogram(name, ranges, counts, logged_counts,
1026 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561027}
1028
[email protected]07c02402012-10-31 06:20:251029HistogramType BooleanHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281030 return BOOLEAN_HISTOGRAM;
1031}
1032
asvitkine24d3e9a2015-05-27 05:22:141033BooleanHistogram::BooleanHistogram(const std::string& name,
[email protected]34d062322012-08-01 21:34:081034 const BucketRanges* ranges)
[email protected]15ce3842013-06-27 14:38:451035 : LinearHistogram(name, 1, 2, ranges) {}
initial.commitd7cae122008-07-26 21:49:381036
bcwhitefa8485b2017-05-01 16:43:251037BooleanHistogram::BooleanHistogram(
1038 const std::string& name,
1039 const BucketRanges* ranges,
1040 const DelayedPersistentAllocation& counts,
1041 const DelayedPersistentAllocation& logged_counts,
1042 HistogramSamples::Metadata* meta,
1043 HistogramSamples::Metadata* logged_meta)
1044 : LinearHistogram(name,
1045 1,
1046 2,
1047 ranges,
1048 counts,
1049 logged_counts,
1050 meta,
bcwhitec85a1f822016-02-18 21:22:141051 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561052
[email protected]c50c21d2013-01-11 21:52:441053HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141054 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441055 int flags;
1056 int declared_min;
1057 int declared_max;
jam1eacd7e2016-02-08 22:48:161058 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:141059 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441060
1061 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1062 &declared_max, &bucket_count, &range_checksum)) {
1063 return NULL;
1064 }
1065
1066 HistogramBase* histogram = BooleanHistogram::FactoryGet(
1067 histogram_name, flags);
1068 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1069 // The serialized histogram might be corrupted.
1070 return NULL;
1071 }
1072 return histogram;
1073}
1074
initial.commitd7cae122008-07-26 21:49:381075//------------------------------------------------------------------------------
[email protected]70cc56e42010-04-29 22:39:551076// CustomHistogram:
1077//------------------------------------------------------------------------------
1078
bcwhite5cb99eb2016-02-01 21:07:561079class CustomHistogram::Factory : public Histogram::Factory {
1080 public:
1081 Factory(const std::string& name,
1082 const std::vector<Sample>* custom_ranges,
1083 int32_t flags)
1084 : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
1085 custom_ranges_ = custom_ranges;
1086 }
1087
1088 protected:
1089 BucketRanges* CreateRanges() override {
1090 // Remove the duplicates in the custom ranges array.
1091 std::vector<int> ranges = *custom_ranges_;
1092 ranges.push_back(0); // Ensure we have a zero value.
1093 ranges.push_back(HistogramBase::kSampleType_MAX);
1094 std::sort(ranges.begin(), ranges.end());
1095 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
1096
1097 BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
jam1eacd7e2016-02-08 22:48:161098 for (uint32_t i = 0; i < ranges.size(); i++) {
bcwhite5cb99eb2016-02-01 21:07:561099 bucket_ranges->set_range(i, ranges[i]);
1100 }
1101 bucket_ranges->ResetChecksum();
1102 return bucket_ranges;
1103 }
1104
dcheng093de9b2016-04-04 21:25:511105 std::unique_ptr<HistogramBase> HeapAlloc(
1106 const BucketRanges* ranges) override {
1107 return WrapUnique(new CustomHistogram(name_, ranges));
bcwhite5cb99eb2016-02-01 21:07:561108 }
1109
1110 private:
1111 const std::vector<Sample>* custom_ranges_;
1112
1113 DISALLOW_COPY_AND_ASSIGN(Factory);
1114};
1115
asvitkine24d3e9a2015-05-27 05:22:141116HistogramBase* CustomHistogram::FactoryGet(
1117 const std::string& name,
1118 const std::vector<Sample>& custom_ranges,
avi9b6f42932015-12-26 22:15:141119 int32_t flags) {
[email protected]34d062322012-08-01 21:34:081120 CHECK(ValidateCustomRanges(custom_ranges));
[email protected]70cc56e42010-04-29 22:39:551121
bcwhite5cb99eb2016-02-01 21:07:561122 return Factory(name, &custom_ranges, flags).Build();
[email protected]70cc56e42010-04-29 22:39:551123}
1124
asvitkine5c2d5022015-06-19 00:37:501125HistogramBase* CustomHistogram::FactoryGet(
1126 const char* name,
1127 const std::vector<Sample>& custom_ranges,
avi9b6f42932015-12-26 22:15:141128 int32_t flags) {
asvitkine5c2d5022015-06-19 00:37:501129 return FactoryGet(std::string(name), custom_ranges, flags);
1130}
1131
dcheng093de9b2016-04-04 21:25:511132std::unique_ptr<HistogramBase> CustomHistogram::PersistentCreate(
bcwhite5cb99eb2016-02-01 21:07:561133 const std::string& name,
1134 const BucketRanges* ranges,
bcwhitefa8485b2017-05-01 16:43:251135 const DelayedPersistentAllocation& counts,
1136 const DelayedPersistentAllocation& logged_counts,
bcwhitec85a1f822016-02-18 21:22:141137 HistogramSamples::Metadata* meta,
1138 HistogramSamples::Metadata* logged_meta) {
bcwhitefa8485b2017-05-01 16:43:251139 return WrapUnique(new CustomHistogram(name, ranges, counts, logged_counts,
1140 meta, logged_meta));
bcwhite5cb99eb2016-02-01 21:07:561141}
1142
[email protected]07c02402012-10-31 06:20:251143HistogramType CustomHistogram::GetHistogramType() const {
[email protected]5d91c9e2010-07-28 17:25:281144 return CUSTOM_HISTOGRAM;
1145}
1146
[email protected]961fefb2011-05-24 13:59:581147// static
asvitkine24d3e9a2015-05-27 05:22:141148std::vector<Sample> CustomHistogram::ArrayToCustomRanges(
jam1eacd7e2016-02-08 22:48:161149 const Sample* values, uint32_t num_values) {
asvitkine24d3e9a2015-05-27 05:22:141150 std::vector<Sample> all_values;
jam1eacd7e2016-02-08 22:48:161151 for (uint32_t i = 0; i < num_values; ++i) {
[email protected]961fefb2011-05-24 13:59:581152 Sample value = values[i];
1153 all_values.push_back(value);
1154
1155 // Ensure that a guard bucket is added. If we end up with duplicate
1156 // values, FactoryGet will take care of removing them.
1157 all_values.push_back(value + 1);
1158 }
1159 return all_values;
1160}
1161
asvitkine24d3e9a2015-05-27 05:22:141162CustomHistogram::CustomHistogram(const std::string& name,
[email protected]34d062322012-08-01 21:34:081163 const BucketRanges* ranges)
1164 : Histogram(name,
1165 ranges->range(1),
[email protected]15ce3842013-06-27 14:38:451166 ranges->range(ranges->bucket_count() - 1),
[email protected]34d062322012-08-01 21:34:081167 ranges) {}
[email protected]70cc56e42010-04-29 22:39:551168
bcwhitefa8485b2017-05-01 16:43:251169CustomHistogram::CustomHistogram(
1170 const std::string& name,
1171 const BucketRanges* ranges,
1172 const DelayedPersistentAllocation& counts,
1173 const DelayedPersistentAllocation& logged_counts,
1174 HistogramSamples::Metadata* meta,
1175 HistogramSamples::Metadata* logged_meta)
bcwhite5cb99eb2016-02-01 21:07:561176 : Histogram(name,
1177 ranges->range(1),
1178 ranges->range(ranges->bucket_count() - 1),
1179 ranges,
1180 counts,
bcwhitec85a1f822016-02-18 21:22:141181 logged_counts,
bcwhitec85a1f822016-02-18 21:22:141182 meta,
1183 logged_meta) {}
bcwhite5cb99eb2016-02-01 21:07:561184
[email protected]c50c21d2013-01-11 21:52:441185bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
1186 if (!Histogram::SerializeInfoImpl(pickle))
1187 return false;
[email protected]cd56dff2011-11-13 04:19:151188
[email protected]c50c21d2013-01-11 21:52:441189 // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't
1190 // write them.
jam1eacd7e2016-02-08 22:48:161191 for (uint32_t i = 1; i < bucket_ranges()->bucket_count(); ++i) {
[email protected]c50c21d2013-01-11 21:52:441192 if (!pickle->WriteInt(bucket_ranges()->range(i)))
[email protected]cd56dff2011-11-13 04:19:151193 return false;
1194 }
1195 return true;
1196}
1197
jam1eacd7e2016-02-08 22:48:161198double CustomHistogram::GetBucketSize(Count current, uint32_t i) const {
brianderson7406e5c2016-06-23 21:34:471199 // If this is a histogram of enum values, normalizing the bucket count
1200 // by the bucket range is not helpful, so just return the bucket count.
1201 return current;
[email protected]70cc56e42010-04-29 22:39:551202}
1203
[email protected]34d062322012-08-01 21:34:081204// static
[email protected]c50c21d2013-01-11 21:52:441205HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
asvitkine24d3e9a2015-05-27 05:22:141206 std::string histogram_name;
[email protected]c50c21d2013-01-11 21:52:441207 int flags;
1208 int declared_min;
1209 int declared_max;
jam1eacd7e2016-02-08 22:48:161210 uint32_t bucket_count;
avi9b6f42932015-12-26 22:15:141211 uint32_t range_checksum;
[email protected]c50c21d2013-01-11 21:52:441212
1213 if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
1214 &declared_max, &bucket_count, &range_checksum)) {
1215 return NULL;
1216 }
1217
1218 // First and last ranges are not serialized.
asvitkine24d3e9a2015-05-27 05:22:141219 std::vector<Sample> sample_ranges(bucket_count - 1);
[email protected]c50c21d2013-01-11 21:52:441220
jam1eacd7e2016-02-08 22:48:161221 for (uint32_t i = 0; i < sample_ranges.size(); ++i) {
[email protected]c50c21d2013-01-11 21:52:441222 if (!iter->ReadInt(&sample_ranges[i]))
1223 return NULL;
1224 }
1225
1226 HistogramBase* histogram = CustomHistogram::FactoryGet(
1227 histogram_name, sample_ranges, flags);
1228 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
1229 // The serialized histogram might be corrupted.
1230 return NULL;
1231 }
1232 return histogram;
1233}
1234
1235// static
[email protected]34d062322012-08-01 21:34:081236bool CustomHistogram::ValidateCustomRanges(
asvitkine24d3e9a2015-05-27 05:22:141237 const std::vector<Sample>& custom_ranges) {
[email protected]640d95ef2012-08-04 06:23:031238 bool has_valid_range = false;
jam1eacd7e2016-02-08 22:48:161239 for (uint32_t i = 0; i < custom_ranges.size(); i++) {
[email protected]640d95ef2012-08-04 06:23:031240 Sample sample = custom_ranges[i];
1241 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
[email protected]34d062322012-08-01 21:34:081242 return false;
[email protected]640d95ef2012-08-04 06:23:031243 if (sample != 0)
1244 has_valid_range = true;
[email protected]34d062322012-08-01 21:34:081245 }
[email protected]640d95ef2012-08-04 06:23:031246 return has_valid_range;
[email protected]34d062322012-08-01 21:34:081247}
1248
[email protected]835d7c82010-10-14 04:38:381249} // namespace base