Use lock-free lazy initialization for static histogram references

Make all histogram macros thread safe, and fast by again
using statics to achieve performance.

...at the cost of:
Leak all histograms to avoid races at shutdown.

Also included leak suppression for valgrind.

r=rtenneti
BUG=78207
Review URL: http://codereview.chromium.org/6780035

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


CrOS-Libchrome-Original-Commit: 81ce9f3b1eb34dc7f6954f0f6657a76b0f01fc12
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 39881d1..1154c3e 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
 
@@ -122,6 +122,7 @@
     : type_(type),
       nestable_tasks_allowed_(true),
       exception_restoration_(false),
+      message_histogram_(NULL),
       state_(NULL),
 #ifdef OS_WIN
       os_modal_loop_(false),
@@ -531,7 +532,7 @@
 // on each thread.
 
 void MessageLoop::StartHistogrammer() {
-  if (enable_histogrammer_ && !message_histogram_.get()
+  if (enable_histogrammer_ && !message_histogram_
       && base::StatisticsRecorder::IsActive()) {
     DCHECK(!thread_name_.empty());
     message_histogram_ = base::LinearHistogram::FactoryGet(
@@ -544,7 +545,7 @@
 }
 
 void MessageLoop::HistogramEvent(int event) {
-  if (message_histogram_.get())
+  if (message_histogram_)
     message_histogram_->Add(event);
 }
 
diff --git a/base/message_loop.h b/base/message_loop.h
index 7da04d3..519e4a3 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -473,7 +473,7 @@
 
   std::string thread_name_;
   // A profiling histogram showing the counts of various messages and events.
-  scoped_refptr<base::Histogram> message_histogram_;
+  base::Histogram* message_histogram_;
 
   // A null terminated list which creates an incoming_queue of tasks that are
   // acquired under a mutex for processing on this instance's thread. These
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index bf765c2..4262853 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -73,9 +73,12 @@
 // static
 const size_t Histogram::kBucketCount_MAX = 16384u;
 
-scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name,
-    Sample minimum, Sample maximum, size_t bucket_count, Flags flags) {
-  scoped_refptr<Histogram> histogram(NULL);
+Histogram* Histogram::FactoryGet(const std::string& name,
+                                 Sample minimum,
+                                 Sample maximum,
+                                 size_t bucket_count,
+                                 Flags flags) {
+  Histogram* histogram(NULL);
 
   // Defensive code.
   if (minimum < 1)
@@ -84,10 +87,16 @@
     maximum = kSampleType_MAX - 1;
 
   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
-    histogram = new Histogram(name, minimum, maximum, bucket_count);
-    histogram->InitializeBucketRange();
-    histogram->SetFlags(flags);
-    StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+    // Extra variable is not needed... but this keeps this section basically
+    // identical to other derived classes in this file (and compiler will
+    // optimize away the extra variable.
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    Histogram* tentative_histogram =
+        new Histogram(name, minimum, maximum, bucket_count);
+    tentative_histogram->InitializeBucketRange();
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
   }
 
   DCHECK_EQ(HISTOGRAM, histogram->histogram_type());
@@ -95,11 +104,11 @@
   return histogram;
 }
 
-scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name,
-                                                   TimeDelta minimum,
-                                                   TimeDelta maximum,
-                                                   size_t bucket_count,
-                                                   Flags flags) {
+Histogram* Histogram::FactoryTimeGet(const std::string& name,
+                                     TimeDelta minimum,
+                                     TimeDelta maximum,
+                                     size_t bucket_count,
+                                     Flags flags) {
   return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
                     bucket_count, flags);
 }
@@ -259,7 +268,7 @@
 
   DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
 
-  scoped_refptr<Histogram> render_histogram(NULL);
+  Histogram* render_histogram(NULL);
 
   if (histogram_type == HISTOGRAM) {
     render_histogram = Histogram::FactoryGet(
@@ -761,12 +770,12 @@
 LinearHistogram::~LinearHistogram() {
 }
 
-scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
-                                                     Sample minimum,
-                                                     Sample maximum,
-                                                     size_t bucket_count,
-                                                     Flags flags) {
-  scoped_refptr<Histogram> histogram(NULL);
+Histogram* LinearHistogram::FactoryGet(const std::string& name,
+                                       Sample minimum,
+                                       Sample maximum,
+                                       size_t bucket_count,
+                                       Flags flags) {
+  Histogram* histogram(NULL);
 
   if (minimum < 1)
     minimum = 1;
@@ -774,12 +783,13 @@
     maximum = kSampleType_MAX - 1;
 
   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
-    LinearHistogram* linear_histogram =
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    LinearHistogram* tentative_histogram =
         new LinearHistogram(name, minimum, maximum, bucket_count);
-    linear_histogram->InitializeBucketRange();
-    histogram = linear_histogram;
-    histogram->SetFlags(flags);
-    StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+    tentative_histogram->InitializeBucketRange();
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
   }
 
   DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type());
@@ -787,12 +797,11 @@
   return histogram;
 }
 
-scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet(
-    const std::string& name,
-    TimeDelta minimum,
-    TimeDelta maximum,
-    size_t bucket_count,
-    Flags flags) {
+Histogram* LinearHistogram::FactoryTimeGet(const std::string& name,
+                                           TimeDelta minimum,
+                                           TimeDelta maximum,
+                                           size_t bucket_count,
+                                           Flags flags) {
   return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
                     bucket_count, flags);
 }
@@ -862,16 +871,16 @@
 // This section provides implementation for BooleanHistogram.
 //------------------------------------------------------------------------------
 
-scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name,
-                                                      Flags flags) {
-  scoped_refptr<Histogram> histogram(NULL);
+Histogram* BooleanHistogram::FactoryGet(const std::string& name, Flags flags) {
+  Histogram* histogram(NULL);
 
   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
-    BooleanHistogram* boolean_histogram = new BooleanHistogram(name);
-    boolean_histogram->InitializeBucketRange();
-    histogram = boolean_histogram;
-    histogram->SetFlags(flags);
-    StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BooleanHistogram* tentative_histogram = new BooleanHistogram(name);
+    tentative_histogram->InitializeBucketRange();
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
   }
 
   DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type());
