Index: base/metrics/histogram.cc |
=================================================================== |
--- base/metrics/histogram.cc (revision 146394) |
+++ base/metrics/histogram.cc (working copy) |
@@ -14,8 +14,8 @@ |
#include <algorithm> |
#include <string> |
-#include "base/debug/leak_annotations.h" |
#include "base/logging.h" |
+#include "base/metrics/statistics_recorder.h" |
#include "base/pickle.h" |
#include "base/stringprintf.h" |
#include "base/synchronization/lock.h" |
@@ -74,13 +74,6 @@ |
// 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, |
@@ -1037,265 +1030,6 @@ |
return 1; |
} |
-//------------------------------------------------------------------------------ |
-// The next section handles global (central) support for all histograms, as well |
-// as startup/teardown of this service. |
-//------------------------------------------------------------------------------ |
- |
-// This singleton instance should be started during the single threaded portion |
-// of main(), and hence it is not thread safe. It initializes globals to |
-// provide support for all future calls. |
-StatisticsRecorder::StatisticsRecorder() { |
- DCHECK(!histograms_); |
- if (lock_ == NULL) { |
- // This will leak on purpose. It's the only way to make sure we won't race |
- // against the static uninitialization of the module while one of our |
- // static methods relying on the lock get called at an inappropriate time |
- // during the termination phase. Since it's a static data member, we will |
- // leak one per process, which would be similar to the instance allocated |
- // during static initialization and released only on process termination. |
- lock_ = new base::Lock; |
- } |
- base::AutoLock auto_lock(*lock_); |
- histograms_ = new HistogramMap; |
- ranges_ = new RangesMap; |
-} |
- |
-StatisticsRecorder::~StatisticsRecorder() { |
- DCHECK(histograms_ && lock_); |
- |
- if (dump_on_exit_) { |
- std::string output; |
- WriteGraph("", &output); |
- DLOG(INFO) << output; |
- } |
- // Clean up. |
- HistogramMap* histograms = NULL; |
- { |
- base::AutoLock auto_lock(*lock_); |
- 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. |
-} |
- |
-// static |
-bool StatisticsRecorder::IsActive() { |
- if (lock_ == NULL) |
- return false; |
- base::AutoLock auto_lock(*lock_); |
- return NULL != histograms_; |
-} |
- |
-Histogram* StatisticsRecorder::RegisterOrDeleteDuplicate(Histogram* histogram) { |
- // As per crbug.com/79322 the histograms are intentionally leaked, so we need |
- // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once |
- // for an object, the duplicates should not be annotated. |
- // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr) |
- // twice if (lock_ == NULL) || (!histograms_). |
- DCHECK(histogram->HasValidRangeChecksum()); |
- if (lock_ == NULL) { |
- ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 |
- return histogram; |
- } |
- base::AutoLock auto_lock(*lock_); |
- if (!histograms_) { |
- ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322 |
- return histogram; |
- } |
- const std::string name = histogram->histogram_name(); |
- HistogramMap::iterator it = histograms_->find(name); |
- // Avoid overwriting a previous registration. |
- 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; |
- } |
- return histogram; |
-} |
- |
-// 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()) |
- return; |
- |
- Histograms snapshot; |
- GetSnapshot(query, &snapshot); |
- for (Histograms::iterator it = snapshot.begin(); |
- it != snapshot.end(); |
- ++it) { |
- (*it)->WriteHTMLGraph(output); |
- output->append("<br><hr><br>"); |
- } |
-} |
- |
-// static |
-void StatisticsRecorder::WriteGraph(const std::string& query, |
- std::string* output) { |
- if (!IsActive()) |
- return; |
- if (query.length()) |
- StringAppendF(output, "Collections of histograms for %s\n", query.c_str()); |
- else |
- output->append("Collections of all histograms\n"); |
- |
- Histograms snapshot; |
- GetSnapshot(query, &snapshot); |
- for (Histograms::iterator it = snapshot.begin(); |
- it != snapshot.end(); |
- ++it) { |
- (*it)->WriteAscii(true, "\n", output); |
- output->append("\n"); |
- } |
-} |
- |
-// static |
-void StatisticsRecorder::GetHistograms(Histograms* output) { |
- if (lock_ == NULL) |
- return; |
- base::AutoLock auto_lock(*lock_); |
- if (!histograms_) |
- return; |
- for (HistogramMap::iterator it = histograms_->begin(); |
- histograms_->end() != it; |
- ++it) { |
- DCHECK_EQ(it->first, it->second->histogram_name()); |
- output->push_back(it->second); |
- } |
-} |
- |
-bool StatisticsRecorder::FindHistogram(const std::string& name, |
- Histogram** histogram) { |
- if (lock_ == NULL) |
- return false; |
- base::AutoLock auto_lock(*lock_); |
- if (!histograms_) |
- return false; |
- HistogramMap::iterator it = histograms_->find(name); |
- if (histograms_->end() == it) |
- return false; |
- *histogram = it->second; |
- return true; |
-} |
- |
-// private static |
-void StatisticsRecorder::GetSnapshot(const std::string& query, |
- Histograms* snapshot) { |
- if (lock_ == NULL) |
- return; |
- base::AutoLock auto_lock(*lock_); |
- if (!histograms_) |
- return; |
- for (HistogramMap::iterator it = histograms_->begin(); |
- histograms_->end() != it; |
- ++it) { |
- if (it->first.find(query) != std::string::npos) |
- snapshot->push_back(it->second); |
- } |
-} |
- |
CachedRanges::CachedRanges(size_t bucket_count, int initial_value) |
: ranges_(bucket_count, initial_value), |
range_checksum_(0) { |
@@ -1322,12 +1056,4 @@ |
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 |