diff options
author | Kristian Monsen <kristianm@google.com> | 2011-06-28 21:49:31 +0100 |
---|---|---|
committer | Kristian Monsen <kristianm@google.com> | 2011-07-08 17:55:00 +0100 |
commit | ddb351dbec246cf1fab5ec20d2d5520909041de1 (patch) | |
tree | 158e3fb57bdcac07c7f1e767fde3c70687c9fbb1 /base/metrics | |
parent | 6b92e04f5f151c896e3088e86f70db7081009308 (diff) | |
download | external_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.h | 49 | ||||
-rw-r--r-- | base/metrics/histogram.cc | 158 | ||||
-rw-r--r-- | base/metrics/histogram.h | 177 | ||||
-rw-r--r-- | base/metrics/histogram_unittest.cc | 117 | ||||
-rw-r--r-- | base/metrics/stats_counters.cc | 16 | ||||
-rw-r--r-- | base/metrics/stats_counters.h | 13 | ||||
-rw-r--r-- | base/metrics/stats_table.cc | 2 | ||||
-rw-r--r-- | base/metrics/stats_table.h | 3 |
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 |