Index: base/metrics/histogram.cc |
=================================================================== |
--- base/metrics/histogram.cc (revision 97408) |
+++ 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, |
@@ -355,7 +362,7 @@ |
} |
Histogram::Sample Histogram::ranges(size_t i) const { |
- return ranges_[i]; |
+ return cached_ranges_->ranges(i); |
} |
size_t Histogram::bucket_count() const { |
@@ -395,7 +402,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(); |
@@ -408,7 +415,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(); |
@@ -429,7 +436,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. |
@@ -525,22 +532,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; |
@@ -557,8 +565,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 |
@@ -1000,6 +1008,7 @@ |
} |
base::AutoLock auto_lock(*lock_); |
histograms_ = new HistogramMap; |
+ ranges_ = new RangesMap; |
} |
StatisticsRecorder::~StatisticsRecorder() { |
@@ -1018,6 +1027,13 @@ |
histograms_ = NULL; |
} |
delete histograms; |
+ RangesMap* ranges = NULL; |
+ { |
+ base::AutoLock auto_lock(*lock_); |
+ ranges = ranges_; |
+ ranges_ = NULL; |
+ } |
+ delete ranges; |
jar (doing other things)
2011/10/04 22:32:38
I'd suggest we explicity comment that we are going
ramant (doing other things)
2011/10/19 01:09:52
Done.
|
// 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. |
} |
@@ -1052,6 +1068,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; |
@@ -1060,6 +1078,83 @@ |
} |
// static |
+void StatisticsRecorder::RegisterOrDeleteDuplicateRanges(Histogram* histogram) { |
+ DCHECK(histogram); |
+ CachedRanges* cached_ranges = histogram->cached_ranges(); |
jar (doing other things)
2011/10/04 22:32:38
nit: suggest name change for the local variable he
ramant (doing other things)
2011/10/19 01:09:52
Done.
|
+ DCHECK(cached_ranges); |
+ uint32 checksum = histogram->range_checksum(); |
+ cached_ranges->SetRangeChecksum(checksum); |
+ |
+ RangesMap::iterator ranges_it = ranges_->find(checksum); |
+ if (ranges_->end() == ranges_it) { |
+ // Register the new CachedRanges. |
+ std::list<CachedRanges*>* ranges_list(new std::list<CachedRanges*>()); |
jar (doing other things)
2011/10/04 22:32:38
nit: suggest name change for local variable:
rang
ramant (doing other things)
2011/10/19 01:09:52
Done.
|
+ ranges_list->push_front(cached_ranges); |
+ (*ranges_)[checksum] = ranges_list; |
+ return; |
+ } |
+ |
+ // Use the registered CachedRanges if the registered CachedRanges has same |
+ // ranges_ as |histogram|'s CachedRanges. |
+ std::list<CachedRanges*>* ranges_list = ranges_it->second; |
+ std::list<CachedRanges*>::iterator ranges_list_it; |
+ for (ranges_list_it = ranges_list->begin(); |
+ ranges_list_it != ranges_list->end(); |
+ ++ranges_list_it) { |
+ CachedRanges* existing_cached_ranges = *ranges_list_it; |
+ DCHECK(existing_cached_ranges); |
+ if (existing_cached_ranges->Equals(cached_ranges)) { |
+ histogram->set_cached_ranges(existing_cached_ranges); |
+ ++number_of_vectors_saved_; |
+ saved_ranges_size_ += cached_ranges->size(); |
+ delete cached_ranges; |
+ return; |
+ } |
+ } |
+ |
+ // We haven't found a CachedRanges which has the same ranges. Register the |
+ // new CachedRanges. |
+ DCHECK(ranges_list_it == ranges_list->end()); |
+ ranges_list->push_front(cached_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.FirstUpload.Count." + suffix, |
jar (doing other things)
2011/10/04 22:32:38
For histogram naming, it is always nice to have si
ramant (doing other things)
2011/10/19 01:09:52
Done.
|
+ number_of_histograms_); |
+ UMA_HISTOGRAM_COUNTS_10000("Histogram.FirstUpload.RangesSaved." + suffix, |
+ number_of_vectors_saved_); |
+ UMA_HISTOGRAM_COUNTS("Histogram.FirstUpload.RangesElementsSaved." + 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.SecondUpload.Count." + suffix, |
+ number_of_histograms_); |
+ UMA_HISTOGRAM_COUNTS_10000("Histogram.SecondUpload.RangesSaved." + suffix, |
+ number_of_vectors_saved_); |
+ UMA_HISTOGRAM_COUNTS("Histogram.SecondUpload.RangesElementsSaved" + 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.RestOfUploads.Count." + suffix, |
+ number_of_histograms_); |
+ UMA_HISTOGRAM_COUNTS_10000("Histogram.RestOfUploads.RangesSaved." + suffix, |
+ number_of_vectors_saved_); |
+ UMA_HISTOGRAM_COUNTS("Histogram.RestOfUploads.RangesElementsSaved." + suffix, |
+ static_cast<int>(saved_ranges_size_)); |
+} |
+ |
+// static |
void StatisticsRecorder::WriteHTMLGraph(const std::string& query, |
std::string* output) { |
if (!IsActive()) |
@@ -1140,11 +1235,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 |