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

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

Issue 4174002: Try to detect internal corruption of histogram instances.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_unittest.cc » ('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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 } 54 }
55 55
56 Histogram::Histogram(const std::string& name, Sample minimum, 56 Histogram::Histogram(const std::string& name, Sample minimum,
57 Sample maximum, size_t bucket_count) 57 Sample maximum, size_t bucket_count)
58 : histogram_name_(name), 58 : histogram_name_(name),
59 declared_min_(minimum), 59 declared_min_(minimum),
60 declared_max_(maximum), 60 declared_max_(maximum),
61 bucket_count_(bucket_count), 61 bucket_count_(bucket_count),
62 flags_(kNoFlags), 62 flags_(kNoFlags),
63 ranges_(bucket_count + 1, 0), 63 ranges_(bucket_count + 1, 0),
64 range_checksum_(0),
64 sample_() { 65 sample_() {
65 Initialize(); 66 Initialize();
66 } 67 }
67 68
68 Histogram::Histogram(const std::string& name, TimeDelta minimum, 69 Histogram::Histogram(const std::string& name, TimeDelta minimum,
69 TimeDelta maximum, size_t bucket_count) 70 TimeDelta maximum, size_t bucket_count)
70 : histogram_name_(name), 71 : histogram_name_(name),
71 declared_min_(static_cast<int> (minimum.InMilliseconds())), 72 declared_min_(static_cast<int> (minimum.InMilliseconds())),
72 declared_max_(static_cast<int> (maximum.InMilliseconds())), 73 declared_max_(static_cast<int> (maximum.InMilliseconds())),
73 bucket_count_(bucket_count), 74 bucket_count_(bucket_count),
74 flags_(kNoFlags), 75 flags_(kNoFlags),
75 ranges_(bucket_count + 1, 0), 76 ranges_(bucket_count + 1, 0),
77 range_checksum_(0),
76 sample_() { 78 sample_() {
77 Initialize(); 79 Initialize();
78 } 80 }
79 81
80 Histogram::~Histogram() { 82 Histogram::~Histogram() {
81 if (StatisticsRecorder::dump_on_exit()) { 83 if (StatisticsRecorder::dump_on_exit()) {
82 std::string output; 84 std::string output;
83 WriteAscii(true, "\n", &output); 85 WriteAscii(true, "\n", &output);
84 LOG(INFO) << output; 86 LOG(INFO) << output;
85 } 87 }
86 88
87 // Just to make sure most derived class did this properly... 89 // Just to make sure most derived class did this properly...
88 DCHECK(ValidateBucketRanges()); 90 DCHECK(ValidateBucketRanges());
91 DCHECK(HasValidRangeChecksum());
89 } 92 }
90 93
91 bool Histogram::PrintEmptyBucket(size_t index) const { 94 bool Histogram::PrintEmptyBucket(size_t index) const {
92 return true; 95 return true;
93 } 96 }
94 97
95 void Histogram::Add(int value) { 98 void Histogram::Add(int value) {
96 if (value > kSampleType_MAX - 1) 99 if (value > kSampleType_MAX - 1)
97 value = kSampleType_MAX - 1; 100 value = kSampleType_MAX - 1;
98 if (value < 0) 101 if (value < 0)
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 ranges_[bucket_count_] = kSampleType_MAX; 214 ranges_[bucket_count_] = kSampleType_MAX;
212 InitializeBucketRange(); 215 InitializeBucketRange();
213 DCHECK(ValidateBucketRanges()); 216 DCHECK(ValidateBucketRanges());
214 StatisticsRecorder::Register(this); 217 StatisticsRecorder::Register(this);
215 } 218 }
216 219
217 // Calculate what range of values are held in each bucket. 220 // Calculate what range of values are held in each bucket.
218 // We have to be careful that we don't pick a ratio between starting points in 221 // We have to be careful that we don't pick a ratio between starting points in
219 // consecutive buckets that is sooo small, that the integer bounds are the same 222 // consecutive buckets that is sooo small, that the integer bounds are the same
220 // (effectively making one bucket get no values). We need to avoid: 223 // (effectively making one bucket get no values). We need to avoid:
221 // (ranges_[i] == ranges_[i + 1] 224 // ranges_[i] == ranges_[i + 1]
222 // To avoid that, we just do a fine-grained bucket width as far as we need to 225 // To avoid that, we just do a fine-grained bucket width as far as we need to
223 // until we get a ratio that moves us along at least 2 units at a time. From 226 // until we get a ratio that moves us along at least 2 units at a time. From
224 // that bucket onward we do use the exponential growth of buckets. 227 // that bucket onward we do use the exponential growth of buckets.
225 void Histogram::InitializeBucketRange() { 228 void Histogram::InitializeBucketRange() {
226 double log_max = log(static_cast<double>(declared_max())); 229 double log_max = log(static_cast<double>(declared_max()));
227 double log_ratio; 230 double log_ratio;
228 double log_next; 231 double log_next;
229 size_t bucket_index = 1; 232 size_t bucket_index = 1;
230 Sample current = declared_min(); 233 Sample current = declared_min();
231 SetBucketRange(bucket_index, current); 234 SetBucketRange(bucket_index, current);
232 while (bucket_count() > ++bucket_index) { 235 while (bucket_count() > ++bucket_index) {
233 double log_current; 236 double log_current;
234 log_current = log(static_cast<double>(current)); 237 log_current = log(static_cast<double>(current));
235 // Calculate the count'th root of the range. 238 // Calculate the count'th root of the range.
236 log_ratio = (log_max - log_current) / (bucket_count() - bucket_index); 239 log_ratio = (log_max - log_current) / (bucket_count() - bucket_index);
237 // See where the next bucket would start. 240 // See where the next bucket would start.
238 log_next = log_current + log_ratio; 241 log_next = log_current + log_ratio;
239 int next; 242 int next;
240 next = static_cast<int>(floor(exp(log_next) + 0.5)); 243 next = static_cast<int>(floor(exp(log_next) + 0.5));
241 if (next > current) 244 if (next > current)
242 current = next; 245 current = next;
243 else 246 else
244 ++current; // Just do a narrow bucket, and keep trying. 247 ++current; // Just do a narrow bucket, and keep trying.
245 SetBucketRange(bucket_index, current); 248 SetBucketRange(bucket_index, current);
246 } 249 }
250 ResetRangeChecksum();
247 251
248 DCHECK_EQ(bucket_count(), bucket_index); 252 DCHECK_EQ(bucket_count(), bucket_index);
249 } 253 }
250 254
251 size_t Histogram::BucketIndex(Sample value) const { 255 size_t Histogram::BucketIndex(Sample value) const {
252 // Use simple binary search. This is very general, but there are better 256 // Use simple binary search. This is very general, but there are better
253 // approaches if we knew that the buckets were linearly distributed. 257 // approaches if we knew that the buckets were linearly distributed.
254 DCHECK_LE(ranges(0), value); 258 DCHECK_LE(ranges(0), value);
255 DCHECK_GT(ranges(bucket_count()), value); 259 DCHECK_GT(ranges(bucket_count()), value);
256 size_t under = 0; 260 size_t under = 0;
(...skipping 23 matching lines...) Expand all
280 // not have 0-graphical-height buckets. 284 // not have 0-graphical-height buckets.
281 double Histogram::GetBucketSize(Count current, size_t i) const { 285 double Histogram::GetBucketSize(Count current, size_t i) const {
282 DCHECK_GT(ranges(i + 1), ranges(i)); 286 DCHECK_GT(ranges(i + 1), ranges(i));
283 static const double kTransitionWidth = 5; 287 static const double kTransitionWidth = 5;
284 double denominator = ranges(i + 1) - ranges(i); 288 double denominator = ranges(i + 1) - ranges(i);
285 if (denominator > kTransitionWidth) 289 if (denominator > kTransitionWidth)
286 denominator = kTransitionWidth; // Stop trying to normalize. 290 denominator = kTransitionWidth; // Stop trying to normalize.
287 return current/denominator; 291 return current/denominator;
288 } 292 }
289 293
294 void Histogram::ResetRangeChecksum() {
295 range_checksum_ = CalculateRangeChecksum();
296 }
297
298 bool Histogram::HasValidRangeChecksum() const {
299 return CalculateRangeChecksum() == range_checksum_;
300 }
301
302 Histogram::Sample Histogram::CalculateRangeChecksum() const {
303 DCHECK_EQ(ranges_.size(), bucket_count() + 1);
304 Sample checksum = 0;
305 for (size_t index = 0; index < bucket_count(); ++index) {
306 checksum += ranges(index);
307 }
308 return checksum;
309 }
310
290 //------------------------------------------------------------------------------ 311 //------------------------------------------------------------------------------
291 // The following two methods can be overridden to provide a thread safe 312 // The following two methods can be overridden to provide a thread safe
292 // version of this class. The cost of locking is low... but an error in each 313 // version of this class. The cost of locking is low... but an error in each
293 // of these methods has minimal impact. For now, I'll leave this unlocked, 314 // of these methods has minimal impact. For now, I'll leave this unlocked,
294 // and I don't believe I can loose more than a count or two. 315 // and I don't believe I can loose more than a count or two.
295 // The vectors are NOT reallocated, so there is no risk of them moving around. 316 // The vectors are NOT reallocated, so there is no risk of them moving around.
296 317
297 // Update histogram data with new sample. 318 // Update histogram data with new sample.
298 void Histogram::Accumulate(Sample value, Count count, size_t index) { 319 void Histogram::Accumulate(Sample value, Count count, size_t index) {
299 // Note locking not done in this version!!! 320 // Note locking not done in this version!!!
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 // static 431 // static
411 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, 432 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
412 const SampleSet& snapshot) { 433 const SampleSet& snapshot) {
413 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type()); 434 DCHECK_NE(NOT_VALID_IN_RENDERER, histogram.histogram_type());
414 435
415 Pickle pickle; 436 Pickle pickle;
416 pickle.WriteString(histogram.histogram_name()); 437 pickle.WriteString(histogram.histogram_name());
417 pickle.WriteInt(histogram.declared_min()); 438 pickle.WriteInt(histogram.declared_min());
418 pickle.WriteInt(histogram.declared_max()); 439 pickle.WriteInt(histogram.declared_max());
419 pickle.WriteSize(histogram.bucket_count()); 440 pickle.WriteSize(histogram.bucket_count());
441 pickle.WriteInt(histogram.range_checksum());
420 pickle.WriteInt(histogram.histogram_type()); 442 pickle.WriteInt(histogram.histogram_type());
421 pickle.WriteInt(histogram.flags()); 443 pickle.WriteInt(histogram.flags());
422 444
423 snapshot.Serialize(&pickle); 445 snapshot.Serialize(&pickle);
424 return std::string(static_cast<const char*>(pickle.data()), pickle.size()); 446 return std::string(static_cast<const char*>(pickle.data()), pickle.size());
425 } 447 }
426 448
427 // static 449 // static
428 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { 450 bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
429 if (histogram_info.empty()) { 451 if (histogram_info.empty()) {
430 return false; 452 return false;
431 } 453 }
432 454
433 Pickle pickle(histogram_info.data(), 455 Pickle pickle(histogram_info.data(),
434 static_cast<int>(histogram_info.size())); 456 static_cast<int>(histogram_info.size()));
435 void* iter = NULL; 457 std::string histogram_name;
436 size_t bucket_count;
437 int declared_min; 458 int declared_min;
438 int declared_max; 459 int declared_max;
460 size_t bucket_count;
461 int range_checksum;
439 int histogram_type; 462 int histogram_type;
440 int pickle_flags; 463 int pickle_flags;
441 std::string histogram_name;
442 SampleSet sample; 464 SampleSet sample;
443 465
466 void* iter = NULL;
444 if (!pickle.ReadString(&iter, &histogram_name) || 467 if (!pickle.ReadString(&iter, &histogram_name) ||
445 !pickle.ReadInt(&iter, &declared_min) || 468 !pickle.ReadInt(&iter, &declared_min) ||
446 !pickle.ReadInt(&iter, &declared_max) || 469 !pickle.ReadInt(&iter, &declared_max) ||
447 !pickle.ReadSize(&iter, &bucket_count) || 470 !pickle.ReadSize(&iter, &bucket_count) ||
471 !pickle.ReadInt(&iter, &range_checksum) ||
448 !pickle.ReadInt(&iter, &histogram_type) || 472 !pickle.ReadInt(&iter, &histogram_type) ||
449 !pickle.ReadInt(&iter, &pickle_flags) || 473 !pickle.ReadInt(&iter, &pickle_flags) ||
450 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) { 474 !sample.Histogram::SampleSet::Deserialize(&iter, pickle)) {
451 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name; 475 LOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
452 return false; 476 return false;
453 } 477 }
454 DCHECK(pickle_flags & kIPCSerializationSourceFlag); 478 DCHECK(pickle_flags & kIPCSerializationSourceFlag);
455 // Since these fields may have come from an untrusted renderer, do additional 479 // Since these fields may have come from an untrusted renderer, do additional
456 // checks above and beyond those in Histogram::Initialize() 480 // checks above and beyond those in Histogram::Initialize()
457 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min || 481 if (declared_max <= 0 || declared_min <= 0 || declared_max < declared_min ||
(...skipping 18 matching lines...) Expand all
476 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags); 500 render_histogram = BooleanHistogram::FactoryGet(histogram_name, flags);
477 } else { 501 } else {
478 LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " 502 LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: "
479 << histogram_type; 503 << histogram_type;
480 return false; 504 return false;
481 } 505 }
482 506
483 DCHECK_EQ(render_histogram->declared_min(), declared_min); 507 DCHECK_EQ(render_histogram->declared_min(), declared_min);
484 DCHECK_EQ(render_histogram->declared_max(), declared_max); 508 DCHECK_EQ(render_histogram->declared_max(), declared_max);
485 DCHECK_EQ(render_histogram->bucket_count(), bucket_count); 509 DCHECK_EQ(render_histogram->bucket_count(), bucket_count);
510 DCHECK_EQ(render_histogram->range_checksum(), range_checksum);
486 DCHECK_EQ(render_histogram->histogram_type(), histogram_type); 511 DCHECK_EQ(render_histogram->histogram_type(), histogram_type);
487 512
488 if (render_histogram->flags() & kIPCSerializationSourceFlag) { 513 if (render_histogram->flags() & kIPCSerializationSourceFlag) {
489 DVLOG(1) << "Single process mode, histogram observed and not copied: " 514 DVLOG(1) << "Single process mode, histogram observed and not copied: "
490 << histogram_name; 515 << histogram_name;
491 } else { 516 } else {
492 DCHECK_EQ(flags & render_histogram->flags(), flags); 517 DCHECK_EQ(flags & render_histogram->flags(), flags);
493 render_histogram->AddSampleSet(sample); 518 render_histogram->AddSampleSet(sample);
494 } 519 }
495 520
496 return true; 521 return true;
497 } 522 }
498 523
499 //------------------------------------------------------------------------------ 524 //------------------------------------------------------------------------------
525 // Methods for the validating a sample and a related histogram.
526 //------------------------------------------------------------------------------
527
528 Histogram::Inconsistencies Histogram::FindCorruption(
529 const SampleSet& snapshot) const {
530 int inconsistencies = NO_INCONSISTENCIES;
531 Sample previous_range = -1; // Bottom range is always 0.
532 Sample checksum = 0;
533 int64 count = 0;
534 for (size_t index = 0; index < bucket_count(); ++index) {
535 count += snapshot.counts(index);
536 int new_range = ranges(index);
537 checksum += new_range;
538 if (previous_range >= new_range)
539 inconsistencies |= BUCKET_ORDER_ERROR;
540 previous_range = new_range;
541 }
542
543 if (checksum != range_checksum_)
544 inconsistencies |= RANGE_CHECKSUM_ERROR;
545
546 int64 delta64 = snapshot.redundant_count() - count;
547 if (delta64 != 0) {
548 int delta = static_cast<int>(delta64);
549 if (delta != delta64)
550 delta = INT_MAX; // Flag all giant errors as INT_MAX.
551 // Since snapshots of histograms are taken asynchronously relative to
552 // sampling (and snapped from different threads), it is pretty likely that
553 // we'll catch a redundant count that doesn't match the sample count. We
554 // allow for a certain amount of slop before flagging this as an
555 // inconsistency. Even with an inconsistency, we'll snapshot it again (for
556 // UMA in about a half hour, so we'll eventually get the data, if it was
557 // not the result of a corruption. If histograms show that 1 is "too tight"
558 // then we may try to use 2 or 3 for this slop value.
559 const int kCommonRaceBasedCountMismatch = 1;
560 if (delta > 0) {
561 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
562 if (delta > kCommonRaceBasedCountMismatch)
563 inconsistencies |= COUNT_HIGH_ERROR;
564 } else {
565 DCHECK_GT(0, delta);
566 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
567 if (-delta > kCommonRaceBasedCountMismatch)
568 inconsistencies |= COUNT_LOW_ERROR;
569 }
570 }
571 return static_cast<Inconsistencies>(inconsistencies);
572 }
573
574 //------------------------------------------------------------------------------
500 // Methods for the Histogram::SampleSet class 575 // Methods for the Histogram::SampleSet class
501 //------------------------------------------------------------------------------ 576 //------------------------------------------------------------------------------
502 577
503 Histogram::SampleSet::SampleSet() 578 Histogram::SampleSet::SampleSet()
504 : counts_(), 579 : counts_(),
505 sum_(0), 580 sum_(0),
506 square_sum_(0) { 581 square_sum_(0),
582 redundant_count_(0) {
507 } 583 }
508 584
509 Histogram::SampleSet::~SampleSet() { 585 Histogram::SampleSet::~SampleSet() {
510 } 586 }
511 587
512 void Histogram::SampleSet::Resize(const Histogram& histogram) { 588 void Histogram::SampleSet::Resize(const Histogram& histogram) {
513 counts_.resize(histogram.bucket_count(), 0); 589 counts_.resize(histogram.bucket_count(), 0);
514 } 590 }
515 591
516 void Histogram::SampleSet::CheckSize(const Histogram& histogram) const { 592 void Histogram::SampleSet::CheckSize(const Histogram& histogram) const {
517 DCHECK_EQ(histogram.bucket_count(), counts_.size()); 593 DCHECK_EQ(histogram.bucket_count(), counts_.size());
518 } 594 }
519 595
520 596
521 void Histogram::SampleSet::Accumulate(Sample value, Count count, 597 void Histogram::SampleSet::Accumulate(Sample value, Count count,
522 size_t index) { 598 size_t index) {
523 DCHECK(count == 1 || count == -1); 599 DCHECK(count == 1 || count == -1);
524 counts_[index] += count; 600 counts_[index] += count;
525 sum_ += count * value; 601 sum_ += count * value;
526 square_sum_ += (count * value) * static_cast<int64>(value); 602 square_sum_ += (count * value) * static_cast<int64>(value);
603 redundant_count_ += count;
527 DCHECK_GE(counts_[index], 0); 604 DCHECK_GE(counts_[index], 0);
528 DCHECK_GE(sum_, 0); 605 DCHECK_GE(sum_, 0);
529 DCHECK_GE(square_sum_, 0); 606 DCHECK_GE(square_sum_, 0);
607 DCHECK_GE(redundant_count_, 0);
530 } 608 }
531 609
532 Count Histogram::SampleSet::TotalCount() const { 610 Count Histogram::SampleSet::TotalCount() const {
533 Count total = 0; 611 Count total = 0;
534 for (Counts::const_iterator it = counts_.begin(); 612 for (Counts::const_iterator it = counts_.begin();
535 it != counts_.end(); 613 it != counts_.end();
536 ++it) { 614 ++it) {
537 total += *it; 615 total += *it;
538 } 616 }
617 DCHECK_EQ(total, redundant_count_);
539 return total; 618 return total;
540 } 619 }
541 620
542 void Histogram::SampleSet::Add(const SampleSet& other) { 621 void Histogram::SampleSet::Add(const SampleSet& other) {
543 DCHECK_EQ(counts_.size(), other.counts_.size()); 622 DCHECK_EQ(counts_.size(), other.counts_.size());
544 sum_ += other.sum_; 623 sum_ += other.sum_;
545 square_sum_ += other.square_sum_; 624 square_sum_ += other.square_sum_;
625 redundant_count_ += other.redundant_count_;
546 for (size_t index = 0; index < counts_.size(); ++index) 626 for (size_t index = 0; index < counts_.size(); ++index)
547 counts_[index] += other.counts_[index]; 627 counts_[index] += other.counts_[index];
548 } 628 }
549 629
550 void Histogram::SampleSet::Subtract(const SampleSet& other) { 630 void Histogram::SampleSet::Subtract(const SampleSet& other) {
551 DCHECK_EQ(counts_.size(), other.counts_.size()); 631 DCHECK_EQ(counts_.size(), other.counts_.size());
552 // Note: Race conditions in snapshotting a sum or square_sum may lead to 632 // Note: Race conditions in snapshotting a sum or square_sum may lead to
553 // (temporary) negative values when snapshots are later combined (and deltas 633 // (temporary) negative values when snapshots are later combined (and deltas
554 // calculated). As a result, we don't currently CHCEK() for positive values. 634 // calculated). As a result, we don't currently CHCEK() for positive values.
555 sum_ -= other.sum_; 635 sum_ -= other.sum_;
556 square_sum_ -= other.square_sum_; 636 square_sum_ -= other.square_sum_;
637 redundant_count_ -= other.redundant_count_;
557 for (size_t index = 0; index < counts_.size(); ++index) { 638 for (size_t index = 0; index < counts_.size(); ++index) {
558 counts_[index] -= other.counts_[index]; 639 counts_[index] -= other.counts_[index];
559 DCHECK_GE(counts_[index], 0); 640 DCHECK_GE(counts_[index], 0);
560 } 641 }
561 } 642 }
562 643
563 bool Histogram::SampleSet::Serialize(Pickle* pickle) const { 644 bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
564 pickle->WriteInt64(sum_); 645 pickle->WriteInt64(sum_);
565 pickle->WriteInt64(square_sum_); 646 pickle->WriteInt64(square_sum_);
647 pickle->WriteInt64(redundant_count_);
566 pickle->WriteSize(counts_.size()); 648 pickle->WriteSize(counts_.size());
567 649
568 for (size_t index = 0; index < counts_.size(); ++index) { 650 for (size_t index = 0; index < counts_.size(); ++index) {
569 pickle->WriteInt(counts_[index]); 651 pickle->WriteInt(counts_[index]);
570 } 652 }
571 653
572 return true; 654 return true;
573 } 655 }
574 656
575 bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) { 657 bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
576 DCHECK_EQ(counts_.size(), 0u); 658 DCHECK_EQ(counts_.size(), 0u);
577 DCHECK_EQ(sum_, 0); 659 DCHECK_EQ(sum_, 0);
578 DCHECK_EQ(square_sum_, 0); 660 DCHECK_EQ(square_sum_, 0);
661 DCHECK_EQ(redundant_count_, 0);
579 662
580 size_t counts_size; 663 size_t counts_size;
581 664
582 if (!pickle.ReadInt64(iter, &sum_) || 665 if (!pickle.ReadInt64(iter, &sum_) ||
583 !pickle.ReadInt64(iter, &square_sum_) || 666 !pickle.ReadInt64(iter, &square_sum_) ||
667 !pickle.ReadInt64(iter, &redundant_count_) ||
584 !pickle.ReadSize(iter, &counts_size)) { 668 !pickle.ReadSize(iter, &counts_size)) {
585 return false; 669 return false;
586 } 670 }
587 671
588 if (counts_size == 0) 672 if (counts_size == 0)
589 return false; 673 return false;
590 674
675 int count = 0;
591 for (size_t index = 0; index < counts_size; ++index) { 676 for (size_t index = 0; index < counts_size; ++index) {
592 int i; 677 int i;
593 if (!pickle.ReadInt(iter, &i)) 678 if (!pickle.ReadInt(iter, &i))
594 return false; 679 return false;
595 counts_.push_back(i); 680 counts_.push_back(i);
681 count += i;
596 } 682 }
597 683 DCHECK_EQ(count, redundant_count_);
598 return true; 684 return count == redundant_count_;
599 } 685 }
600 686
601 //------------------------------------------------------------------------------ 687 //------------------------------------------------------------------------------
602 // LinearHistogram: This histogram uses a traditional set of evenly spaced 688 // LinearHistogram: This histogram uses a traditional set of evenly spaced
603 // buckets. 689 // buckets.
604 //------------------------------------------------------------------------------ 690 //------------------------------------------------------------------------------
605 691
606 scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name, 692 scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
607 Sample minimum, 693 Sample minimum,
608 Sample maximum, 694 Sample maximum,
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
687 void LinearHistogram::InitializeBucketRange() { 773 void LinearHistogram::InitializeBucketRange() {
688 DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here. 774 DCHECK_GT(declared_min(), 0); // 0 is the underflow bucket here.
689 double min = declared_min(); 775 double min = declared_min();
690 double max = declared_max(); 776 double max = declared_max();
691 size_t i; 777 size_t i;
692 for (i = 1; i < bucket_count(); ++i) { 778 for (i = 1; i < bucket_count(); ++i) {
693 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) / 779 double linear_range = (min * (bucket_count() -1 - i) + max * (i - 1)) /
694 (bucket_count() - 2); 780 (bucket_count() - 2);
695 SetBucketRange(i, static_cast<int> (linear_range + 0.5)); 781 SetBucketRange(i, static_cast<int> (linear_range + 0.5));
696 } 782 }
783 ResetRangeChecksum();
697 } 784 }
698 785
699 double LinearHistogram::GetBucketSize(Count current, size_t i) const { 786 double LinearHistogram::GetBucketSize(Count current, size_t i) const {
700 DCHECK_GT(ranges(i + 1), ranges(i)); 787 DCHECK_GT(ranges(i + 1), ranges(i));
701 // Adjacent buckets with different widths would have "surprisingly" many (few) 788 // Adjacent buckets with different widths would have "surprisingly" many (few)
702 // samples in a histogram if we didn't normalize this way. 789 // samples in a histogram if we didn't normalize this way.
703 double denominator = ranges(i + 1) - ranges(i); 790 double denominator = ranges(i + 1) - ranges(i);
704 return current/denominator; 791 return current/denominator;
705 } 792 }
706 793
(...skipping 26 matching lines...) Expand all
733 BooleanHistogram::BooleanHistogram(const std::string& name) 820 BooleanHistogram::BooleanHistogram(const std::string& name)
734 : LinearHistogram(name, 1, 2, 3) { 821 : LinearHistogram(name, 1, 2, 3) {
735 } 822 }
736 823
737 //------------------------------------------------------------------------------ 824 //------------------------------------------------------------------------------
738 // CustomHistogram: 825 // CustomHistogram:
739 //------------------------------------------------------------------------------ 826 //------------------------------------------------------------------------------
740 827
741 scoped_refptr<Histogram> CustomHistogram::FactoryGet( 828 scoped_refptr<Histogram> CustomHistogram::FactoryGet(
742 const std::string& name, 829 const std::string& name,
743 const std::vector<int>& custom_ranges, 830 const std::vector<Sample>& custom_ranges,
744 Flags flags) { 831 Flags flags) {
745 scoped_refptr<Histogram> histogram(NULL); 832 scoped_refptr<Histogram> histogram(NULL);
746 833
747 // Remove the duplicates in the custom ranges array. 834 // Remove the duplicates in the custom ranges array.
748 std::vector<int> ranges = custom_ranges; 835 std::vector<int> ranges = custom_ranges;
749 ranges.push_back(0); // Ensure we have a zero value. 836 ranges.push_back(0); // Ensure we have a zero value.
750 std::sort(ranges.begin(), ranges.end()); 837 std::sort(ranges.begin(), ranges.end());
751 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end()); 838 ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
752 if (ranges.size() <= 1) { 839 if (ranges.size() <= 1) {
753 DCHECK(false); 840 DCHECK(false);
(...skipping 13 matching lines...) Expand all
767 ranges.size())); 854 ranges.size()));
768 histogram->SetFlags(flags); 855 histogram->SetFlags(flags);
769 return histogram; 856 return histogram;
770 } 857 }
771 858
772 Histogram::ClassType CustomHistogram::histogram_type() const { 859 Histogram::ClassType CustomHistogram::histogram_type() const {
773 return CUSTOM_HISTOGRAM; 860 return CUSTOM_HISTOGRAM;
774 } 861 }
775 862
776 CustomHistogram::CustomHistogram(const std::string& name, 863 CustomHistogram::CustomHistogram(const std::string& name,
777 const std::vector<int>& custom_ranges) 864 const std::vector<Sample>& custom_ranges)
778 : Histogram(name, custom_ranges[1], custom_ranges.back(), 865 : Histogram(name, custom_ranges[1], custom_ranges.back(),
779 custom_ranges.size()) { 866 custom_ranges.size()) {
780 DCHECK_GT(custom_ranges.size(), 1u); 867 DCHECK_GT(custom_ranges.size(), 1u);
781 DCHECK_EQ(custom_ranges[0], 0); 868 DCHECK_EQ(custom_ranges[0], 0);
782 ranges_vector_ = &custom_ranges; 869 ranges_vector_ = &custom_ranges;
783 InitializeBucketRange(); 870 InitializeBucketRange();
784 ranges_vector_ = NULL; 871 ranges_vector_ = NULL;
785 DCHECK(ValidateBucketRanges()); 872 DCHECK(ValidateBucketRanges());
786 } 873 }
787 874
788 void CustomHistogram::InitializeBucketRange() { 875 void CustomHistogram::InitializeBucketRange() {
789 DCHECK_LE(ranges_vector_->size(), bucket_count()); 876 DCHECK_LE(ranges_vector_->size(), bucket_count());
790 for (size_t index = 0; index < ranges_vector_->size(); ++index) 877 for (size_t index = 0; index < ranges_vector_->size(); ++index)
791 SetBucketRange(index, (*ranges_vector_)[index]); 878 SetBucketRange(index, (*ranges_vector_)[index]);
879 ResetRangeChecksum();
792 } 880 }
793 881
794 double CustomHistogram::GetBucketSize(Count current, size_t i) const { 882 double CustomHistogram::GetBucketSize(Count current, size_t i) const {
795 return 1; 883 return 1;
796 } 884 }
797 885
798 //------------------------------------------------------------------------------ 886 //------------------------------------------------------------------------------
799 // The next section handles global (central) support for all histograms, as well 887 // The next section handles global (central) support for all histograms, as well
800 // as startup/teardown of this service. 888 // as startup/teardown of this service.
801 //------------------------------------------------------------------------------ 889 //------------------------------------------------------------------------------
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
927 } 1015 }
928 1016
929 // static 1017 // static
930 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL; 1018 StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
931 // static 1019 // static
932 Lock* StatisticsRecorder::lock_ = NULL; 1020 Lock* StatisticsRecorder::lock_ = NULL;
933 // static 1021 // static
934 bool StatisticsRecorder::dump_on_exit_ = false; 1022 bool StatisticsRecorder::dump_on_exit_ = false;
935 1023
936 } // namespace base 1024 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698