From e8829a1981a2d9d849c377c28f9444fdefee0f44 Mon Sep 17 00:00:00 2001 From: "jar@chromium.org" Date: Sun, 6 Dec 2009 00:09:37 +0000 Subject: Use factory to create histograms, and refcounts to track lifetimes This is CL patch 377028 by Raman Tenneti, with minor changes to make the try-bots happier. It is cleanup that better ensures lifetimes of histograms (making it harder for users to abuse them). bug=16495 (repairs leak induced by the first landing) bug=18840 (should make leaks less possible) tbr=raman.tenneti Review URL: http://codereview.chromium.org/462027 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@33933 0039d316-1c4b-4281-b951-d872f2087c98 --- base/histogram.cc | 262 ++++++++++++----- base/histogram.h | 317 ++++++++++++++------- base/histogram_unittest.cc | 129 +++++---- base/message_loop.cc | 7 +- base/message_loop.h | 2 +- chrome/browser/chrome_browser_application_mac.mm | 9 +- chrome/browser/diagnostics/sqlite_diagnostics.cc | 8 +- chrome/browser/jankometer.cc | 22 +- chrome/browser/net/dns_host_info.cc | 9 +- .../websocket_experiment_runner.cc | 72 +++-- .../renderer_host/buffered_resource_handler.cc | 25 +- .../safe_browsing/safe_browsing_blocking_page.cc | 8 +- chrome/browser/ssl/ssl_blocking_page.cc | 8 +- chrome/browser/sync/profile_sync_service.cc | 11 +- chrome/renderer/render_thread.cc | 16 +- net/base/connection_type_histograms.cc | 22 +- net/base/mime_sniffer.cc | 86 +++--- net/base/sdch_manager.cc | 9 +- net/disk_cache/histogram_macros.h | 8 +- net/disk_cache/stats.cc | 3 +- net/disk_cache/stats.h | 2 +- net/disk_cache/stats_histogram.cc | 31 ++ net/disk_cache/stats_histogram.h | 16 +- net/ftp/ftp_network_transaction.cc | 22 +- net/ftp/ftp_server_type_histograms.cc | 22 +- net/http/http_network_transaction.cc | 49 ++-- net/socket_stream/socket_stream_metrics.cc | 22 +- 27 files changed, 774 insertions(+), 423 deletions(-) diff --git a/base/histogram.cc b/base/histogram.cc index 55af96d..3a5a5b2 100644 --- a/base/histogram.cc +++ b/base/histogram.cc @@ -23,7 +23,42 @@ typedef Histogram::Count Count; // static const int Histogram::kHexRangePrintingFlag = 0x8000; -Histogram::Histogram(const char* name, Sample minimum, +scoped_refptr Histogram::HistogramFactoryGet( + const std::string& name, Sample minimum, Sample maximum, + size_t bucket_count) { + scoped_refptr histogram(NULL); + + // Defensive code. + if (minimum <= 0) + minimum = 1; + if (maximum >= kSampleType_MAX) + maximum = kSampleType_MAX - 1; + + if (StatisticsRecorder::FindHistogram(name, &histogram)) { + DCHECK(histogram.get() != NULL); + } else { + histogram = new Histogram(name, minimum, maximum, bucket_count); + scoped_refptr registered_histogram(NULL); + StatisticsRecorder::FindHistogram(name, ®istered_histogram); + // Allow a NULL return to mean that the StatisticsRecorder was not started. + if (registered_histogram.get() != NULL && + registered_histogram.get() != histogram.get()) + histogram = registered_histogram; + } + + DCHECK(HISTOGRAM == histogram->histogram_type()); + DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); + return histogram; +} + +scoped_refptr Histogram::HistogramFactoryGet( + const std::string& name, base::TimeDelta minimum, base::TimeDelta maximum, + size_t bucket_count) { + return HistogramFactoryGet(name, + minimum.InMilliseconds(), maximum.InMilliseconds(), bucket_count); +} + +Histogram::Histogram(const std::string& name, Sample minimum, Sample maximum, size_t bucket_count) : histogram_name_(name), declared_min_(minimum), @@ -31,12 +66,11 @@ Histogram::Histogram(const char* name, Sample minimum, bucket_count_(bucket_count), flags_(0), ranges_(bucket_count + 1, 0), - sample_(), - registered_(false) { + sample_() { Initialize(); } -Histogram::Histogram(const char* name, TimeDelta minimum, +Histogram::Histogram(const std::string& name, TimeDelta minimum, TimeDelta maximum, size_t bucket_count) : histogram_name_(name), declared_min_(static_cast (minimum.InMilliseconds())), @@ -44,21 +78,23 @@ Histogram::Histogram(const char* name, TimeDelta minimum, bucket_count_(bucket_count), flags_(0), ranges_(bucket_count + 1, 0), - sample_(), - registered_(false) { + sample_() { Initialize(); } Histogram::~Histogram() { - if (registered_) - StatisticsRecorder::UnRegister(this); + DCHECK(!(kPlannedLeakFlag & flags_)); + if (StatisticsRecorder::dump_on_exit()) { + std::string output; + WriteAscii(true, "\n", &output); + LOG(INFO) << output; + } + // Just to make sure most derived class did this properly... DCHECK(ValidateBucketRanges()); } void Histogram::Add(int value) { - if (!registered_) - registered_ = StatisticsRecorder::Register(this); if (value >= kSampleType_MAX) value = kSampleType_MAX - 1; if (value < 0) @@ -170,7 +206,7 @@ void Histogram::Initialize() { ranges_[bucket_count_] = kSampleType_MAX; InitializeBucketRange(); DCHECK(ValidateBucketRanges()); - registered_ = StatisticsRecorder::Register(this); + StatisticsRecorder::Register(this); } // Calculate what range of values are held in each bucket. @@ -353,14 +389,15 @@ void Histogram::WriteAsciiBucketGraph(double current_size, double max_size, // static std::string Histogram::SerializeHistogramInfo(const Histogram& histogram, const SampleSet& snapshot) { - Pickle pickle; + DCHECK(histogram.histogram_type() != NOT_VALID_IN_RENDERER); + Pickle pickle; pickle.WriteString(histogram.histogram_name()); pickle.WriteInt(histogram.declared_min()); pickle.WriteInt(histogram.declared_max()); pickle.WriteSize(histogram.bucket_count()); pickle.WriteInt(histogram.histogram_type()); - pickle.WriteInt(histogram.flags()); + pickle.WriteInt(histogram.flags() & ~kIPCSerializationSourceFlag); snapshot.Serialize(&pickle); return std::string(static_cast(pickle.data()), pickle.size()); @@ -394,27 +431,27 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { return false; } - Histogram* render_histogram = - StatisticsRecorder::GetHistogram(histogram_name); - - if (render_histogram == NULL) { - if (histogram_type == EXPONENTIAL) { - render_histogram = new Histogram(histogram_name.c_str(), - declared_min, - declared_max, - bucket_count); - } else if (histogram_type == LINEAR) { - render_histogram = new LinearHistogram(histogram_name.c_str(), - declared_min, - declared_max, - bucket_count); - } else { - LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " << - histogram_type; - return false; - } - DCHECK(!(flags & kRendererHistogramFlag)); - render_histogram->SetFlags(flags | kRendererHistogramFlag); + DCHECK(histogram_type != NOT_VALID_IN_RENDERER); + + scoped_refptr render_histogram(NULL); + + if (histogram_type == HISTOGRAM) { + render_histogram = Histogram::HistogramFactoryGet( + histogram_name, declared_min, declared_max, bucket_count); + } else if (histogram_type == LINEAR_HISTOGRAM) { + render_histogram = LinearHistogram::LinearHistogramFactoryGet( + histogram_name, declared_min, declared_max, bucket_count); + } else if (histogram_type == BOOLEAN_HISTOGRAM) { + render_histogram = BooleanHistogram::BooleanHistogramFactoryGet( + histogram_name); + } else if (histogram_type == THREAD_SAFE_HISTOGRAM) { + render_histogram = + ThreadSafeHistogram::ThreadSafeHistogramFactoryGet( + histogram_name, declared_min, declared_max, bucket_count); + } else { + LOG(ERROR) << "Error Deserializing Histogram Unknown histogram_type: " << + histogram_type; + return false; } DCHECK(declared_min == render_histogram->declared_min()); @@ -422,17 +459,16 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) { DCHECK(bucket_count == render_histogram->bucket_count()); DCHECK(histogram_type == render_histogram->histogram_type()); - if (render_histogram->flags() & kRendererHistogramFlag) { - render_histogram->AddSampleSet(sample); - } else { - DLOG(INFO) << "Single thread mode, histogram observed and not copied: " << + if (render_histogram->flags() & kIPCSerializationSourceFlag) { + DLOG(INFO) << "Single process mode, histogram observed and not copied: " << histogram_name; + } else { + render_histogram->AddSampleSet(sample); } return true; } - //------------------------------------------------------------------------------ // Methods for the Histogram::SampleSet class //------------------------------------------------------------------------------ @@ -537,14 +573,48 @@ bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) { // buckets. //------------------------------------------------------------------------------ -LinearHistogram::LinearHistogram(const char* name, Sample minimum, +scoped_refptr LinearHistogram::LinearHistogramFactoryGet( + const std::string& name, Sample minimum, Sample maximum, + size_t bucket_count) { + scoped_refptr histogram(NULL); + + if (minimum <= 0) + minimum = 1; + if (maximum >= kSampleType_MAX) + maximum = kSampleType_MAX - 1; + + if (StatisticsRecorder::FindHistogram(name, &histogram)) { + DCHECK(histogram.get() != NULL); + } else { + histogram = new LinearHistogram(name, minimum, maximum, bucket_count); + scoped_refptr registered_histogram(NULL); + StatisticsRecorder::FindHistogram(name, ®istered_histogram); + if (registered_histogram.get() != NULL && + registered_histogram.get() != histogram.get()) + histogram = registered_histogram; + } + + DCHECK(LINEAR_HISTOGRAM == histogram->histogram_type()); + DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); + + return histogram; +} + +scoped_refptr LinearHistogram::LinearHistogramFactoryGet( + const std::string& name, base::TimeDelta minimum, base::TimeDelta maximum, + size_t bucket_count) { + return LinearHistogramFactoryGet(name, minimum.InMilliseconds(), + maximum.InMilliseconds(), bucket_count); +} + +LinearHistogram::LinearHistogram(const std::string& name, Sample minimum, Sample maximum, size_t bucket_count) : Histogram(name, minimum >= 1 ? minimum : 1, maximum, bucket_count) { InitializeBucketRange(); DCHECK(ValidateBucketRanges()); } -LinearHistogram::LinearHistogram(const char* name, +LinearHistogram::LinearHistogram(const std::string& name, TimeDelta minimum, TimeDelta maximum, size_t bucket_count) : Histogram(name, minimum >= TimeDelta::FromMilliseconds(1) ? minimum : TimeDelta::FromMilliseconds(1), @@ -595,11 +665,61 @@ double LinearHistogram::GetBucketSize(Count current, size_t i) const { } //------------------------------------------------------------------------------ +// This section provides implementation for BooleanHistogram. +//------------------------------------------------------------------------------ + +scoped_refptr BooleanHistogram::BooleanHistogramFactoryGet( + const std::string& name) { + scoped_refptr histogram(NULL); + + if (StatisticsRecorder::FindHistogram(name, &histogram)) { + DCHECK(histogram.get() != NULL); + } else { + histogram = new BooleanHistogram(name); + scoped_refptr registered_histogram(NULL); + StatisticsRecorder::FindHistogram(name, ®istered_histogram); + if (registered_histogram.get() != NULL && + registered_histogram.get() != histogram.get()) + histogram = registered_histogram; + } + + DCHECK(BOOLEAN_HISTOGRAM == histogram->histogram_type()); + + return histogram; +} + +//------------------------------------------------------------------------------ // This section provides implementation for ThreadSafeHistogram. //------------------------------------------------------------------------------ -ThreadSafeHistogram::ThreadSafeHistogram(const char* name, Sample minimum, - Sample maximum, size_t bucket_count) +scoped_refptr ThreadSafeHistogram::ThreadSafeHistogramFactoryGet( + const std::string& name, Sample minimum, Sample maximum, + size_t bucket_count) { + scoped_refptr histogram(NULL); + + if (minimum <= 0) + minimum = 1; + if (maximum >= kSampleType_MAX) + maximum = kSampleType_MAX - 1; + + if (StatisticsRecorder::FindHistogram(name, &histogram)) { + DCHECK(histogram.get() != NULL); + } else { + histogram = new ThreadSafeHistogram(name, minimum, maximum, bucket_count); + scoped_refptr registered_histogram(NULL); + StatisticsRecorder::FindHistogram(name, ®istered_histogram); + if (registered_histogram.get() != NULL && + registered_histogram.get() != histogram.get()) + histogram = registered_histogram; + } + + DCHECK(THREAD_SAFE_HISTOGRAM == histogram->histogram_type()); + DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); + return histogram; +} + +ThreadSafeHistogram::ThreadSafeHistogram(const std::string& name, + Sample minimum, Sample maximum, size_t bucket_count) : Histogram(name, minimum, maximum, bucket_count), lock_() { } @@ -657,34 +777,22 @@ bool StatisticsRecorder::WasStarted() { return NULL != histograms_; } +// Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a +// reference, and we are called while in the Histogram constructor. In that +// scenario, a ref_ptr would have incremented the ref count when the histogram +// was passed to us, decremented it when we returned, and the instance would be +// destroyed before assignment (when value was returned by new). // static -bool StatisticsRecorder::Register(Histogram* histogram) { +void StatisticsRecorder::Register(Histogram* histogram) { if (!histograms_) - return false; + return; const std::string name = histogram->histogram_name(); AutoLock auto_lock(*lock_); - if (histograms_->end() != histograms_->find(name)) { - // Check to be sure it is compatible.... and if not, then do a CHECK() - return false; // This name is already registered. - } - (*histograms_)[name] = histogram; - return true; -} + DCHECK(histograms_->end() == histograms_->find(name)); -// static -void StatisticsRecorder::UnRegister(Histogram* histogram) { - if (!histograms_) - return; - const std::string name = histogram->histogram_name(); - AutoLock auto_lock(*lock_); - DCHECK(histograms_->end() != histograms_->find(name)); - histograms_->erase(name); - if (dump_on_exit_) { - std::string output; - histogram->WriteAscii(true, "\n", &output); - LOG(INFO) << output; - } + (*histograms_)[name] = histogram; + return; } // static @@ -743,17 +851,31 @@ void StatisticsRecorder::GetHistograms(Histograms* output) { } } -Histogram* StatisticsRecorder::GetHistogram(const std::string& query) { +// static +void StatisticsRecorder::GetHistogramsForRenderer(Histograms* output) { if (!histograms_) - return NULL; + return; AutoLock auto_lock(*lock_); for (HistogramMap::iterator it = histograms_->begin(); histograms_->end() != it; ++it) { - if (it->first.find(query) != std::string::npos) - return it->second; + scoped_refptr histogram = it->second; + if (!(histogram->flags() & kIPCSerializationSourceFlag)) + histogram->SetFlags(kIPCSerializationSourceFlag); + output->push_back(histogram); } - return NULL; +} + +bool StatisticsRecorder::FindHistogram(const std::string& name, + scoped_refptr* histogram) { + if (!histograms_) + return false; + AutoLock auto_lock(*lock_); + HistogramMap::iterator it = histograms_->find(name); + if (histograms_->end() == it) + return false; + *histogram = it->second; + return true; } // private static diff --git a/base/histogram.h b/base/histogram.h index 4d40c1b..0c94fc0 100644 --- a/base/histogram.h +++ b/base/histogram.h @@ -36,6 +36,8 @@ #include #include "base/lock.h" +#include "base/ref_counted.h" +#include "base/logging.h" #include "base/time.h" //------------------------------------------------------------------------------ @@ -43,47 +45,56 @@ // The first four macros use 50 buckets. #define HISTOGRAM_TIMES(name, sample) do { \ - static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ - base::TimeDelta::FromSeconds(10), 50); \ - counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), base::TimeDelta::FromMilliseconds(1), \ + base::TimeDelta::FromSeconds(10), 50); \ + counter->AddTime(sample); \ } while (0) #define HISTOGRAM_COUNTS(name, sample) do { \ - static Histogram counter((name), 1, 1000000, 50); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1, 1000000, 50); \ + counter->Add(sample); \ } while (0) #define HISTOGRAM_COUNTS_100(name, sample) do { \ - static Histogram counter((name), 1, 100, 50); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1, 100, 50); \ + counter->Add(sample); \ } while (0) #define HISTOGRAM_COUNTS_10000(name, sample) do { \ - static Histogram counter((name), 1, 10000, 50); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1, 10000, 50); \ + counter->Add(sample); \ } while (0) #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ - static Histogram counter((name), min, max, bucket_count); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), min, max, bucket_count); \ + counter->Add(sample); \ } while (0) #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) do { \ - static LinearHistogram counter((name), 1, 100, 101); \ - counter.Add(under_one_hundred); \ + static scoped_refptr counter = \ + LinearHistogram::LinearHistogramFactoryGet(\ + (name), 1, 100, 101); \ + counter->Add(under_one_hundred); \ } while (0) // For folks that need real specific times, use this to select a precise range // of times you want plotted, and the number of buckets you want used. #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ - static Histogram counter((name), min, max, bucket_count); \ - counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), min, max, bucket_count); \ + counter->AddTime(sample); \ } while (0) // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ - static Histogram counter((name), min, max, bucket_count); \ - if ((sample) < (max)) counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), min, max, bucket_count); \ + if ((sample) < (max)) counter->AddTime(sample); \ } while (0) //------------------------------------------------------------------------------ @@ -101,12 +112,14 @@ // be equal in number or fewer than the corresponding calls to Add(). #define ASSET_HISTOGRAM_COUNTS(name, sample) do { \ - static ThreadSafeHistogram counter((name), 1, 1000000, 50); \ + static scoped_refptr counter = \ + ThreadSafeHistogram::ThreadSafeHistogramFactoryGet(\ + (name), 1, 1000000, 50); \ if (0 == sample) break; \ if (sample >= 0) \ - counter.Add(sample); \ + counter->Add(sample); \ else\ - counter.Remove(-sample); \ + counter->Remove(-sample); \ } while (0) //------------------------------------------------------------------------------ @@ -150,92 +163,122 @@ static const int kUmaTargetedHistogramFlag = 0x1; -// This indicates the histogram is shadow copy of renderer histrogram -// constructed by unpick method and updated regularly from renderer upload -// of histograms. -static const int kRendererHistogramFlag = 1 << 4; +// This indicates the histogram is pickled to be sent across an IPC Channel. +// If we observe this flag during unpickle method, then we are running in a +// single process mode. +static const int kIPCSerializationSourceFlag = 1 << 4; + +// Some histograms aren't currently destroyed. Until such users properly +// decref those histograms, we will mark there histograms as planned to leak so +// that we can catch any user that directly tries to call delete "directly" +// rather than using the reference counting features that should take care of +// this. +// TODO(jar): Make this flag unnecessary! +static const int kPlannedLeakFlag = 1 << 5; #define UMA_HISTOGRAM_TIMES(name, sample) do { \ - static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ - base::TimeDelta::FromSeconds(10), 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), base::TimeDelta::FromMilliseconds(1), \ + base::TimeDelta::FromSeconds(10), 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->AddTime(sample); \ } while (0) #define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) do { \ - static Histogram counter((name), base::TimeDelta::FromMilliseconds(10), \ - base::TimeDelta::FromMinutes(3), 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), base::TimeDelta::FromMilliseconds(10), \ + base::TimeDelta::FromMinutes(3), 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->AddTime(sample); \ } while (0) // Use this macro when times can routinely be much longer than 10 seconds. #define UMA_HISTOGRAM_LONG_TIMES(name, sample) do { \ - static Histogram counter((name), base::TimeDelta::FromMilliseconds(1), \ - base::TimeDelta::FromHours(1), 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), base::TimeDelta::FromMilliseconds(1), \ + base::TimeDelta::FromHours(1), 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->AddTime(sample); \ } while (0) #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ - static Histogram counter((name), min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->AddTime(sample); \ } while (0) #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ - static Histogram counter((name), min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - if ((sample) < (max)) counter.AddTime(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + if ((sample) < (max)) counter->AddTime(sample); \ } while (0) #define UMA_HISTOGRAM_COUNTS(name, sample) do { \ - static Histogram counter((name), 1, 1000000, 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1, 1000000, 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } while (0) #define UMA_HISTOGRAM_COUNTS_100(name, sample) do { \ - static Histogram counter((name), 1, 100, 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1, 100, 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } while (0) #define UMA_HISTOGRAM_COUNTS_10000(name, sample) do { \ - static Histogram counter((name), 1, 10000, 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1, 10000, 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } while (0) #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ - static Histogram counter((name), min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } while (0) #define UMA_HISTOGRAM_MEMORY_KB(name, sample) do { \ - static Histogram counter((name), 1000, 500000, 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1000, 500000, 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } while (0) #define UMA_HISTOGRAM_MEMORY_MB(name, sample) do { \ - static Histogram counter((name), 1, 1000, 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = Histogram::HistogramFactoryGet(\ + (name), 1, 1000, 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } while (0) #define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) do { \ - static LinearHistogram counter((name), 1, 100, 101); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(under_one_hundred); \ + static scoped_refptr counter = \ + LinearHistogram::LinearHistogramFactoryGet(\ + (name), 1, 100, 101); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(under_one_hundred); \ } while (0) //------------------------------------------------------------------------------ class Pickle; +class Histogram; +class LinearHistogram; +class BooleanHistogram; +class ThreadSafeHistogram; + +namespace disk_cache { + class StatsHistogram; +}; // namespace disk_cache -class Histogram { + +class Histogram : public base::RefCountedThreadSafe { public: typedef int Sample; // Used for samples (and ranges of samples). typedef int Count; // Used to count samples in a bucket. @@ -246,11 +289,26 @@ class Histogram { static const int kHexRangePrintingFlag; + /* These enums are meant to facilitate deserialization of renderer histograms + into the browser. */ + enum ClassType { + HISTOGRAM, + LINEAR_HISTOGRAM, + BOOLEAN_HISTOGRAM, + THREAD_SAFE_HISTOGRAM, + NOT_VALID_IN_RENDERER + }; + enum BucketLayout { EXPONENTIAL, LINEAR }; + struct DescriptionPair { + Sample sample; + const char* description; // Null means end of a list of pairs. + }; + //---------------------------------------------------------------------------- // Statistic values, developed over the life of the histogram. @@ -288,14 +346,18 @@ class Histogram { int64 square_sum_; // sum of squares of samples. }; //---------------------------------------------------------------------------- - - Histogram(const char* name, Sample minimum, - Sample maximum, size_t bucket_count); - Histogram(const char* name, base::TimeDelta minimum, - base::TimeDelta maximum, size_t bucket_count); - virtual ~Histogram(); + // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit + // default underflow bucket. + static scoped_refptr HistogramFactoryGet(const std::string& name, + Sample minimum, Sample maximum, size_t bucket_count); + static scoped_refptr HistogramFactoryGet(const std::string& name, + base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count); void Add(int value); + + // This method is an interface, used only by BooleanHistogram. + virtual void AddBoolean(bool value) { DCHECK(false); } + // Accept a TimeDelta to increment. void AddTime(base::TimeDelta time) { Add(static_cast(time.InMilliseconds())); @@ -303,6 +365,13 @@ class Histogram { void AddSampleSet(const SampleSet& sample); + // This method is an interface, used only by ThreadSafeHistogram. + virtual void Remove(int value) { DCHECK(false); } + + // This method is an interface, used only by LinearHistogram. + virtual void SetRangeDescriptions(const DescriptionPair descriptions[]) + { DCHECK(false); } + // The following methods provide graphical histogram displays. void WriteHTMLGraph(std::string* output) const; void WriteAscii(bool graph_it, const std::string& newline, @@ -315,8 +384,6 @@ class Histogram { void ClearFlags(int flags) { flags_ &= ~flags; } int flags() const { return flags_; } - virtual BucketLayout histogram_type() const { return EXPONENTIAL; } - // Convenience methods for serializing/deserializing the histograms. // Histograms from Renderer process are serialized and sent to the browser. // Browser process reconstructs the histogram from the pickled version @@ -332,10 +399,10 @@ class Histogram { // browser process. static bool DeserializeHistogramInfo(const std::string& histogram_info); - //---------------------------------------------------------------------------- - // Accessors for serialization and testing. + // Accessors for factory constuction, serialization and testing. //---------------------------------------------------------------------------- + virtual ClassType histogram_type() const { return HISTOGRAM; } const std::string histogram_name() const { return histogram_name_; } Sample declared_min() const { return declared_min_; } Sample declared_max() const { return declared_max_; } @@ -345,7 +412,28 @@ class Histogram { // Override with atomic/locked snapshot if needed. virtual void SnapshotSample(SampleSet* sample) const; + virtual bool HasConstructorArguments(Sample minimum, Sample maximum, + size_t bucket_count) { + return ((minimum == declared_min_) && (maximum == declared_max_) && + (bucket_count == bucket_count_)); + } + + virtual bool HasConstructorTimeDeltaArguments(base::TimeDelta minimum, + base::TimeDelta maximum, size_t bucket_count) { + return ((minimum.InMilliseconds() == declared_min_) && + (maximum.InMilliseconds() == declared_max_) && + (bucket_count == bucket_count_)); + } + protected: + friend class base::RefCountedThreadSafe; + Histogram(const std::string& name, Sample minimum, + Sample maximum, size_t bucket_count); + Histogram(const std::string& name, base::TimeDelta minimum, + base::TimeDelta maximum, size_t bucket_count); + + virtual ~Histogram(); + // Method to override to skip the display of the i'th bucket if it's empty. virtual bool PrintEmptyBucket(size_t index) const { return true; } @@ -434,9 +522,6 @@ class Histogram { // sample. SampleSet sample_; - // Indicate if successfully registered. - bool registered_; - DISALLOW_COPY_AND_ASSIGN(Histogram); }; @@ -446,24 +531,30 @@ class Histogram { // buckets. class LinearHistogram : public Histogram { public: - struct DescriptionPair { - Sample sample; - const char* description; // Null means end of a list of pairs. - }; - LinearHistogram(const char* name, Sample minimum, - Sample maximum, size_t bucket_count); - - LinearHistogram(const char* name, base::TimeDelta minimum, - base::TimeDelta maximum, size_t bucket_count); - ~LinearHistogram() {} + virtual ClassType histogram_type() const { return LINEAR_HISTOGRAM; } // Store a list of number/text values for use in rendering the histogram. // The last element in the array has a null in its "description" slot. - void SetRangeDescriptions(const DescriptionPair descriptions[]); + virtual void SetRangeDescriptions(const DescriptionPair descriptions[]); - virtual BucketLayout histogram_type() const { return LINEAR; } + /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit + default underflow bucket. */ + static scoped_refptr LinearHistogramFactoryGet( + const std::string& name, Sample minimum, Sample maximum, + size_t bucket_count); + static scoped_refptr LinearHistogramFactoryGet( + const std::string& name, base::TimeDelta minimum, + base::TimeDelta maximum, size_t bucket_count); protected: + LinearHistogram(const std::string& name, Sample minimum, + Sample maximum, size_t bucket_count); + + LinearHistogram(const std::string& name, base::TimeDelta minimum, + base::TimeDelta maximum, size_t bucket_count); + + virtual ~LinearHistogram() {} + // Initialize ranges_ mapping. virtual void InitializeBucketRange(); virtual double GetBucketSize(Count current, size_t i) const; @@ -491,13 +582,18 @@ class LinearHistogram : public Histogram { // BooleanHistogram is a histogram for booleans. class BooleanHistogram : public LinearHistogram { public: - explicit BooleanHistogram(const char* name) - : LinearHistogram(name, 0, 2, 3) { - } + static scoped_refptr BooleanHistogramFactoryGet( + const std::string& name); + + virtual ClassType histogram_type() const { return BOOLEAN_HISTOGRAM; } - void AddBoolean(bool value) { Add(value ? 1 : 0); } + virtual void AddBoolean(bool value) { Add(value ? 1 : 0); } private: + explicit BooleanHistogram(const std::string& name) + : LinearHistogram(name, 1, 2, 3) { + } + DISALLOW_COPY_AND_ASSIGN(BooleanHistogram); }; @@ -507,13 +603,21 @@ class BooleanHistogram : public LinearHistogram { class ThreadSafeHistogram : public Histogram { public: - ThreadSafeHistogram(const char* name, Sample minimum, - Sample maximum, size_t bucket_count); + static scoped_refptr ThreadSafeHistogramFactoryGet( + const std::string& name, Sample minimum, Sample maximum, + size_t bucket_count); + + virtual ClassType histogram_type() const { return THREAD_SAFE_HISTOGRAM; } // Provide the analog to Add() - void Remove(int value); + virtual void Remove(int value); protected: + ThreadSafeHistogram(const std::string& name, Sample minimum, + Sample maximum, size_t bucket_count); + + virtual ~ThreadSafeHistogram() {} + // Provide locked versions to get precise counts. virtual void Accumulate(Sample value, Count count, size_t index); @@ -532,7 +636,7 @@ class ThreadSafeHistogram : public Histogram { class StatisticsRecorder { public: - typedef std::vector Histograms; + typedef std::vector > Histograms; StatisticsRecorder(); @@ -542,10 +646,7 @@ class StatisticsRecorder { static bool WasStarted(); // Register, or add a new histogram to the collection of statistics. - // Return true if registered. - static bool Register(Histogram* histogram); - // Unregister, or remove, a histogram from the collection of statistics. - static void UnRegister(Histogram* histogram); + static void Register(Histogram* histogram); // Methods for printing histograms. Only histograms which have query as // a substring are written to output (an empty string will process all @@ -556,8 +657,16 @@ class StatisticsRecorder { // Method for extracting histograms which were marked for use by UMA. static void GetHistograms(Histograms* output); - // Find a histogram by name. This method is thread safe. - static Histogram* GetHistogram(const std::string& query); + // Method for extracting histograms for renderer and the histogram's flag is + // set to kIPCSerializationSourceFlag. + static void GetHistogramsForRenderer(Histograms* output); + + // Find a histogram by name. It matches the exact name. This method is thread + // safe. + static bool FindHistogram(const std::string& query, + scoped_refptr* histogram); + + static bool dump_on_exit() { return dump_on_exit_; } static void set_dump_on_exit(bool enable) { dump_on_exit_ = enable; } @@ -570,7 +679,7 @@ class StatisticsRecorder { private: // We keep all registered histograms in a map, from name to histogram. - typedef std::map HistogramMap; + typedef std::map > HistogramMap; static HistogramMap* histograms_; diff --git a/base/histogram_unittest.cc b/base/histogram_unittest.cc index 3f2ed4c..4d5de51 100644 --- a/base/histogram_unittest.cc +++ b/base/histogram_unittest.cc @@ -19,11 +19,17 @@ class HistogramTest : public testing::Test { // Check for basic syntax and use. TEST(HistogramTest, StartupShutdownTest) { // Try basic construction - Histogram histogram("TestHistogram", 1, 1000, 10); - Histogram histogram1("Test1Histogram", 1, 1000, 10); - - LinearHistogram linear_histogram("TestLinearHistogram", 1, 1000, 10); - LinearHistogram linear_histogram1("Test1LinearHistogram", 1, 1000, 10); + scoped_refptr histogram = + Histogram::HistogramFactoryGet("TestHistogram", 1, 1000, 10); + scoped_refptr histogram1 = + Histogram::HistogramFactoryGet("Test1Histogram", 1, 1000, 10); + + scoped_refptr linear_histogram = + LinearHistogram::LinearHistogramFactoryGet("TestLinearHistogram", 1, 1000, + 10); + scoped_refptr linear_histogram1 = + LinearHistogram::LinearHistogramFactoryGet("Test1LinearHistogram", 1, + 1000, 10); // Use standard macros (but with fixed samples) HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1)); @@ -57,17 +63,23 @@ TEST(HistogramTest, RecordedStartupTest) { EXPECT_EQ(0U, histograms.size()); // Try basic construction - Histogram histogram("TestHistogram", 1, 1000, 10); + scoped_refptr histogram = + Histogram::HistogramFactoryGet("TestHistogram", 1, 1000, 10); histograms.clear(); StatisticsRecorder::GetHistograms(&histograms); // Load up lists EXPECT_EQ(1U, histograms.size()); - Histogram histogram1("Test1Histogram", 1, 1000, 10); + scoped_refptr histogram1 = + Histogram::HistogramFactoryGet("Test1Histogram", 1, 1000, 10); histograms.clear(); StatisticsRecorder::GetHistograms(&histograms); // Load up lists EXPECT_EQ(2U, histograms.size()); - LinearHistogram linear_histogram("TestLinearHistogram", 1, 1000, 10); - LinearHistogram linear_histogram1("Test1LinearHistogram", 1, 1000, 10); + scoped_refptr linear_histogram = + LinearHistogram::LinearHistogramFactoryGet( + "TestLinearHistogram", 1, 1000, 10); + scoped_refptr linear_histogram1 = + LinearHistogram::LinearHistogramFactoryGet( + "Test1LinearHistogram", 1, 1000, 10); histograms.clear(); StatisticsRecorder::GetHistograms(&histograms); // Load up lists EXPECT_EQ(4U, histograms.size()); @@ -102,55 +114,62 @@ TEST(HistogramTest, RangeTest) { recorder.GetHistograms(&histograms); EXPECT_EQ(0U, histograms.size()); - Histogram histogram("Histogram", 1, 64, 8); // As mentioned in header file. + scoped_refptr histogram = Histogram::HistogramFactoryGet( + "Histogram", 1, 64, 8); // As mentioned in header file. // Check that we got a nice exponential when there was enough rooom. - EXPECT_EQ(0, histogram.ranges(0)); + EXPECT_EQ(0, histogram->ranges(0)); int power_of_2 = 1; for (int i = 1; i < 8; i++) { - EXPECT_EQ(power_of_2, histogram.ranges(i)); + EXPECT_EQ(power_of_2, histogram->ranges(i)); power_of_2 *= 2; } - EXPECT_EQ(INT_MAX, histogram.ranges(8)); + EXPECT_EQ(INT_MAX, histogram->ranges(8)); - Histogram short_histogram("Histogram Shortened", 1, 7, 8); + scoped_refptr short_histogram = + Histogram::HistogramFactoryGet("Histogram Shortened", 1, 7, 8); // Check that when the number of buckets is short, we get a linear histogram // for lack of space to do otherwise. for (int i = 0; i < 8; i++) - EXPECT_EQ(i, short_histogram.ranges(i)); - EXPECT_EQ(INT_MAX, short_histogram.ranges(8)); + EXPECT_EQ(i, short_histogram->ranges(i)); + EXPECT_EQ(INT_MAX, short_histogram->ranges(8)); - LinearHistogram linear_histogram("Linear", 1, 7, 8); + scoped_refptr linear_histogram = + LinearHistogram::LinearHistogramFactoryGet("Linear", 1, 7, 8); // We also get a nice linear set of bucket ranges when we ask for it for (int i = 0; i < 8; i++) - EXPECT_EQ(i, linear_histogram.ranges(i)); - EXPECT_EQ(INT_MAX, linear_histogram.ranges(8)); + EXPECT_EQ(i, linear_histogram->ranges(i)); + EXPECT_EQ(INT_MAX, linear_histogram->ranges(8)); - LinearHistogram linear_broad_histogram("Linear widened", 2, 14, 8); + scoped_refptr linear_broad_histogram = + LinearHistogram::LinearHistogramFactoryGet( + "Linear widened", 2, 14, 8); // ...but when the list has more space, then the ranges naturally spread out. for (int i = 0; i < 8; i++) - EXPECT_EQ(2 * i, linear_broad_histogram.ranges(i)); - EXPECT_EQ(INT_MAX, linear_broad_histogram.ranges(8)); + EXPECT_EQ(2 * i, linear_broad_histogram->ranges(i)); + EXPECT_EQ(INT_MAX, linear_broad_histogram->ranges(8)); - ThreadSafeHistogram threadsafe_histogram("ThreadSafe", 1, 32, 15); + scoped_refptr threadsafe_histogram = + ThreadSafeHistogram::ThreadSafeHistogramFactoryGet("ThreadSafe", 1, 32, + 15); // When space is a little tight, we transition from linear to exponential. // This is what happens in both the basic histogram, and the threadsafe // variant (which is derived). - EXPECT_EQ(0, threadsafe_histogram.ranges(0)); - EXPECT_EQ(1, threadsafe_histogram.ranges(1)); - EXPECT_EQ(2, threadsafe_histogram.ranges(2)); - EXPECT_EQ(3, threadsafe_histogram.ranges(3)); - EXPECT_EQ(4, threadsafe_histogram.ranges(4)); - EXPECT_EQ(5, threadsafe_histogram.ranges(5)); - EXPECT_EQ(6, threadsafe_histogram.ranges(6)); - EXPECT_EQ(7, threadsafe_histogram.ranges(7)); - EXPECT_EQ(9, threadsafe_histogram.ranges(8)); - EXPECT_EQ(11, threadsafe_histogram.ranges(9)); - EXPECT_EQ(14, threadsafe_histogram.ranges(10)); - EXPECT_EQ(17, threadsafe_histogram.ranges(11)); - EXPECT_EQ(21, threadsafe_histogram.ranges(12)); - EXPECT_EQ(26, threadsafe_histogram.ranges(13)); - EXPECT_EQ(32, threadsafe_histogram.ranges(14)); - EXPECT_EQ(INT_MAX, threadsafe_histogram.ranges(15)); + EXPECT_EQ(0, threadsafe_histogram->ranges(0)); + EXPECT_EQ(1, threadsafe_histogram->ranges(1)); + EXPECT_EQ(2, threadsafe_histogram->ranges(2)); + EXPECT_EQ(3, threadsafe_histogram->ranges(3)); + EXPECT_EQ(4, threadsafe_histogram->ranges(4)); + EXPECT_EQ(5, threadsafe_histogram->ranges(5)); + EXPECT_EQ(6, threadsafe_histogram->ranges(6)); + EXPECT_EQ(7, threadsafe_histogram->ranges(7)); + EXPECT_EQ(9, threadsafe_histogram->ranges(8)); + EXPECT_EQ(11, threadsafe_histogram->ranges(9)); + EXPECT_EQ(14, threadsafe_histogram->ranges(10)); + EXPECT_EQ(17, threadsafe_histogram->ranges(11)); + EXPECT_EQ(21, threadsafe_histogram->ranges(12)); + EXPECT_EQ(26, threadsafe_histogram->ranges(13)); + EXPECT_EQ(32, threadsafe_histogram->ranges(14)); + EXPECT_EQ(INT_MAX, threadsafe_histogram->ranges(15)); recorder.GetHistograms(&histograms); EXPECT_EQ(5U, histograms.size()); @@ -159,21 +178,22 @@ TEST(HistogramTest, RangeTest) { // Make sure histogram handles out-of-bounds data gracefully. TEST(HistogramTest, BoundsTest) { const size_t kBucketCount = 50; - Histogram histogram("Bounded", 10, 100, kBucketCount); + scoped_refptr histogram = Histogram::HistogramFactoryGet("Bounded", + 10, 100, kBucketCount); // Put two samples "out of bounds" above and below. - histogram.Add(5); - histogram.Add(-50); + histogram->Add(5); + histogram->Add(-50); - histogram.Add(100); - histogram.Add(10000); + histogram->Add(100); + histogram->Add(10000); // Verify they landed in the underflow, and overflow buckets. Histogram::SampleSet sample; - histogram.SnapshotSample(&sample); + histogram->SnapshotSample(&sample); EXPECT_EQ(2, sample.counts(0)); EXPECT_EQ(0, sample.counts(1)); - size_t array_size = histogram.bucket_count(); + size_t array_size = histogram->bucket_count(); EXPECT_EQ(kBucketCount, array_size); EXPECT_EQ(0, sample.counts(array_size - 2)); EXPECT_EQ(2, sample.counts(array_size - 1)); @@ -181,31 +201,32 @@ TEST(HistogramTest, BoundsTest) { // Check to be sure samples land as expected is "correct" buckets. TEST(HistogramTest, BucketPlacementTest) { - Histogram histogram("Histogram", 1, 64, 8); // As mentioned in header file. + scoped_refptr histogram = Histogram::HistogramFactoryGet( + "Histogram", 1, 64, 8); // As mentioned in header file. // Check that we got a nice exponential since there was enough rooom. - EXPECT_EQ(0, histogram.ranges(0)); + EXPECT_EQ(0, histogram->ranges(0)); int power_of_2 = 1; for (int i = 1; i < 8; i++) { - EXPECT_EQ(power_of_2, histogram.ranges(i)); + EXPECT_EQ(power_of_2, histogram->ranges(i)); power_of_2 *= 2; } - EXPECT_EQ(INT_MAX, histogram.ranges(8)); + EXPECT_EQ(INT_MAX, histogram->ranges(8)); // Add i+1 samples to the i'th bucket. - histogram.Add(0); + histogram->Add(0); power_of_2 = 1; for (int i = 1; i < 8; i++) { for (int j = 0; j <= i; j++) - histogram.Add(power_of_2); + histogram->Add(power_of_2); power_of_2 *= 2; } // Leave overflow bucket empty. // Check to see that the bucket counts reflect our additions. Histogram::SampleSet sample; - histogram.SnapshotSample(&sample); - EXPECT_EQ(INT_MAX, histogram.ranges(8)); + histogram->SnapshotSample(&sample); + EXPECT_EQ(INT_MAX, histogram->ranges(8)); for (int i = 0; i < 8; i++) EXPECT_EQ(i + 1, sample.counts(i)); } diff --git a/base/message_loop.cc b/base/message_loop.cc index ddca7dbf..64913e5 100644 --- a/base/message_loop.cc +++ b/base/message_loop.cc @@ -531,11 +531,12 @@ void MessageLoop::StartHistogrammer() { if (enable_histogrammer_ && !message_histogram_.get() && StatisticsRecorder::WasStarted()) { DCHECK(!thread_name_.empty()); - message_histogram_.reset( - new LinearHistogram(("MsgLoop:" + thread_name_).c_str(), + message_histogram_ = + LinearHistogram::LinearHistogramFactoryGet( + ("MsgLoop:" + thread_name_), kLeastNonZeroMessageId, kMaxMessageId, - kNumberOfDistinctMessagesDisplayed)); + kNumberOfDistinctMessagesDisplayed); message_histogram_->SetFlags(message_histogram_->kHexRangePrintingFlag); message_histogram_->SetRangeDescriptions(event_descriptions_); } diff --git a/base/message_loop.h b/base/message_loop.h index ff4531c..e45adde 100644 --- a/base/message_loop.h +++ b/base/message_loop.h @@ -397,7 +397,7 @@ class MessageLoop : public base::MessagePump::Delegate { std::string thread_name_; // A profiling histogram showing the counts of various messages and events. - scoped_ptr message_histogram_; + scoped_refptr message_histogram_; // A null terminated list which creates an incoming_queue of tasks that are // aquired under a mutex for processing on this instance's thread. These tasks diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm index 48bef43..3aa31013 100644 --- a/chrome/browser/chrome_browser_application_mac.mm +++ b/chrome/browser/chrome_browser_application_mac.mm @@ -91,10 +91,11 @@ size_t BinForException(NSException* exception) { } void RecordExceptionWithUma(NSException* exception) { - static LinearHistogram histogram("OSX.NSException", 0, kUnknownNSException, - kUnknownNSException + 1); - histogram.SetFlags(kUmaTargetedHistogramFlag); - histogram.Add(BinForException(exception)); + static scoped_refptr histogram = + LinearHistogram::LinearHistogramFactoryGet("OSX.NSException", + 0, kUnknownNSException, kUnknownNSException + 1); + histogram->SetFlags(kUmaTargetedHistogramFlag); + histogram->Add(BinForException(exception)); } void Terminate() { diff --git a/chrome/browser/diagnostics/sqlite_diagnostics.cc b/chrome/browser/diagnostics/sqlite_diagnostics.cc index f3ca31d..b266002 100644 --- a/chrome/browser/diagnostics/sqlite_diagnostics.cc +++ b/chrome/browser/diagnostics/sqlite_diagnostics.cc @@ -43,9 +43,11 @@ class BasicSqliteErrrorHandler : public sql::ErrorDelegate { static void RecordErrorInHistogram(int error) { // The histogram values from sqlite result codes go currently from 1 to // 26 currently but 50 gives them room to grow. - static LinearHistogram histogram(kHistogramNames[unique], 1, 50, 51); - histogram.SetFlags(kUmaTargetedHistogramFlag); - histogram.Add(error); + static scoped_refptr histogram = + LinearHistogram::LinearHistogramFactoryGet(kHistogramNames[unique], 1, + 50, 51); + histogram->SetFlags(kUmaTargetedHistogramFlag); + histogram->Add(error); } }; diff --git a/chrome/browser/jankometer.cc b/chrome/browser/jankometer.cc index 32b42ca..10d2f14 100644 --- a/chrome/browser/jankometer.cc +++ b/chrome/browser/jankometer.cc @@ -91,13 +91,15 @@ class JankObserver : public base::RefCountedThreadSafe, : MaxMessageDelay_(excessive_duration), slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name), queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name), - process_times_((std::string("Chrome.ProcMsgL ") + - thread_name).c_str(), 1, 3600000, 50), - total_times_((std::string("Chrome.TotalMsgL ") + - thread_name).c_str(), 1, 3600000, 50), total_time_watchdog_(excessive_duration, thread_name, watchdog_enable) { - process_times_.SetFlags(kUmaTargetedHistogramFlag); - total_times_.SetFlags(kUmaTargetedHistogramFlag); + process_times_ = Histogram::HistogramFactoryGet( + (std::string("Chrome.ProcMsgL ") + thread_name), + 1, 3600000, 50); + total_times_ = Histogram::HistogramFactoryGet( + (std::string("Chrome.TotalMsgL ") + thread_name), + 1, 3600000, 50); + process_times_->SetFlags(kUmaTargetedHistogramFlag); + total_times_->SetFlags(kUmaTargetedHistogramFlag); } // Attaches the observer to the current thread's message loop. You can only @@ -137,8 +139,8 @@ class JankObserver : public base::RefCountedThreadSafe, TimeTicks now = TimeTicks::Now(); if (begin_process_message_ != TimeTicks()) { TimeDelta processing_time = now - begin_process_message_; - process_times_.AddTime(processing_time); - total_times_.AddTime(queueing_time_ + processing_time); + process_times_->AddTime(processing_time); + total_times_->AddTime(queueing_time_ + processing_time); } if (now - begin_process_message_ > TimeDelta::FromMilliseconds(kMaxMessageProcessingMs)) { @@ -208,8 +210,8 @@ class JankObserver : public base::RefCountedThreadSafe, // Counters for the two types of jank we measure. StatsCounter slow_processing_counter_; // Messages with long processing time. StatsCounter queueing_delay_counter_; // Messages with long queueing delay. - Histogram process_times_; // Time spent processing task. - Histogram total_times_; // Total of queueing plus processing time. + scoped_refptr process_times_; // Time spent processing task. + scoped_refptr total_times_; // Total queueing plus processing. JankWatchdog total_time_watchdog_; // Watching for excessive total_time. DISALLOW_EVIL_CONSTRUCTORS(JankObserver); diff --git a/chrome/browser/net/dns_host_info.cc b/chrome/browser/net/dns_host_info.cc index 63eae34..755f54d 100644 --- a/chrome/browser/net/dns_host_info.cc +++ b/chrome/browser/net/dns_host_info.cc @@ -104,10 +104,11 @@ void DnsHostInfo::RemoveFromQueue() { } // Make a custom linear histogram for the region from 0 to boundary. const size_t kBucketCount = 52; - static LinearHistogram histogram("DNS.QueueRecycledUnder2", TimeDelta(), - kBoundary, kBucketCount); - histogram.SetFlags(kUmaTargetedHistogramFlag); - histogram.AddTime(queue_duration_); + static scoped_refptr histogram = + LinearHistogram::LinearHistogramFactoryGet("DNS.QueueRecycledUnder2", + TimeDelta(), kBoundary, kBucketCount); + histogram->SetFlags(kUmaTargetedHistogramFlag); + histogram->AddTime(queue_duration_); } void DnsHostInfo::SetPendingDeleteState() { diff --git a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc index 1dfa3d6..8d03b6f 100644 --- a/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc +++ b/chrome/browser/net/websocket_experiment/websocket_experiment_runner.cc @@ -28,31 +28,36 @@ static const int kWebSocketTimeSec = 10; static const int kTimeBucketCount = 50; // TODO(ukai): Use new thread-safe-reference-counted Histograms. -#define UPDATE_HISTOGRAM(name, sample, min, max, bucket_count) do { \ - switch (task_state_) { \ - case STATE_RUN_WS: \ - { \ - static LinearHistogram counter( \ - "WebSocketExperiment.Basic." name, min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ +#define UPDATE_HISTOGRAM(name, sample, min, max, bucket_count) do { \ + switch (task_state_) { \ + case STATE_RUN_WS: \ + { \ + static scoped_refptr counter = \ + LinearHistogram::LinearHistogramFactoryGet(\ + "WebSocketExperiment.Basic." name, \ + min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } \ break; \ case STATE_RUN_WSS: \ { \ - static LinearHistogram counter( \ - "WebSocketExperiment.Secure." name, min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = \ + LinearHistogram::LinearHistogramFactoryGet(\ + "WebSocketExperiment.Secure." name, \ + min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } \ break; \ case STATE_RUN_WS_NODEFAULT_PORT: \ { \ - static LinearHistogram counter( \ - "WebSocketExperiment.NoDefaultPort." name, \ - min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = \ + LinearHistogram::LinearHistogramFactoryGet(\ + "WebSocketExperiment.NoDefaultPort." name, \ + min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } \ break; \ default: \ @@ -61,31 +66,36 @@ static const int kTimeBucketCount = 50; } \ } while (0) -#define UPDATE_HISTOGRAM_TIMES(name, sample, min, max, bucket_count) do { \ +#define UPDATE_HISTOGRAM_TIMES(name, sample, min, max, bucket_count) do { \ switch (task_state_) { \ case STATE_RUN_WS: \ { \ - static Histogram counter( \ - "WebSocketExperiment.Basic." name, min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.AddTime(sample); \ + static scoped_refptr counter = \ + Histogram::HistogramFactoryGet(\ + "WebSocketExperiment.Basic." name, \ + min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->AddTime(sample); \ } \ break; \ case STATE_RUN_WSS: \ { \ - static Histogram counter( \ - "WebSocketExperiment.Secure." name, min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.AddTime(sample); \ + static scoped_refptr counter = \ + Histogram::HistogramFactoryGet(\ + "WebSocketExperiment.Secure." name, \ + min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->AddTime(sample); \ } \ break; \ case STATE_RUN_WS_NODEFAULT_PORT: \ { \ - static Histogram counter( \ - "WebSocketExperiment.NoDefaultPort." name, \ - min, max, bucket_count); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.AddTime(sample); \ + static scoped_refptr counter = \ + Histogram::HistogramFactoryGet(\ + "WebSocketExperiment.NoDefaultPort." name, \ + min, max, bucket_count); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->AddTime(sample); \ } \ break; \ default: \ diff --git a/chrome/browser/renderer_host/buffered_resource_handler.cc b/chrome/browser/renderer_host/buffered_resource_handler.cc index f3ca82f..6cf4430 100644 --- a/chrome/browser/renderer_host/buffered_resource_handler.cc +++ b/chrome/browser/renderer_host/buffered_resource_handler.cc @@ -30,18 +30,23 @@ const int kMaxBytesToSniff = 512; void RecordSnifferMetrics(bool sniffing_blocked, bool we_would_like_to_sniff, const std::string& mime_type) { - static BooleanHistogram nosniff_usage("nosniff.usage"); - nosniff_usage.SetFlags(kUmaTargetedHistogramFlag); - nosniff_usage.AddBoolean(sniffing_blocked); + static scoped_refptr nosniff_usage = + BooleanHistogram::BooleanHistogramFactoryGet("nosniff.usage"); + nosniff_usage->SetFlags(kUmaTargetedHistogramFlag); + nosniff_usage->AddBoolean(sniffing_blocked); if (sniffing_blocked) { - static BooleanHistogram nosniff_otherwise("nosniff.otherwise"); - nosniff_otherwise.SetFlags(kUmaTargetedHistogramFlag); - nosniff_otherwise.AddBoolean(we_would_like_to_sniff); - - static BooleanHistogram nosniff_empty_mime_type("nosniff.empty_mime_type"); - nosniff_empty_mime_type.SetFlags(kUmaTargetedHistogramFlag); - nosniff_empty_mime_type.AddBoolean(mime_type.empty()); + static scoped_refptr nosniff_otherwise = + BooleanHistogram::BooleanHistogramFactoryGet( + "nosniff.otherwise"); + nosniff_otherwise->SetFlags(kUmaTargetedHistogramFlag); + nosniff_otherwise->AddBoolean(we_would_like_to_sniff); + + static scoped_refptr nosniff_empty_mime_type = + BooleanHistogram::BooleanHistogramFactoryGet( + "nosniff.empty_mime_type"); + nosniff_empty_mime_type->SetFlags(kUmaTargetedHistogramFlag); + nosniff_empty_mime_type->AddBoolean(mime_type.empty()); } } diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc index a96146ce..3f559c0 100644 --- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc +++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc @@ -69,9 +69,11 @@ enum SafeBrowsingBlockingPageEvent { }; void RecordSafeBrowsingBlockingPageStats(SafeBrowsingBlockingPageEvent event) { - static LinearHistogram histogram("interstial.safe_browsing", 0, 2, 3); - histogram.SetFlags(kUmaTargetedHistogramFlag); - histogram.Add(event); + static scoped_refptr histogram = + LinearHistogram::LinearHistogramFactoryGet("interstial.safe_browsing", + 1, 2, 3); + histogram->SetFlags(kUmaTargetedHistogramFlag); + histogram->Add(event); } } // namespace diff --git a/chrome/browser/ssl/ssl_blocking_page.cc b/chrome/browser/ssl/ssl_blocking_page.cc index 2de2d58c..d0f3d6a 100644 --- a/chrome/browser/ssl/ssl_blocking_page.cc +++ b/chrome/browser/ssl/ssl_blocking_page.cc @@ -34,9 +34,11 @@ enum SSLBlockingPageEvent { }; void RecordSSLBlockingPageStats(SSLBlockingPageEvent event) { - static LinearHistogram histogram("interstial.ssl", 0, 2, 3); - histogram.SetFlags(kUmaTargetedHistogramFlag); - histogram.Add(event); + static scoped_refptr histogram = + LinearHistogram::LinearHistogramFactoryGet( + "interstial.ssl", 1, 2, 3); + histogram->SetFlags(kUmaTargetedHistogramFlag); + histogram->Add(event); } } // namespace diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc index 4cd9c6b..570b9a3 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -450,11 +450,12 @@ void ProfileSyncService::RemoveObserver(Observer* observer) { } void ProfileSyncService::SyncEvent(SyncEventCodes code) { - static LinearHistogram histogram("Sync.EventCodes", MIN_SYNC_EVENT_CODE, - MAX_SYNC_EVENT_CODE - 1, - MAX_SYNC_EVENT_CODE); - histogram.SetFlags(kUmaTargetedHistogramFlag); - histogram.Add(code); + static scoped_refptr histogram = + LinearHistogram::LinearHistogramFactoryGet("Sync.EventCodes", + MIN_SYNC_EVENT_CODE + 1, MAX_SYNC_EVENT_CODE - 1, + MAX_SYNC_EVENT_CODE); + histogram->SetFlags(kUmaTargetedHistogramFlag); + histogram->Add(code); } bool ProfileSyncService::IsSyncEnabled() { diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc index a4b36a6..d22f52a0 100644 --- a/chrome/renderer/render_thread.cc +++ b/chrome/renderer/render_thread.cc @@ -482,11 +482,17 @@ void RenderThread::SetCacheMode(bool enabled) { static void* CreateHistogram( const char *name, int min, int max, size_t buckets) { - Histogram* histogram = new Histogram(name, min, max, buckets); - if (histogram) { - histogram->SetFlags(kUmaTargetedHistogramFlag); - } - return histogram; + if (min <= 0) + min = 1; + scoped_refptr histogram = + Histogram::HistogramFactoryGet(name, min, max, buckets); + // We verify this was not being destructed by setting a novel "PlannedLeak" + // flag and watching out for the flag in the destructor. + histogram->SetFlags(kUmaTargetedHistogramFlag | kPlannedLeakFlag); + // We'll end up leaking these histograms, unless there is some code hiding in + // there to do the dec-ref. + histogram->AddRef(); + return histogram.get(); } static void AddHistogramSample(void* hist, int sample) { diff --git a/net/base/connection_type_histograms.cc b/net/base/connection_type_histograms.cc index 6e4a929..d200bde 100644 --- a/net/base/connection_type_histograms.cc +++ b/net/base/connection_type_histograms.cc @@ -22,22 +22,24 @@ namespace net { // expansion. void UpdateConnectionTypeHistograms(ConnectionType type) { static bool had_connection_type[NUM_OF_CONNECTION_TYPES]; - static LinearHistogram counter1("Net.HadConnectionType", - 1, NUM_OF_CONNECTION_TYPES, - NUM_OF_CONNECTION_TYPES + 1); - static LinearHistogram counter2("Net.ConnectionTypeCount", - 1, NUM_OF_CONNECTION_TYPES, - NUM_OF_CONNECTION_TYPES + 1); + static scoped_refptr counter1 = + LinearHistogram::LinearHistogramFactoryGet("Net.HadConnectionType", + 1, NUM_OF_CONNECTION_TYPES, + NUM_OF_CONNECTION_TYPES + 1); + static scoped_refptr counter2 = + LinearHistogram::LinearHistogramFactoryGet("Net.ConnectionTypeCount", + 1, NUM_OF_CONNECTION_TYPES, + NUM_OF_CONNECTION_TYPES + 1); if (type >= 0 && type < NUM_OF_CONNECTION_TYPES) { if (!had_connection_type[type]) { had_connection_type[type] = true; - counter1.SetFlags(kUmaTargetedHistogramFlag); - counter1.Add(type); + counter1->SetFlags(kUmaTargetedHistogramFlag); + counter1->Add(type); } } - counter2.SetFlags(kUmaTargetedHistogramFlag); - counter2.Add(type); + counter2->SetFlags(kUmaTargetedHistogramFlag); + counter2->Add(type); } } // namespace net diff --git a/net/base/mime_sniffer.cc b/net/base/mime_sniffer.cc index 07feb33..211cf8c 100644 --- a/net/base/mime_sniffer.cc +++ b/net/base/mime_sniffer.cc @@ -99,18 +99,6 @@ #include "googleurl/src/gurl.h" #include "net/base/mime_util.h" -namespace { - -class SnifferHistogram : public LinearHistogram { - public: - SnifferHistogram(const char* name, int array_size) - : LinearHistogram(name, 0, array_size - 1, array_size) { - SetFlags(kUmaTargetedHistogramFlag); - } -}; - -} // namespace - namespace net { // We aren't interested in looking at more than 512 bytes of content @@ -218,6 +206,15 @@ static const MagicNumber kSniffableTags[] = { MAGIC_HTML_TAG("p") // Mozilla }; +static scoped_refptr UMASnifferHistogramGet(const char* name, + int array_size) { + scoped_refptr counter = + LinearHistogram::LinearHistogramFactoryGet( + name, 1, array_size - 1, array_size); + counter->SetFlags(kUmaTargetedHistogramFlag); + return counter; +} + static bool MatchMagicNumber(const char* content, size_t size, const MagicNumber* magic_entry, std::string* result) { @@ -273,22 +270,24 @@ static bool SniffForHTML(const char* content, size_t size, if (!IsAsciiWhitespace(*pos)) break; } - static SnifferHistogram counter("mime_sniffer.kSniffableTags2", - arraysize(kSniffableTags)); + static scoped_refptr counter = + UMASnifferHistogramGet("mime_sniffer.kSniffableTags2", + arraysize(kSniffableTags)); // |pos| now points to first non-whitespace character (or at end). return CheckForMagicNumbers(pos, end - pos, kSniffableTags, arraysize(kSniffableTags), - &counter, result); + counter.get(), result); } static bool SniffForMagicNumbers(const char* content, size_t size, std::string* result) { // Check our big table of Magic Numbers - static SnifferHistogram counter("mime_sniffer.kMagicNumbers2", - arraysize(kMagicNumbers)); + static scoped_refptr counter = + UMASnifferHistogramGet("mime_sniffer.kMagicNumbers2", + arraysize(kMagicNumbers)); return CheckForMagicNumbers(content, size, kMagicNumbers, arraysize(kMagicNumbers), - &counter, result); + counter.get(), result); } // Byte order marks @@ -320,8 +319,9 @@ static bool SniffXML(const char* content, size_t size, std::string* result) { // We want to skip XML processing instructions (of the form " counter = + UMASnifferHistogramGet("mime_sniffer.kMagicXML2", + arraysize(kMagicXML)); const int kMaxTagIterations = 5; for (int i = 0; i < kMaxTagIterations && pos < end; ++i) { pos = reinterpret_cast(memchr(pos, '<', end - pos)); @@ -341,7 +341,7 @@ static bool SniffXML(const char* content, size_t size, std::string* result) { if (CheckForMagicNumbers(pos, end - pos, kMagicXML, arraysize(kMagicXML), - &counter, result)) + counter.get(), result)) return true; // TODO(evanm): handle RSS 1.0, which is an RDF format and more difficult @@ -388,12 +388,13 @@ static char kByteLooksBinary[] = { static bool LooksBinary(const char* content, size_t size) { // First, we look for a BOM. - static SnifferHistogram counter("mime_sniffer.kByteOrderMark2", - arraysize(kByteOrderMark)); + static scoped_refptr counter = + UMASnifferHistogramGet("mime_sniffer.kByteOrderMark2", + arraysize(kByteOrderMark)); std::string unused; if (CheckForMagicNumbers(content, size, kByteOrderMark, arraysize(kByteOrderMark), - &counter, &unused)) { + counter.get(), &unused)) { // If there is BOM, we think the buffer is not binary. return false; } @@ -422,17 +423,18 @@ static bool IsUnknownMimeType(const std::string& mime_type) { // Firefox rejects a mime type if it is exactly */* "*/*", }; - static SnifferHistogram counter("mime_sniffer.kUnknownMimeTypes2", - arraysize(kUnknownMimeTypes) + 1); + static scoped_refptr counter = + UMASnifferHistogramGet("mime_sniffer.kUnknownMimeTypes2", + arraysize(kUnknownMimeTypes) + 1); for (size_t i = 0; i < arraysize(kUnknownMimeTypes); ++i) { if (mime_type == kUnknownMimeTypes[i]) { - counter.Add(i); + counter->Add(i); return true; } } if (mime_type.find('/') == std::string::npos) { // Firefox rejects a mime type if it does not contain a slash - counter.Add(arraysize(kUnknownMimeTypes)); + counter->Add(arraysize(kUnknownMimeTypes)); return true; } return false; @@ -441,7 +443,8 @@ static bool IsUnknownMimeType(const std::string& mime_type) { // Sniff a crx (chrome extension) file. static bool SniffCRX(const char* content, size_t content_size, const GURL& url, const std::string& type_hint, std::string* result) { - static SnifferHistogram counter("mime_sniffer.kSniffCRX", 3); + static scoped_refptr counter = + UMASnifferHistogramGet("mime_sniffer.kSniffCRX", 3); // Technically, the crx magic number is just Cr24, but the bytes after that // are a version number which changes infrequently. Including it in the @@ -459,7 +462,7 @@ static bool SniffCRX(const char* content, size_t content_size, const GURL& url, const int kExtensionLength = arraysize(kCRXExtension) - 1; // ignore null if (url.path().rfind(kCRXExtension, std::string::npos, kExtensionLength) == url.path().size() - kExtensionLength) { - counter.Add(1); + counter->Add(1); } else { return false; } @@ -467,7 +470,7 @@ static bool SniffCRX(const char* content, size_t content_size, const GURL& url, if (CheckForMagicNumbers(content, content_size, kCRXMagicNumbers, arraysize(kCRXMagicNumbers), NULL, result)) { - counter.Add(2); + counter->Add(2); } else { return false; } @@ -476,15 +479,15 @@ static bool SniffCRX(const char* content, size_t content_size, const GURL& url, } bool ShouldSniffMimeType(const GURL& url, const std::string& mime_type) { - static SnifferHistogram should_sniff_counter( - "mime_sniffer.ShouldSniffMimeType2", 3); + static scoped_refptr should_sniff_counter = + UMASnifferHistogramGet("mime_sniffer.ShouldSniffMimeType2", 3); // We are willing to sniff the mime type for HTTP, HTTPS, and FTP bool sniffable_scheme = url.is_empty() || url.SchemeIs("http") || url.SchemeIs("https") || url.SchemeIs("ftp"); if (!sniffable_scheme) { - should_sniff_counter.Add(1); + should_sniff_counter->Add(1); return false; } @@ -501,23 +504,24 @@ bool ShouldSniffMimeType(const GURL& url, const std::string& mime_type) { "text/xml", "application/xml", }; - static SnifferHistogram counter("mime_sniffer.kSniffableTypes2", - arraysize(kSniffableTypes) + 1); + static scoped_refptr counter = + UMASnifferHistogramGet("mime_sniffer.kSniffableTypes2", + arraysize(kSniffableTypes) + 1); for (size_t i = 0; i < arraysize(kSniffableTypes); ++i) { if (mime_type == kSniffableTypes[i]) { - counter.Add(i); - should_sniff_counter.Add(2); + counter->Add(i); + should_sniff_counter->Add(2); return true; } } if (IsUnknownMimeType(mime_type)) { // The web server didn't specify a content type or specified a mime // type that we ignore. - counter.Add(arraysize(kSniffableTypes)); - should_sniff_counter.Add(2); + counter->Add(arraysize(kSniffableTypes)); + should_sniff_counter->Add(2); return true; } - should_sniff_counter.Add(1); + should_sniff_counter->Add(1); return false; } diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc index b30a171..126a1b6 100644 --- a/net/base/sdch_manager.cc +++ b/net/base/sdch_manager.cc @@ -32,10 +32,11 @@ SdchManager* SdchManager::Global() { // static void SdchManager::SdchErrorRecovery(ProblemCodes problem) { - static LinearHistogram histogram("Sdch3.ProblemCodes_4", MIN_PROBLEM_CODE, - MAX_PROBLEM_CODE - 1, MAX_PROBLEM_CODE); - histogram.SetFlags(kUmaTargetedHistogramFlag); - histogram.Add(problem); + static scoped_refptr histogram = + LinearHistogram::LinearHistogramFactoryGet("Sdch3.ProblemCodes_4", + MIN_PROBLEM_CODE + 1, MAX_PROBLEM_CODE - 1, MAX_PROBLEM_CODE); + histogram->SetFlags(kUmaTargetedHistogramFlag); + histogram->Add(problem); } // static diff --git a/net/disk_cache/histogram_macros.h b/net/disk_cache/histogram_macros.h index 6ff66ea..6d63dc8 100644 --- a/net/disk_cache/histogram_macros.h +++ b/net/disk_cache/histogram_macros.h @@ -26,9 +26,11 @@ UMA_HISTOGRAM_TIMES(name, Time::Now() - initial_time) #define UMA_HISTOGRAM_CACHE_ERROR(name, sample) do { \ - static LinearHistogram counter((name), 0, 49, 50); \ - counter.SetFlags(kUmaTargetedHistogramFlag); \ - counter.Add(sample); \ + static scoped_refptr counter = \ + LinearHistogram::LinearHistogramFactoryGet(\ + (name), 1, 49, 50); \ + counter->SetFlags(kUmaTargetedHistogramFlag); \ + counter->Add(sample); \ } while (0) #ifdef NET_DISK_CACHE_BACKEND_IMPL_CC_ diff --git a/net/disk_cache/stats.cc b/net/disk_cache/stats.cc index a351a6c..e69ea00 100644 --- a/net/disk_cache/stats.cc +++ b/net/disk_cache/stats.cc @@ -138,7 +138,8 @@ bool Stats::Init(BackendImpl* backend, uint32* storage_addr) { backend->ShouldReportAgain()) { // Stats may be reused when the cache is re-created, but we want only one // histogram at any given time. - size_histogram_.reset(new StatsHistogram("DiskCache.SizeStats")); + size_histogram_ = + StatsHistogram::StatsHistogramFactoryGet("DiskCache.SizeStats"); size_histogram_->Init(this); } } diff --git a/net/disk_cache/stats.h b/net/disk_cache/stats.h index 1dcd39f..13536b1 100644 --- a/net/disk_cache/stats.h +++ b/net/disk_cache/stats.h @@ -84,7 +84,7 @@ class Stats { uint32 storage_addr_; int data_sizes_[kDataSizesLength]; int64 counters_[MAX_COUNTER]; - scoped_ptr size_histogram_; + scoped_refptr size_histogram_; DISALLOW_COPY_AND_ASSIGN(Stats); }; diff --git a/net/disk_cache/stats_histogram.cc b/net/disk_cache/stats_histogram.cc index f605934..e6eaf90 100644 --- a/net/disk_cache/stats_histogram.cc +++ b/net/disk_cache/stats_histogram.cc @@ -12,6 +12,37 @@ namespace disk_cache { // Static. const Stats* StatsHistogram::stats_ = NULL; +scoped_refptr StatsHistogram::StatsHistogramFactoryGet( + const std::string& name) { + scoped_refptr histogram(NULL); + + Sample minimum = 1; + Sample maximum = disk_cache::Stats::kDataSizesLength - 1; + size_t bucket_count = disk_cache::Stats::kDataSizesLength; + + if (StatisticsRecorder::FindHistogram(name, &histogram)) { + DCHECK(histogram.get() != NULL); + } else { + histogram = new StatsHistogram(name, minimum, maximum, bucket_count); + scoped_refptr registered_histogram(NULL); + StatisticsRecorder::FindHistogram(name, ®istered_histogram); + if (registered_histogram.get() != NULL && + registered_histogram.get() != histogram.get()) + histogram = registered_histogram; + } + + DCHECK(HISTOGRAM == histogram->histogram_type()); + DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count)); + + // We're preparing for an otherwise unsafe upcast by ensuring we have the + // proper class type. + Histogram* temp_histogram = histogram.get(); + StatsHistogram* temp_stats_histogram = + static_cast(temp_histogram); + scoped_refptr return_histogram = temp_stats_histogram; + return return_histogram; +} + bool StatsHistogram::Init(const Stats* stats) { DCHECK(stats); if (stats_) diff --git a/net/disk_cache/stats_histogram.h b/net/disk_cache/stats_histogram.h index 8db3bb3..995d486 100644 --- a/net/disk_cache/stats_histogram.h +++ b/net/disk_cache/stats_histogram.h @@ -5,6 +5,8 @@ #ifndef NET_DISK_CACHE_STATS_HISTOGRAM_H_ #define NET_DISK_CACHE_STATS_HISTOGRAM_H_ +#include + #include "base/histogram.h" namespace disk_cache { @@ -14,6 +16,10 @@ class Stats; // This class provides support for sending the disk cache size stats as a UMA // histogram. We'll provide our own storage and management for the data, and a // SampleSet with a copy of our data. +// +// Class derivation of Histogram "deprecated," and should not be copied, and +// may eventually go away. +// class StatsHistogram : public Histogram { public: class StatsSamples : public SampleSet { @@ -23,10 +29,14 @@ class StatsHistogram : public Histogram { } }; - explicit StatsHistogram(const char* name) - : Histogram(name, 1, 1, 2), init_(false) {} + explicit StatsHistogram(const std::string& name, Sample minimum, + Sample maximum, size_t bucket_count) + : Histogram(name, minimum, maximum, bucket_count), init_(false) {} ~StatsHistogram(); + static scoped_refptr + StatsHistogramFactoryGet(const std::string& name); + // We'll be reporting data from the given set of cache stats. bool Init(const Stats* stats); @@ -35,6 +45,8 @@ class StatsHistogram : public Histogram { virtual void SnapshotSample(SampleSet* sample) const; private: + friend class Histogram; + bool init_; static const Stats* stats_; DISALLOW_COPY_AND_ASSIGN(StatsHistogram); diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc index 1dfc99b..8014d07 100644 --- a/net/ftp/ftp_network_transaction.cc +++ b/net/ftp/ftp_network_transaction.cc @@ -1162,21 +1162,23 @@ void FtpNetworkTransaction::RecordDataConnectionError(int result) { break; }; static bool had_error_type[NUM_OF_NET_ERROR_TYPES]; - static LinearHistogram error_flagged("Net.FtpDataConnectionErrorHappened", - 1, NUM_OF_NET_ERROR_TYPES, - NUM_OF_NET_ERROR_TYPES + 1); - static LinearHistogram error_counter("Net.FtpDataConnectionErrorCount", - 1, NUM_OF_NET_ERROR_TYPES, - NUM_OF_NET_ERROR_TYPES + 1); + static scoped_refptr error_flagged = + LinearHistogram::LinearHistogramFactoryGet( + "Net.FtpDataConnectionErrorHappened", + 1, NUM_OF_NET_ERROR_TYPES, NUM_OF_NET_ERROR_TYPES + 1); + static scoped_refptr error_counter = + LinearHistogram::LinearHistogramFactoryGet( + "Net.FtpDataConnectionErrorCount", + 1, NUM_OF_NET_ERROR_TYPES, NUM_OF_NET_ERROR_TYPES + 1); DCHECK(type >= 0 && type < NUM_OF_NET_ERROR_TYPES); if (!had_error_type[type]) { had_error_type[type] = true; - error_flagged.SetFlags(kUmaTargetedHistogramFlag); - error_flagged.Add(type); + error_flagged->SetFlags(kUmaTargetedHistogramFlag); + error_flagged->Add(type); } - error_counter.SetFlags(kUmaTargetedHistogramFlag); - error_counter.Add(type); + error_counter->SetFlags(kUmaTargetedHistogramFlag); + error_counter->Add(type); } } // namespace net diff --git a/net/ftp/ftp_server_type_histograms.cc b/net/ftp/ftp_server_type_histograms.cc index 3f419a8..60ab9b9 100644 --- a/net/ftp/ftp_server_type_histograms.cc +++ b/net/ftp/ftp_server_type_histograms.cc @@ -22,22 +22,24 @@ namespace net { // expansion. void UpdateFtpServerTypeHistograms(FtpServerType type) { static bool had_server_type[NUM_OF_SERVER_TYPES]; - static LinearHistogram counter1("Net.HadFtpServerType", - 1, NUM_OF_SERVER_TYPES, - NUM_OF_SERVER_TYPES + 1); - static LinearHistogram counter2("Net.FtpServerTypeCount", - 1, NUM_OF_SERVER_TYPES, - NUM_OF_SERVER_TYPES + 1); + static scoped_refptr counter1 = + LinearHistogram::LinearHistogramFactoryGet("Net.HadFtpServerType", + 1, NUM_OF_SERVER_TYPES, + NUM_OF_SERVER_TYPES + 1); + static scoped_refptr counter2 = + LinearHistogram::LinearHistogramFactoryGet("Net.FtpServerTypeCount", + 1, NUM_OF_SERVER_TYPES, + NUM_OF_SERVER_TYPES + 1); if (type >= 0 && type < NUM_OF_SERVER_TYPES) { if (!had_server_type[type]) { had_server_type[type] = true; - counter1.SetFlags(kUmaTargetedHistogramFlag); - counter1.Add(type); + counter1->SetFlags(kUmaTargetedHistogramFlag); + counter1->Add(type); } } - counter2.SetFlags(kUmaTargetedHistogramFlag); - counter2.Add(type); + counter2->SetFlags(kUmaTargetedHistogramFlag); + counter2->Add(type); } } // namespace net diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index bdf3e3d..7ca82e38 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -996,18 +996,22 @@ void HttpNetworkTransaction::LogTCPConnectedMetrics( 100); } - static LinearHistogram tcp_socket_type_counter( - "Net.TCPSocketType", - 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1); - tcp_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag); - tcp_socket_type_counter.Add(handle.reuse_type()); + static scoped_refptr tcp_socket_type_counter = + LinearHistogram::LinearHistogramFactoryGet( + "Net.TCPSocketType", + 1, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1); + tcp_socket_type_counter->SetFlags(kUmaTargetedHistogramFlag); + tcp_socket_type_counter->Add(handle.reuse_type()); if (use_late_binding_histogram) { - static LinearHistogram tcp_socket_type_counter2( - FieldTrial::MakeName("Net.TCPSocketType", "SocketLateBinding").data(), - 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1); - tcp_socket_type_counter2.SetFlags(kUmaTargetedHistogramFlag); - tcp_socket_type_counter2.Add(handle.reuse_type()); + static scoped_refptr tcp_socket_type_counter2 = + LinearHistogram::LinearHistogramFactoryGet( + FieldTrial::MakeName("Net.TCPSocketType", + "SocketLateBinding").data(), + 1, ClientSocketHandle::NUM_TYPES, + ClientSocketHandle::NUM_TYPES + 1); + tcp_socket_type_counter2->SetFlags(kUmaTargetedHistogramFlag); + tcp_socket_type_counter2->Add(handle.reuse_type()); } UMA_HISTOGRAM_CLIPPED_TIMES( @@ -1065,19 +1069,22 @@ void HttpNetworkTransaction::LogIOErrorMetrics( static const bool use_late_binding_histogram = !FieldTrial::MakeName("", "SocketLateBinding").empty(); - static LinearHistogram io_error_socket_type_counter( - "Net.IOError_SocketReuseType", - 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1); - io_error_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag); - io_error_socket_type_counter.Add(handle.reuse_type()); + static scoped_refptr io_error_socket_type_counter = + LinearHistogram::LinearHistogramFactoryGet( + "Net.IOError_SocketReuseType", + 1, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1); + io_error_socket_type_counter->SetFlags(kUmaTargetedHistogramFlag); + io_error_socket_type_counter->Add(handle.reuse_type()); if (use_late_binding_histogram) { - static LinearHistogram io_error_socket_type_counter( - FieldTrial::MakeName("Net.IOError_SocketReuseType", - "SocketLateBinding").data(), - 0, ClientSocketHandle::NUM_TYPES, ClientSocketHandle::NUM_TYPES + 1); - io_error_socket_type_counter.SetFlags(kUmaTargetedHistogramFlag); - io_error_socket_type_counter.Add(handle.reuse_type()); + static scoped_refptr io_error_socket_type_counter = + LinearHistogram::LinearHistogramFactoryGet( + FieldTrial::MakeName("Net.IOError_SocketReuseType", + "SocketLateBinding").data(), + 1, ClientSocketHandle::NUM_TYPES, + ClientSocketHandle::NUM_TYPES + 1); + io_error_socket_type_counter->SetFlags(kUmaTargetedHistogramFlag); + io_error_socket_type_counter->Add(handle.reuse_type()); } switch (handle.reuse_type()) { diff --git a/net/socket_stream/socket_stream_metrics.cc b/net/socket_stream/socket_stream_metrics.cc index f7a55a4..6220eb5 100644 --- a/net/socket_stream/socket_stream_metrics.cc +++ b/net/socket_stream/socket_stream_metrics.cc @@ -83,19 +83,21 @@ void SocketStreamMetrics::OnClose() { } void SocketStreamMetrics::CountProtocolType(ProtocolType protocol_type) { - static LinearHistogram counter("Net.SocketStream.ProtocolType", - 0, NUM_PROTOCOL_TYPES, - NUM_PROTOCOL_TYPES + 1); - counter.SetFlags(kUmaTargetedHistogramFlag); - counter.Add(protocol_type); + static scoped_refptr counter = + LinearHistogram::LinearHistogramFactoryGet( + "Net.SocketStream.ProtocolType", + 0, NUM_PROTOCOL_TYPES, NUM_PROTOCOL_TYPES + 1); + counter->SetFlags(kUmaTargetedHistogramFlag); + counter->Add(protocol_type); } void SocketStreamMetrics::CountConnectionType(ConnectionType connection_type) { - static LinearHistogram counter("Net.SocketStream.ConnectionType", - 1, NUM_CONNECTION_TYPES, - NUM_CONNECTION_TYPES + 1); - counter.SetFlags(kUmaTargetedHistogramFlag); - counter.Add(connection_type); + static scoped_refptr counter = + LinearHistogram::LinearHistogramFactoryGet( + "Net.SocketStream.ConnectionType", + 1, NUM_CONNECTION_TYPES, NUM_CONNECTION_TYPES + 1); + counter->SetFlags(kUmaTargetedHistogramFlag); + counter->Add(connection_type); } -- cgit v1.1