@@ -894,11 +903,10 @@
 // CustomHistogram:
 //------------------------------------------------------------------------------
 
-scoped_refptr<Histogram> CustomHistogram::FactoryGet(
-    const std::string& name,
-    const std::vector<Sample>& custom_ranges,
-    Flags flags) {
-  scoped_refptr<Histogram> histogram(NULL);
+Histogram* CustomHistogram::FactoryGet(const std::string& name,
+                                       const std::vector<Sample>& custom_ranges,
+                                       Flags flags) {
+  Histogram* histogram(NULL);
 
   // Remove the duplicates in the custom ranges array.
   std::vector<int> ranges = custom_ranges;
@@ -914,11 +922,12 @@
   DCHECK_LT(ranges.back(), kSampleType_MAX);
 
   if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
-    CustomHistogram* custom_histogram = new CustomHistogram(name, ranges);
-    custom_histogram->InitializedCustomBucketRange(ranges);
-    histogram = custom_histogram;
-    histogram->SetFlags(flags);
-    StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    CustomHistogram* tentative_histogram = new CustomHistogram(name, ranges);
+    tentative_histogram->InitializedCustomBucketRange(ranges);
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
   }
 
   DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM);
@@ -1004,27 +1013,23 @@
   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
-void StatisticsRecorder::RegisterOrDiscardDuplicate(
-    scoped_refptr<Histogram>* histogram) {
-  DCHECK((*histogram)->HasValidRangeChecksum());
+Histogram* StatisticsRecorder::RegisterOrDeleteDuplicate(Histogram* histogram) {
+  DCHECK(histogram->HasValidRangeChecksum());
   if (lock_ == NULL)
-    return;
+    return histogram;
   base::AutoLock auto_lock(*lock_);
   if (!histograms_)
-    return;
-  const std::string name = (*histogram)->histogram_name();
+    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;
-  else
-    *histogram = it->second;
+  if (histograms_->end() == it) {
+    (*histograms_)[name] = histogram;
+  } else {
+    delete histogram;  // We already have one by this name.
+    histogram = it->second;
+  }
+  return histogram;
 }
 
 // static
@@ -1087,7 +1092,7 @@
 }
 
 bool StatisticsRecorder::FindHistogram(const std::string& name,
-                                       scoped_refptr<Histogram>* histogram) {
+                                       Histogram** histogram) {
   if (lock_ == NULL)
     return false;
   base::AutoLock auto_lock(*lock_);
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index be375df..b7ae10a 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -28,6 +28,15 @@
 // at the low end of the histogram scale, but allows the histogram to cover a
 // gigantic range with the addition of very few buckets.
 
+// Histograms use a pattern involving a function static variable, that is a
+// pointer to a histogram.  This static is explicitly initialized on any thread
+// that detects a uninitialized (NULL) pointer.  The potentially racy
+// initialization is not a problem as it is always set to point to the same
+// value (i.e., the FactoryGet always returns the same value).  FactoryGet
+// is also completely thread safe, which results in a completely thread safe,
+// and relatively fast, set of counters.  To avoid races at shutdown, the static
+// pointer is NOT deleted, and we leak the histograms at process termination.
+
 #ifndef BASE_METRICS_HISTOGRAM_H_
 #define BASE_METRICS_HISTOGRAM_H_
 #pragma once
@@ -39,7 +48,6 @@
 #include "base/base_api.h"
 #include "base/gtest_prod_util.h"
 #include "base/logging.h"
-#include "base/memory/ref_counted.h"
 #include "base/time.h"
 
 class Pickle;
@@ -66,11 +74,12 @@
     name, sample, 1, 10000, 50)
 
 #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
