| 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 |