Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(885)

Side by Side Diff: base/metrics/histogram.cc

Issue 2867303004: [histogram] Make histograms more resistant to overflows. (Closed)
Patch Set: final final fix Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_base.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 // The code below has subtle thread-safety guarantees! All changes to
460 // the underlying SampleVectors use atomic integer operations, which guarantee
461 // eventual consistency, but do not guarantee full synchronization between
462 // different entries in the SampleVector. In particular, this means that
463 // concurrent updates to the histogram might result in the reported sum not
464 // matching the individual bucket counts; or there being some buckets that are
465 // logically updated "together", but end up being only partially updated when
466 // a snapshot is captured. Note that this is why it's important to subtract
467 // exactly the snapshotted unlogged samples, rather than simply resetting the
468 // vector: this way, the next snapshot will include any concurrent updates
469 // missed by the current snapshot.
459 470
460 std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector(); 471 std::unique_ptr<HistogramSamples> snapshot = SnapshotUnloggedSamples();
461 if (!logged_samples_) { 472 unlogged_samples_->Subtract(*snapshot);
462 // If nothing has been previously logged, save this one as 473 logged_samples_->Add(*snapshot);
463 // |logged_samples_| and gather another snapshot to return.
464 logged_samples_.swap(snapshot);
465 return SnapshotSampleVector();
466 }
467 474
468 // Subtract what was previously logged and update that information.
469 snapshot->Subtract(*logged_samples_);
470 logged_samples_->Add(*snapshot);
471 return snapshot; 475 return snapshot;
472 } 476 }
473 477
474 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const { 478 std::unique_ptr<HistogramSamples> Histogram::SnapshotFinalDelta() const {
475 DCHECK(!final_delta_created_); 479 DCHECK(!final_delta_created_);
476 final_delta_created_ = true; 480 final_delta_created_ = true;
477 481
478 std::unique_ptr<HistogramSamples> snapshot = SnapshotSampleVector(); 482 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 } 483 }
485 484
486 void Histogram::AddSamples(const HistogramSamples& samples) { 485 void Histogram::AddSamples(const HistogramSamples& samples) {
487 samples_->Add(samples); 486 unlogged_samples_->Add(samples);
488 } 487 }
489 488
490 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) { 489 bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
491 return samples_->AddFromPickle(iter); 490 return unlogged_samples_->AddFromPickle(iter);
492 } 491 }
493 492
494 // The following methods provide a graphical histogram display. 493 // The following methods provide a graphical histogram display.
495 void Histogram::WriteHTMLGraph(std::string* output) const { 494 void Histogram::WriteHTMLGraph(std::string* output) const {
496 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc. 495 // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
497 output->append("<PRE>"); 496 output->append("<PRE>");
498 WriteAsciiImpl(true, "<br>", output); 497 WriteAsciiImpl(true, "<br>", output);
499 output->append("</PRE>"); 498 output->append("</PRE>");
500 } 499 }
501 500
(...skipping 12 matching lines...) Expand all
514 } 513 }
515 514
516 Histogram::Histogram(const std::string& name, 515 Histogram::Histogram(const std::string& name,
517 Sample minimum, 516 Sample minimum,
518 Sample maximum, 517 Sample maximum,
519 const BucketRanges* ranges) 518 const BucketRanges* ranges)
520 : HistogramBase(name), 519 : HistogramBase(name),
521 bucket_ranges_(ranges), 520 bucket_ranges_(ranges),
522 declared_min_(minimum), 521 declared_min_(minimum),
523 declared_max_(maximum) { 522 declared_max_(maximum) {
524 if (ranges) 523 if (ranges) {
525 samples_.reset(new SampleVector(HashMetricName(name), ranges)); 524 unlogged_samples_.reset(new SampleVector(HashMetricName(name), ranges));
525 logged_samples_.reset(new SampleVector(unlogged_samples_->id(), ranges));
526 }
526 } 527 }
527 528
528 Histogram::Histogram(const std::string& name, 529 Histogram::Histogram(const std::string& name,
529 Sample minimum, 530 Sample minimum,
530 Sample maximum, 531 Sample maximum,
531 const BucketRanges* ranges, 532 const BucketRanges* ranges,
532 const DelayedPersistentAllocation& counts, 533 const DelayedPersistentAllocation& counts,
533 const DelayedPersistentAllocation& logged_counts, 534 const DelayedPersistentAllocation& logged_counts,
534 HistogramSamples::Metadata* meta, 535 HistogramSamples::Metadata* meta,
535 HistogramSamples::Metadata* logged_meta) 536 HistogramSamples::Metadata* logged_meta)
536 : HistogramBase(name), 537 : HistogramBase(name),
537 bucket_ranges_(ranges), 538 bucket_ranges_(ranges),
538 declared_min_(minimum), 539 declared_min_(minimum),
539 declared_max_(maximum) { 540 declared_max_(maximum) {
540 if (ranges) { 541 if (ranges) {
541 samples_.reset( 542 unlogged_samples_.reset(
542 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts)); 543 new PersistentSampleVector(HashMetricName(name), ranges, meta, counts));
543 logged_samples_.reset(new PersistentSampleVector( 544 logged_samples_.reset(new PersistentSampleVector(
544 samples_->id(), ranges, logged_meta, logged_counts)); 545 unlogged_samples_->id(), ranges, logged_meta, logged_counts));
545 } 546 }
546 } 547 }
547 548
548 Histogram::~Histogram() { 549 Histogram::~Histogram() {
549 } 550 }
550 551
551 bool Histogram::PrintEmptyBucket(uint32_t index) const { 552 bool Histogram::PrintEmptyBucket(uint32_t index) const {
552 return true; 553 return true;
553 } 554 }
554 555
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 HistogramBase* histogram = Histogram::FactoryGet( 592 HistogramBase* histogram = Histogram::FactoryGet(
592 histogram_name, declared_min, declared_max, bucket_count, flags); 593 histogram_name, declared_min, declared_max, bucket_count, flags);
593 594
594 if (!ValidateRangeChecksum(*histogram, range_checksum)) { 595 if (!ValidateRangeChecksum(*histogram, range_checksum)) {
595 // The serialized histogram might be corrupted. 596 // The serialized histogram might be corrupted.
596 return NULL; 597 return NULL;
597 } 598 }
598 return histogram; 599 return histogram;
599 } 600 }
600 601
601 std::unique_ptr<SampleVector> Histogram::SnapshotSampleVector() const { 602 std::unique_ptr<SampleVector> Histogram::SnapshotAllSamples() const {
602 std::unique_ptr<SampleVector> samples( 603 std::unique_ptr<SampleVector> samples = SnapshotUnloggedSamples();
603 new SampleVector(samples_->id(), bucket_ranges())); 604 samples->Add(*logged_samples_);
604 samples->Add(*samples_);
605 return samples; 605 return samples;
606 } 606 }
607 607
608 std::unique_ptr<SampleVector> Histogram::SnapshotUnloggedSamples() const {
609 std::unique_ptr<SampleVector> samples(
610 new SampleVector(unlogged_samples_->id(), bucket_ranges()));
611 samples->Add(*unlogged_samples_);
612 return samples;
613 }
614
608 void Histogram::WriteAsciiImpl(bool graph_it, 615 void Histogram::WriteAsciiImpl(bool graph_it,
609 const std::string& newline, 616 const std::string& newline,
610 std::string* output) const { 617 std::string* output) const {
611 // Get local (stack) copies of all effectively volatile class data so that we 618 // Get local (stack) copies of all effectively volatile class data so that we
612 // are consistent across our output activities. 619 // are consistent across our output activities.
613 std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); 620 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
614 Count sample_count = snapshot->TotalCount(); 621 Count sample_count = snapshot->TotalCount();
615 622
616 WriteAsciiHeader(*snapshot, sample_count, output); 623 WriteAsciiHeader(*snapshot, sample_count, output);
617 output->append(newline); 624 output->append(newline);
618 625
619 // Prepare to normalize graphical rendering of bucket contents. 626 // Prepare to normalize graphical rendering of bucket contents.
620 double max_size = 0; 627 double max_size = 0;
621 if (graph_it) 628 if (graph_it)
622 max_size = GetPeakBucketSize(*snapshot); 629 max_size = GetPeakBucketSize(*snapshot);
623 630
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 void Histogram::GetParameters(DictionaryValue* params) const { 722 void Histogram::GetParameters(DictionaryValue* params) const {
716 params->SetString("type", HistogramTypeToString(GetHistogramType())); 723 params->SetString("type", HistogramTypeToString(GetHistogramType()));
717 params->SetInteger("min", declared_min()); 724 params->SetInteger("min", declared_min());
718 params->SetInteger("max", declared_max()); 725 params->SetInteger("max", declared_max());
719 params->SetInteger("bucket_count", static_cast<int>(bucket_count())); 726 params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
720 } 727 }
721 728
722 void Histogram::GetCountAndBucketData(Count* count, 729 void Histogram::GetCountAndBucketData(Count* count,
723 int64_t* sum, 730 int64_t* sum,
724 ListValue* buckets) const { 731 ListValue* buckets) const {
725 std::unique_ptr<SampleVector> snapshot = SnapshotSampleVector(); 732 std::unique_ptr<SampleVector> snapshot = SnapshotAllSamples();
726 *count = snapshot->TotalCount(); 733 *count = snapshot->TotalCount();
727 *sum = snapshot->sum(); 734 *sum = snapshot->sum();
728 uint32_t index = 0; 735 uint32_t index = 0;
729 for (uint32_t i = 0; i < bucket_count(); ++i) { 736 for (uint32_t i = 0; i < bucket_count(); ++i) {
730 Sample count_at_index = snapshot->GetCountAtIndex(i); 737 Sample count_at_index = snapshot->GetCountAtIndex(i);
731 if (count_at_index > 0) { 738 if (count_at_index > 0) {
732 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue()); 739 std::unique_ptr<DictionaryValue> bucket_value(new DictionaryValue());
733 bucket_value->SetInteger("low", ranges(i)); 740 bucket_value->SetInteger("low", ranges(i));
734 if (i != bucket_count() - 1) 741 if (i != bucket_count() - 1)
735 bucket_value->SetInteger("high", ranges(i + 1)); 742 bucket_value->SetInteger("high", ranges(i + 1));
(...skipping 467 matching lines...) Expand 10 before | Expand all | Expand 10 after
1203 Sample sample = custom_ranges[i]; 1210 Sample sample = custom_ranges[i];
1204 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1) 1211 if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
1205 return false; 1212 return false;
1206 if (sample != 0) 1213 if (sample != 0)
1207 has_valid_range = true; 1214 has_valid_range = true;
1208 } 1215 }
1209 return has_valid_range; 1216 return has_valid_range;
1210 } 1217 }
1211 1218
1212 } // namespace base 1219 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698