Chromium Code Reviews| Index: base/metrics/histogram.h |
| =================================================================== |
| --- base/metrics/histogram.h (revision 80018) |
| +++ base/metrics/histogram.h (working copy) |
| @@ -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. |
|
rvargas (doing something else)
2011/04/01 19:20:52
Have you considered using LazyInstance<> instead?
jar (doing other things)
2011/04/01 21:50:27
As per discussion, one major point is that this co
willchan no longer on Chromium
2011/04/02 07:43:31
I think you misunderstand LazyInstance. Both LazyI
|
| + |
| #ifndef BASE_METRICS_HISTOGRAM_H_ |
| #define BASE_METRICS_HISTOGRAM_H_ |
| #pragma once |
| @@ -39,7 +48,6 @@ |
| #include "base/base_api.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/logging.h" |
| -#include "base/memory/ref_counted.h" |
| #include "base/time.h" |
| class Pickle; |
| @@ -66,11 +74,12 @@ |
| name, sample, 1, 10000, 50) |
| #define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| - base::Histogram::kNoFlags); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| + base::Histogram::kNoFlags); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->Add(sample); \ |
| + counter->Add(sample); \ |
| } while (0) |
| #define HISTOGRAM_PERCENTAGE(name, under_one_hundred) \ |
| @@ -79,40 +88,43 @@ |
| // For folks that need real specific times, use this to select a precise range |
| // of times you want plotted, and the number of buckets you want used. |
| #define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| - base::Histogram::kNoFlags); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| + base::Histogram::kNoFlags); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->AddTime(sample); \ |
| + counter->AddTime(sample); \ |
| } while (0) |
| -// DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. |
| +// DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. .... |
|
ramant (doing other things)
2011/04/01 20:05:38
More than 80 characters. Did you want to delete th
jar (doing other things)
2011/04/01 21:50:27
Done.
|
| #define HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| - base::Histogram::kNoFlags); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| + base::Histogram::kNoFlags); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if ((sample) < (max) && counter.get()) counter->AddTime(sample); \ |
| + if ((sample) < (max)) counter->AddTime(sample); \ |
| } while (0) |
| // Support histograming of an enumerated value. The samples should always be |
| // less than boundary_value. |
| #define HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| - boundary_value + 1, \ |
| - base::Histogram::kNoFlags); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| + boundary_value + 1, base::Histogram::kNoFlags); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->Add(sample); \ |
| + counter->Add(sample); \ |
| } while (0) |
| #define HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| - base::Histogram::kNoFlags); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| + base::Histogram::kNoFlags); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->Add(sample); \ |
| + counter->Add(sample); \ |
| } while (0) |
| @@ -172,20 +184,22 @@ |
| base::TimeDelta::FromHours(1), 50) |
| #define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| base::Histogram::kUmaTargetedHistogramFlag); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->AddTime(sample); \ |
| + counter->AddTime(sample); \ |
| } while (0) |
| // DO NOT USE THIS. It is being phased out, in favor of HISTOGRAM_CUSTOM_TIMES. |
| #define UMA_HISTOGRAM_CLIPPED_TIMES(name, sample, min, max, bucket_count) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| - base::Histogram::kUmaTargetedHistogramFlag); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \ |
| + base::Histogram::kUmaTargetedHistogramFlag); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if ((sample) < (max) && counter.get()) counter->AddTime(sample); \ |
| + if ((sample) < (max)) counter->AddTime(sample); \ |
| } while (0) |
| #define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| @@ -198,11 +212,12 @@ |
| name, sample, 1, 10000, 50) |
| #define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| - base::Histogram::kUmaTargetedHistogramFlag); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::Histogram::FactoryGet(name, min, max, bucket_count, \ |
| + base::Histogram::kUmaTargetedHistogramFlag); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->Add(sample); \ |
| + counter->Add(sample); \ |
| } while (0) |
| #define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \ |
| @@ -215,19 +230,21 @@ |
| UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101) |
| #define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| - boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::LinearHistogram::FactoryGet(name, 1, boundary_value, \ |
| + boundary_value + 1, base::Histogram::kUmaTargetedHistogramFlag); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->Add(sample); \ |
| + counter->Add(sample); \ |
| } while (0) |
| #define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) do { \ |
| - scoped_refptr<base::Histogram> counter = \ |
| - base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| - base::Histogram::kUmaTargetedHistogramFlag); \ |
| + static base::Histogram* counter(NULL); \ |
| + if (!counter) \ |
| + counter = base::CustomHistogram::FactoryGet(name, custom_ranges, \ |
| + base::Histogram::kUmaTargetedHistogramFlag); \ |
| DCHECK_EQ(name, counter->histogram_name()); \ |
| - if (counter.get()) counter->Add(sample); \ |
| + counter->Add(sample); \ |
| } while (0) |
| //------------------------------------------------------------------------------ |
| @@ -237,7 +254,7 @@ |
| class Histogram; |
| class LinearHistogram; |
| -class BASE_API Histogram : public base::RefCountedThreadSafe<Histogram> { |
| +class BASE_API Histogram { |
| public: |
| typedef int Sample; // Used for samples (and ranges of samples). |
| typedef int Count; // Used to count samples in a bucket. |
| @@ -347,11 +364,16 @@ |
| //---------------------------------------------------------------------------- |
| // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit |
| // default underflow bucket. |
| - static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
| - Sample minimum, Sample maximum, size_t bucket_count, Flags flags); |
| - static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, |
| - base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count, |
| - Flags flags); |
| + static Histogram* FactoryGet(const std::string& name, |
| + Sample minimum, |
| + Sample maximum, |
| + size_t bucket_count, |
| + Flags flags); |
| + static Histogram* FactoryTimeGet(const std::string& name, |
| + base::TimeDelta minimum, |
| + base::TimeDelta maximum, |
| + size_t bucket_count, |
| + Flags flags); |
| void Add(int value); |
| @@ -426,7 +448,6 @@ |
| bool HasValidRangeChecksum() const; |
| protected: |
| - friend class base::RefCountedThreadSafe<Histogram>; |
| Histogram(const std::string& name, Sample minimum, |
| Sample maximum, size_t bucket_count); |
| Histogram(const std::string& name, TimeDelta minimum, |
| @@ -480,6 +501,8 @@ |
| FRIEND_TEST(HistogramTest, Crc32SampleHash); |
| FRIEND_TEST(HistogramTest, Crc32TableTest); |
| + friend class StatisticsRecorder; // To allow it to delete duplicates. |
| + |
| // Post constructor initialization. |
| void Initialize(); |
| @@ -555,11 +578,16 @@ |
| /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit |
| default underflow bucket. */ |
| - static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
| - Sample minimum, Sample maximum, size_t bucket_count, Flags flags); |
| - static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name, |
| - TimeDelta minimum, TimeDelta maximum, size_t bucket_count, |
| - Flags flags); |
| + static Histogram* FactoryGet(const std::string& name, |
| + Sample minimum, |
| + Sample maximum, |
| + size_t bucket_count, |
| + Flags flags); |
| + static Histogram* FactoryTimeGet(const std::string& name, |
| + TimeDelta minimum, |
| + TimeDelta maximum, |
| + size_t bucket_count, |
| + Flags flags); |
| // Overridden from Histogram: |
| virtual ClassType histogram_type() const; |
| @@ -602,8 +630,7 @@ |
| // BooleanHistogram is a histogram for booleans. |
| class BASE_API BooleanHistogram : public LinearHistogram { |
| public: |
| - static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
| - Flags flags); |
| + static Histogram* FactoryGet(const std::string& name, Flags flags); |
| virtual ClassType histogram_type() const; |
| @@ -621,8 +648,9 @@ |
| class BASE_API CustomHistogram : public Histogram { |
| public: |
| - static scoped_refptr<Histogram> FactoryGet(const std::string& name, |
| - const std::vector<Sample>& custom_ranges, Flags flags); |
| + static Histogram* FactoryGet(const std::string& name, |
| + const std::vector<Sample>& custom_ranges, |
| + Flags flags); |
| // Overridden from Histogram: |
| virtual ClassType histogram_type() const; |
| @@ -645,7 +673,7 @@ |
| class BASE_API StatisticsRecorder { |
| public: |
| - typedef std::vector<scoped_refptr<Histogram> > Histograms; |
| + typedef std::vector<Histogram*> Histograms; |
| StatisticsRecorder(); |
| @@ -656,9 +684,9 @@ |
| // Register, or add a new histogram to the collection of statistics. If an |
| // identically named histogram is already registered, then the argument |
| - // |histogram| will be replaced by the previously registered value, discarding |
| - // the referenced argument. |
| - static void RegisterOrDiscardDuplicate(scoped_refptr<Histogram>* histogram); |
| + // |histogram| will deleted. The returns value is always the registered |
|
rvargas (doing something else)
2011/04/01 19:20:52
nit: the returned value
jar (doing other things)
2011/04/01 21:50:27
Done.
|
| + // histogram (either the argument, or the pre-existing registered histogram). |
| + static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram); |
| // Methods for printing histograms. Only histograms which have query as |
| // a substring are written to output (an empty string will process all |
| @@ -672,8 +700,7 @@ |
| // Find a histogram by name. It matches the exact name. This method is thread |
| // safe. If a matching histogram is not found, then the |histogram| is |
| // not changed. |
| - static bool FindHistogram(const std::string& query, |
| - scoped_refptr<Histogram>* histogram); |
| + static bool FindHistogram(const std::string& query, Histogram** histogram); |
| static bool dump_on_exit() { return dump_on_exit_; } |
| @@ -688,7 +715,7 @@ |
| private: |
| // We keep all registered histograms in a map, from name to histogram. |
| - typedef std::map<std::string, scoped_refptr<Histogram> > HistogramMap; |
| + typedef std::map<std::string, Histogram*> HistogramMap; |
| static HistogramMap* histograms_; |