Move StatisticsRecorder out of histogram.cc/h for further refactoring.

Review URL: https://chromiumcodereview.appspot.com/10703037

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146659 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 567d30ea4b9b9a9c96e7ed2dd61ee166f615cfd7
diff --git a/base/base.gypi b/base/base.gypi
index 6971953..92d66fa 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -239,6 +239,8 @@
           'metrics/histogram_flattener.h',
           'metrics/histogram_snapshot_manager.cc',
           'metrics/histogram_snapshot_manager.h',
+          'metrics/statistics_recorder.cc',
+          'metrics/statistics_recorder.h',
           'metrics/stats_counters.cc',
           'metrics/stats_counters.h',
           'metrics/stats_table.cc',
diff --git a/base/message_loop.cc b/base/message_loop.cc
index f3bb4bb..6b994bc 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -16,6 +16,7 @@
 #include "base/message_loop_proxy_impl.h"
 #include "base/message_pump_default.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/run_loop.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/thread_task_runner_handle.h"
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 923ac9c..e176e8f 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -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
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 39fe200..735de55 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -40,7 +40,6 @@
 #ifndef BASE_METRICS_HISTOGRAM_H_
 #define BASE_METRICS_HISTOGRAM_H_
 
-#include <list>
 #include <map>
 #include <string>
 #include <vector>
@@ -774,90 +773,6 @@
   DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
 };
 
