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