summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorjar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-05 04:48:53 +0000
committerjar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-05 04:48:53 +0000
commit81ce9f3b1eb34dc7f6954f0f6657a76b0f01fc12 (patch)
tree41b3caf1a55ba3cfa2f6cf13b0a5ce3d773d631f /base
parent4f7f4854821e8e4933ad2c662bfd9417eb604a68 (diff)
downloadchromium_src-81ce9f3b1eb34dc7f6954f0f6657a76b0f01fc12.zip
chromium_src-81ce9f3b1eb34dc7f6954f0f6657a76b0f01fc12.tar.gz
chromium_src-81ce9f3b1eb34dc7f6954f0f6657a76b0f01fc12.tar.bz2
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
Diffstat (limited to 'base')
-rw-r--r--base/message_loop.cc7
-rw-r--r--base/message_loop.h2
-rw-r--r--base/metrics/histogram.cc135
-rw-r--r--base/metrics/histogram.h155
-rw-r--r--base/metrics/histogram_unittest.cc117
5 files changed, 232 insertions, 184 deletions
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 @@ MessageLoop::MessageLoop(Type type)
: 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 @@ void MessageLoop::PostTask_Helper(
// 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::StartHistogrammer() {
}
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 @@ class BASE_API MessageLoop : public base::MessagePump::Delegate {
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 @@ typedef Histogram::Count Count;
// 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 @@ scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name,
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 @@ scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name,
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 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
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 @@ bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
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 @@ scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
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 @@ scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
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 @@ bool LinearHistogram::PrintEmptyBucket(size_t index) const {
// 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 @@ BooleanHistogram::BooleanHistogram(const std::string& name)
// 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 @@ scoped_refptr<Histogram> CustomHistogram::FactoryGet(
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 @@ bool StatisticsRecorder::IsActive() {
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 @@ void StatisticsRecorder::GetHistograms(Histograms* output) {
}
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 be375dff..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 @@ class Lock;
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 @@ class Lock;
// 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 @@ class Lock;
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 @@ class Lock;
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 @@ class Lock;
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 CustomHistogram;
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 @@ class BASE_API Histogram : public base::RefCountedThreadSafe<Histogram> {
//----------------------------------------------------------------------------
// 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 @@ class BASE_API Histogram : public base::RefCountedThreadSafe<Histogram> {
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 @@ class BASE_API Histogram : public base::RefCountedThreadSafe<Histogram> {
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 @@ class BASE_API LinearHistogram : public Histogram {
/* 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 @@ class BASE_API LinearHistogram : public Histogram {
// 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 BooleanHistogram : public LinearHistogram {
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 CustomHistogram : public Histogram {
class BASE_API StatisticsRecorder {
public:
- typedef std::vector<scoped_refptr<Histogram> > Histograms;
+ typedef std::vector<Histogram*> Histograms;
StatisticsRecorder();
@@ -656,9 +684,9 @@ class BASE_API StatisticsRecorder {
// 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 @@ class BASE_API StatisticsRecorder {
// 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 @@ class BASE_API StatisticsRecorder {
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 @@ class HistogramTest : public testing::Test {
// 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);
-
- 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* 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);
+
+
+ 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 @@ TEST(HistogramTest, StartupShutdownTest) {
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 @@ TEST(HistogramTest, RecordedStartupTest) {
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 @@ TEST(HistogramTest, RecordedStartupTest) {
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 @@ TEST(HistogramTest, RangeTest) {
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 @@ TEST(HistogramTest, RangeTest) {
}
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 @@ TEST(HistogramTest, RangeTest) {
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 @@ TEST(HistogramTest, CustomRangeTest) {
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 @@ TEST(HistogramTest, CustomRangeTest) {
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 @@ TEST(HistogramTest, CustomRangeTest) {
// 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 @@ TEST(HistogramTest, BoundsTest) {
// 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 @@ TEST(HistogramTest, BucketPlacementTest) {
// 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, CorruptSampleCounts) {
}
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);