-//------------------------------------------------------------------------------
-// StatisticsRecorder handles all histograms in the system.  It provides a
-// general place for histograms to register, and supports a global API for
-// accessing (i.e., dumping, or graphing) the data in all the histograms.
-
-class BASE_EXPORT StatisticsRecorder {
- public:
-  typedef std::vector<Histogram*> Histograms;
-
-  StatisticsRecorder();
-
-  ~StatisticsRecorder();
-
-  // Find out if histograms can now be registered into our list.
-  static bool IsActive();
-
-  // Register, or add a new histogram to the collection of statistics. If an
-  // identically named histogram is already registered, then the argument
-  // |histogram| will deleted.  The returned value is always the registered
-  // histogram (either the argument, or the pre-existing registered histogram).
-  static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram);
-
-  // Register, or add a new cached_ranges_ of |histogram|. If an identical
-  // cached_ranges_ is already registered, then the cached_ranges_ of
-  // |histogram| is deleted and the |histogram|'s cached_ranges_ is reset to the
-  // registered cached_ranges_.  The cached_ranges_ of |histogram| is always the
-  // registered CachedRanges (either the argument's cached_ranges_, or the
-  // pre-existing registered cached_ranges_).
-  static void RegisterOrDeleteDuplicateRanges(Histogram* histogram);
-
-  // Method for collecting stats about histograms created in browser and
-  // renderer processes. |suffix| is appended to histogram names. |suffix| could
-  // be either browser or renderer.
-  static void CollectHistogramStats(const std::string& suffix);
-
-  // Methods for printing histograms.  Only histograms which have query as
-  // a substring are written to output (an empty string will process all
-  // registered histograms).
-  static void WriteHTMLGraph(const std::string& query, std::string* output);
-  static void WriteGraph(const std::string& query, std::string* output);
-
-  // Method for extracting histograms which were marked for use by UMA.
-  static void GetHistograms(Histograms* output);
-
-  // Find a histogram by name. It matches the exact name. This method is thread
-  // safe.  If a matching histogram is not found, then the |histogram| is
-  // not changed.
-  static bool FindHistogram(const std::string& query, Histogram** histogram);
-
-  static bool dump_on_exit() { return dump_on_exit_; }
-
-  static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; }
-
-  // GetSnapshot copies some of the pointers to registered histograms into the
-  // caller supplied vector (Histograms).  Only histograms with names matching
-  // query are returned. The query must be a substring of histogram name for its
-  // pointer to be copied.
-  static void GetSnapshot(const std::string& query, Histograms* snapshot);
-
-
- private:
-  // We keep all registered histograms in a map, from name to histogram.
-  typedef std::map<std::string, Histogram*> HistogramMap;
-
-  // We keep all |cached_ranges_| in a map, from checksum to a list of
-  // |cached_ranges_|.  Checksum is calculated from the |ranges_| in
-  // |cached_ranges_|.
-  typedef std::map<uint32, std::list<CachedRanges*>*> RangesMap;
-
-  static HistogramMap* histograms_;
-
-  static RangesMap* ranges_;
-
-  // lock protects access to the above map.
-  static base::Lock* lock_;
-
-  // Dump all known histograms to log.
-  static bool dump_on_exit_;
-
-  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
-};
-
-//------------------------------------------------------------------------------
-
 // CachedRanges stores the Ranges vector. Histograms that have same Ranges
 // vector will use the same CachedRanges object.
 class BASE_EXPORT CachedRanges {
diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc
index b325f73..9d9398d 100644
--- a/base/metrics/histogram_snapshot_manager.cc
+++ b/base/metrics/histogram_snapshot_manager.cc
@@ -4,6 +4,8 @@
 
 #include "base/metrics/histogram_snapshot_manager.h"
 
+#include "base/metrics/statistics_recorder.h"
+
 using base::Histogram;
 using base::StatisticsRecorder;
 
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index bd8a427..5183460 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
@@ -7,8 +7,10 @@
 #include <algorithm>
 #include <vector>
 
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
 #include "base/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
new file mode 100644
index 0000000..37b6f43
--- /dev/null
+++ b/base/metrics/statistics_recorder.cc
@@ -0,0 +1,285 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/statistics_recorder.h"
+
+#include "base/debug/leak_annotations.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/stringprintf.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// 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;
+
+// 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);
+  }
+}
+
+// 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
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
new file mode 100644
index 0000000..b947c53
--- /dev/null
+++ b/base/metrics/statistics_recorder.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// StatisticsRecorder handles all histograms in the system. It provides a
+// general place for histograms to register, and supports a global API for
+// accessing (i.e., dumping, or graphing) the data in all the histograms.
+
+#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
+#define BASE_METRICS_STATISTICS_RECORDER_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class CachedRanges;
+class Histogram;
+class Lock;
+
+class BASE_EXPORT StatisticsRecorder {
+ public:
+  typedef std::vector<Histogram*> Histograms;
+
+  StatisticsRecorder();
+
+  ~StatisticsRecorder();
+
+  // Find out if histograms can now be registered into our list.
+  static bool IsActive();
+
+  // Register, or add a new histogram to the collection of statistics. If an
+  // identically named histogram is already registered, then the argument
+  // |histogram| will deleted.  The returned value is always the registered
+  // histogram (either the argument, or the pre-existing registered histogram).
+  static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram);
+
+  // Register, or add a new cached_ranges_ of |histogram|. If an identical
+  // cached_ranges_ is already registered, then the cached_ranges_ of
+  // |histogram| is deleted and the |histogram|'s cached_ranges_ is reset to the
+  // registered cached_ranges_.  The cached_ranges_ of |histogram| is always the
+  // registered CachedRanges (either the argument's cached_ranges_, or the
+  // pre-existing registered cached_ranges_).
+  static void RegisterOrDeleteDuplicateRanges(Histogram* histogram);
+
+  // Method for collecting stats about histograms created in browser and
+  // renderer processes. |suffix| is appended to histogram names. |suffix| could
+  // be either browser or renderer.
+  static void CollectHistogramStats(const std::string& suffix);
+
+  // Methods for printing histograms.  Only histograms which have query as
+  // a substring are written to output (an empty string will process all
+  // registered histograms).
+  static void WriteHTMLGraph(const std::string& query, std::string* output);
+  static void WriteGraph(const std::string& query, std::string* output);
+
+  // Method for extracting histograms which were marked for use by UMA.
+  static void GetHistograms(Histograms* output);
+
+  // Find a histogram by name. It matches the exact name. This method is thread
+  // safe.  If a matching histogram is not found, then the |histogram| is
+  // not changed.
+  static bool FindHistogram(const std::string& query, Histogram** histogram);
+
+  static bool dump_on_exit() { return dump_on_exit_; }
+
+  static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; }
+
+  // GetSnapshot copies some of the pointers to registered histograms into the
+  // caller supplied vector (Histograms).  Only histograms with names matching
+  // query are returned. The query must be a substring of histogram name for its
+  // pointer to be copied.
+  static void GetSnapshot(const std::string& query, Histograms* snapshot);
+
+
+ private:
+  // We keep all registered histograms in a map, from name to histogram.
+  typedef std::map<std::string, Histogram*> HistogramMap;
+
+  // We keep all |cached_ranges_| in a map, from checksum to a list of
+  // |cached_ranges_|.  Checksum is calculated from the |ranges_| in
+  // |cached_ranges_|.
+  typedef std::map<uint32, std::list<CachedRanges*>*> RangesMap;
+
+  static HistogramMap* histograms_;
+
+  static RangesMap* ranges_;
+
+  // lock protects access to the above map.
+  static base::Lock* lock_;
+
+  // Dump all known histograms to log.
+  static bool dump_on_exit_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_STATISTICS_RECORDER_H_