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

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: reorganized persistence around PersistentGet methods to fix visibility problems 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
Index: base/metrics/histogram.cc
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 62c2bc808dad38aac0c125ee9ab6bd8d61de52c3..b8a7d8ab76d0017e1d5dd0ba759849d613626a0e 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,147 @@ 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);
Alexei Svitkine (slow) 2016/01/12 21:54:44 Nit: Remove the extra line.
bcwhite 2016/01/13 13:38:29 Done.
- HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+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) {}
+
+ 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;
+ }
+
+ // 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() {
+ 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);
+
+ // Sometimes the bucket info is dynamically determined in 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);
+ 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);
+ }
- tentative_histogram->SetFlags(flags);
+ // 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);
+ }
+
+ 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 +254,17 @@ HistogramBase* Histogram::FactoryTimeGet(const char* name,
flags);
}
+HistogramBase* Histogram::PersistentGet(const char* 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 +459,22 @@ 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)
Alexei Svitkine (slow) 2016/01/12 21:54:44 Nit: {}'s since body is multi-line.
bcwhite 2016/01/13 13:38:29 Done.
+ samples_.reset(new SampleVector(HashMetricName(name),
+ counts, counts_size, meta, ranges));
+}
+
Histogram::~Histogram() {
}
@@ -545,6 +676,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 +756,18 @@ HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
flags);
}
+HistogramBase* LinearHistogram::PersistentGet(
+ const char* 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 +779,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 +794,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 +872,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() {
+ 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 char* 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 +917,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 +949,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() {
+ // 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 +1001,15 @@ HistogramBase* CustomHistogram::FactoryGet(
return FactoryGet(std::string(name), custom_ranges, flags);
}
+HistogramBase* CustomHistogram::PersistentGet(
+ const char* 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 +1036,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 +1111,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

Powered by Google App Engine
This is Rietveld 408576698