-    scoped_refptr<base::Histogram> counter = \
-        base::Histogram::FactoryGet(name, min, max, bucket_count, \
-                                    base::Histogram::kNoFlags); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \
+                                            base::Histogram::kNoFlags); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->Add(sample); \
+    counter->Add(sample); \
   } while (0)
 
 #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
@@ -79,40 +88,43 @@
 // 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 { \
-    scoped_refptr<base::Histogram> counter = \
-        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
-                                        base::Histogram::kNoFlags); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+                                                base::Histogram::kNoFlags); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->AddTime(sample); \
+    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 { \
-    scoped_refptr<base::Histogram> counter = \
-        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
-                                        base::Histogram::kNoFlags); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+                                                base::Histogram::kNoFlags); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if ((sample) < (max) && counter.get()) counter->AddTime(sample); \
+    if ((sample) < (max)) counter->AddTime(sample); \
   } while (0)
 
 // Support histograming of an enumerated value.  The samples should always be
 // less than boundary_value.
 
 #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
-    scoped_refptr<base::Histogram> counter = \
-        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
-                                          boundary_value + 1, \
-                                          base::Histogram::kNoFlags); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+          boundary_value + 1, base::Histogram::kNoFlags); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->Add(sample); \
+    counter->Add(sample); \
   } while (0)
 
 #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \
-    scoped_refptr<base::Histogram> counter = \
-        base::CustomHistogram::FactoryGet(name, custom_ranges, \
-                                          base::Histogram::kNoFlags); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \
+                                                  base::Histogram::kNoFlags); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->Add(sample); \
+    counter->Add(sample); \
   } while (0)
 
 
@@ -172,20 +184,22 @@
     base::TimeDelta::FromHours(1), 50)
 
 #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
-    scoped_refptr<base::Histogram> counter = \
-        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
             base::Histogram::kUmaTargetedHistogramFlag); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->AddTime(sample); \
+    counter->AddTime(sample); \
   } while (0)
 
 // DO NOT USE THIS.  It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES.
 #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \
-    scoped_refptr<base::Histogram> counter = \
-        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
-            base::Histogram::kUmaTargetedHistogramFlag); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+           base::Histogram::kUmaTargetedHistogramFlag); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if ((sample) < (max) && counter.get()) counter->AddTime(sample); \
+    if ((sample) < (max)) counter->AddTime(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
@@ -198,11 +212,12 @@
     name, sample, 1, 10000, 50)
 
 #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
-    scoped_refptr<base::Histogram> counter = \
-       base::Histogram::FactoryGet(name, min, max, bucket_count, \
-           base::Histogram::kUmaTargetedHistogramFlag); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \
+          base::Histogram::kUmaTargetedHistogramFlag); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->Add(sample); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
@@ -215,19 +230,21 @@
     UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
 
 #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
-    scoped_refptr<base::Histogram> counter = \
-        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
-            boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+          boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->Add(sample); \
+    counter->Add(sample); \
   } while (0)
 
 #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \
-    scoped_refptr<base::Histogram> counter = \
-        base::CustomHistogram::FactoryGet(name, custom_ranges, \
-            base::Histogram::kUmaTargetedHistogramFlag); \
+    static base::Histogram* counter(NULL); \
+    if (!counter) \
+      counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \
+          base::Histogram::kUmaTargetedHistogramFlag); \
     DCHECK_EQ(name, counter->histogram_name()); \
