| Index: base/metrics/histogram.cc
|
| ===================================================================
|
| --- base/metrics/histogram.cc (revision 106341)
|
| +++ base/metrics/histogram.cc (working copy)
|
| @@ -74,6 +74,13 @@
|
| // static
|
| const size_t Histogram::kBucketCount_MAX = 16384u;
|
|
|
| +// Collect the number of histograms created.
|
| +static uint32 number_of_histograms_ = 0;
|
| +// Collect the number of vectors saved because of caching ranges.
|
| +static uint32 number_of_vectors_saved_ = 0;
|
| +// Collect the number of ranges_ elements saved because of caching ranges.
|
| +static size_t saved_ranges_size_ = 0;
|
| +
|
| Histogram* Histogram::FactoryGet(const std::string& name,
|
| Sample minimum,
|
| Sample maximum,
|
| @@ -363,7 +370,7 @@
|
| }
|
|
|
| Histogram::Sample Histogram::ranges(size_t i) const {
|
| - return ranges_[i];
|
| + return cached_ranges_->ranges(i);
|
| }
|
|
|
| size_t Histogram::bucket_count() const {
|
| @@ -403,7 +410,7 @@
|
| declared_max_(maximum),
|
| bucket_count_(bucket_count),
|
| flags_(kNoFlags),
|
| - ranges_(bucket_count + 1, 0),
|
| + cached_ranges_(new CachedRanges(bucket_count + 1, 0)),
|
| range_checksum_(0),
|
| sample_() {
|
| Initialize();
|
| @@ -416,7 +423,7 @@
|
| declared_max_(static_cast<int> (maximum.InMilliseconds())),
|
| bucket_count_(bucket_count),
|
| flags_(kNoFlags),
|
| - ranges_(bucket_count + 1, 0),
|
| + cached_ranges_(new CachedRanges(bucket_count + 1, 0)),
|
| range_checksum_(0),
|
| sample_() {
|
| Initialize();
|
| @@ -437,7 +444,7 @@
|
| // We have to be careful that we don't pick a ratio between starting points in
|
| // consecutive buckets that is sooo small, that the integer bounds are the same
|
| // (effectively making one bucket get no values). We need to avoid:
|
| -// ranges_[i] == ranges_[i + 1]
|
| +// ranges(i) == ranges(i + 1)
|
| // To avoid that, we just do a fine-grained bucket width as far as we need to
|
| // until we get a ratio that moves us along at least 2 units at a time. From
|
| // that bucket onward we do use the exponential growth of buckets.
|
| @@ -533,22 +540,23 @@
|
| void Histogram::SetBucketRange(size_t i, Sample value) {
|
| DCHECK_GT(bucket_count_, i);
|
| DCHECK_GE(value, 0);
|
| - ranges_[i] = value;
|
| + cached_ranges_->SetBucketRange(i, value);
|
| }
|
|
|
| bool Histogram::ValidateBucketRanges() const {
|
| // Standard assertions that all bucket ranges should satisfy.
|
| - DCHECK_EQ(bucket_count_ + 1, ranges_.size());
|
| - DCHECK_EQ(0, ranges_[0]);
|
| - DCHECK_EQ(declared_min(), ranges_[1]);
|
| - DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
|
| - DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
|
| + DCHECK_EQ(bucket_count_ + 1, cached_ranges_->size());
|
| + DCHECK_EQ(0, ranges(0));
|
| + DCHECK_EQ(declared_min(), ranges(1));
|
| + DCHECK_EQ(declared_max(), ranges(bucket_count_ - 1));
|
| + DCHECK_EQ(kSampleType_MAX, ranges(bucket_count_));
|
| return true;
|
| }
|
|
|
| uint32 Histogram::CalculateRangeChecksum() const {
|
| - DCHECK_EQ(ranges_.size(), bucket_count() + 1);
|
| - uint32 checksum = static_cast<uint32>(ranges_.size()); // Seed checksum.
|
| + DCHECK_EQ(cached_ranges_->size(), bucket_count() + 1);
|
| + // Seed checksum.
|
| + uint32 checksum = static_cast<uint32>(cached_ranges_->size());
|
| for (size_t index = 0; index < bucket_count(); ++index)
|
| checksum = Crc32(checksum, ranges(index));
|
| return checksum;
|
| @@ -565,8 +573,8 @@
|
| CHECK_LT(bucket_count_, kBucketCount_MAX);
|
| size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
|
| DCHECK_LE(bucket_count_, maximal_bucket_count);
|
| - DCHECK_EQ(0, ranges_[0]);
|
| - ranges_[bucket_count_] = kSampleType_MAX;
|
| + DCHECK_EQ(0, ranges(0));
|
| + cached_ranges_->SetBucketRange(bucket_count_, kSampleType_MAX);
|
| }
|
|
|
| // We generate the CRC-32 using the low order bits to select whether to XOR in
|
| @@ -1008,6 +1016,7 @@
|
| }
|
| base::AutoLock auto_lock(*lock_);
|
| histograms_ = new HistogramMap;
|
| + ranges_ = new RangesMap;
|
| }
|
|
|
| StatisticsRecorder::~StatisticsRecorder() {
|
| @@ -1025,7 +1034,15 @@
|
| histograms = histograms_;
|
| histograms_ = NULL;
|
| }
|
| + RangesMap* ranges = NULL;
|
| + {
|
| + base::AutoLock auto_lock(*lock_);
|
| + ranges = ranges_;
|
| + ranges_ = NULL;
|
| + }
|
| + // We are going to leak the histograms and the ranges.
|
| delete histograms;
|
| + delete ranges;
|
| // We don't delete lock_ on purpose to avoid having to properly protect
|
| // against it going away after we checked for NULL in the static methods.
|
| }
|
| @@ -1060,6 +1077,8 @@
|
| if (histograms_->end() == it) {
|
| (*histograms_)[name] = histogram;
|
| ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
|
| + RegisterOrDeleteDuplicateRanges(histogram);
|
| + ++number_of_histograms_;
|
| } else {
|
| delete histogram; // We already have one by this name.
|
| histogram = it->second;
|
| @@ -1068,6 +1087,93 @@
|
| }
|
|
|
| // static
|
| +void StatisticsRecorder::RegisterOrDeleteDuplicateRanges(Histogram* histogram) {
|
| + DCHECK(histogram);
|
| + CachedRanges* histogram_ranges = histogram->cached_ranges();
|
| + DCHECK(histogram_ranges);
|
| + uint32 checksum = histogram->range_checksum();
|
| + histogram_ranges->SetRangeChecksum(checksum);
|
| +
|
| + RangesMap::iterator ranges_it = ranges_->find(checksum);
|
| + if (ranges_->end() == ranges_it) {
|
| + // Register the new CachedRanges.
|
| + std::list<CachedRanges*>* checksum_matching_list(
|
| + new std::list<CachedRanges*>());
|
| + checksum_matching_list->push_front(histogram_ranges);
|
| + (*ranges_)[checksum] = checksum_matching_list;
|
| + return;
|
| + }
|
| +
|
| + // Use the registered CachedRanges if the registered CachedRanges has same
|
| + // ranges_ as |histogram|'s CachedRanges.
|
| + std::list<CachedRanges*>* checksum_matching_list = ranges_it->second;
|
| + std::list<CachedRanges*>::iterator checksum_matching_list_it;
|
| + for (checksum_matching_list_it = checksum_matching_list->begin();
|
| + checksum_matching_list_it != checksum_matching_list->end();
|
| + ++checksum_matching_list_it) {
|
| + CachedRanges* existing_histogram_ranges = *checksum_matching_list_it;
|
| + DCHECK(existing_histogram_ranges);
|
| + if (existing_histogram_ranges->Equals(histogram_ranges)) {
|
| + histogram->set_cached_ranges(existing_histogram_ranges);
|
| + ++number_of_vectors_saved_;
|
| + saved_ranges_size_ += histogram_ranges->size();
|
| + delete histogram_ranges;
|
| + return;
|
| + }
|
| + }
|
| +
|
| + // We haven't found a CachedRanges which has the same ranges. Register the
|
| + // new CachedRanges.
|
| + DCHECK(checksum_matching_list_it == checksum_matching_list->end());
|
| + checksum_matching_list->push_front(histogram_ranges);
|
| +}
|
| +
|
| +// static
|
| +void StatisticsRecorder::CollectHistogramStats(const std::string& suffix) {
|
| + static int uma_upload_attempt = 0;
|
| + ++uma_upload_attempt;
|
| + if (uma_upload_attempt == 1) {
|
| + UMA_HISTOGRAM_COUNTS_10000(
|
| + "Histogram.SharedRange.Count.FirstUpload." + suffix,
|
| + number_of_histograms_);
|
| + UMA_HISTOGRAM_COUNTS_10000(
|
| + "Histogram.SharedRange.RangesSaved.FirstUpload." + suffix,
|
| + number_of_vectors_saved_);
|
| + UMA_HISTOGRAM_COUNTS(
|
| + "Histogram.SharedRange.ElementsSaved.FirstUpload." + suffix,
|
| + static_cast<int>(saved_ranges_size_));
|
| + number_of_histograms_ = 0;
|
| + number_of_vectors_saved_ = 0;
|
| + saved_ranges_size_ = 0;
|
| + return;
|
| + }
|
| + if (uma_upload_attempt == 2) {
|
| + UMA_HISTOGRAM_COUNTS_10000(
|
| + "Histogram.SharedRange.Count.SecondUpload." + suffix,
|
| + number_of_histograms_);
|
| + UMA_HISTOGRAM_COUNTS_10000(
|
| + "Histogram.SharedRange.RangesSaved.SecondUpload." + suffix,
|
| + number_of_vectors_saved_);
|
| + UMA_HISTOGRAM_COUNTS(
|
| + "Histogram.SharedRange.ElementsSaved.SecondUpload." + suffix,
|
| + static_cast<int>(saved_ranges_size_));
|
| + number_of_histograms_ = 0;
|
| + number_of_vectors_saved_ = 0;
|
| + saved_ranges_size_ = 0;
|
| + return;
|
| + }
|
| + UMA_HISTOGRAM_COUNTS_10000(
|
| + "Histogram.SharedRange.Count.RestOfUploads." + suffix,
|
| + number_of_histograms_);
|
| + UMA_HISTOGRAM_COUNTS_10000(
|
| + "Histogram.SharedRange.RangesSaved.RestOfUploads." + suffix,
|
| + number_of_vectors_saved_);
|
| + UMA_HISTOGRAM_COUNTS(
|
| + "Histogram.SharedRange.ElementsSaved.RestOfUploads." + suffix,
|
| + static_cast<int>(saved_ranges_size_));
|
| +}
|
| +
|
| +// static
|
| void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
|
| std::string* output) {
|
| if (!IsActive())
|
| @@ -1148,11 +1254,38 @@
|
| }
|
| }
|
|
|
| +CachedRanges::CachedRanges(size_t bucket_count, int initial_value)
|
| + : ranges_(bucket_count, initial_value),
|
| + range_checksum_(0) {
|
| +}
|
| +
|
| +CachedRanges::~CachedRanges() {
|
| +}
|
| +
|
| +void CachedRanges::SetBucketRange(size_t i, Histogram::Sample value) {
|
| + DCHECK_LT(i, ranges_.size());
|
| + DCHECK_GE(value, 0);
|
| + ranges_[i] = value;
|
| +}
|
| +
|
| +bool CachedRanges::Equals(CachedRanges* other) const {
|
| + if (range_checksum_ != other->range_checksum_)
|
| + return false;
|
| + if (ranges_.size() != other->ranges_.size())
|
| + return false;
|
| + for (size_t index = 0; index < ranges_.size(); ++index) {
|
| + if (ranges_[index] != other->ranges_[index])
|
| + return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| // static
|
| StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
|
| // static
|
| +StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
|
| +// static
|
| base::Lock* StatisticsRecorder::lock_ = NULL;
|
| // static
|
| bool StatisticsRecorder::dump_on_exit_ = false;
|
| -
|
| } // namespace base
|
|
|