OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Histogram is an object that aggregates statistics, and can summarize them in | 5 // Histogram is an object that aggregates statistics, and can summarize them in |
6 // various forms, including ASCII graphical, HTML, and numerically (as a | 6 // various forms, including ASCII graphical, HTML, and numerically (as a |
7 // vector of numbers corresponding to each of the aggregating buckets). | 7 // vector of numbers corresponding to each of the aggregating buckets). |
8 // See header file for details and examples. | 8 // See header file for details and examples. |
9 | 9 |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 // In most cases, the bucket-count, minimum, and maximum values are known | 157 // In most cases, the bucket-count, minimum, and maximum values are known |
158 // when the code is written and so are passed in explicitly. In other | 158 // when the code is written and so are passed in explicitly. In other |
159 // cases (such as with a CustomHistogram), they are calculated dynamically | 159 // cases (such as with a CustomHistogram), they are calculated dynamically |
160 // at run-time. In the latter case, those ctor parameters are zero and | 160 // at run-time. In the latter case, those ctor parameters are zero and |
161 // the results extracted from the result of CreateRanges(). | 161 // the results extracted from the result of CreateRanges(). |
162 if (bucket_count_ == 0) { | 162 if (bucket_count_ == 0) { |
163 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); | 163 bucket_count_ = static_cast<uint32_t>(registered_ranges->bucket_count()); |
164 minimum_ = registered_ranges->range(1); | 164 minimum_ = registered_ranges->range(1); |
165 maximum_ = registered_ranges->range(bucket_count_ - 1); | 165 maximum_ = registered_ranges->range(bucket_count_ - 1); |
166 } | 166 } |
| 167 DCHECK_EQ(minimum_, registered_ranges->range(1)); |
| 168 DCHECK_EQ(maximum_, registered_ranges->range(bucket_count_ - 1)); |
167 | 169 |
168 // Try to create the histogram using a "persistent" allocator. As of | 170 // Try to create the histogram using a "persistent" allocator. As of |
169 // 2016-02-25, the availability of such is controlled by a base::Feature | 171 // 2016-02-25, the availability of such is controlled by a base::Feature |
170 // that is off by default. If the allocator doesn't exist or if | 172 // that is off by default. If the allocator doesn't exist or if |
171 // allocating from it fails, code below will allocate the histogram from | 173 // allocating from it fails, code below will allocate the histogram from |
172 // the process heap. | 174 // the process heap. |
173 PersistentHistogramAllocator::Reference histogram_ref = 0; | 175 PersistentHistogramAllocator::Reference histogram_ref = 0; |
174 std::unique_ptr<HistogramBase> tentative_histogram; | 176 std::unique_ptr<HistogramBase> tentative_histogram; |
175 PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get(); | 177 PersistentHistogramAllocator* allocator = GlobalHistogramAllocator::Get(); |
176 if (allocator) { | 178 if (allocator) { |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 } else { | 353 } else { |
352 DCHECK_GT(0, delta); | 354 DCHECK_GT(0, delta); |
353 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); | 355 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta); |
354 if (-delta > kCommonRaceBasedCountMismatch) | 356 if (-delta > kCommonRaceBasedCountMismatch) |
355 inconsistencies |= COUNT_LOW_ERROR; | 357 inconsistencies |= COUNT_LOW_ERROR; |
356 } | 358 } |
357 } | 359 } |
358 return inconsistencies; | 360 return inconsistencies; |
359 } | 361 } |
360 | 362 |
| 363 Sample Histogram::declared_min() const { |
| 364 if (bucket_ranges_->bucket_count() < 2) |
| 365 return -1; |
| 366 return bucket_ranges_->range(1); |
| 367 } |
| 368 |
| 369 Sample Histogram::declared_max() const { |
| 370 if (bucket_ranges_->bucket_count() < 2) |
| 371 return -1; |
| 372 return bucket_ranges_->range(bucket_ranges_->bucket_count() - 1); |
| 373 } |
| 374 |
361 Sample Histogram::ranges(uint32_t i) const { | 375 Sample Histogram::ranges(uint32_t i) const { |
362 return bucket_ranges_->range(i); | 376 return bucket_ranges_->range(i); |
363 } | 377 } |
364 | 378 |
365 uint32_t Histogram::bucket_count() const { | 379 uint32_t Histogram::bucket_count() const { |
366 return static_cast<uint32_t>(bucket_ranges_->bucket_count()); | 380 return static_cast<uint32_t>(bucket_ranges_->bucket_count()); |
367 } | 381 } |
368 | 382 |
369 // static | 383 // static |
370 bool Histogram::InspectConstructionArguments(const std::string& name, | 384 bool Histogram::InspectConstructionArguments(const std::string& name, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 return unlogged_samples_->id(); | 438 return unlogged_samples_->id(); |
425 } | 439 } |
426 | 440 |
427 HistogramType Histogram::GetHistogramType() const { | 441 HistogramType Histogram::GetHistogramType() const { |
428 return HISTOGRAM; | 442 return HISTOGRAM; |
429 } | 443 } |
430 | 444 |
431 bool Histogram::HasConstructionArguments(Sample expected_minimum, | 445 bool Histogram::HasConstructionArguments(Sample expected_minimum, |
432 Sample expected_maximum, | 446 Sample expected_maximum, |
433 uint32_t expected_bucket_count) const { | 447 uint32_t expected_bucket_count) const { |
434 return ((expected_minimum == declared_min_) && | 448 return (expected_bucket_count == bucket_count() && |
435 (expected_maximum == declared_max_) && | 449 expected_minimum == declared_min() && |
436 (expected_bucket_count == bucket_count())); | 450 expected_maximum == declared_max()); |
437 } | 451 } |
438 | 452 |
439 void Histogram::Add(int value) { | 453 void Histogram::Add(int value) { |
440 AddCount(value, 1); | 454 AddCount(value, 1); |
441 } | 455 } |
442 | 456 |
443 void Histogram::AddCount(int value, int count) { | 457 void Histogram::AddCount(int value, int count) { |
444 DCHECK_EQ(0, ranges(0)); | 458 DCHECK_EQ(0, ranges(0)); |
445 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count())); | 459 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count())); |
446 | 460 |
447 if (value > kSampleType_MAX - 1) | 461 if (value > kSampleType_MAX - 1) |
448 value = kSampleType_MAX - 1; | 462 value = kSampleType_MAX - 1; |
449 if (value < 0) | 463 if (value < 0) |
450 value = 0; | 464 value = 0; |
451 if (count <= 0) { | 465 if (count <= 0) { |
452 NOTREACHED(); | 466 NOTREACHED(); |
453 return; | 467 return; |
454 } | 468 } |
455 unlogged_samples_->Accumulate(value, count); | 469 unlogged_samples_->Accumulate(value, count); |
456 | 470 |
457 FindAndRunCallback(value); | 471 FindAndRunCallback(value); |
458 } | 472 } |
459 | 473 |
460 std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const { | 474 std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const { |
461 return SnapshotAllSamples(); | 475 return SnapshotAllSamples(); |
462 } | 476 } |
463 | 477 |
464 std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() { | 478 std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() { |
| 479 #if DCHECK_IS_ON() |
465 DCHECK(!final_delta_created_); | 480 DCHECK(!final_delta_created_); |
| 481 #endif |
| 482 |
466 // The code below has subtle thread-safety guarantees! All changes to | 483 // The code below has subtle thread-safety guarantees! All changes to |
467 // the underlying SampleVectors use atomic integer operations, which guarantee | 484 // the underlying SampleVectors use atomic integer operations, which guarantee |
468 // eventual consistency, but do not guarantee full synchronization between | 485 // eventual consistency, but do not guarantee full synchronization between |
469 // different entries in the SampleVector. In particular, this means that | 486 // different entries in the SampleVector. In particular, this means that |
470 // concurrent updates to the histogram might result in the reported sum not | 487 // concurrent updates to the histogram might result in the reported sum not |
471 // matching the individual bucket counts; or there being some buckets that are | 488 // matching the individual bucket counts; or there being some buckets that are |
472 // logically updated "together", but end up being only partially updated when | 489 // logically updated "together", but end up being only partially updated when |
473 // a snapshot is captured. Note that this is why it's important to subtract | 490 // a snapshot is captured. Note that this is why it's important to subtract |
474 // exactly the snapshotted unlogged samples, rather than simply resetting the | 491 // exactly the snapshotted unlogged samples, rather than simply resetting the |
475 // vector: this way, the next snapshot will include any concurrent updates | 492 // vector: this way, the next snapshot will include any concurrent updates |
476 // missed by the current snapshot. | 493 // missed by the current snapshot. |
477 | 494 |
478 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples(); | 495 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples(); |
479 unlogged_samples_->Subtract(*snapshot); | 496 unlogged_samples_->Subtract(*snapshot); |
480 logged_samples_->Add(*snapshot); | 497 logged_samples_->Add(*snapshot); |
481 | 498 |
482 return snapshot; | 499 return snapshot; |
483 } | 500 } |
484 | 501 |
485 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { | 502 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { |
| 503 #if DCHECK_IS_ON() |
486 DCHECK(!final_delta_created_); | 504 DCHECK(!final_delta_created_); |
487 final_delta_created_ = true; | 505 final_delta_created_ = true; |
| 506 #endif |
488 | 507 |
489 return SnapshotUnloggedSamples(); | 508 return SnapshotUnloggedSamples(); |
490 } | 509 } |
491 | 510 |
492 void Histogram::AddSamples(const HistogramSamples& samples) { | 511 void Histogram::AddSamples(const HistogramSamples& samples) { |
493 unlogged_samples_->Add(samples); | 512 unlogged_samples_->Add(samples); |
494 } | 513 } |
495 | 514 |
496 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { | 515 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { |
497 return unlogged_samples_->AddFromPickle(iter); | 516 return unlogged_samples_->AddFromPickle(iter); |
(...skipping 14 matching lines...) Expand all Loading... |
512 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { | 531 bool Histogram::SerializeInfoImpl(Pickle* pickle) const { |
513 DCHECK(bucket_ranges()->HasValidChecksum()); | 532 DCHECK(bucket_ranges()->HasValidChecksum()); |
514 return pickle->WriteString(histogram_name()) && | 533 return pickle->WriteString(histogram_name()) && |
515 pickle->WriteInt(flags()) && | 534 pickle->WriteInt(flags()) && |
516 pickle->WriteInt(declared_min()) && | 535 pickle->WriteInt(declared_min()) && |
517 pickle->WriteInt(declared_max()) && | 536 pickle->WriteInt(declared_max()) && |
518 pickle->WriteUInt32(bucket_count()) && | 537 pickle->WriteUInt32(bucket_count()) && |
519 pickle->WriteUInt32(bucket_ranges()->checksum()); | 538 pickle->WriteUInt32(bucket_ranges()->checksum()); |
520 } | 539 } |
521 | 540 |
| 541 // TODO(bcwhite): Remove minimum/maximum parameters from here and call chain. |
522 Histogram::Histogram(const std::string& name, | 542 Histogram::Histogram(const std::string& name, |
523 Sample minimum, | 543 Sample minimum, |
524 Sample maximum, | 544 Sample maximum, |
525 const BucketRanges* ranges) | 545 const BucketRanges* ranges) |
526 : HistogramBase(name), | 546 : HistogramBase(name), bucket_ranges_(ranges) { |
527 bucket_ranges_(ranges), | |
528 declared_min_(minimum), | |
529 declared_max_(maximum) { | |
530 // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved. | 547 // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved. |
531 CHECK(ranges) << name << ": " << minimum << "-" << maximum; | 548 CHECK(ranges) << name << ": " << minimum << "-" << maximum; |
532 unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 549 unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
533 logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges)); | 550 logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges)); |
534 } | 551 } |
535 | 552 |
536 Histogram::Histogram(const std::string& name, | 553 Histogram::Histogram(const std::string& name, |
537 Sample minimum, | 554 Sample minimum, |
538 Sample maximum, | 555 Sample maximum, |
539 const BucketRanges* ranges, | 556 const BucketRanges* ranges, |
540 const DelayedPersistentAllocation& counts, | 557 const DelayedPersistentAllocation& counts, |
541 const DelayedPersistentAllocation& logged_counts, | 558 const DelayedPersistentAllocation& logged_counts, |
542 HistogramSamples::Metadata* meta, | 559 HistogramSamples::Metadata* meta, |
543 HistogramSamples::Metadata* logged_meta) | 560 HistogramSamples::Metadata* logged_meta) |
544 : HistogramBase(name), | 561 : HistogramBase(name), bucket_ranges_(ranges) { |
545 bucket_ranges_(ranges), | |
546 declared_min_(minimum), | |
547 declared_max_(maximum) { | |
548 // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved. | 562 // TODO(bcwhite): Make this a DCHECK once crbug/734049 is resolved. |
549 CHECK(ranges) << name << ": " << minimum << "-" << maximum; | 563 CHECK(ranges) << name << ": " << minimum << "-" << maximum; |
550 unlogged_samples_.reset( | 564 unlogged_samples_.reset( |
551 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); | 565 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); |
552 logged_samples_.reset(new PersistentSampleVector( | 566 logged_samples_.reset(new PersistentSampleVector( |
553 unlogged_samples_->id(), ranges, logged_meta, logged_counts)); | 567 unlogged_samples_->id(), ranges, logged_meta, logged_counts)); |
554 } | 568 } |
555 | 569 |
556 Histogram::~Histogram() { | 570 Histogram::~Histogram() { |
557 } | 571 } |
(...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1221 Sample sample = custom_ranges[i]; | 1235 Sample sample = custom_ranges[i]; |
1222 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1236 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
1223 return false; | 1237 return false; |
1224 if (sample != 0) | 1238 if (sample != 0) |
1225 has_valid_range = true; | 1239 has_valid_range = true; |
1226 } | 1240 } |
1227 return has_valid_range; | 1241 return has_valid_range; |
1228 } | 1242 } |
1229 | 1243 |
1230 } // namespace base | 1244 } // namespace base |
OLD | NEW |