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 (in particular, |
464 logged_samples_.swap(snapshot); | 464 // SampleVector::Subtract and SampleVector::Accumulate are thread-safe). |
465 return SnapshotSampleVector(); | 465 // Snapshot is taken by atomically copying all existing samples. Reset is |
466 } | 466 // implemented by subtracting copied snapshot, leaving samples added |
| 467 // concurrently from another thread in unlogged_samples to be reported by |
| 468 // the next call to SnapshotDelta. |
467 | 469 |
468 // Subtract what was previously logged and update that information. | 470 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples(); |
469 snapshot->Subtract(*logged_samples_); | 471 unlogged_samples_->Subtract(*snapshot); |
470 logged_samples_->Add(*snapshot); | 472 logged_samples_->Add(*snapshot); |
| 473 |
471 return snapshot; | 474 return snapshot; |
472 } | 475 } |
473 | 476 |
474 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { | 477 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { |
475 DCHECK(!final_delta_created_); | 478 DCHECK(!final_delta_created_); |
476 final_delta_created_ = true; | 479 final_delta_created_ = true; |
477 | 480 |
478 std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector(); | 481 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 } | 482 } |
485 | 483 |
486 void Histogram::AddSamples(const HistogramSamples& samples) { | 484 void Histogram::AddSamples(const HistogramSamples& samples) { |
487 samples_->Add(samples); | 485 unlogged_samples_->Add(samples); |
488 } | 486 } |
489 | 487 |
490 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { | 488 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { |
491 return samples_->AddFromPickle(iter); | 489 return unlogged_samples_->AddFromPickle(iter); |
492 } | 490 } |
493 | 491 |
494 // The following methods provide a graphical histogram display. | 492 // The following methods provide a graphical histogram display. |
495 void Histogram::WriteHTMLGraph(std::string* output) const { | 493 void Histogram::WriteHTMLGraph(std::string* output) const { |
496 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. | 494 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. |
497 output->append("<PRE>"); | 495 output->append("<PRE>"); |
498 WriteAsciiImpl(true, "<br>", output); | 496 WriteAsciiImpl(true, "<br>", output); |
499 output->append("</PRE>"); | 497 output->append("</PRE>"); |
500 } | 498 } |
501 | 499 |
(...skipping 12 matching lines...) Expand all Loading... |
514 } | 512 } |
515 | 513 |
516 Histogram::Histogram(const std::string& name, | 514 Histogram::Histogram(const std::string& name, |
517 Sample minimum, | 515 Sample minimum, |
518 Sample maximum, | 516 Sample maximum, |
519 const BucketRanges* ranges) | 517 const BucketRanges* ranges) |
520 : HistogramBase(name), | 518 : HistogramBase(name), |
521 bucket_ranges_(ranges), | 519 bucket_ranges_(ranges), |
522 declared_min_(minimum), | 520 declared_min_(minimum), |
523 declared_max_(maximum) { | 521 declared_max_(maximum) { |
524 if (ranges) | 522 if (ranges) { |
525 samples_.reset(new SampleVector(HashMetricName(name), ranges)); | 523 unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges)); |
| 524 logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges)); |
| 525 } |
526 } | 526 } |
527 | 527 |
528 Histogram::Histogram(const std::string& name, | 528 Histogram::Histogram(const std::string& name, |
529 Sample minimum, | 529 Sample minimum, |
530 Sample maximum, | 530 Sample maximum, |
531 const BucketRanges* ranges, | 531 const BucketRanges* ranges, |
532 const DelayedPersistentAllocation& counts, | 532 const DelayedPersistentAllocation& counts, |
533 const DelayedPersistentAllocation& logged_counts, | 533 const DelayedPersistentAllocation& logged_counts, |
534 HistogramSamples::Metadata* meta, | 534 HistogramSamples::Metadata* meta, |
535 HistogramSamples::Metadata* logged_meta) | 535 HistogramSamples::Metadata* logged_meta) |
536 : HistogramBase(name), | 536 : HistogramBase(name), |
537 bucket_ranges_(ranges), | 537 bucket_ranges_(ranges), |
538 declared_min_(minimum), | 538 declared_min_(minimum), |
539 declared_max_(maximum) { | 539 declared_max_(maximum) { |
540 if (ranges) { | 540 if (ranges) { |
541 samples_.reset( | 541 unlogged_samples_.reset( |
542 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); | 542 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); |
543 logged_samples_.reset(new PersistentSampleVector( | 543 logged_samples_.reset(new PersistentSampleVector( |
544 samples_->id(), ranges, logged_meta, logged_counts)); | 544 unlogged_samples_->id(), ranges, logged_meta, logged_counts)); |
545 } | 545 } |
546 } | 546 } |
547 | 547 |
548 Histogram::~Histogram() { | 548 Histogram::~Histogram() { |
549 } | 549 } |
550 | 550 |
551 bool Histogram::PrintEmptyBucket(uint32_t index) const { | 551 bool Histogram::PrintEmptyBucket(uint32_t index) const { |
552 return true; | 552 return true; |
553 } | 553 } |
554 | 554 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 HistogramBase* histogram = Histogram::FactoryGet( | 591 HistogramBase* histogram = Histogram::FactoryGet( |
592 histogram_name, declared_min, declared_max, bucket_count, flags); | 592 histogram_name, declared_min, declared_max, bucket_count, flags); |
593 | 593 |
594 if (!ValidateRangeChecksum(*histogram, range_checksum)) { | 594 if (!ValidateRangeChecksum(*histogram, range_checksum)) { |
595 // The serialized histogram might be corrupted. | 595 // The serialized histogram might be corrupted. |
596 return NULL; | 596 return NULL; |
597 } | 597 } |
598 return histogram; | 598 return histogram; |
599 } | 599 } |
600 | 600 |
601 std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const { | 601 std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const { |
602 std::unique_ptr<SampleVector> samples( | 602 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamples(); |
603 new SampleVector(samples_->id(), bucket_ranges())); | 603 samples->Add(*logged_samples_); |
604 samples->Add(*samples_); | |
605 return samples; | 604 return samples; |
606 } | 605 } |
607 | 606 |
| 607 std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const { |
| 608 std::unique_ptr<SampleVector> samples( |
| 609 new SampleVector(unlogged_samples_->id(), bucket_ranges())); |
| 610 samples->Add(*unlogged_samples_); |
| 611 return samples; |
| 612 } |
| 613 |
608 void Histogram::WriteAsciiImpl(bool graph_it, | 614 void Histogram::WriteAsciiImpl(bool graph_it, |
609 const std::string& newline, | 615 const std::string& newline, |
610 std::string* output) const { | 616 std::string* output) const { |
611 // Get local (stack) copies of all effectively volatile class data so that we | 617 // Get local (stack) copies of all effectively volatile class data so that we |
612 // are consistent across our output activities. | 618 // are consistent across our output activities. |
613 std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 619 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples(); |
614 Count sample_count = snapshot->TotalCount(); | 620 Count sample_count = snapshot->TotalCount(); |
615 | 621 |
616 WriteAsciiHeader(*snapshot, sample_count, output); | 622 WriteAsciiHeader(*snapshot, sample_count, output); |
617 output->append(newline); | 623 output->append(newline); |
618 | 624 |
619 // Prepare to normalize graphical rendering of bucket contents. | 625 // Prepare to normalize graphical rendering of bucket contents. |
620 double max_size = 0; | 626 double max_size = 0; |
621 if (graph_it) | 627 if (graph_it) |
622 max_size = GetPeakBucketSize(*snapshot); | 628 max_size = GetPeakBucketSize(*snapshot); |
623 | 629 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
715 void Histogram::GetParameters(DictionaryValue* params) const { | 721 void Histogram::GetParameters(DictionaryValue* params) const { |
716 params->SetString("type", HistogramTypeToString(GetHistogramType())); | 722 params->SetString("type", HistogramTypeToString(GetHistogramType())); |
717 params->SetInteger("min", declared_min()); | 723 params->SetInteger("min", declared_min()); |
718 params->SetInteger("max", declared_max()); | 724 params->SetInteger("max", declared_max()); |
719 params->SetInteger("bucket_count", static_cast<int>(bucket_count())); | 725 params->SetInteger("bucket_count", static_cast<int>(bucket_count())); |
720 } | 726 } |
721 | 727 |
722 void Histogram::GetCountAndBucketData(Count* count, | 728 void Histogram::GetCountAndBucketData(Count* count, |
723 int64_t* sum, | 729 int64_t* sum, |
724 ListValue* buckets) const { | 730 ListValue* buckets) const { |
725 std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); | 731 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples(); |
726 *count = snapshot->TotalCount(); | 732 *count = snapshot->TotalCount(); |
727 *sum = snapshot->sum(); | 733 *sum = snapshot->sum(); |
728 uint32_t index = 0; | 734 uint32_t index = 0; |
729 for (uint32_t i = 0; i < bucket_count(); ++i) { | 735 for (uint32_t i = 0; i < bucket_count(); ++i) { |
730 Sample count_at_index = snapshot->GetCountAtIndex(i); | 736 Sample count_at_index = snapshot->GetCountAtIndex(i); |
731 if (count_at_index > 0) { | 737 if (count_at_index > 0) { |
732 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue()); | 738 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue()); |
733 bucket_value->SetInteger("low", ranges(i)); | 739 bucket_value->SetInteger("low", ranges(i)); |
734 if (i != bucket_count() - 1) | 740 if (i != bucket_count() - 1) |
735 bucket_value->SetInteger("high", ranges(i + 1)); | 741 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]; | 1209 Sample sample = custom_ranges[i]; |
1204 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) | 1210 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) |
1205 return false; | 1211 return false; |
1206 if (sample != 0) | 1212 if (sample != 0) |
1207 has_valid_range = true; | 1213 has_valid_range = true; |
1208 } | 1214 } |
1209 return has_valid_range; | 1215 return has_valid_range; |
1210 } | 1216 } |
1211 | 1217 |
1212 } // namespace base | 1218 } // namespace base |
OLD | NEW |