Chromium Code Reviews| 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 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 407 | 407 |
| 408 if (!check_okay) { | 408 if (!check_okay) { |
| 409 UMA_HISTOGRAM_SPARSE_SLOWLY("Histogram.BadConstructionArguments", | 409 UMA_HISTOGRAM_SPARSE_SLOWLY("Histogram.BadConstructionArguments", |
| 410 static_cast<Sample>(HashMetricName(name))); | 410 static_cast<Sample>(HashMetricName(name))); |
| 411 } | 411 } |
| 412 | 412 |
| 413 return check_okay; | 413 return check_okay; |
| 414 } | 414 } |
| 415 | 415 |
| 416 uint64_t Histogram::name_hash() const { | 416 uint64_t Histogram::name_hash() const { |
| 417 return samples_->id(); | 417 return unlogged_samples_->id(); |
| 418 } | 418 } |
| 419 | 419 |
| 420 HistogramType Histogram::GetHistogramType() const { | 420 HistogramType Histogram::GetHistogramType() const { |
| 421 return HISTOGRAM; | 421 return HISTOGRAM; |
| 422 } | 422 } |
| 423 | 423 |
| 424 bool Histogram::HasConstructionArguments(Sample expected_minimum, | 424 bool Histogram::HasConstructionArguments(Sample expected_minimum, |
| 425 Sample expected_maximum, | 425 Sample expected_maximum, |
| 426 uint32_t expected_bucket_count) const { | 426 uint32_t expected_bucket_count) const { |
| 427 return ((expected_minimum == declared_min_) && | 427 return ((expected_minimum == declared_min_) && |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 438 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count())); | 438 DCHECK_EQ(kSampleType_MAX, ranges(bucket_count())); |
| 439 | 439 |
| 440 if (value > kSampleType_MAX - 1) | 440 if (value > kSampleType_MAX - 1) |
| 441 value = kSampleType_MAX - 1; | 441 value = kSampleType_MAX - 1; |
| 442 if (value < 0) | 442 if (value < 0) |
| 443 value = 0; | 443 value = 0; |
| 444 if (count <= 0) { | 444 if (count <= 0) { |
| 445 NOTREACHED(); | 445 NOTREACHED(); |
| 446 return; | 446 return; |
| 447 } | 447 } |
| 448 samples_->Accumulate(value, count); | 448 unlogged_samples_->Accumulate(value, count); |
| 449 | 449 |
| 450 FindAndRunCallback(value); | 450 FindAndRunCallback(value); |
| 451 } | 451 } |
| 452 | 452 |
| 453 std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const { | 453 std::unique_ptr<HistogramSamples> Histogram::SnapshotSamples() const { |
| 454 return SnapshotSampleVector(); | 454 return SnapshotAllSamples(); |
| 455 } | 455 } |
| 456 | 456 |
| 457 std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() { | 457 std::unique_ptr<HistogramSamples> Histogram::SnapshotDelta() { |
| 458 DCHECK(!final_delta_created_); | 458 DCHECK(!final_delta_created_); |
| 459 | 459 |
| 460 std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector(); | 460 // This code takes unlogged samples, adds them to logged samples, |
| 461 if (!logged_samples_) { | 461 // resets them and returns them. |
| 462 // If nothing has been previously logged, save this one as | 462 // Correctness of this code relies on unlogged_samples being thread-safe |
| 463 // |logged_samples_| and gather another snapshot to return. | 463 // due to atomic integer operations. Snapshot is taken by atomically copying |
| 464 logged_samples_.swap(snapshot); | 464 // all existing samples. Reset is implemented by subtracting copied snapshot, |
| 465 return SnapshotSampleVector(); | 465 // leaving samples added concurrently from another thread in unlogged_samples |
| 466 } | 466 // to be reported by the next call to SnapshotDelta. |
|
Alexei Svitkine (slow)
2017/05/11 13:54:35
Maybe call out the function names where the atomic
bcwhite
2017/05/11 17:34:52
Basically, every individual operation is atomic bu
altimin
2017/05/11 17:55:43
I think that does not belong here. We should menti
| |
| 467 | 467 |
| 468 // Subtract what was previously logged and update that information. | 468 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples(); |
| 469 snapshot->Subtract(*logged_samples_); | 469 unlogged_samples_->Subtract(*snapshot); |
| 470 logged_samples_->Add(*snapshot); | 470 logged_samples_->Add(*snapshot); |
| 471 | |
| 471 return snapshot; | 472 return snapshot; |
| 472 } | 473 } |
| 473 | 474 |
| 474 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { | 475 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { |
| 475 DCHECK(!final_delta_created_); | 476 DCHECK(!final_delta_created_); |
| 476 final_delta_created_ = true; | 477 final_delta_created_ = true; |
| 477 | 478 |
| 478 std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector(); | 479 return SnapshotUnloggedSamples(); |
| 479 | |
| 480 // Subtract what was previously logged and then return. | |
| 481 if (logged_samples_) | |
| 482 snapshot->Subtract(*logged_samples_); | |
| 483 return snapshot; | |
| 484 } | 480 } |
| 485 | 481 |
| 486 void Histogram::AddSamples(const HistogramSamples& samples) { | 482 void Histogram::AddSamples(const HistogramSamples& samples) { |
| 487 samples_->Add(samples); | 483 unlogged_samples_->Add(samples); |
| 488 } | 484 } |
| 489 | 485 |
| 490 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { | 486 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { |
| 491 return samples_->AddFromPickle(iter); | 487 return unlogged_samples_->AddFromPickle(iter); |
| 492 } | 488 } |
| 493 | 489 |
| 494 // The following methods provide a graphical histogram display. | 490 // The following methods provide a graphical histogram display. |
| 495 void Histogram::WriteHTMLGraph(std::string* output) const { | 491 void Histogram::WriteHTMLGraph(std::string* output) const { |
| 496 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. | 492 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. |
| 497 output->append("<PRE>"); | 493 output->append("<PRE>"); |
| 498 WriteAsciiImpl(true, "<br>", output); | 494 WriteAsciiImpl(true, "<br>", output); |
| 499 output->append("</PRE>"); | 495 output->append("</PRE>"); |
| 500 } | 496 } |
| 501 | 497 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 514 } | 510 } |
| 515 | 511 |
| 516 Histogram::Histogram(const std::string& name, | 512 Histogram::Histogram(const std::string& name, |
| 517 Sample minimum, | 513 Sample minimum, |
| 518 Sample maximum, | 514 Sample maximum, |
| 519 const BucketRanges* ranges) | 515 const BucketRanges* ranges) |
| 520 : HistogramBase(name), | 516 : HistogramBase(name), |
| 521 bucket_ranges_(ranges), | 517 bucket_ranges_(ranges), |
| 522 declared_min_(minimum), | 518 declared_min_(minimum), |
| 523 declared_max_(maximum) { | 519 declared_max_(maximum) { |
| 524 if (ranges) | 520 if (ranges) { |
| 525 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 521 unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
| 522 logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges)); | |
| 523 } | |
| 526 } | 524 } |
| 527 | 525 |
| 528 Histogram::Histogram(const std::string& name, | 526 Histogram::Histogram(const std::string& name, |
| 529 Sample minimum, | 527 Sample minimum, |
| 530 Sample maximum, | 528 Sample maximum, |
| 531 const BucketRanges* ranges, | 529 const BucketRanges* ranges, |
| 532 const DelayedPersistentAllocation& counts, | 530 const DelayedPersistentAllocation& counts, |
| 533 const DelayedPersistentAllocation& logged_counts, | 531 const DelayedPersistentAllocation& logged_counts, |
| 534 HistogramSamples::Metadata* meta, | 532 HistogramSamples::Metadata* meta, |
| 535 HistogramSamples::Metadata* logged_meta) | 533 HistogramSamples::Metadata* logged_meta) |
| 536 : HistogramBase(name), | 534 : HistogramBase(name), |
| 537 bucket_ranges_(ranges), | 535 bucket_ranges_(ranges), |
| 538 declared_min_(minimum), | 536 declared_min_(minimum), |
| 539 declared_max_(maximum) { | 537 declared_max_(maximum) { |
| 540 if (ranges) { | 538 if (ranges) { |
| 541 samples_.reset( | 539 unlogged_samples_.reset( |
| 542 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); | 540 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); |
| 543 logged_samples_.reset(new PersistentSampleVector( | 541 logged_samples_.reset(new PersistentSampleVector( |
| 544 samples_->id(), ranges, logged_meta, logged_counts)); | 542 unlogged_samples_->id(), ranges, logged_meta, logged_counts)); |
| 545 } | 543 } |
| 546 } | 544 } |
| 547 | 545 |
| 548 Histogram::~Histogram() { | 546 Histogram::~Histogram() { |
| 549 } | 547 } |
| 550 | 548 |
| 551 bool Histogram::PrintEmptyBucket(uint32_t index) const { | 549 bool Histogram::PrintEmptyBucket(uint32_t index) const { |
| 552 return true; | 550 return true; |
| 553 } | 551 } |
| 554 | 552 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 591 HistogramBase* histogram = Histogram::FactoryGet( | 589 HistogramBase* histogram = Histogram::FactoryGet( |
| 592 histogram_name, declared_min, declared_max, bucket_count, flags); | 590 histogram_name, declared_min, declared_max, bucket_count, flags); |
| 593 | 591 |
| 594 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 592 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
| 595 // The serialized histogram might be corrupted. | 593 // The serialized histogram might be corrupted. |
| 596 return NULL; | 594 return NULL; |
| 597 } | 595 } |
| 598 return histogram; | 596 return histogram; |
| 599 } | 597 } |
| 600 | 598 |
| 601 std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const { | 599 std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const { |
| 602 std::unique_ptr<SampleVector> samples( | 600 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamples(); |
| 603 new SampleVector(samples_->id(), bucket_ranges())); | 601 samples->Add(*logged_samples_); |
| 604 samples->Add(*samples_); | |
| 605 return samples; | 602 return samples; |
| 606 } | 603 } |
| 607 | 604 |
| 605 std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const { | |
| 606 std::unique_ptr<SampleVector> samples( | |
| 607 new SampleVector(unlogged_samples_->id(), bucket_ranges())); | |
| 608 samples->Add(*unlogged_samples_); | |
| 609 return samples; | |
| 610 } | |
| 611 | |
| 608 void Histogram::WriteAsciiImpl(bool graph_it, | 612 void Histogram::WriteAsciiImpl(bool graph_it, |
| 609 const std::string& newline, | 613 const std::string& newline, |
| 610 std::string* output) const { | 614 std::string* output) const { |
| 611 // Get local (stack) copies of all effectively volatile class data so that we | 615 // Get local (stack) copies of all effectively volatile class data so that we |
| 612 // are consistent across our output activities. | 616 // are consistent across our output activities. |
| 613 std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 617 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples(); |
| 614 Count sample_count = snapshot->TotalCount(); | 618 Count sample_count = snapshot->TotalCount(); |
| 615 | 619 |
| 616 WriteAsciiHeader(*snapshot, sample_count, output); | 620 WriteAsciiHeader(*snapshot, sample_count, output); |
| 617 output->append(newline); | 621 output->append(newline); |
| 618 | 622 |
| 619 // Prepare to normalize graphical rendering of bucket contents. | 623 // Prepare to normalize graphical rendering of bucket contents. |
| 620 double max_size = 0; | 624 double max_size = 0; |
| 621 if (graph_it) | 625 if (graph_it) |
| 622 max_size = GetPeakBucketSize(*snapshot); | 626 max_size = GetPeakBucketSize(*snapshot); |
| 623 | 627 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 715 void Histogram::GetParameters(DictionaryValue* params) const { | 719 void Histogram::GetParameters(DictionaryValue* params) const { |
| 716 params->SetString("type", HistogramTypeToString(GetHistogramType())); | 720 params->SetString("type", HistogramTypeToString(GetHistogramType())); |
| 717 params->SetInteger("min", declared_min()); | 721 params->SetInteger("min", declared_min()); |
| 718 params->SetInteger("max", declared_max()); | 722 params->SetInteger("max", declared_max()); |
| 719 params->SetInteger("bucket_count", static_cast<int>(bucket_count())); | 723 params->SetInteger("bucket_count", static_cast<int>(bucket_count())); |
| 720 } | 724 } |
| 721 | 725 |
| 722 void Histogram::GetCountAndBucketData(Count* count, | 726 void Histogram::GetCountAndBucketData(Count* count, |
| 723 int64_t* sum, | 727 int64_t* sum, |
| 724 ListValue* buckets) const { | 728 ListValue* buckets) const { |
| 725 std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 729 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples(); |
| 726 *count = snapshot->TotalCount(); | 730 *count = snapshot->TotalCount(); |
| 727 *sum = snapshot->sum(); | 731 *sum = snapshot->sum(); |
| 728 uint32_t index = 0; | 732 uint32_t index = 0; |
| 729 for (uint32_t i = 0; i < bucket_count(); ++i) { | 733 for (uint32_t i = 0; i < bucket_count(); ++i) { |
| 730 Sample count_at_index = snapshot->GetCountAtIndex(i); | 734 Sample count_at_index = snapshot->GetCountAtIndex(i); |
| 731 if (count_at_index > 0) { | 735 if (count_at_index > 0) { |
| 732 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue()); | 736 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue()); |
| 733 bucket_value->SetInteger("low", ranges(i)); | 737 bucket_value->SetInteger("low", ranges(i)); |
| 734 if (i != bucket_count() - 1) | 738 if (i != bucket_count() - 1) |
| 735 bucket_value->SetInteger("high", ranges(i + 1)); | 739 bucket_value->SetInteger("high", ranges(i + 1)); |
| (...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1203 Sample sample = custom_ranges[i]; | 1207 Sample sample = custom_ranges[i]; |
| 1204 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1208 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
| 1205 return false; | 1209 return false; |
| 1206 if (sample != 0) | 1210 if (sample != 0) |
| 1207 has_valid_range = true; | 1211 has_valid_range = true; |
| 1208 } | 1212 } |
| 1209 return has_valid_range; | 1213 return has_valid_range; |
| 1210 } | 1214 } |
| 1211 | 1215 |
| 1212 } // namespace base | 1216 } // namespace base |
| OLD | NEW |