OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |