summaryrefslogtreecommitdiffstats
path: root/base/metrics
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2011-06-28 21:49:31 +0100
committerKristian Monsen <kristianm@google.com>2011-07-08 17:55:00 +0100
commitddb351dbec246cf1fab5ec20d2d5520909041de1 (patch)
tree158e3fb57bdcac07c7f1e767fde3c70687c9fbb1 /base/metrics
parent6b92e04f5f151c896e3088e86f70db7081009308 (diff)
downloadexternal_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.zip
external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.gz
external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.bz2
Merge Chromium at r12.0.742.93: Initial merge by git
Change-Id: Ic5ee2fec31358bbee305f7e915442377bfa6cda6
Diffstat (limited to 'base/metrics')
-rw-r--r--base/metrics/field_trial.h49
-rw-r--r--base/metrics/histogram.cc158
-rw-r--r--base/metrics/histogram.h177
-rw-r--r--base/metrics/histogram_unittest.cc117
-rw-r--r--base/metrics/stats_counters.cc16
-rw-r--r--base/metrics/stats_counters.h13
-rw-r--r--base/metrics/stats_table.cc2
-rw-r--r--base/metrics/stats_table.h3
8 files changed, 300 insertions, 235 deletions
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 8b4a606..dcfd391 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -30,32 +30,44 @@
// Somewhere in main thread initialization code, we'd probably define an
// instance of a FieldTrial, with code such as:
-// // Note, FieldTrials are reference counted, and persist automagically until
+// // FieldTrials are reference counted, and persist automagically until
// // process teardown, courtesy of their automatic registration in
// // FieldTrialList.
-// scoped_refptr<FieldTrial> trial = new FieldTrial("MemoryExperiment", 1000);
-// int group1 = trial->AppendGroup("high_mem", 20); // 2% in high_mem group.
-// int group2 = trial->AppendGroup("low_mem", 20); // 2% in low_mem group.
+// // Note: This field trial will run in Chrome instances compiled through
+// // 8 July, 2015, and after that all instances will be in "StandardMem".
+// scoped_refptr<FieldTrial> trial = new FieldTrial("MemoryExperiment", 1000,
+// "StandardMem", 2015, 7, 8);
+// const int kHighMemGroup =
+// trial->AppendGroup("HighMem", 20); // 2% in HighMem group.
+// const int kLowMemGroup =
+// trial->AppendGroup("LowMem", 20); // 2% in LowMem group.
// // Take action depending of which group we randomly land in.
-// if (trial->group() == group1)
+// if (trial->group() == kHighMemGroup)
// SetPruningAlgorithm(kType1); // Sample setting of browser state.
-// else if (trial->group() == group2)
+// else if (trial->group() == kLowMemGroup)
// SetPruningAlgorithm(kType2); // Sample alternate setting.
-// We then modify any histograms we wish to correlate with our experiment to
-// have slighly different names, depending on what group the trial instance
-// happened (randomly) to be assigned to:
+// We then, in addition to our original histogram, output histograms which have
+// slightly different names depending on what group the trial instance happened
+// to randomly be assigned:
-// HISTOGRAM_COUNTS(FieldTrial::MakeName("Memory.RendererTotal",
-// "MemoryExperiment").data(), count);
+// HISTOGRAM_COUNTS("Memory.RendererTotal", count); // The original histogram.
+// static bool use_memoryexperiment_histogram(
+// base::FieldTrialList::Find("MemoryExperiment") &&
+// !base::FieldTrialList::Find("MemoryExperiment")->group_name().empty());
+// if (use_memoryexperiment_histogram) {
+// HISTOGRAM_COUNTS(FieldTrial::MakeName("Memory.RendererTotal",
+// "MemoryExperiment"), count);
+// }
-// The above code will create 3 distinct histograms, with each run of the
+// The above code will create four distinct histograms, with each run of the
// application being assigned to of of the three groups, and for each group, the
// correspondingly named histogram will be populated:
-// Memory.RendererTotal // 96% of users still fill this histogram.
-// Memory.RendererTotal_high_mem // 2% of users will fill this histogram.
-// Memory.RendererTotal_low_mem // 2% of users will fill this histogram.
+// Memory.RendererTotal // 100% of users still fill this histogram.
+// Memory.RendererTotal_HighMem // 2% of users will fill this histogram.
+// Memory.RendererTotal_LowMem // 2% of users will fill this histogram.
+// Memory.RendererTotal_StandardMem // 96% of users will fill this histogram.
//------------------------------------------------------------------------------
@@ -66,8 +78,9 @@
#include <map>
#include <string>
+#include "base/base_api.h"
#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
+#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/time.h"
@@ -75,7 +88,7 @@ namespace base {
class FieldTrialList;
-class FieldTrial : public RefCounted<FieldTrial> {
+class BASE_API FieldTrial : public RefCounted<FieldTrial> {
public:
typedef int Probability; // Probability type for being selected in a trial.
@@ -198,7 +211,7 @@ class FieldTrial : public RefCounted<FieldTrial> {
// Class with a list of all active field trials. A trial is active if it has
// been registered, which includes evaluating its state based on its probaility.
// Only one instance of this class exists.
-class FieldTrialList {
+class BASE_API FieldTrialList {
public:
// Define a separator charactor to use when creating a persistent form of an
// instance. This is intended for use as a command line argument, passed to a
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 1d6f884..4262853 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -73,9 +73,12 @@ typedef Histogram::Count Count;
// static
const size_t Histogram::kBucketCount_MAX = 16384u;
-scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name,
- Sample minimum, Sample maximum, size_t bucket_count, Flags flags) {
- scoped_refptr<Histogram> histogram(NULL);
+Histogram* Histogram::FactoryGet(const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ Flags flags) {
+ Histogram* histogram(NULL);
// Defensive code.
if (minimum < 1)
@@ -84,22 +87,28 @@ scoped_refptr<Histogram> Histogram::FactoryGet(const std::string& name,
maximum = kSampleType_MAX - 1;
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
- histogram = new Histogram(name, minimum, maximum, bucket_count);
- histogram->InitializeBucketRange();
- StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+ // Extra variable is not needed... but this keeps this section basically
+ // identical to other derived classes in this file (and compiler will
+ // optimize away the extra variable.
+ // To avoid racy destruction at shutdown, the following will be leaked.
+ Histogram* tentative_histogram =
+ new Histogram(name, minimum, maximum, bucket_count);
+ tentative_histogram->InitializeBucketRange();
+ tentative_histogram->SetFlags(flags);
+ histogram =
+ StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
}
DCHECK_EQ(HISTOGRAM, histogram->histogram_type());
DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
- histogram->SetFlags(flags);
return histogram;
}
-scoped_refptr<Histogram> Histogram::FactoryTimeGet(const std::string& name,
- TimeDelta minimum,
- TimeDelta maximum,
- size_t bucket_count,
- Flags flags) {
+Histogram* Histogram::FactoryTimeGet(const std::string& name,
+ TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count,
+ Flags flags) {
return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
bucket_count, flags);
}
@@ -259,7 +268,7 @@ bool Histogram::DeserializeHistogramInfo(const std::string& histogram_info) {
DCHECK_NE(NOT_VALID_IN_RENDERER, histogram_type);
- scoped_refptr<Histogram> render_histogram(NULL);
+ Histogram* render_histogram(NULL);
if (histogram_type == HISTOGRAM) {
render_histogram = Histogram::FactoryGet(
@@ -610,13 +619,8 @@ void Histogram::WriteAsciiHeader(const SampleSet& snapshot,
DCHECK_EQ(snapshot.sum(), 0);
} else {
double average = static_cast<float>(snapshot.sum()) / sample_count;
- double variance = static_cast<float>(snapshot.square_sum())/sample_count
- - average * average;
- double standard_deviation = sqrt(variance);
- StringAppendF(output,
- ", average = %.1f, standard deviation = %.1f",
- average, standard_deviation);
+ StringAppendF(output, ", average = %.1f", average);
}
if (flags_ & ~kHexRangePrintingFlag)
StringAppendF(output, " (flags = 0x%x)", flags_ & ~kHexRangePrintingFlag);
@@ -661,7 +665,6 @@ void Histogram::WriteAsciiBucketGraph(double current_size, double max_size,
Histogram::SampleSet::SampleSet()
: counts_(),
sum_(0),
- square_sum_(0),
redundant_count_(0) {
}
@@ -682,11 +685,9 @@ void Histogram::SampleSet::Accumulate(Sample value, Count count,
DCHECK(count == 1 || count == -1);
counts_[index] += count;
sum_ += count * value;
- square_sum_ += (count * value) * static_cast<int64>(value);
redundant_count_ += count;
DCHECK_GE(counts_[index], 0);
DCHECK_GE(sum_, 0);
- DCHECK_GE(square_sum_, 0);
DCHECK_GE(redundant_count_, 0);
}
@@ -703,7 +704,6 @@ Count Histogram::SampleSet::TotalCount() const {
void Histogram::SampleSet::Add(const SampleSet& other) {
DCHECK_EQ(counts_.size(), other.counts_.size());
sum_ += other.sum_;
- square_sum_ += other.square_sum_;
redundant_count_ += other.redundant_count_;
for (size_t index = 0; index < counts_.size(); ++index)
counts_[index] += other.counts_[index];
@@ -711,11 +711,10 @@ void Histogram::SampleSet::Add(const SampleSet& other) {
void Histogram::SampleSet::Subtract(const SampleSet& other) {
DCHECK_EQ(counts_.size(), other.counts_.size());
- // Note: Race conditions in snapshotting a sum or square_sum may lead to
- // (temporary) negative values when snapshots are later combined (and deltas
- // calculated). As a result, we don't currently CHCEK() for positive values.
+ // Note: Race conditions in snapshotting a sum may lead to (temporary)
+ // negative values when snapshots are later combined (and deltas calculated).
+ // As a result, we don't currently CHCEK() for positive values.
sum_ -= other.sum_;
- square_sum_ -= other.square_sum_;
redundant_count_ -= other.redundant_count_;
for (size_t index = 0; index < counts_.size(); ++index) {
counts_[index] -= other.counts_[index];
@@ -725,7 +724,6 @@ void Histogram::SampleSet::Subtract(const SampleSet& other) {
bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
pickle->WriteInt64(sum_);
- pickle->WriteInt64(square_sum_);
pickle->WriteInt64(redundant_count_);
pickle->WriteSize(counts_.size());
@@ -739,13 +737,11 @@ bool Histogram::SampleSet::Serialize(Pickle* pickle) const {
bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
DCHECK_EQ(counts_.size(), 0u);
DCHECK_EQ(sum_, 0);
- DCHECK_EQ(square_sum_, 0);
DCHECK_EQ(redundant_count_, 0);
size_t counts_size;
if (!pickle.ReadInt64(iter, &sum_) ||
- !pickle.ReadInt64(iter, &square_sum_) ||
!pickle.ReadInt64(iter, &redundant_count_) ||
!pickle.ReadSize(iter, &counts_size)) {
return false;
@@ -774,12 +770,12 @@ bool Histogram::SampleSet::Deserialize(void** iter, const Pickle& pickle) {
LinearHistogram::~LinearHistogram() {
}
-scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
- Sample minimum,
- Sample maximum,
- size_t bucket_count,
- Flags flags) {
- scoped_refptr<Histogram> histogram(NULL);
+Histogram* LinearHistogram::FactoryGet(const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ Flags flags) {
+ Histogram* histogram(NULL);
if (minimum < 1)
minimum = 1;
@@ -787,25 +783,25 @@ scoped_refptr<Histogram> LinearHistogram::FactoryGet(const std::string& name,
maximum = kSampleType_MAX - 1;
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
- LinearHistogram* linear_histogram =
+ // To avoid racy destruction at shutdown, the following will be leaked.
+ LinearHistogram* tentative_histogram =
new LinearHistogram(name, minimum, maximum, bucket_count);
- linear_histogram->InitializeBucketRange();
- histogram = linear_histogram;
- StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+ tentative_histogram->InitializeBucketRange();
+ tentative_histogram->SetFlags(flags);
+ histogram =
+ StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
}
DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type());
DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
- histogram->SetFlags(flags);
return histogram;
}
-scoped_refptr<Histogram> LinearHistogram::FactoryTimeGet(
- const std::string& name,
- TimeDelta minimum,
- TimeDelta maximum,
- size_t bucket_count,
- Flags flags) {
+Histogram* LinearHistogram::FactoryTimeGet(const std::string& name,
+ TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count,
+ Flags flags) {
return FactoryGet(name, minimum.InMilliseconds(), maximum.InMilliseconds(),
bucket_count, flags);
}
@@ -875,19 +871,19 @@ bool LinearHistogram::PrintEmptyBucket(size_t index) const {
// This section provides implementation for BooleanHistogram.
//------------------------------------------------------------------------------
-scoped_refptr<Histogram> BooleanHistogram::FactoryGet(const std::string& name,
- Flags flags) {
- scoped_refptr<Histogram> histogram(NULL);
+Histogram* BooleanHistogram::FactoryGet(const std::string& name, Flags flags) {
+ Histogram* histogram(NULL);
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
- BooleanHistogram* boolean_histogram = new BooleanHistogram(name);
- boolean_histogram->InitializeBucketRange();
- histogram = boolean_histogram;
- StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+ // To avoid racy destruction at shutdown, the following will be leaked.
+ BooleanHistogram* tentative_histogram = new BooleanHistogram(name);
+ tentative_histogram->InitializeBucketRange();
+ tentative_histogram->SetFlags(flags);
+ histogram =
+ StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
}
DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type());
- histogram->SetFlags(flags);
return histogram;
}
@@ -907,11 +903,10 @@ BooleanHistogram::BooleanHistogram(const std::string& name)
// CustomHistogram:
//------------------------------------------------------------------------------
-scoped_refptr<Histogram> CustomHistogram::FactoryGet(
- const std::string& name,
- const std::vector<Sample>& custom_ranges,
- Flags flags) {
- scoped_refptr<Histogram> histogram(NULL);
+Histogram* CustomHistogram::FactoryGet(const std::string& name,
+ const std::vector<Sample>& custom_ranges,
+ Flags flags) {
+ Histogram* histogram(NULL);
// Remove the duplicates in the custom ranges array.
std::vector<int> ranges = custom_ranges;
@@ -927,16 +922,17 @@ scoped_refptr<Histogram> CustomHistogram::FactoryGet(
DCHECK_LT(ranges.back(), kSampleType_MAX);
if (!StatisticsRecorder::FindHistogram(name, &histogram)) {
- CustomHistogram* custom_histogram = new CustomHistogram(name, ranges);
- custom_histogram->InitializedCustomBucketRange(ranges);
- histogram = custom_histogram;
- StatisticsRecorder::RegisterOrDiscardDuplicate(&histogram);
+ // To avoid racy destruction at shutdown, the following will be leaked.
+ CustomHistogram* tentative_histogram = new CustomHistogram(name, ranges);
+ tentative_histogram->InitializedCustomBucketRange(ranges);
+ tentative_histogram->SetFlags(flags);
+ histogram =
+ StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
}
DCHECK_EQ(histogram->histogram_type(), CUSTOM_HISTOGRAM);
DCHECK(histogram->HasConstructorArguments(ranges[1], ranges.back(),
ranges.size()));
- histogram->SetFlags(flags);
return histogram;
}
@@ -1017,27 +1013,23 @@ bool StatisticsRecorder::IsActive() {
return NULL != histograms_;
}
-// Note: We can't accept a ref_ptr to |histogram| because we *might* not keep a
-// reference, and we are called while in the Histogram constructor. In that
-// scenario, a ref_ptr would have incremented the ref count when the histogram
-// was passed to us, decremented it when we returned, and the instance would be
-// destroyed before assignment (when value was returned by new).
-// static
-void StatisticsRecorder::RegisterOrDiscardDuplicate(
- scoped_refptr<Histogram>* histogram) {
- DCHECK((*histogram)->HasValidRangeChecksum());
+Histogram* StatisticsRecorder::RegisterOrDeleteDuplicate(Histogram* histogram) {
+ DCHECK(histogram->HasValidRangeChecksum());
if (lock_ == NULL)
- return;
+ return histogram;
base::AutoLock auto_lock(*lock_);
if (!histograms_)
- return;
- const std::string name = (*histogram)->histogram_name();
+ return histogram;
+ const std::string name = histogram->histogram_name();
HistogramMap::iterator it = histograms_->find(name);
// Avoid overwriting a previous registration.
- if (histograms_->end() == it)
- (*histograms_)[name] = *histogram;
- else
- *histogram = it->second;
+ if (histograms_->end() == it) {
+ (*histograms_)[name] = histogram;
+ } else {
+ delete histogram; // We already have one by this name.
+ histogram = it->second;
+ }
+ return histogram;
}
// static
@@ -1100,7 +1092,7 @@ void StatisticsRecorder::GetHistograms(Histograms* output) {
}
bool StatisticsRecorder::FindHistogram(const std::string& name,
- scoped_refptr<Histogram>* histogram) {
+ Histogram** histogram) {
if (lock_ == NULL)
return false;
base::AutoLock auto_lock(*lock_);
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 347932a..bc58ee5 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -28,6 +28,15 @@
// at the low end of the histogram scale, but allows the histogram to cover a
// gigantic range with the addition of very few buckets.
+// Histograms use a pattern involving a function static variable, that is a
+// pointer to a histogram. This static is explicitly initialized on any thread
+// that detects a uninitialized (NULL) pointer. The potentially racy
+// initialization is not a problem as it is always set to point to the same
+// value (i.e., the FactoryGet always returns the same value). FactoryGet
+// is also completely thread safe, which results in a completely thread safe,
+// and relatively fast, set of counters. To avoid races at shutdown, the static
+// pointer is NOT deleted, and we leak the histograms at process termination.
+
#ifndef BASE_METRICS_HISTOGRAM_H_
#define BASE_METRICS_HISTOGRAM_H_
#pragma once
@@ -36,8 +45,8 @@
#include <string>
#include <vector>
+#include "base/base_api.h"
#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
#include "base/logging.h"
#include "base/time.h"
@@ -65,11 +74,12 @@ class Lock;
name, sample, 1, 10000, 50)
#define HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
- static 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) \
@@ -78,40 +88,43 @@ class Lock;
// For folks that need real specific times, use this to select a precise range
// of times you want plotted, and the number of buckets you want used.
#define HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
- static 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 { \
- static 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 { \
- static 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 { \
- static 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)
@@ -171,20 +184,22 @@ class Lock;
base::TimeDelta::FromHours(1), 50)
#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) do { \
- static 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 { \
- static 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( \
@@ -197,11 +212,12 @@ class Lock;
name, sample, 1, 10000, 50)
#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) do { \
- static 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( \
@@ -213,20 +229,31 @@ class Lock;
#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+#define UMA_HISTOGRAM_BOOLEAN(name, sample) do { \
+ static base::Histogram* counter(NULL); \
+ if (!counter) \
+ counter = base::BooleanHistogram::FactoryGet(name, \
+ base::Histogram::kUmaTargetedHistogramFlag); \
+ DCHECK_EQ(name, counter->histogram_name()); \
+ counter->AddBoolean(sample); \
+ } while (0)
+
#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) do { \
- static 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 { \
- static 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)
//------------------------------------------------------------------------------
@@ -236,7 +263,7 @@ class CustomHistogram;
class Histogram;
class LinearHistogram;
-class 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.
@@ -295,7 +322,7 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
//----------------------------------------------------------------------------
// Statistic values, developed over the life of the histogram.
- class SampleSet {
+ class BASE_API SampleSet {
public:
explicit SampleSet();
~SampleSet();
@@ -311,7 +338,6 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
Count counts(size_t i) const { return counts_[i]; }
Count TotalCount() const;
int64 sum() const { return sum_; }
- int64 square_sum() const { return square_sum_; }
int64 redundant_count() const { return redundant_count_; }
// Arithmetic manipulation of corresponding elements of the set.
@@ -329,7 +355,6 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// Save simple stats locally. Note that this MIGHT get done in base class
// without shared memory at some point.
int64 sum_; // sum of samples.
- int64 square_sum_; // sum of squares of samples.
private:
// Allow tests to corrupt our innards for testing purposes.
@@ -348,11 +373,16 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
//----------------------------------------------------------------------------
// minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
// default underflow bucket.
- static scoped_refptr<Histogram> FactoryGet(const std::string& name,
- Sample minimum, Sample maximum, size_t bucket_count, Flags flags);
- static scoped_refptr<Histogram> FactoryTimeGet(const std::string& name,
- base::TimeDelta minimum, base::TimeDelta maximum, size_t bucket_count,
- Flags flags);
+ static Histogram* FactoryGet(const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ Flags flags);
+ static Histogram* FactoryTimeGet(const std::string& name,
+ base::TimeDelta minimum,
+ base::TimeDelta maximum,
+ size_t bucket_count,
+ Flags flags);
void Add(int value);
@@ -427,7 +457,6 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
bool HasValidRangeChecksum() const;
protected:
- friend class base::RefCountedThreadSafe<Histogram>;
Histogram(const std::string& name, Sample minimum,
Sample maximum, size_t bucket_count);
Histogram(const std::string& name, TimeDelta minimum,
@@ -481,6 +510,8 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
FRIEND_TEST(HistogramTest, Crc32SampleHash);
FRIEND_TEST(HistogramTest, Crc32TableTest);
+ friend class StatisticsRecorder; // To allow it to delete duplicates.
+
// Post constructor initialization.
void Initialize();
@@ -550,17 +581,22 @@ class Histogram : public base::RefCountedThreadSafe<Histogram> {
// LinearHistogram is a more traditional histogram, with evenly spaced
// buckets.
-class LinearHistogram : public Histogram {
+class BASE_API LinearHistogram : public Histogram {
public:
virtual ~LinearHistogram();
/* 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;
@@ -601,10 +637,9 @@ class LinearHistogram : public Histogram {
//------------------------------------------------------------------------------
// BooleanHistogram is a histogram for booleans.
-class BooleanHistogram : public LinearHistogram {
+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;
@@ -619,11 +654,12 @@ class BooleanHistogram : public LinearHistogram {
//------------------------------------------------------------------------------
// CustomHistogram is a histogram for a set of custom integers.
-class CustomHistogram : public Histogram {
+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;
@@ -644,9 +680,9 @@ class CustomHistogram : public Histogram {
// general place for histograms to register, and supports a global API for
// accessing (i.e., dumping, or graphing) the data in all the histograms.
-class StatisticsRecorder {
+class BASE_API StatisticsRecorder {
public:
- typedef std::vector<scoped_refptr<Histogram> > Histograms;
+ typedef std::vector<Histogram*> Histograms;
StatisticsRecorder();
@@ -657,9 +693,9 @@ class StatisticsRecorder {
// Register, or add a new histogram to the collection of statistics. If an
// identically named histogram is already registered, then the argument
- // |histogram| will be replaced by the previously registered value, discarding
- // the referenced argument.
- static void RegisterOrDiscardDuplicate(scoped_refptr<Histogram>* histogram);
+ // |histogram| will deleted. The returned value is always the registered
+ // histogram (either the argument, or the pre-existing registered histogram).
+ static Histogram* RegisterOrDeleteDuplicate(Histogram* histogram);
// Methods for printing histograms. Only histograms which have query as
// a substring are written to output (an empty string will process all
@@ -673,8 +709,7 @@ class StatisticsRecorder {
// Find a histogram by name. It matches the exact name. This method is thread
// safe. If a matching histogram is not found, then the |histogram| is
// not changed.
- static bool FindHistogram(const std::string& query,
- scoped_refptr<Histogram>* histogram);
+ static bool FindHistogram(const std::string& query, Histogram** histogram);
static bool dump_on_exit() { return dump_on_exit_; }
@@ -689,7 +724,7 @@ class StatisticsRecorder {
private:
// We keep all registered histograms in a map, from name to histogram.
- typedef std::map<std::string, scoped_refptr<Histogram> > HistogramMap;
+ typedef std::map<std::string, Histogram*> HistogramMap;
static HistogramMap* histograms_;
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index afa69a6..496ff63 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -1,10 +1,11 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Test of Histogram class
#include "base/metrics/histogram.h"
+#include "base/scoped_ptr.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,15 +18,22 @@ class HistogramTest : public testing::Test {
// Check for basic syntax and use.
TEST(HistogramTest, StartupShutdownTest) {
// Try basic construction
- scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
- "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
- scoped_refptr<Histogram> histogram1 = Histogram::FactoryGet(
- "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags);
-
- scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
- "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
- scoped_refptr<Histogram> linear_histogram1 = LinearHistogram::FactoryGet(
- "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
+ Histogram* histogram(Histogram::FactoryGet(
+ "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
+ Histogram* histogram1(Histogram::FactoryGet(
+ "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
+ EXPECT_NE(histogram, histogram1);
+
+
+ Histogram* linear_histogram(LinearHistogram::FactoryGet(
+ "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
+ Histogram* linear_histogram1(LinearHistogram::FactoryGet(
+ "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
+ EXPECT_NE(linear_histogram, linear_histogram1);
std::vector<int> custom_ranges;
custom_ranges.push_back(1);
@@ -33,10 +41,12 @@ TEST(HistogramTest, StartupShutdownTest) {
custom_ranges.push_back(10);
custom_ranges.push_back(20);
custom_ranges.push_back(30);
- scoped_refptr<Histogram> custom_histogram = CustomHistogram::FactoryGet(
- "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
- scoped_refptr<Histogram> custom_histogram1 = CustomHistogram::FactoryGet(
- "Test1CustomHistogram", custom_ranges, Histogram::kNoFlags);
+ Histogram* custom_histogram(CustomHistogram::FactoryGet(
+ "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
+ Histogram* custom_histogram1(CustomHistogram::FactoryGet(
+ "Test1CustomHistogram", custom_ranges, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
// Use standard macros (but with fixed samples)
HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
@@ -70,25 +80,29 @@ TEST(HistogramTest, RecordedStartupTest) {
EXPECT_EQ(0U, histograms.size());
// Try basic construction
- scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
- "TestHistogram", 1, 1000, 10, Histogram::kNoFlags);
+ Histogram* histogram(Histogram::FactoryGet(
+ "TestHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram);
histograms.clear();
StatisticsRecorder::GetHistograms(&histograms); // Load up lists
EXPECT_EQ(1U, histograms.size());
- scoped_refptr<Histogram> histogram1 = Histogram::FactoryGet(
- "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags);
+ Histogram* histogram1(Histogram::FactoryGet(
+ "Test1Histogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), histogram1);
histograms.clear();
StatisticsRecorder::GetHistograms(&histograms); // Load up lists
EXPECT_EQ(2U, histograms.size());
- scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
- "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
+ Histogram* linear_histogram(LinearHistogram::FactoryGet(
+ "TestLinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram);
histograms.clear();
StatisticsRecorder::GetHistograms(&histograms); // Load up lists
EXPECT_EQ(3U, histograms.size());
- scoped_refptr<Histogram> linear_histogram1 = LinearHistogram::FactoryGet(
- "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags);
+ Histogram* linear_histogram1(LinearHistogram::FactoryGet(
+ "Test1LinearHistogram", 1, 1000, 10, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), linear_histogram1);
histograms.clear();
StatisticsRecorder::GetHistograms(&histograms); // Load up lists
EXPECT_EQ(4U, histograms.size());
@@ -99,10 +113,12 @@ TEST(HistogramTest, RecordedStartupTest) {
custom_ranges.push_back(10);
custom_ranges.push_back(20);
custom_ranges.push_back(30);
- scoped_refptr<Histogram> custom_histogram = CustomHistogram::FactoryGet(
- "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
- scoped_refptr<Histogram> custom_histogram1 = CustomHistogram::FactoryGet(
- "TestCustomHistogram", custom_ranges, Histogram::kNoFlags);
+ Histogram* custom_histogram(CustomHistogram::FactoryGet(
+ "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram);
+ Histogram* custom_histogram1(CustomHistogram::FactoryGet(
+ "TestCustomHistogram", custom_ranges, Histogram::kNoFlags));
+ EXPECT_NE(reinterpret_cast<Histogram*>(NULL), custom_histogram1);
histograms.clear();
StatisticsRecorder::GetHistograms(&histograms); // Load up lists
@@ -138,8 +154,8 @@ TEST(HistogramTest, RangeTest) {
recorder.GetHistograms(&histograms);
EXPECT_EQ(0U, histograms.size());
- scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags); // As per header file.
+ Histogram* histogram(Histogram::FactoryGet(
+ "Histogram", 1, 64, 8, Histogram::kNoFlags)); // As per header file.
// Check that we got a nice exponential when there was enough rooom.
EXPECT_EQ(0, histogram->ranges(0));
int power_of_2 = 1;
@@ -149,31 +165,30 @@ TEST(HistogramTest, RangeTest) {
}
EXPECT_EQ(INT_MAX, histogram->ranges(8));
- scoped_refptr<Histogram> short_histogram = Histogram::FactoryGet(
- "Histogram Shortened", 1, 7, 8, Histogram::kNoFlags);
+ Histogram* short_histogram(Histogram::FactoryGet(
+ "Histogram Shortened", 1, 7, 8, Histogram::kNoFlags));
// Check that when the number of buckets is short, we get a linear histogram
// for lack of space to do otherwise.
for (int i = 0; i < 8; i++)
EXPECT_EQ(i, short_histogram->ranges(i));
EXPECT_EQ(INT_MAX, short_histogram->ranges(8));
- scoped_refptr<Histogram> linear_histogram = LinearHistogram::FactoryGet(
- "Linear", 1, 7, 8, Histogram::kNoFlags);
+ Histogram* linear_histogram(LinearHistogram::FactoryGet(
+ "Linear", 1, 7, 8, Histogram::kNoFlags));
// We also get a nice linear set of bucket ranges when we ask for it
for (int i = 0; i < 8; i++)
EXPECT_EQ(i, linear_histogram->ranges(i));
EXPECT_EQ(INT_MAX, linear_histogram->ranges(8));
- scoped_refptr<Histogram> linear_broad_histogram = LinearHistogram::FactoryGet(
- "Linear widened", 2, 14, 8, Histogram::kNoFlags);
+ Histogram* linear_broad_histogram(LinearHistogram::FactoryGet(
+ "Linear widened", 2, 14, 8, Histogram::kNoFlags));
// ...but when the list has more space, then the ranges naturally spread out.
for (int i = 0; i < 8; i++)
EXPECT_EQ(2 * i, linear_broad_histogram->ranges(i));
EXPECT_EQ(INT_MAX, linear_broad_histogram->ranges(8));
- scoped_refptr<Histogram> transitioning_histogram =
- Histogram::FactoryGet("LinearAndExponential", 1, 32, 15,
- Histogram::kNoFlags);
+ Histogram* transitioning_histogram(Histogram::FactoryGet(
+ "LinearAndExponential", 1, 32, 15, Histogram::kNoFlags));
// When space is a little tight, we transition from linear to exponential.
EXPECT_EQ(0, transitioning_histogram->ranges(0));
EXPECT_EQ(1, transitioning_histogram->ranges(1));
@@ -198,8 +213,8 @@ TEST(HistogramTest, RangeTest) {
custom_ranges.push_back(10);
custom_ranges.push_back(11);
custom_ranges.push_back(300);
- scoped_refptr<Histogram> test_custom_histogram = CustomHistogram::FactoryGet(
- "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags);
+ Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
+ "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(0));
EXPECT_EQ(custom_ranges[1], test_custom_histogram->ranges(1));
@@ -221,8 +236,8 @@ TEST(HistogramTest, CustomRangeTest) {
custom_ranges.push_back(9);
custom_ranges.push_back(10);
custom_ranges.push_back(11);
- scoped_refptr<Histogram> test_custom_histogram = CustomHistogram::FactoryGet(
- "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags);
+ Histogram* test_custom_histogram(CustomHistogram::FactoryGet(
+ "TestCustomRangeHistogram", custom_ranges, Histogram::kNoFlags));
EXPECT_EQ(0, test_custom_histogram->ranges(0)); // Auto added
EXPECT_EQ(custom_ranges[0], test_custom_histogram->ranges(1));
@@ -242,8 +257,8 @@ TEST(HistogramTest, CustomRangeTest) {
custom_ranges.push_back(0); // Push an explicit zero.
custom_ranges.push_back(kBig);
- scoped_refptr<Histogram> unsorted_histogram = CustomHistogram::FactoryGet(
- "TestCustomUnsortedDupedHistogram", custom_ranges, Histogram::kNoFlags);
+ Histogram* unsorted_histogram(CustomHistogram::FactoryGet(
+ "TestCustomUnsortedDupedHistogram", custom_ranges, Histogram::kNoFlags));
EXPECT_EQ(0, unsorted_histogram->ranges(0));
EXPECT_EQ(kSmall, unsorted_histogram->ranges(1));
EXPECT_EQ(kMid, unsorted_histogram->ranges(2));
@@ -254,8 +269,8 @@ TEST(HistogramTest, CustomRangeTest) {
// Make sure histogram handles out-of-bounds data gracefully.
TEST(HistogramTest, BoundsTest) {
const size_t kBucketCount = 50;
- scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
- "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags);
+ Histogram* histogram(Histogram::FactoryGet(
+ "Bounded", 10, 100, kBucketCount, Histogram::kNoFlags));
// Put two samples "out of bounds" above and below.
histogram->Add(5);
@@ -277,8 +292,8 @@ TEST(HistogramTest, BoundsTest) {
// Check to be sure samples land as expected is "correct" buckets.
TEST(HistogramTest, BucketPlacementTest) {
- scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags); // As per header file.
+ Histogram* histogram(Histogram::FactoryGet(
+ "Histogram", 1, 64, 8, Histogram::kNoFlags)); // As per header file.
// Check that we got a nice exponential since there was enough rooom.
EXPECT_EQ(0, histogram->ranges(0));
@@ -314,8 +329,8 @@ TEST(HistogramTest, BucketPlacementTest) {
// out to the base namespace here. We need to be friends to corrupt the
// internals of the histogram and/or sampleset.
TEST(HistogramTest, CorruptSampleCounts) {
- scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags); // As per header file.
+ Histogram* histogram(Histogram::FactoryGet(
+ "Histogram", 1, 64, 8, Histogram::kNoFlags)); // As per header file.
EXPECT_EQ(0, histogram->sample_.redundant_count());
histogram->Add(20); // Add some samples.
@@ -339,8 +354,8 @@ TEST(HistogramTest, CorruptSampleCounts) {
}
TEST(HistogramTest, CorruptBucketBounds) {
- scoped_refptr<Histogram> histogram = Histogram::FactoryGet(
- "Histogram", 1, 64, 8, Histogram::kNoFlags); // As per header file.
+ Histogram* histogram(Histogram::FactoryGet(
+ "Histogram", 1, 64, 8, Histogram::kNoFlags)); // As per header file.
Histogram::SampleSet snapshot;
histogram->SnapshotSample(&snapshot);
diff --git a/base/metrics/stats_counters.cc b/base/metrics/stats_counters.cc
index 958f048..f763220 100644
--- a/base/metrics/stats_counters.cc
+++ b/base/metrics/stats_counters.cc
@@ -9,8 +9,12 @@ namespace base {
StatsCounter::StatsCounter(const std::string& name)
: counter_id_(-1) {
// We prepend the name with 'c:' to indicate that it is a counter.
- name_ = "c:";
- name_.append(name);
+ if (StatsTable::current()) {
+ // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
+ // static.
+ name_ = "c:";
+ name_.append(name);
+ }
}
StatsCounter::~StatsCounter() {
@@ -61,8 +65,12 @@ int* StatsCounter::GetPtr() {
StatsCounterTimer::StatsCounterTimer(const std::string& name) {
// we prepend the name with 't:' to indicate that it is a timer.
- name_ = "t:";
- name_.append(name);
+ if (StatsTable::current()) {
+ // TODO(mbelshe): name_ construction is racy and it may corrupt memory for
+ // static.
+ name_ = "t:";
+ name_.append(name);
+ }
}
StatsCounterTimer::~StatsCounterTimer() {
diff --git a/base/metrics/stats_counters.h b/base/metrics/stats_counters.h
index 2de2b73..f40dcbe 100644
--- a/base/metrics/stats_counters.h
+++ b/base/metrics/stats_counters.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,7 @@
#include <string>
+#include "base/base_api.h"
#include "base/metrics/stats_table.h"
#include "base/time.h"
@@ -46,14 +47,14 @@ namespace base {
//------------------------------------------------------------------------------
// First provide generic macros, which exist in production as well as debug.
#define STATS_COUNTER(name, delta) do { \
- static base::StatsCounter counter(name); \
+ base::StatsCounter counter(name); \
counter.Add(delta); \
} while (0)
#define SIMPLE_STATS_COUNTER(name) STATS_COUNTER(name, 1)
#define RATE_COUNTER(name, duration) do { \
- static base::StatsRate hit_count(name); \
+ base::StatsRate hit_count(name); \
hit_count.AddTime(duration); \
} while (0)
@@ -74,7 +75,7 @@ namespace base {
//------------------------------------------------------------------------------
// StatsCounter represents a counter in the StatsTable class.
-class StatsCounter {
+class BASE_API StatsCounter {
public:
// Create a StatsCounter object.
explicit StatsCounter(const std::string& name);
@@ -128,7 +129,7 @@ class StatsCounter {
// A StatsCounterTimer is a StatsCounter which keeps a timer during
// the scope of the StatsCounterTimer. On destruction, it will record
// its time measurement.
-class StatsCounterTimer : protected StatsCounter {
+class BASE_API StatsCounterTimer : protected StatsCounter {
public:
// Constructs and starts the timer.
explicit StatsCounterTimer(const std::string& name);
@@ -157,7 +158,7 @@ class StatsCounterTimer : protected StatsCounter {
// A StatsRate is a timer that keeps a count of the number of intervals added so
// that several statistics can be produced:
// min, max, avg, count, total
-class StatsRate : public StatsCounterTimer {
+class BASE_API StatsRate : public StatsCounterTimer {
public:
// Constructs and starts the timer.
explicit StatsRate(const std::string& name);
diff --git a/base/metrics/stats_table.cc b/base/metrics/stats_table.cc
index 0e8d016..488c690 100644
--- a/base/metrics/stats_table.cc
+++ b/base/metrics/stats_table.cc
@@ -5,8 +5,8 @@
#include "base/metrics/stats_table.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/process_util.h"
-#include "base/scoped_ptr.h"
#include "base/shared_memory.h"
#include "base/string_piece.h"
#include "base/string_util.h"
diff --git a/base/metrics/stats_table.h b/base/metrics/stats_table.h
index 94f7463..c8ebae7 100644
--- a/base/metrics/stats_table.h
+++ b/base/metrics/stats_table.h
@@ -23,6 +23,7 @@
#include <string>
+#include "base/base_api.h"
#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "base/synchronization/lock.h"
@@ -30,7 +31,7 @@
namespace base {
-class StatsTable {
+class BASE_API StatsTable {
public:
// Create a new StatsTable.
// If a StatsTable already exists with the specified name, this StatsTable