Use factory to create histograms, and refcounts to track lifetimes

This is CL patch 377028 by Raman Tenneti, with minor changes to
make the try-bots happier.

It is cleanup that better ensures lifetimes of histograms (making it harder
for users to abuse them).  

bug=16495 (repairs leak induced by the first landing)
bug=18840 (should make leaks less possible)
tbr=raman.tenneti
Review URL: http://codereview.chromium.org/462027

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


CrOS-Libchrome-Original-Commit: e8829a1981a2d9d849c377c28f9444fdefee0f44
diff --git a/base/histogram.cc b/base/histogram.cc
index 55af96d..3a5a5b2 100644
--- a/base/histogram.cc
+++ b/base/histogram.cc
@@ -23,7 +23,42 @@
 // static
 const int Histogram::kHexRangePrintingFlag = 0x8000;
 
-Histogram::Histogram(const char* name, Sample minimum,
+scoped_refptr<Histogram> Histogram::HistogramFactoryGet(
+    const std::string& name, Sample minimum, Sample maximum,
+    size_t bucket_count) {
+  scoped_refptr<Histogram> histogram(NULL);
+
+  // Defensive code.
+  if (minimum <= 0)
+    minimum = 1;
+  if (maximum >= kSampleType_MAX)
+    maximum = kSampleType_MAX - 1;
+
+  if (StatisticsRecorder::FindHistogram(name, &histogram)) {
+    DCHECK(histogram.get() != NULL);
+  } else {
+    histogram = new Histogram(name, minimum, maximum, bucket_count);
+    scoped_refptr<Histogram> registered_histogram(NULL);
+    StatisticsRecorder::FindHistogram(name, &registered_histogram);
+    // Allow a NULL return to mean that the StatisticsRecorder was not started.
+    if (registered_histogram.get() != NULL &&
+        registered_histogram.get() != histogram.get())
+      histogram = registered_histogram;
+  }
+
+  DCHECK(HISTOGRAM == histogram->histogram_type());
+  DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
+  return histogram;
+}
+
+scoped_refptr<Histogram> Histogram::HistogramFactoryGet(
+    const std::string& name, base::TimeDelta minimum, base::TimeDelta maximum,
+    size_t bucket_count) {
+  return HistogramFactoryGet(name,
+      minimum.InMilliseconds(), maximum.InMilliseconds(), bucket_count);
+}
+
+Histogram::Histogram(const std::string& name, Sample minimum,
                      Sample maximum, size_t bucket_count)
   : histogram_name_(name),
     declared_min_(minimum),
@@ -31,12 +66,11 @@
     bucket_count_(bucket_count),
     flags_(0),
     ranges_(bucket_count + 1, 0),
-    sample_(),
-    registered_(false) {
+    sample_() {
   Initialize();
 }
 
-Histogram::Histogram(const char* name, TimeDelta minimum,
+Histogram::Histogram(const std::string& name, TimeDelta minimum,
                      TimeDelta maximum, size_t bucket_count)
   : histogram_name_(name),
     declared_min_(static_cast<int> (minimum.InMilliseconds())),
@@ -44,21 +78,23 @@
     bucket_count_(bucket_count),
     flags_(0),
     ranges_(bucket_count + 1, 0),
-    sample_(),
-    registered_(false) {
+    sample_() {
   Initialize();
 }
 
 Histogram::~Histogram() {
-  if (registered_)
-    StatisticsRecorder::UnRegister(this);
+  DCHECK(!(kPlannedLeakFlag & flags_));
+  if (StatisticsRecorder::dump_on_exit()) {
+    std::string output;
+    WriteAscii(true, "\n", &output);
+    LOG(INFO) << output;
+  }
+
   // Just to make sure most derived class did this properly...
   DCHECK(ValidateBucketRanges());
 }
 
 void Histogram::Add(int value) {
-  if (!registered_)
-    registered_ = StatisticsRecorder::Register(this);
   if (value >= kSampleType_MAX)
     value = kSampleType_MAX - 1;
   if (value < 0)
@@ -170,7 +206,7 @@
   ranges_[bucket_count_] = kSampleType_MAX;
   InitializeBucketRange();
   DCHECK(ValidateBucketRanges());
-  registered_ = StatisticsRecorder::Register(this);
+  StatisticsRecorder::Register(this);
 }
 
 // Calculate what range of values are held in each bucket.
@@ -353,14 +389,15 @@
 // static
 std::string Histogram::SerializeHistogramInfo(const Histogram& histogram,
                                               const SampleSet& snapshot) {
-  Pickle pickle;
+  DCHECK(histogram.histogram_type() != NOT_VALID_IN_RENDERER);
 
+  Pickle pickle;
   pickle.WriteString(histogram.histogram_name());
   pickle.WriteInt(histogram.declared_min());
   pickle.WriteInt(histogram.declared_max());
   pickle.WriteSize(histogram.bucket_count());
   pickle.WriteInt(histogram.histogram_type());
-  pickle.WriteInt(histogram.flags());
+  pickle.WriteInt(histogram.flags() & ~kIPCSerializationSourceFlag);
 
   snapshot.Serialize(&pickle);
   return std::string(static_cast<const char*>(pickle.data()), pickle.size());
@@ -394,27 +431,27 @@
     return false;
   }
 
-  Histogram* render_histogram =
-      StatisticsRecorder::GetHistogram(histogram_name);
+  DCHECK(histogram_type != NOT_VALID_IN_RENDERER);
 
-  if (render_histogram == NULL) {
-    if (histogram_type ==  EXPONENTIAL) {
-      render_histogram = new Histogram(histogram_name.c_str(),
-                                       declared_min,
-                                       declared_max,
-                                       bucket_count);
-    } else if (histogram_type == LINEAR) {
-      render_histogram = new LinearHistogram(histogram_name.c_str(),
-                                             declared_min,
-                                             declared_max,
-                                             bucket_count);
-    } else {
-      LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " <<
-          histogram_type;
-      return false;
-    }
-    DCHECK(!(flags & kRendererHistogramFlag));
-    render_histogram->SetFlags(flags | kRendererHistogramFlag);
+  scoped_refptr<Histogram> render_histogram(NULL);
+
+  if (histogram_type ==  HISTOGRAM) {
+    render_histogram = Histogram::HistogramFactoryGet(
+        histogram_name, declared_min, declared_max, bucket_count);
+  } else if (histogram_type == LINEAR_HISTOGRAM) {
+    render_histogram = LinearHistogram::LinearHistogramFactoryGet(
+        histogram_name, declared_min, declared_max, bucket_count);
+  } else if (histogram_type == BOOLEAN_HISTOGRAM) {
+    render_histogram = BooleanHistogram::BooleanHistogramFactoryGet(
+        histogram_name);
+  } else if (histogram_type == THREAD_SAFE_HISTOGRAM) {
+    render_histogram =
+        ThreadSafeHistogram::ThreadSafeHistogramFactoryGet(
+            histogram_name, declared_min, declared_max, bucket_count);
+  } else {
+    LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " <<
+        histogram_type;
+    return false;
   }
 
   DCHECK(declared_min == render_histogram->declared_min());
@@ -422,17 +459,16 @@
   DCHECK(bucket_count == render_histogram->bucket_count());
   DCHECK(histogram_type == render_histogram->histogram_type());
 
-  if (render_histogram->flags() & kRendererHistogramFlag) {
-    render_histogram->AddSampleSet(sample);
-  } else {
-    DLOG(INFO) << "Single thread mode, histogram observed and not copied: " <<
+  if (render_histogram->flags() & kIPCSerializationSourceFlag) {
+    DLOG(INFO) << "Single process mode, histogram observed and not copied: " <<
         histogram_name;
+  } else {
+    render_histogram->AddSampleSet(sample);
   }
 
   return true;
 }
 
-
 //------------------------------------------------------------------------------
 // Methods for the Histogram::SampleSet class
 //------------------------------------------------------------------------------
@@ -537,14 +573,48 @@
 // buckets.
 //------------------------------------------------------------------------------
 
-LinearHistogram::LinearHistogram(const char* name, Sample minimum,
+scoped_refptr<Histogram> LinearHistogram::LinearHistogramFactoryGet(
+    const std::string& name, Sample minimum, Sample maximum,
+    size_t bucket_count) {
+  scoped_refptr<Histogram> histogram(NULL);
+
+  if (minimum <= 0)
+    minimum = 1;
+  if (maximum >= kSampleType_MAX)
+    maximum = kSampleType_MAX - 1;
+
+  if (StatisticsRecorder::FindHistogram(name, &histogram)) {
+    DCHECK(histogram.get() != NULL);
+  } else {
+    histogram = new LinearHistogram(name, minimum, maximum, bucket_count);
+    scoped_refptr<Histogram> registered_histogram(NULL);
+    StatisticsRecorder::FindHistogram(name, &registered_histogram);
+    if (registered_histogram.get() != NULL &&
+        registered_histogram.get() != histogram.get())
+      histogram = registered_histogram;
+  }
+
+  DCHECK(LINEAR_HISTOGRAM == histogram->histogram_type());
+  DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
+
+  return histogram;
+}
+
+scoped_refptr<Histogram> LinearHistogram::LinearHistogramFactoryGet(
+    const std::string& name, base::TimeDelta minimum, base::TimeDelta maximum,
+    size_t bucket_count) {
+  return LinearHistogramFactoryGet(name, minimum.InMilliseconds(),
+      maximum.InMilliseconds(), bucket_count);
+}
+
+LinearHistogram::LinearHistogram(const std::string& name, Sample minimum,
     Sample maximum, size_t bucket_count)
     : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) {
   InitializeBucketRange();
   DCHECK(ValidateBucketRanges());
 }
 
-LinearHistogram::LinearHistogram(const char* name,
+LinearHistogram::LinearHistogram(const std::string& name,
     TimeDelta minimum, TimeDelta maximum, size_t bucket_count)
     : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ?
                                  minimum : TimeDelta::FromMilliseconds(1),
@@ -595,11 +665,61 @@
 }
 
 //------------------------------------------------------------------------------
+// This section provides implementation for BooleanHistogram.
+//------------------------------------------------------------------------------
+
+scoped_refptr<Histogram> BooleanHistogram::BooleanHistogramFactoryGet(
+    const std::string& name) {
+  scoped_refptr<Histogram> histogram(NULL);
+
+  if (StatisticsRecorder::FindHistogram(name, &histogram)) {
+    DCHECK(histogram.get() != NULL);
+  } else {
+    histogram = new BooleanHistogram(name);
+    scoped_refptr<Histogram> registered_histogram(NULL);
+    StatisticsRecorder::FindHistogram(name, &registered_histogram);
+    if (registered_histogram.get() != NULL &&
+        registered_histogram.get() != histogram.get())
+      histogram = registered_histogram;
+  }
+
+  DCHECK(BOOLEAN_HISTOGRAM == histogram->histogram_type());
+
+  return histogram;
+}
+
+//------------------------------------------------------------------------------
 // This section provides implementation for ThreadSafeHistogram.
 //------------------------------------------------------------------------------
 
-ThreadSafeHistogram::ThreadSafeHistogram(const char* name, Sample minimum,
-                                         Sample maximum, size_t bucket_count)
+scoped_refptr<Histogram> ThreadSafeHistogram::ThreadSafeHistogramFactoryGet(
+    const std::string& name, Sample minimum, Sample maximum,
+    size_t bucket_count) {
+  scoped_refptr<Histogram> histogram(NULL);
+
+  if (minimum <= 0)
+    minimum = 1;
+  if (maximum >= kSampleType_MAX)
+    maximum = kSampleType_MAX - 1;
+
+  if (StatisticsRecorder::FindHistogram(name, &histogram)) {
+    DCHECK(histogram.get() != NULL);
+  } else {
+    histogram = new ThreadSafeHistogram(name, minimum, maximum, bucket_count);
+    scoped_refptr<Histogram> registered_histogram(NULL);
+    StatisticsRecorder::FindHistogram(name, &registered_histogram);
+    if (registered_histogram.get() != NULL &&
+        registered_histogram.get() != histogram.get())
+      histogram = registered_histogram;
+  }
+
+  DCHECK(THREAD_SAFE_HISTOGRAM == histogram->histogram_type());
+  DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
+  return histogram;
+}
+
+ThreadSafeHistogram::ThreadSafeHistogram(const std::string& name,
+     Sample minimum, Sample maximum, size_t bucket_count)
     : Histogram(name, minimum, maximum, bucket_count),
       lock_() {
   }
@@ -657,34 +777,22 @@
   return NULL != histograms_;
 }
 
+// Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a
+// reference, and we are called while in the Histogram constructor. In that
+// scenario, a ref_ptr would have incremented the ref count when the histogram
+// was passed to us, decremented it when we returned, and the instance would be
+// destroyed before assignment (when value was returned by new).
 // static
-bool StatisticsRecorder::Register(Histogram* histogram) {
-  if (!histograms_)
-    return false;
-  const std::string name = histogram->histogram_name();
-  AutoLock auto_lock(*lock_);
-
-  if (histograms_->end() != histograms_->find(name)) {
-    // Check to be sure it is compatible.... and if not, then do a CHECK()
-    return false;  // This name is already registered.
-  }
-  (*histograms_)[name] = histogram;
-  return true;
-}
-
-// static
-void StatisticsRecorder::UnRegister(Histogram* histogram) {
+void StatisticsRecorder::Register(Histogram* histogram) {
   if (!histograms_)
     return;
   const std::string name = histogram->histogram_name();
   AutoLock auto_lock(*lock_);
-  DCHECK(histograms_->end() != histograms_->find(name));
-  histograms_->erase(name);
-  if (dump_on_exit_) {
-    std::string output;
-    histogram->WriteAscii(true, "\n", &output);
-    LOG(INFO) << output;
-  }
+
+  DCHECK(histograms_->end() == histograms_->find(name));
+
+  (*histograms_)[name] = histogram;
+  return;
 }
 
 // static
@@ -743,17 +851,31 @@
   }
 }
 
-Histogram* StatisticsRecorder::GetHistogram(const std::string& query) {
+// static
+void StatisticsRecorder::GetHistogramsForRenderer(Histograms* output) {
   if (!histograms_)
-    return NULL;
+    return;
   AutoLock auto_lock(*lock_);
   for (HistogramMap::iterator it = histograms_->begin();
        histograms_->end() != it;
        ++it) {
-    if (it->first.find(query) != std::string::npos)
-      return it->second;
+    scoped_refptr<Histogram> histogram = it->second;
+    if (!(histogram->flags() & kIPCSerializationSourceFlag))
+      histogram->SetFlags(kIPCSerializationSourceFlag);
+    output->push_back(histogram);
   }
-  return NULL;
+}
+
+bool StatisticsRecorder::FindHistogram(const std::string& name,
+                                       scoped_refptr<Histogram>* histogram) {
+  if (!histograms_)
+    return false;
+  AutoLock auto_lock(*lock_);
+  HistogramMap::iterator it = histograms_->find(name);
+  if (histograms_->end() == it)
+    return false;
+  *histogram = it->second;
+  return true;
 }
 
 // private static
diff --git a/base/histogram.h b/base/histogram.h
index 4d40c1b..0c94fc0 100644
--- a/base/histogram.h
+++ b/base/histogram.h
@@ -36,6 +36,8 @@
 #include <vector>
 
 #include "base/lock.h"
+#include "base/ref_counted.h"
+#include "base/logging.h"
 #include "base/time.h"
 
 //------------------------------------------------------------------------------
@@ -43,47 +45,56 @@
 // The first four macros use 50 buckets.
 
 #define HISTOGRAM_TIMES(name, sample) do { \
-    static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \
-                             base::TimeDelta::FromSeconds(10), 50); \
-    counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), base::TimeDelta::FromMilliseconds(1), \
+        base::TimeDelta::FromSeconds(10), 50); \
+    counter->AddTime(sample); \
   } while (0)
 
 #define HISTOGRAM_COUNTS(name, sample) do { \
