diff options
author | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-05 04:48:53 +0000 |
---|---|---|
committer | jar@chromium.org <jar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-05 04:48:53 +0000 |
commit | 81ce9f3b1eb34dc7f6954f0f6657a76b0f01fc12 (patch) | |
tree | 41b3caf1a55ba3cfa2f6cf13b0a5ce3d773d631f /base | |
parent | 4f7f4854821e8e4933ad2c662bfd9417eb604a68 (diff) | |
download | chromium_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.cc | 7 | ||||
-rw-r--r-- | base/message_loop.h | 2 | ||||
-rw-r--r-- | base/metrics/histogram.cc | 135 | ||||
-rw-r--r-- | base/metrics/histogram.h | 155 | ||||
-rw-r--r-- | base/metrics/histogram_unittest.cc | 117 |
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); |