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