-    static Histogram counter((name), 1, 1000000, 50); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1, 1000000, 50); \
+    counter->Add(sample); \
   } while (0)
 
 #define HISTOGRAM_COUNTS_100(name, sample) do { \
-    static Histogram counter((name), 1, 100, 50); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1, 100, 50); \
+    counter->Add(sample); \
   } while (0)
 
 #define HISTOGRAM_COUNTS_10000(name, sample) do { \
-    static Histogram counter((name), 1, 10000, 50); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1, 10000, 50); \
+    counter->Add(sample); \
   } while (0)
 
 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
-    static Histogram counter((name), min, max, bucket_count); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), min, max, bucket_count); \
+    counter->Add(sample); \
   } while (0)
 
 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) do { \
-    static LinearHistogram counter((name), 1, 100, 101); \
-    counter.Add(under_one_hundred); \
+    static scoped_refptr<Histogram> counter = \
+        LinearHistogram::LinearHistogramFactoryGet(\
+            (name), 1, 100, 101); \
+    counter->Add(under_one_hundred); \
   } while (0)
 
 // For folks that need real specific times, use this to select a precise range
 // of times you want plotted, and the number of buckets you want used.
 #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
-    static Histogram counter((name), min, max, bucket_count); \
-    counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), min, max, bucket_count); \
+    counter->AddTime(sample); \
   } while (0)
 
 // DO NOT USE THIS.  It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
 #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