-    if (counter.get()) counter->Add(sample); \
+    counter->Add(sample); \
   } while (0)
 
 //------------------------------------------------------------------------------
@@ -237,7 +254,7 @@
 class Histogram;
 class LinearHistogram;
 
-class BASE_API Histogram : public base::RefCountedThreadSafe<Histogram> {
+class BASE_API Histogram {
  public:
   typedef int Sample;  // Used for samples (and ranges of samples).
   typedef int Count;  // Used to count samples in a bucket.
@@ -347,11 +364,16 @@
   //----------------------------------------------------------------------------
   // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
   // default underflow bucket.
-  static scoped_refptr<Histogram> FactoryGet(const std::string& name,
-      Sample minimum, Sample maximum, size_t bucket_count, Flags flags);
-  static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name,
-      base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count,
-      Flags flags);
+  static Histogram* FactoryGet(const std::string& name,
+                               Sample minimum,
+                               Sample maximum,
+                               size_t bucket_count,
+                               Flags flags);
+  static Histogram* FactoryTimeGet(const std::string& name,
+                                   base::TimeDelta minimum,
+                                   base::TimeDelta maximum,
+                                   size_t bucket_count,
+                                   Flags flags);
 
   void Add(int value);
 
@@ -426,7 +448,6 @@
   bool HasValidRangeChecksum() const;
 
  protected:
-  friend class base::RefCountedThreadSafe<Histogram>;
   Histogram(const std::string& name, Sample minimum,
             Sample maximum, size_t bucket_count);
   Histogram(const std::string& name, TimeDelta minimum,
@@ -480,6 +501,8 @@
   FRIEND_TEST(HistogramTest, Crc32SampleHash);
   FRIEND_TEST(HistogramTest, Crc32TableTest);
 
+  friend class StatisticsRecorder;  // To allow it to delete duplicates.
+
   // Post constructor initialization.
   void Initialize();
 
@@ -555,11 +578,16 @@
 
   /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
      default underflow bucket. */
-  static scoped_refptr<Histogram> FactoryGet(const std::string& name,
-      Sample minimum, Sample maximum, size_t bucket_count, Flags flags);
-  static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name,
-      TimeDelta minimum, TimeDelta maximum, size_t bucket_count,
-      Flags flags);
+  static Histogram* FactoryGet(const std::string& name,
+                               Sample minimum,
+                               Sample maximum,
+                               size_t bucket_count,
+                               Flags flags);
+  static Histogram* FactoryTimeGet(const std::string& name,
+                                   TimeDelta minimum,
+                                   TimeDelta maximum,
+                                   size_t bucket_count,
+                                   Flags flags);
 
   // Overridden from Histogram:
   virtual ClassType histogram_type() const;
@@ -602,8 +630,7 @@
 // BooleanHistogram is a histogram for booleans.
 class BASE_API BooleanHistogram : public LinearHistogram {
  public:
-  static scoped_refptr<Histogram> FactoryGet(const std::string& name,
-      Flags flags);
+  static Histogram* FactoryGet(const std::string& name, Flags flags);
 
   virtual ClassType histogram_type() const;
 
@@ -621,8 +648,9 @@
 class BASE_API CustomHistogram : public Histogram {
  public:
 
-  static scoped_refptr<Histogram> FactoryGet(const std::string& name,
-      const std::vector<Sample>& custom_ranges, Flags flags);
+  static Histogram* FactoryGet(const std::string& name,
+                               const std::vector<Sample>& custom_ranges,
+                               Flags flags);
 
   // Overridden from Histogram:
   virtual ClassType histogram_type() const;
@@ -645,7 +673,7 @@
 
 class BASE_API StatisticsRecorder {
  public:
-  typedef std::vector<scoped_refptr<Histogram> > Histograms;
+  typedef std::vector<Histogram*> Histograms;
 
   StatisticsRecorder();
 
@@ -656,9 +684,9 @@
 
   // Register, or add a new histogram to the collection of statistics. If an
   // identically named histogram is already registered, then the argument
-  // |histogram| will be replaced by the previously registered value, discarding
-  // the referenced argument.
-  static void RegisterOrDiscardDuplicate(scoped_refptr<Histogram>* histogram);
+  // |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);
 
   // Methods for printing histograms.  Only histograms which have query as
   // a substring are written to output (an empty string will process all
@@ -672,8 +700,7 @@
   // 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,
-                            scoped_refptr<Histogram>* histogram);
+  static bool FindHistogram(const std::string& query, Histogram** histogram);
 
   static bool dump_on_exit() { return dump_on_exit_; }
 
@@ -688,7 +715,7 @@
 
  private:
   // We keep all registered histograms in a map, from name to histogram.
-  typedef std::map<std::string, scoped_refptr<Histogram> > HistogramMap;
+  typedef std::map<std::string, Histogram*> HistogramMap;
 
   static HistogramMap* histograms_;
 
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index afa69a6..496ff63 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -1,10 +1,11 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
 
 // Test of Histogram class
 
 #include "base/metrics/histogram.h"
+#include "base/scoped_ptr.h"
 #include "base/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -17,15 +18,22 @@
 // Check for basic syntax and use.
 TEST(HistogramTest, StartupShutdownTest) {
   // Try basic construction
-  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
-      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
-  scoped_refptr<Histogram> histogram1 = Histogram::FactoryGet(
-      "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram* histogram(Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
+  Histogram* histogram1(Histogram::FactoryGet(
+      "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
+  EXPECT_NE(histogram, histogram1);
 
-  scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
-      "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
-  scoped_refptr<Histogram> linear_histogram1 = LinearHistogram::FactoryGet(
-      "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
+
+  Histogram* linear_histogram(LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
+  Histogram* linear_histogram1(LinearHistogram::FactoryGet(
+      "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
+  EXPECT_NE(linear_histogram, linear_histogram1);
 
   std::vector<int> custom_ranges;
   custom_ranges.push_back(1);
@@ -33,10 +41,12 @@
   custom_ranges.push_back(10);
   custom_ranges.push_back(20);
   custom_ranges.push_back(30);
-  scoped_refptr<Histogram> custom_histogram = CustomHistogram::FactoryGet(
-      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
-  scoped_refptr<Histogram> custom_histogram1 = CustomHistogram::FactoryGet(
-      "Test1CustomHistogram", custom_ranges, Histogram::kNoFlags);
+  Histogram* custom_histogram(CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
+  Histogram* custom_histogram1(CustomHistogram::FactoryGet(
+      "Test1CustomHistogram", custom_ranges, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
 
   // Use standard macros (but with fixed samples)
   HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
@@ -70,25 +80,29 @@
   EXPECT_EQ(0U, histograms.size());
 
   // Try basic construction
-  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
-      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram* histogram(Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
   EXPECT_EQ(1U, histograms.size());
-  scoped_refptr<Histogram> histogram1 = Histogram::FactoryGet(
-      "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram* histogram1(Histogram::FactoryGet(
+      "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
   EXPECT_EQ(2U, histograms.size());
 
-  scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
-      "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram* linear_histogram(LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
   EXPECT_EQ(3U, histograms.size());
 
-  scoped_refptr<Histogram> linear_histogram1 = LinearHistogram::FactoryGet(
-      "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram* linear_histogram1(LinearHistogram::FactoryGet(
+      "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
   EXPECT_EQ(4U, histograms.size());
@@ -99,10 +113,12 @@
   custom_ranges.push_back(10);
   custom_ranges.push_back(20);
   custom_ranges.push_back(30);
-  scoped_refptr<Histogram> custom_histogram = CustomHistogram::FactoryGet(
-      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
-  scoped_refptr<Histogram> custom_histogram1 = CustomHistogram::FactoryGet(
-      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
+  Histogram* custom_histogram(CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
+  Histogram* custom_histogram1(CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+  EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
 
   histograms.clear();
   StatisticsRecorder::GetHistograms(&histograms);  // Load up lists
@@ -138,8 +154,8 @@
   recorder.GetHistograms(&histograms);
   EXPECT_EQ(0U, histograms.size());
 
-  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
-      "Histogram", 1, 64, 8, Histogram::kNoFlags);  // As per header file.
+  Histogram* histogram(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
   // Check that we got a nice exponential when there was enough rooom.
   EXPECT_EQ(0, histogram->ranges(0));
   int power_of_2 = 1;
@@ -149,31 +165,30 @@
   }
   EXPECT_EQ(INT_MAX, histogram->ranges(8));
 
-  scoped_refptr<Histogram> short_histogram = Histogram::FactoryGet(
-      "Histogram Shortened", 1, 7, 8, Histogram::kNoFlags);
+  Histogram* short_histogram(Histogram::FactoryGet(
+      "Histogram Shortened", 1, 7, 8, Histogram::kNoFlags));
   // 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));
 
-  scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
-      "Linear", 1, 7, 8, Histogram::kNoFlags);
+  Histogram* linear_histogram(LinearHistogram::FactoryGet(
+      "Linear", 1, 7, 8, Histogram::kNoFlags));
   // 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));
 
-  scoped_refptr<Histogram> linear_broad_histogram = LinearHistogram::FactoryGet(
-      "Linear widened", 2, 14, 8, Histogram::kNoFlags);
+  Histogram* linear_broad_histogram(LinearHistogram::FactoryGet(
+      "Linear widened", 2, 14, 8, Histogram::kNoFlags));
   // ...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));
 
-  scoped_refptr<Histogram> transitioning_histogram =
-      Histogram::FactoryGet("LinearAndExponential", 1, 32, 15,
-                                      Histogram::kNoFlags);
+  Histogram* transitioning_histogram(Histogram::FactoryGet(
+      "LinearAndExponential", 1, 32, 15, Histogram::kNoFlags));
   // When space is a little tight, we transition from linear to exponential.
   EXPECT_EQ(0, transitioning_histogram->ranges(0));
   EXPECT_EQ(1, transitioning_histogram->ranges(1));
@@ -198,8 +213,8 @@
   custom_ranges.push_back(10);
   custom_ranges.push_back(11);
   custom_ranges.push_back(300);
-  scoped_refptr<Histogram> test_custom_histogram = CustomHistogram::FactoryGet(
-      "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags);
+  Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
+      "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
 
   EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(0));
   EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(1));
@@ -221,8 +236,8 @@
   custom_ranges.push_back(9);
   custom_ranges.push_back(10);
   custom_ranges.push_back(11);
-  scoped_refptr<Histogram> test_custom_histogram = CustomHistogram::FactoryGet(
-      "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags);
+  Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
+      "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
 
   EXPECT_EQ(0, test_custom_histogram->ranges(0));  // Auto added
   EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(1));
@@ -242,8 +257,8 @@
   custom_ranges.push_back(0);  // Push an explicit zero.
   custom_ranges.push_back(kBig);
 
-  scoped_refptr<Histogram> unsorted_histogram = CustomHistogram::FactoryGet(
-      "TestCustomUnsortedDupedHistogram", custom_ranges, Histogram::kNoFlags);
+  Histogram* unsorted_histogram(CustomHistogram::FactoryGet(
+      "TestCustomUnsortedDupedHistogram", custom_ranges, Histogram::kNoFlags));
   EXPECT_EQ(0, unsorted_histogram->ranges(0));
   EXPECT_EQ(kSmall, unsorted_histogram->ranges(1));
   EXPECT_EQ(kMid, unsorted_histogram->ranges(2));
@@ -254,8 +269,8 @@
 // Make sure histogram handles out-of-bounds data gracefully.
 TEST(HistogramTest, BoundsTest) {
   const size_t kBucketCount = 50;
-  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
-      "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags);
+  Histogram* histogram(Histogram::FactoryGet(
+      "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags));
 
   // Put two samples "out of bounds" above and below.
   histogram->Add(5);
@@ -277,8 +292,8 @@
 
 // Check to be sure samples land as expected is "correct" buckets.
 TEST(HistogramTest, BucketPlacementTest) {
-  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
-      "Histogram", 1, 64, 8, Histogram::kNoFlags);  // As per header file.
+  Histogram* histogram(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
 
   // Check that we got a nice exponential since there was enough rooom.
   EXPECT_EQ(0, histogram->ranges(0));
@@ -314,8 +329,8 @@
 // out to the base namespace here.  We need to be friends to corrupt the
 // internals of the histogram and/or sampleset.
 TEST(HistogramTest, CorruptSampleCounts) {
-  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
-      "Histogram", 1, 64, 8, Histogram::kNoFlags);  // As per header file.
+  Histogram* histogram(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
 
   EXPECT_EQ(0, histogram->sample_.redundant_count());
   histogram->Add(20);  // Add some samples.
@@ -339,8 +354,8 @@
 }
 
 TEST(HistogramTest, CorruptBucketBounds) {
-  scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
-      "Histogram", 1, 64, 8, Histogram::kNoFlags);  // As per header file.
+  Histogram* histogram(Histogram::FactoryGet(
+      "Histogram", 1, 64, 8, Histogram::kNoFlags));  // As per header file.
 
   Histogram::SampleSet snapshot;
   histogram->SnapshotSample(&snapshot);