Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3493)

Unified Diff: base/metrics/histogram.cc

Issue 1425533011: Support "shared" histograms between processes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@shmem-alloc
Patch Set: moved Create-Result histogram to private space and added to histograms.xml Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_base.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/metrics/histogram.cc
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 62c2bc808dad38aac0c125ee9ab6bd8d61de52c3..a1a6ac7f86277f5cae0f76c7b66e9daab3b8b0a6 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -19,7 +19,9 @@
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_persistence.h"
#include "base/metrics/metrics_hashes.h"
+#include "base/metrics/persistent_memory_allocator.h"
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
@@ -84,45 +86,160 @@ typedef HistogramBase::Sample Sample;
// static
const size_t Histogram::kBucketCount_MAX = 16384u;
-HistogramBase* Histogram::FactoryGet(const std::string& name,
- Sample minimum,
- Sample maximum,
- size_t bucket_count,
- int32_t flags) {
- bool valid_arguments =
- InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
- DCHECK(valid_arguments);
+class Histogram::Factory {
+ public:
+ Factory(const std::string& name,
+ HistogramBase::Sample minimum,
+ HistogramBase::Sample maximum,
+ size_t bucket_count,
+ int32_t flags)
+ : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
+
+ // Create histogram based on construction parameters. Caller takes
+ // ownership of the returned object.
+ HistogramBase* Build();
+
+ protected:
+ Factory(const std::string& name,
+ HistogramType histogram_type,
+ HistogramBase::Sample minimum,
+ HistogramBase::Sample maximum,
+ size_t bucket_count,
+ int32_t flags)
+ : name_(name),
+ histogram_type_(histogram_type),
+ minimum_(minimum),
+ maximum_(maximum),
+ bucket_count_(bucket_count),
+ flags_(flags) {}
+
+ // Create a BucketRanges structure appropriate for this histogram.
+ virtual BucketRanges* CreateRanges() {
+ BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
+ Histogram::InitializeBucketRanges(minimum_, maximum_, ranges);
+ return ranges;
+ }
- HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+ // Allocate the correct Histogram object off the heap (in case persistent
+ // memory is not available).
+ virtual HistogramBase* HeapAlloc(const BucketRanges* ranges) {
+ return new Histogram(name_, minimum_, maximum_, ranges);
+ }
+
+ // Perform any required datafill on the just-created histogram. If
+ // overridden, be sure to call the "super" version.
+ virtual void FillHistogram(HistogramBase* histogram) {
+ histogram->SetFlags(flags_);
+ }
+
+ // These values are protected (instead of private) because they need to
+ // be accessible to methods of sub-classes in order to avoid passing
+ // unnecessary parameters everywhere.
+ const std::string& name_;
+ const HistogramType histogram_type_;
+ HistogramBase::Sample minimum_;
+ HistogramBase::Sample maximum_;
+ size_t bucket_count_;
+ int32_t flags_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
+HistogramBase* Histogram::Factory::Build() {
+ // Import histograms from known persistent storage. Histograms could have
+ // been added by other processes and they must be fetched and recognized
+ // locally in order to be found by FindHistograms() below. If the persistent
+ // memory segment is not shared between processes, this call does nothing.
+ ImportPersistentHistograms();
+
+ HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
if (!histogram) {
// To avoid racy destruction at shutdown, the following will be leaked.
- BucketRanges* ranges = new BucketRanges(bucket_count + 1);
- InitializeBucketRanges(minimum, maximum, ranges);
+ const BucketRanges* created_ranges = CreateRanges();
const BucketRanges* registered_ranges =
- StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+ StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges);
+
+ // In most cases, the bucket-count, minimum, and maximum values are known
+ // when the code is written and so are passed in explicitly. In other
+ // cases (such as with a CustomHistogram), they are calculated dynamically
+ // at run-time. In the latter case, those ctor parameters are zero and
+ // the results extracted from the result of CreateRanges().
+ if (bucket_count_ == 0) {
+ bucket_count_ = registered_ranges->bucket_count();
+ minimum_ = registered_ranges->range(1);
+ maximum_ = registered_ranges->range(bucket_count_ - 1);
+ }
- Histogram* tentative_histogram =
- new Histogram(name, minimum, maximum, registered_ranges);
+ // Try to create the histogram using a "persistent" allocator. As of
+ // 2015-01-14, the availability of such is controlled by a base::Feature
+ // that is off by default. If the allocator doesn't exist or if
+ // allocating from it fails, code below will allocate the histogram from
+ // the process heap.
+ PersistentMemoryAllocator::Reference histogram_ref = 0;
+ HistogramBase* tentative_histogram = nullptr;
+ PersistentMemoryAllocator* allocator =
+ GetPersistentHistogramMemoryAllocator();
+ if (allocator) {
+ flags_ |= HistogramBase::kIsPersistent;
+ tentative_histogram = AllocatePersistentHistogram(
+ allocator,
+ histogram_type_,
+ name_,
+ minimum_,
+ maximum_,
+ registered_ranges,
+ flags_,
+ &histogram_ref);
+ }
+
+ // Handle the case where no persistent allocator is present or the
+ // persistent allocation fails (perhaps because it is full).
+ if (!tentative_histogram) {
+ DCHECK(!histogram_ref); // Should never have been set.
+ DCHECK(!allocator); // Shouldn't have failed.
+ flags_ &= ~HistogramBase::kIsPersistent;
+ tentative_histogram = HeapAlloc(registered_ranges);
+ }
- tentative_histogram->SetFlags(flags);
+ FillHistogram(tentative_histogram);
histogram =
StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+
+ // Persistent histograms need some follow-up processing.
+ if (histogram_ref) {
+ FinalizePersistentHistogram(histogram_ref,
+ histogram == tentative_histogram);
+ }
}
- DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType());
- if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) {
+ DCHECK_EQ(histogram_type_, histogram->GetHistogramType());
+ if (bucket_count_ != 0 &&
+ !histogram->HasConstructionArguments(minimum_, maximum_, bucket_count_)) {
// The construction arguments do not match the existing histogram. This can
// come about if an extension updates in the middle of a chrome run and has
// changed one of them, or simply by bad code within Chrome itself. We
// return NULL here with the expectation that bad code in Chrome will crash
// on dereference, but extension/Pepper APIs will guard against NULL and not
// crash.
- DLOG(ERROR) << "Histogram " << name << " has bad construction arguments";
- return NULL;
+ DLOG(ERROR) << "Histogram " << name_ << " has bad construction arguments";
+ return nullptr;
}
return histogram;
}
+HistogramBase* Histogram::FactoryGet(const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ int32_t flags) {
+ bool valid_arguments =
+ InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
+ DCHECK(valid_arguments);
+
+ return Factory(name, minimum, maximum, bucket_count, flags).Build();
+}
+
HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
TimeDelta minimum,
TimeDelta maximum,
@@ -150,6 +267,17 @@ HistogramBase* Histogram::FactoryTimeGet(const char* name,
flags);
}
+HistogramBase* Histogram::PersistentGet(const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ HistogramSamples::Metadata* meta) {
+ return new Histogram(name, minimum, maximum, ranges, counts, counts_size,
+ meta);
+}
+
// Calculate what range of values are held in each bucket.
// We have to be careful that we don't pick a ratio between starting points in
// consecutive buckets that is sooo small, that the integer bounds are the same
@@ -344,6 +472,23 @@ Histogram::Histogram(const std::string& name,
samples_.reset(new SampleVector(HashMetricName(name), ranges));
}
+Histogram::Histogram(const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ HistogramSamples::Metadata* meta)
+ : HistogramBase(name),
+ bucket_ranges_(ranges),
+ declared_min_(minimum),
+ declared_max_(maximum) {
+ if (ranges) {
+ samples_.reset(new SampleVector(HashMetricName(name),
+ counts, counts_size, meta, ranges));
+ }
+}
+
Histogram::~Histogram() {
}
@@ -545,6 +690,48 @@ void Histogram::GetCountAndBucketData(Count* count,
// buckets.
//------------------------------------------------------------------------------
+class LinearHistogram::Factory : public Histogram::Factory {
+ public:
+ Factory(const std::string& name,
+ HistogramBase::Sample minimum,
+ HistogramBase::Sample maximum,
+ size_t bucket_count,
+ int32_t flags,
+ const DescriptionPair* descriptions)
+ : Histogram::Factory(name, LINEAR_HISTOGRAM, minimum, maximum,
+ bucket_count, flags) {
+ descriptions_ = descriptions;
+ }
+
+ protected:
+ BucketRanges* CreateRanges() override {
+ BucketRanges* ranges = new BucketRanges(bucket_count_ + 1);
+ LinearHistogram::InitializeBucketRanges(minimum_, maximum_, ranges);
+ return ranges;
+ }
+
+ HistogramBase* HeapAlloc(const BucketRanges* ranges) override {
+ return new LinearHistogram(name_, minimum_, maximum_, ranges);
+ }
+
+ void FillHistogram(HistogramBase* base_histogram) override {
+ Histogram::Factory::FillHistogram(base_histogram);
+ LinearHistogram* histogram = static_cast<LinearHistogram*>(base_histogram);
+ // Set range descriptions.
+ if (descriptions_) {
+ for (int i = 0; descriptions_[i].description; ++i) {
+ histogram->bucket_description_[descriptions_[i].sample] =
+ descriptions_[i].description;
+ }
+ }
+ }
+
+ private:
+ const DescriptionPair* descriptions_;
+
+ DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
LinearHistogram::~LinearHistogram() {}
HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
@@ -583,6 +770,18 @@ HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
flags);
}
+HistogramBase* LinearHistogram::PersistentGet(
+ const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ HistogramSamples::Metadata* meta) {
+ return new LinearHistogram(name, minimum, maximum, ranges, counts,
+ counts_size, meta);
+}
+
HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
const std::string& name,
Sample minimum,
@@ -594,42 +793,8 @@ HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
name, &minimum, &maximum, &bucket_count);
DCHECK(valid_arguments);
- HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
- if (!histogram) {
- // To avoid racy destruction at shutdown, the following will be leaked.
- BucketRanges* ranges = new BucketRanges(bucket_count + 1);
- InitializeBucketRanges(minimum, maximum, ranges);
- const BucketRanges* registered_ranges =
- StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
-
- LinearHistogram* tentative_histogram =
- new LinearHistogram(name, minimum, maximum, registered_ranges);
-
- // Set range descriptions.
- if (descriptions) {
- for (int i = 0; descriptions[i].description; ++i) {
- tentative_histogram->bucket_description_[descriptions[i].sample] =
- descriptions[i].description;
- }
- }
-
- tentative_histogram->SetFlags(flags);
- histogram =
- StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
- }
-
- DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType());
- if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) {
- // The construction arguments do not match the existing histogram. This can
- // come about if an extension updates in the middle of a chrome run and has
- // changed one of them, or simply by bad code within Chrome itself. We
- // return NULL here with the expectation that bad code in Chrome will crash
- // on dereference, but extension/Pepper APIs will guard against NULL and not
- // crash.
- DLOG(ERROR) << "Histogram " << name << " has bad construction arguments";
- return NULL;
- }
- return histogram;
+ return Factory(name, minimum, maximum, bucket_count, flags, descriptions)
+ .Build();
}
HistogramType LinearHistogram::GetHistogramType() const {
@@ -643,6 +808,21 @@ LinearHistogram::LinearHistogram(const std::string& name,
: Histogram(name, minimum, maximum, ranges) {
}
+LinearHistogram::LinearHistogram(const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ HistogramSamples::Metadata* meta)
+ : Histogram(name,
+ minimum,
+ maximum,
+ ranges,
+ counts,
+ counts_size,
+ meta) {}
+
double LinearHistogram::GetBucketSize(Count current, size_t i) const {
DCHECK_GT(ranges(i + 1), ranges(i));
// Adjacent buckets with different widths would have "surprisingly" many (few)
@@ -706,32 +886,43 @@ HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
// This section provides implementation for BooleanHistogram.
//------------------------------------------------------------------------------
-HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
- int32_t flags) {
- HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
- if (!histogram) {
- // To avoid racy destruction at shutdown, the following will be leaked.
- BucketRanges* ranges = new BucketRanges(4);
- LinearHistogram::InitializeBucketRanges(1, 2, ranges);
- const BucketRanges* registered_ranges =
- StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+class BooleanHistogram::Factory : public Histogram::Factory {
+ public:
+ Factory(const std::string& name, int32_t flags)
+ : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
- BooleanHistogram* tentative_histogram =
- new BooleanHistogram(name, registered_ranges);
+ protected:
+ BucketRanges* CreateRanges() override {
+ BucketRanges* ranges = new BucketRanges(3 + 1);
+ LinearHistogram::InitializeBucketRanges(1, 2, ranges);
+ return ranges;
+ }
- tentative_histogram->SetFlags(flags);
- histogram =
- StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+ HistogramBase* HeapAlloc(const BucketRanges* ranges) override {
+ return new BooleanHistogram(name_, ranges);
}
- DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType());
- return histogram;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
+HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
+ int32_t flags) {
+ return Factory(name, flags).Build();
}
HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
return FactoryGet(std::string(name), flags);
}
+HistogramBase* BooleanHistogram::PersistentGet(
+ const std::string& name,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ HistogramSamples::Metadata* meta) {
+ return new BooleanHistogram(name, ranges, counts, meta);
+}
+
HistogramType BooleanHistogram::GetHistogramType() const {
return BOOLEAN_HISTOGRAM;
}
@@ -740,6 +931,12 @@ BooleanHistogram::BooleanHistogram(const std::string& name,
const BucketRanges* ranges)
: LinearHistogram(name, 1, 2, ranges) {}
+BooleanHistogram::BooleanHistogram(const std::string& name,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ HistogramSamples::Metadata* meta)
+ : LinearHistogram(name, 1, 2, ranges, counts, 2, meta) {}
+
HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
std::string histogram_name;
int flags;
@@ -766,30 +963,49 @@ HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
// CustomHistogram:
//------------------------------------------------------------------------------
+class CustomHistogram::Factory : public Histogram::Factory {
+ public:
+ Factory(const std::string& name,
+ const std::vector<Sample>* custom_ranges,
+ int32_t flags)
+ : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
+ custom_ranges_ = custom_ranges;
+ }
+
+ protected:
+ BucketRanges* CreateRanges() override {
+ // Remove the duplicates in the custom ranges array.
+ std::vector<int> ranges = *custom_ranges_;
+ ranges.push_back(0); // Ensure we have a zero value.
+ ranges.push_back(HistogramBase::kSampleType_MAX);
+ std::sort(ranges.begin(), ranges.end());
+ ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
+
+ BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
+ for (size_t i = 0; i < ranges.size(); i++) {
+ bucket_ranges->set_range(i, ranges[i]);
+ }
+ bucket_ranges->ResetChecksum();
+ return bucket_ranges;
+ }
+
+ HistogramBase* HeapAlloc(const BucketRanges* ranges) override {
+ return new CustomHistogram(name_, ranges);
+ }
+
+ private:
+ const std::vector<Sample>* custom_ranges_;
+
+ DISALLOW_COPY_AND_ASSIGN(Factory);
+};
+
HistogramBase* CustomHistogram::FactoryGet(
const std::string& name,
const std::vector<Sample>& custom_ranges,
int32_t flags) {
CHECK(ValidateCustomRanges(custom_ranges));
- HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
- if (!histogram) {
- BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges);
- const BucketRanges* registered_ranges =
- StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
-
- // To avoid racy destruction at shutdown, the following will be leaked.
- CustomHistogram* tentative_histogram =
- new CustomHistogram(name, registered_ranges);
-
- tentative_histogram->SetFlags(flags);
-
- histogram =
- StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
- }
-
- DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM);
- return histogram;
+ return Factory(name, &custom_ranges, flags).Build();
}
HistogramBase* CustomHistogram::FactoryGet(
@@ -799,6 +1015,15 @@ HistogramBase* CustomHistogram::FactoryGet(
return FactoryGet(std::string(name), custom_ranges, flags);
}
+HistogramBase* CustomHistogram::PersistentGet(
+ const std::string& name,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ HistogramSamples::Metadata* meta) {
+ return new CustomHistogram(name, ranges, counts, counts_size, meta);
+}
+
HistogramType CustomHistogram::GetHistogramType() const {
return CUSTOM_HISTOGRAM;
}
@@ -825,6 +1050,19 @@ CustomHistogram::CustomHistogram(const std::string& name,
ranges->range(ranges->bucket_count() - 1),
ranges) {}
+CustomHistogram::CustomHistogram(const std::string& name,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ HistogramSamples::Metadata* meta)
+ : Histogram(name,
+ ranges->range(1),
+ ranges->range(ranges->bucket_count() - 1),
+ ranges,
+ counts,
+ counts_size,
+ meta) {}
+
bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
if (!Histogram::SerializeInfoImpl(pickle))
return false;
@@ -887,22 +1125,4 @@ bool CustomHistogram::ValidateCustomRanges(
return has_valid_range;
}
-// static
-BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges(
- const std::vector<Sample>& custom_ranges) {
- // Remove the duplicates in the custom ranges array.
- std::vector<int> ranges = custom_ranges;
- ranges.push_back(0); // Ensure we have a zero value.
- ranges.push_back(HistogramBase::kSampleType_MAX);
- std::sort(ranges.begin(), ranges.end());
- ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
-
- BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
- for (size_t i = 0; i < ranges.size(); i++) {
- bucket_ranges->set_range(i, ranges[i]);
- }
- bucket_ranges->ResetChecksum();
- return bucket_ranges;
-}
-
} // namespace base
« no previous file with comments | « base/metrics/histogram.h ('k') | base/metrics/histogram_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698