-    static Histogram counter((name), min, max, bucket_count); \
-    if ((sample) < (max)) counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), min, max, bucket_count); \
+    if ((sample) < (max)) counter->AddTime(sample); \
   } while (0)
 
 //------------------------------------------------------------------------------
@@ -101,12 +112,14 @@
 // be equal in number or fewer than the corresponding calls to Add().
 
 #define ASSET_HISTOGRAM_COUNTS(name, sample) do { \
-    static ThreadSafeHistogram counter((name), 1, 1000000, 50); \
+    static scoped_refptr<Histogram> counter = \
+        ThreadSafeHistogram::ThreadSafeHistogramFactoryGet(\
+            (name), 1, 1000000, 50); \
     if (0 == sample) break; \
     if (sample >= 0) \
-      counter.Add(sample); \
+      counter->Add(sample); \
     else\
-      counter.Remove(-sample); \
+      counter->Remove(-sample); \
   } while (0)
 
 //------------------------------------------------------------------------------
@@ -150,92 +163,122 @@
 
 static const int kUmaTargetedHistogramFlag = 0x1;
 
-// This indicates the histogram is shadow copy of renderer histrogram
-// constructed by unpick method and updated regularly from renderer upload
-// of histograms.
-static const int kRendererHistogramFlag = 1 << 4;
+// This indicates the histogram is pickled to be sent across an IPC Channel.
+// If we observe this flag during unpickle method, then we are running in a
+// single process mode.
+static const int kIPCSerializationSourceFlag = 1 << 4;
+
+// Some histograms aren't currently destroyed.  Until such users properly
+// decref those histograms, we will mark there histograms as planned to leak so
+// that we can catch any user that directly tries to call delete "directly"
+// rather than using the reference counting features that should take care of
+// this.
+// TODO(jar): Make this flag unnecessary!
+static const int kPlannedLeakFlag = 1 << 5;
 
 #define UMA_HISTOGRAM_TIMES(name, sample) do { \
-    static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \
-                             base::TimeDelta::FromSeconds(10), 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), base::TimeDelta::FromMilliseconds(1), \
+        base::TimeDelta::FromSeconds(10), 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->AddTime(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) do { \
-    static Histogram counter((name), base::TimeDelta::FromMilliseconds(10), \
-                             base::TimeDelta::FromMinutes(3), 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), base::TimeDelta::FromMilliseconds(10), \
+        base::TimeDelta::FromMinutes(3), 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->AddTime(sample); \
   } while (0)
 
 // Use this macro when times can routinely be much longer than 10 seconds.
 #define UMA_HISTOGRAM_LONG_TIMES(name, sample) do { \
-    static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \
-                             base::TimeDelta::FromHours(1), 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), base::TimeDelta::FromMilliseconds(1), \
+        base::TimeDelta::FromHours(1), 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->AddTime(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
-    static Histogram counter((name), min, max, bucket_count); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), min, max, bucket_count); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->AddTime(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
-    static Histogram counter((name), min, max, bucket_count); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    if ((sample) < (max)) counter.AddTime(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), min, max, bucket_count); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    if ((sample) < (max)) counter->AddTime(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_COUNTS(name, sample) do { \
-    static Histogram counter((name), 1, 1000000, 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1, 1000000, 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_COUNTS_100(name, sample) do { \
-    static Histogram counter((name), 1, 100, 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1, 100, 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_COUNTS_10000(name, sample) do { \
-    static Histogram counter((name), 1, 10000, 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1, 10000, 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
-    static Histogram counter((name), min, max, bucket_count); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), min, max, bucket_count); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) do { \
-    static Histogram counter((name), 1000, 500000, 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1000, 500000, 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_MEMORY_MB(name, sample) do { \
-    static Histogram counter((name), 1, 1000, 50); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.Add(sample); \
+    static scoped_refptr<Histogram> counter = Histogram::HistogramFactoryGet(\
+        (name), 1, 1000, 50); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) do { \
-    static LinearHistogram counter((name), 1, 100, 101); \
-    counter.SetFlags(kUmaTargetedHistogramFlag); \
-    counter.Add(under_one_hundred); \
+    static scoped_refptr<Histogram> counter = \
+        LinearHistogram::LinearHistogramFactoryGet(\
+            (name), 1, 100, 101); \
+    counter->SetFlags(kUmaTargetedHistogramFlag); \
+    counter->Add(under_one_hundred); \
   } while (0)
 
 //------------------------------------------------------------------------------
 
 class Pickle;
+class Histogram;
+class LinearHistogram;
+class BooleanHistogram;
+class ThreadSafeHistogram;
 
-class Histogram {
+namespace disk_cache {
+  class StatsHistogram;
+};  // namespace disk_cache
+
+
+class Histogram : public base::RefCountedThreadSafe<Histogram> {
  public:
   typedef int Sample;  // Used for samples (and ranges of samples).
   typedef int Count;  // Used to count samples in a bucket.
@@ -246,11 +289,26 @@
 
   static const int kHexRangePrintingFlag;
 
+  /* These enums are meant to facilitate deserialization of renderer histograms
+     into the browser. */
+  enum ClassType {
+    HISTOGRAM,
+    LINEAR_HISTOGRAM,
+    BOOLEAN_HISTOGRAM,
+    THREAD_SAFE_HISTOGRAM,
+    NOT_VALID_IN_RENDERER
+  };
+
   enum BucketLayout {
     EXPONENTIAL,
     LINEAR
   };
 
+  struct DescriptionPair {
+    Sample sample;
+    const char* description;  // Null means end of a list of pairs.
+  };
+
   //----------------------------------------------------------------------------
   // Statistic values, developed over the life of the histogram.
 
@@ -288,14 +346,18 @@
     int64 square_sum_;  // sum of squares of samples.
   };
   //----------------------------------------------------------------------------
-
-  Histogram(const char* name, Sample minimum,
-            Sample maximum, size_t bucket_count);
-  Histogram(const char* name, base::TimeDelta minimum,
-            base::TimeDelta maximum, size_t bucket_count);
-  virtual ~Histogram();
+  // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
+  // default underflow bucket.
+  static scoped_refptr<Histogram> HistogramFactoryGet(const std::string& name,
+      Sample minimum, Sample maximum, size_t bucket_count);
+  static scoped_refptr<Histogram> HistogramFactoryGet(const std::string& name,
+      base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count);
 
   void Add(int value);
+
+  // This method is an interface, used only by BooleanHistogram.
+  virtual void AddBoolean(bool value) { DCHECK(false); }
+
   // Accept a TimeDelta to increment.
   void AddTime(base::TimeDelta time) {
     Add(static_cast<int>(time.InMilliseconds()));
@@ -303,6 +365,13 @@
 
   void AddSampleSet(const SampleSet& sample);
 
+  // This method is an interface, used only by ThreadSafeHistogram.
+  virtual void Remove(int value) { DCHECK(false); }
+
+  // This method is an interface, used only by LinearHistogram.
+  virtual void SetRangeDescriptions(const DescriptionPair descriptions[])
+      { DCHECK(false); }
+
   // The following methods provide graphical histogram displays.
   void WriteHTMLGraph(std::string* output) const;
   void WriteAscii(bool graph_it, const std::string& newline,
@@ -315,8 +384,6 @@
   void ClearFlags(int flags) { flags_ &= ~flags; }
   int flags() const { return flags_; }
 
-  virtual BucketLayout histogram_type() const { return EXPONENTIAL; }
-
   // Convenience methods for serializing/deserializing the histograms.
   // Histograms from Renderer process are serialized and sent to the browser.
   // Browser process reconstructs the histogram from the pickled version
@@ -332,10 +399,10 @@
   // browser process.
   static bool DeserializeHistogramInfo(const std::string& histogram_info);
 
-
   //----------------------------------------------------------------------------
-  // Accessors for serialization and testing.
+  // Accessors for factory constuction, serialization and testing.
   //----------------------------------------------------------------------------
+  virtual ClassType histogram_type() const { return HISTOGRAM; }
   const std::string histogram_name() const { return histogram_name_; }
   Sample declared_min() const { return declared_min_; }
   Sample declared_max() const { return declared_max_; }
@@ -345,7 +412,28 @@
   // Override with atomic/locked snapshot if needed.
   virtual void SnapshotSample(SampleSet* sample) const;
 
+  virtual bool HasConstructorArguments(Sample minimum, Sample maximum,
+      size_t bucket_count) {
+    return ((minimum == declared_min_) && (maximum == declared_max_) &&
+            (bucket_count == bucket_count_));
+  }
+
+  virtual bool HasConstructorTimeDeltaArguments(base::TimeDelta minimum,
+      base::TimeDelta maximum, size_t bucket_count) {
+    return ((minimum.InMilliseconds() == declared_min_) &&
+            (maximum.InMilliseconds() == declared_max_) &&
+            (bucket_count == bucket_count_));
+  }
+
  protected:
+  friend class base::RefCountedThreadSafe<Histogram>;
+  Histogram(const std::string& name, Sample minimum,
+            Sample maximum, size_t bucket_count);
+  Histogram(const std::string& name, base::TimeDelta minimum,
+            base::TimeDelta maximum, size_t bucket_count);
+
+  virtual ~Histogram();
+
   // Method to override to skip the display of the i'th bucket if it's empty.
   virtual bool PrintEmptyBucket(size_t index) const { return true; }
 
@@ -434,9 +522,6 @@
   // sample.
   SampleSet sample_;
 
-  // Indicate if successfully registered.
-  bool registered_;
-
   DISALLOW_COPY_AND_ASSIGN(Histogram);
 };
 
@@ -446,24 +531,30 @@
 // buckets.
 class LinearHistogram : public Histogram {
  public:
-  struct DescriptionPair {
-    Sample sample;
-    const char* description;  // Null means end of a list of pairs.
-  };
-  LinearHistogram(const char* name, Sample minimum,
-                  Sample maximum, size_t bucket_count);
-
-  LinearHistogram(const char* name, base::TimeDelta minimum,
-                  base::TimeDelta maximum, size_t bucket_count);
-  ~LinearHistogram() {}
+  virtual ClassType histogram_type() const { return LINEAR_HISTOGRAM; }
 
   // Store a list of number/text values for use in rendering the histogram.
   // The last element in the array has a null in its "description" slot.
-  void SetRangeDescriptions(const DescriptionPair descriptions[]);
+  virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
 
-  virtual BucketLayout histogram_type() const { return LINEAR; }
+  /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
+     default underflow bucket. */
+  static scoped_refptr<Histogram> LinearHistogramFactoryGet(
+      const std::string& name, Sample minimum, Sample maximum,
+      size_t bucket_count);
+  static scoped_refptr<Histogram> LinearHistogramFactoryGet(
+      const std::string& name, base::TimeDelta minimum,
+      base::TimeDelta maximum, size_t bucket_count);
 
  protected:
+  LinearHistogram(const std::string& name, Sample minimum,
+                  Sample maximum, size_t bucket_count);
+
+  LinearHistogram(const std::string& name, base::TimeDelta minimum,
+                  base::TimeDelta maximum, size_t bucket_count);
+
+  virtual ~LinearHistogram() {}
+
   // Initialize ranges_ mapping.
   virtual void InitializeBucketRange();
   virtual double GetBucketSize(Count current, size_t i) const;
@@ -491,13 +582,18 @@
 // BooleanHistogram is a histogram for booleans.
 class BooleanHistogram : public LinearHistogram {
  public:
-  explicit BooleanHistogram(const char* name)
-    : LinearHistogram(name, 0, 2, 3) {
-  }
+  static scoped_refptr<Histogram> BooleanHistogramFactoryGet(
+      const std::string& name);
 
-  void AddBoolean(bool value) { Add(value ? 1 : 0); }
+  virtual ClassType histogram_type() const { return BOOLEAN_HISTOGRAM; }
+
+  virtual void AddBoolean(bool value) { Add(value ? 1 : 0); }
 
  private:
+  explicit BooleanHistogram(const std::string& name)
+    : LinearHistogram(name, 1, 2, 3) {
+  }
+
   DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
 };
 
@@ -507,13 +603,21 @@
 
 class ThreadSafeHistogram : public Histogram {
  public:
-  ThreadSafeHistogram(const char* name, Sample minimum,
-                      Sample maximum, size_t bucket_count);
+  static scoped_refptr<Histogram> ThreadSafeHistogramFactoryGet(
+      const std::string& name, Sample minimum, Sample maximum,
+      size_t bucket_count);
+
+  virtual ClassType histogram_type() const { return THREAD_SAFE_HISTOGRAM; }
 
   // Provide the analog to Add()
-  void Remove(int value);
+  virtual void Remove(int value);
 
  protected:
+  ThreadSafeHistogram(const std::string& name, Sample minimum,
+                      Sample maximum, size_t bucket_count);
+
+  virtual ~ThreadSafeHistogram() {}
+
   // Provide locked versions to get precise counts.
   virtual void Accumulate(Sample value, Count count, size_t index);
 
@@ -532,7 +636,7 @@
 
 class StatisticsRecorder {
  public:
-  typedef std::vector<Histogram*> Histograms;
+  typedef std::vector<scoped_refptr<Histogram> > Histograms;
 
   StatisticsRecorder();
 
@@ -542,10 +646,7 @@
   static bool WasStarted();
 
   // Register, or add a new histogram to the collection of statistics.
-  // Return true if registered.
-  static bool Register(Histogram* histogram);
-  // Unregister, or remove, a histogram from the collection of statistics.
-  static void UnRegister(Histogram* histogram);
+  static void Register(Histogram* histogram);
 
   // Methods for printing histograms.  Only histograms which have query as
   // a substring are written to output (an empty string will process all
@@ -556,8 +657,16 @@
   // Method for extracting histograms which were marked for use by UMA.
   static void GetHistograms(Histograms* output);
 
-  // Find a histogram by name.  This method is thread safe.
-  static Histogram* GetHistogram(const std::string& query);
+  // Method for extracting histograms for renderer and the histogram's flag is
+  // set to kIPCSerializationSourceFlag.
+  static void GetHistogramsForRenderer(Histograms* output);
+
+  // Find a histogram by name. It matches the exact name. This method is thread
+  // safe.
+  static bool FindHistogram(const std::string& query,
+                            scoped_refptr<Histogram>* histogram);
+
+  static bool dump_on_exit() { return dump_on_exit_; }
 
   static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; }
 
@@ -570,7 +679,7 @@
 
  private:
   // We keep all registered histograms in a map, from name to histogram.
-  typedef std::map<std::string, Histogram*> HistogramMap;
+  typedef std::map<std::string, scoped_refptr<Histogram> > HistogramMap;
 
   static HistogramMap* histograms_;
 
diff --git a/base/histogram_unittest.cc b/base/histogram_unittest.cc
index 3f2ed4c..4d5de51 100644
--- a/base/histogram_unittest.cc
+++ b/base/histogram_unittest.cc
@@ -19,11 +19,17 @@
 // Check for basic syntax and use.
 TEST(HistogramTest, StartupShutdownTest) {
   // Try basic construction
-  Histogram histogram("TestHistogram", 1, 1000, 10);
-  Histogram histogram1("Test1Histogram", 1, 1000, 10);
+  scoped_refptr<Histogram> histogram =
+    Histogram::HistogramFactoryGet("TestHistogram", 1, 1000, 10);
+  scoped_refptr<Histogram> histogram1 =
+      Histogram::HistogramFactoryGet("Test1Histogram", 1, 1000, 10);
 
-  LinearHistogram linear_histogram("TestLinearHistogram", 1, 1000, 10);
-  LinearHistogram linear_histogram1("Test1LinearHistogram", 1, 1000, 10);
+  scoped_refptr<Histogram> linear_histogram =
+      LinearHistogram::LinearHistogramFactoryGet("TestLinearHistogram", 1, 1000,
+          10);
+  scoped_refptr<Histogram> linear_histogram1 =
+      LinearHistogram::LinearHistogramFactoryGet("Test1LinearHistogram", 1,
+          1000, 10);
 
   // Use standard macros (but with fixed samples)
   HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
@@ -57,17 +63,23 @@
   EXPECT_EQ(0U, histograms.size());
 
   // Try basic construction
-  Histogram histogram("TestHistogram", 1, 1000, 10);
+  scoped_refptr<Histogram> histogram =
+      Histogram::HistogramFactoryGet("TestHistogram", 1, 1000, 10);
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
   EXPECT_EQ(1U, histograms.size());
-  Histogram histogram1("Test1Histogram", 1, 1000, 10);
+  scoped_refptr<Histogram> histogram1 =
+      Histogram::HistogramFactoryGet("Test1Histogram", 1, 1000, 10);
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
   EXPECT_EQ(2U, histograms.size());
 
-  LinearHistogram linear_histogram("TestLinearHistogram", 1, 1000, 10);
-  LinearHistogram linear_histogram1("Test1LinearHistogram", 1, 1000, 10);
+  scoped_refptr<Histogram> linear_histogram =
+      LinearHistogram::LinearHistogramFactoryGet(
+          "TestLinearHistogram", 1, 1000, 10);
+  scoped_refptr<Histogram> linear_histogram1 =
+      LinearHistogram::LinearHistogramFactoryGet(
+          "Test1LinearHistogram", 1, 1000, 10);
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
   EXPECT_EQ(4U, histograms.size());
@@ -102,55 +114,62 @@
   recorder.GetHistograms(&histograms);
   EXPECT_EQ(0U, histograms.size());
 
-  Histogram histogram("Histogram", 1, 64, 8);  // As mentioned in header file.
+  scoped_refptr<Histogram> histogram = Histogram::HistogramFactoryGet(
+      "Histogram", 1, 64, 8);  // As mentioned in header file.
   // Check that we got a nice exponential when there was enough rooom.
-  EXPECT_EQ(0, histogram.ranges(0));
+  EXPECT_EQ(0, histogram->ranges(0));
   int power_of_2 = 1;
   for (int i = 1; i < 8; i++) {
-    EXPECT_EQ(power_of_2, histogram.ranges(i));
+    EXPECT_EQ(power_of_2, histogram->ranges(i));
     power_of_2 *= 2;
   }
-  EXPECT_EQ(INT_MAX, histogram.ranges(8));
+  EXPECT_EQ(INT_MAX, histogram->ranges(8));
 
-  Histogram short_histogram("Histogram Shortened", 1, 7, 8);
+  scoped_refptr<Histogram> short_histogram =
+      Histogram::HistogramFactoryGet("Histogram Shortened", 1, 7, 8);
   // Check that when the number of buckets is short, we get a linear histogram
   // for lack of space to do otherwise.
   for (int i = 0; i < 8; i++)
-    EXPECT_EQ(i, short_histogram.ranges(i));
-  EXPECT_EQ(INT_MAX, short_histogram.ranges(8));
+    EXPECT_EQ(i, short_histogram->ranges(i));
+  EXPECT_EQ(INT_MAX, short_histogram->ranges(8));
 
-  LinearHistogram linear_histogram("Linear", 1, 7, 8);
+  scoped_refptr<Histogram> linear_histogram =
+      LinearHistogram::LinearHistogramFactoryGet("Linear", 1, 7, 8);
   // We also get a nice linear set of bucket ranges when we ask for it
   for (int i = 0; i < 8; i++)
-    EXPECT_EQ(i, linear_histogram.ranges(i));
-  EXPECT_EQ(INT_MAX, linear_histogram.ranges(8));
+    EXPECT_EQ(i, linear_histogram->ranges(i));
+  EXPECT_EQ(INT_MAX, linear_histogram->ranges(8));
 
-  LinearHistogram linear_broad_histogram("Linear widened", 2, 14, 8);
+  scoped_refptr<Histogram> linear_broad_histogram =
+      LinearHistogram::LinearHistogramFactoryGet(
+          "Linear widened", 2, 14, 8);
   // ...but when the list has more space, then the ranges naturally spread out.
   for (int i = 0; i < 8; i++)
-    EXPECT_EQ(2 * i, linear_broad_histogram.ranges(i));
-  EXPECT_EQ(INT_MAX, linear_broad_histogram.ranges(8));
+    EXPECT_EQ(2 * i, linear_broad_histogram->ranges(i));
+  EXPECT_EQ(INT_MAX, linear_broad_histogram->ranges(8));
 
-  ThreadSafeHistogram threadsafe_histogram("ThreadSafe", 1, 32, 15);
+  scoped_refptr<Histogram> threadsafe_histogram =
+      ThreadSafeHistogram::ThreadSafeHistogramFactoryGet("ThreadSafe", 1, 32,
+          15);
   // When space is a little tight, we transition from linear to exponential.
   // This is what happens in both the basic histogram, and the threadsafe
   // variant (which is derived).
-  EXPECT_EQ(0, threadsafe_histogram.ranges(0));
-  EXPECT_EQ(1, threadsafe_histogram.ranges(1));
-  EXPECT_EQ(2, threadsafe_histogram.ranges(2));
-  EXPECT_EQ(3, threadsafe_histogram.ranges(3));
-  EXPECT_EQ(4, threadsafe_histogram.ranges(4));
-  EXPECT_EQ(5, threadsafe_histogram.ranges(5));
-  EXPECT_EQ(6, threadsafe_histogram.ranges(6));
-  EXPECT_EQ(7, threadsafe_histogram.ranges(7));
-  EXPECT_EQ(9, threadsafe_histogram.ranges(8));
-  EXPECT_EQ(11, threadsafe_histogram.ranges(9));
-  EXPECT_EQ(14, threadsafe_histogram.ranges(10));
-  EXPECT_EQ(17, threadsafe_histogram.ranges(11));
-  EXPECT_EQ(21, threadsafe_histogram.ranges(12));
-  EXPECT_EQ(26, threadsafe_histogram.ranges(13));
-  EXPECT_EQ(32, threadsafe_histogram.ranges(14));
-  EXPECT_EQ(INT_MAX, threadsafe_histogram.ranges(15));
+  EXPECT_EQ(0, threadsafe_histogram->ranges(0));
+  EXPECT_EQ(1, threadsafe_histogram->ranges(1));
+  EXPECT_EQ(2, threadsafe_histogram->ranges(2));
+  EXPECT_EQ(3, threadsafe_histogram->ranges(3));
+  EXPECT_EQ(4, threadsafe_histogram->ranges(4));
+  EXPECT_EQ(5, threadsafe_histogram->ranges(5));
+  EXPECT_EQ(6, threadsafe_histogram->ranges(6));
+  EXPECT_EQ(7, threadsafe_histogram->ranges(7));
+  EXPECT_EQ(9, threadsafe_histogram->ranges(8));
+  EXPECT_EQ(11, threadsafe_histogram->ranges(9));
+  EXPECT_EQ(14, threadsafe_histogram->ranges(10));
+  EXPECT_EQ(17, threadsafe_histogram->ranges(11));
+  EXPECT_EQ(21, threadsafe_histogram->ranges(12));
+  EXPECT_EQ(26, threadsafe_histogram->ranges(13));
+  EXPECT_EQ(32, threadsafe_histogram->ranges(14));
+  EXPECT_EQ(INT_MAX, threadsafe_histogram->ranges(15));
 
   recorder.GetHistograms(&histograms);
   EXPECT_EQ(5U, histograms.size());
@@ -159,21 +178,22 @@
 // Make sure histogram handles out-of-bounds data gracefully.
 TEST(HistogramTest, BoundsTest) {
   const size_t kBucketCount = 50;
-  Histogram histogram("Bounded", 10, 100, kBucketCount);
+  scoped_refptr<Histogram> histogram = Histogram::HistogramFactoryGet("Bounded",
+     10, 100, kBucketCount);
 
   // Put two samples "out of bounds" above and below.
-  histogram.Add(5);
-  histogram.Add(-50);
+  histogram->Add(5);
+  histogram->Add(-50);
 
-  histogram.Add(100);
-  histogram.Add(10000);
+  histogram->Add(100);
+  histogram->Add(10000);
 
   // Verify they landed in the underflow, and overflow buckets.
   Histogram::SampleSet sample;
-  histogram.SnapshotSample(&sample);
+  histogram->SnapshotSample(&sample);
   EXPECT_EQ(2, sample.counts(0));
   EXPECT_EQ(0, sample.counts(1));
-  size_t array_size = histogram.bucket_count();
+  size_t array_size = histogram->bucket_count();
   EXPECT_EQ(kBucketCount, array_size);
   EXPECT_EQ(0, sample.counts(array_size - 2));
   EXPECT_EQ(2, sample.counts(array_size - 1));
@@ -181,31 +201,32 @@
 
 // Check to be sure samples land as expected is "correct" buckets.
 TEST(HistogramTest, BucketPlacementTest) {
-  Histogram histogram("Histogram", 1, 64, 8);  // As mentioned in header file.
+  scoped_refptr<Histogram> histogram = Histogram::HistogramFactoryGet(
+      "Histogram", 1, 64, 8);  // As mentioned in header file.
 
   // Check that we got a nice exponential since there was enough rooom.
-  EXPECT_EQ(0, histogram.ranges(0));
+  EXPECT_EQ(0, histogram->ranges(0));
   int power_of_2 = 1;
   for (int i = 1; i < 8; i++) {
-    EXPECT_EQ(power_of_2, histogram.ranges(i));
+    EXPECT_EQ(power_of_2, histogram->ranges(i));
     power_of_2 *= 2;
   }
-  EXPECT_EQ(INT_MAX, histogram.ranges(8));
+  EXPECT_EQ(INT_MAX, histogram->ranges(8));
 
   // Add i+1 samples to the i'th bucket.
-  histogram.Add(0);
+  histogram->Add(0);
   power_of_2 = 1;
   for (int i = 1; i < 8; i++) {
     for (int j = 0; j <= i; j++)
-      histogram.Add(power_of_2);
+      histogram->Add(power_of_2);
     power_of_2 *= 2;
   }
   // Leave overflow bucket empty.
 
   // Check to see that the bucket counts reflect our additions.
   Histogram::SampleSet sample;
-  histogram.SnapshotSample(&sample);
-  EXPECT_EQ(INT_MAX, histogram.ranges(8));
+  histogram->SnapshotSample(&sample);
+  EXPECT_EQ(INT_MAX, histogram->ranges(8));
   for (int i = 0; i < 8; i++)
     EXPECT_EQ(i + 1, sample.counts(i));
 }
diff --git a/base/message_loop.cc b/base/message_loop.cc
index ddca7db..64913e5 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -531,11 +531,12 @@
   if (enable_histogrammer_ && !message_histogram_.get()
       && StatisticsRecorder::WasStarted()) {
     DCHECK(!thread_name_.empty());
-    message_histogram_.reset(
-        new LinearHistogram(("MsgLoop:" + thread_name_).c_str(),
+    message_histogram_ =
+        LinearHistogram::LinearHistogramFactoryGet(
+                            ("MsgLoop:" + thread_name_),
                             kLeastNonZeroMessageId,
                             kMaxMessageId,
-                            kNumberOfDistinctMessagesDisplayed));
+                            kNumberOfDistinctMessagesDisplayed);
     message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag);
     message_histogram_->SetRangeDescriptions(event_descriptions_);
   }
diff --git a/base/message_loop.h b/base/message_loop.h
index ff4531c..e45adde 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -397,7 +397,7 @@
 
   std::string thread_name_;
   // A profiling histogram showing the counts of various messages and events.
-  scoped_ptr<LinearHistogram> message_histogram_;
+  scoped_refptr<Histogram> message_histogram_;
 
   // A null terminated list which creates an incoming_queue of tasks that are
   // aquired under a mutex for processing on this instance's thread. These tasks