Index: base/metrics/histogram.cc |
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc |
index 083856bf87618379a964eb2095aa6cae4d7039c1..e0a45c569033d17ae64cdf74f2ceb26ef92898a4 100644 |
--- a/base/metrics/histogram.cc |
+++ b/base/metrics/histogram.cc |
@@ -17,7 +17,9 @@ |
#include "base/compiler_specific.h" |
#include "base/debug/alias.h" |
#include "base/logging.h" |
+#include "base/memory/persistent_memory_allocator.h" |
#include "base/metrics/histogram_macros.h" |
+#include "base/metrics/histogram_persistence.h" |
#include "base/metrics/metrics_hashes.h" |
#include "base/metrics/sample_vector.h" |
#include "base/metrics/statistics_recorder.h" |
@@ -83,33 +85,75 @@ 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 flags) { |
- bool valid_arguments = |
- InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
- DCHECK(valid_arguments); |
+// static |
+HistogramBase* Histogram::FactoryGet( |
+ std::function<BucketRanges*()> create_ranges, |
+ std::function<HistogramBase*(const BucketRanges*)> heap_alloc, |
+ std::function<void(HistogramBase*)> fill_histogram, |
+ HistogramType histogram_type, |
+ const std::string& name, |
+ Sample minimum, |
+ Sample maximum, |
+ size_t bucket_count, |
+ int32 flags) { |
+ 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 = create_ranges(); |
const BucketRanges* registered_ranges = |
- StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges); |
+ StatisticsRecorder::RegisterOrDeleteDuplicateRanges(created_ranges); |
+ |
+ // Sometimes the bucket info is dynamically determined in create_ranges(). |
+ 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; |
+ if (allocator_) { |
+ flags |= kIsPersistent; |
+ tentative_histogram = AllocatePersistentHistogram( |
+ GetPersistentHistogramMemoryAllocator(), |
+ histogram_type, |
+ name, |
+ minimum, |
+ maximum, |
+ registered_ranges, |
+ flags, |
+ &histogram_ref); |
+ } |
+ if (!tentative_histogram) { |
+ flags &= ~kIsPersistent; |
+ tentative_histogram = heap_alloc(registered_ranges); |
+ } |
+ |
+ fill_histogram(tentative_histogram); |
tentative_histogram->SetFlags(flags); |
histogram = |
StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
+ |
+ // Persistent histograms need some follow-up processing. |
+ if (histogram_ref) { |
+ // If the created persistent histogram is canonical then it needs to be |
+ // marked as "iterable" in order to be found by other processes. |
+ if (histogram == tentative_histogram) |
+ GetPersistentHistogramMemoryAllocator()->MakeIterable(histogram_ref); |
+ // If it's not the canonical one then a race condition must have caused |
+ // two to be created. The allocator does not support releasing the |
+ // acquired memory so just change the type to be empty. |
+ else |
+ GetPersistentHistogramMemoryAllocator()->SetType(histogram_ref, 0); |
+ } |
} |
- 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 |
@@ -122,6 +166,28 @@ HistogramBase* Histogram::FactoryGet(const std::string& name, |
return histogram; |
} |
+HistogramBase* Histogram::FactoryGet(const std::string& name, |
+ Sample minimum, |
+ Sample maximum, |
+ size_t bucket_count, |
+ int32 flags) { |
+ bool valid_arguments = |
+ InspectConstructionArguments(name, &minimum, &maximum, &bucket_count); |
+ DCHECK(valid_arguments); |
+ |
+ return FactoryGet( |
+ [=]()->BucketRanges* { |
+ BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
+ InitializeBucketRanges(minimum, maximum, ranges); |
+ return ranges; |
+ }, |
+ [=, &name](const BucketRanges* ranges)->HistogramBase* { |
+ return new Histogram(name, minimum, maximum, ranges); |
+ }, |
+ [=](HistogramBase* histogram) {}, |
+ HISTOGRAM, name, minimum, maximum, bucket_count, flags); |
+} |
+ |
HistogramBase* Histogram::FactoryTimeGet(const std::string& name, |
TimeDelta minimum, |
TimeDelta maximum, |
@@ -343,6 +409,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) |
+ samples_.reset(new SampleVector(HashMetricName(name), |
+ counts, counts_size, meta, ranges)); |
+} |
+ |
Histogram::~Histogram() { |
} |
@@ -593,42 +675,26 @@ 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; |
+ return Histogram::FactoryGet( |
+ [=]()->BucketRanges* { |
+ BucketRanges* ranges = new BucketRanges(bucket_count + 1); |
+ InitializeBucketRanges(minimum, maximum, ranges); |
+ return ranges; |
+ }, |
+ [=, &name](const BucketRanges* ranges)->HistogramBase* { |
+ return new LinearHistogram(name, minimum, maximum, ranges); |
+ }, |
+ [=](HistogramBase* base) { |
+ LinearHistogram* histogram = static_cast<LinearHistogram*>(base); |
+ // Set range descriptions. |
+ if (descriptions) { |
+ for (int i = 0; descriptions[i].description; ++i) { |
+ 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; |
+ }, |
+ LINEAR_HISTOGRAM, name, minimum, maximum, bucket_count, flags); |
} |
HistogramType LinearHistogram::GetHistogramType() const { |
@@ -642,6 +708,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) |
@@ -707,24 +788,17 @@ HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) { |
HistogramBase* BooleanHistogram::FactoryGet(const std::string& name, |
int32 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); |
- |
- BooleanHistogram* tentative_histogram = |
- new BooleanHistogram(name, registered_ranges); |
- |
- tentative_histogram->SetFlags(flags); |
- histogram = |
- StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram); |
- } |
- |
- DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType()); |
- return histogram; |
+ return Histogram::FactoryGet( |
+ [=]()->BucketRanges* { |
+ BucketRanges* ranges = new BucketRanges(3 + 1); |
+ LinearHistogram::InitializeBucketRanges(1, 2, ranges); |
+ return ranges; |
+ }, |
+ [=, &name](const BucketRanges* ranges)->HistogramBase* { |
+ return new BooleanHistogram(name, ranges); |
+ }, |
+ [=](HistogramBase* histogram) {}, |
+ BOOLEAN_HISTOGRAM, name, 1, 2, 3, flags); |
} |
HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) { |
@@ -739,6 +813,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; |
@@ -771,24 +851,27 @@ HistogramBase* CustomHistogram::FactoryGet( |
int32 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 Histogram::FactoryGet( |
+ [&]()->BucketRanges* { |
+ // 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; |
+ }, |
+ [=, &name](const BucketRanges* ranges)->HistogramBase* { |
+ return new CustomHistogram(name, ranges); |
+ }, |
+ [=](HistogramBase* histogram) {}, |
+ CUSTOM_HISTOGRAM, name, 0, 0, 0, flags); |
} |
HistogramBase* CustomHistogram::FactoryGet( |
@@ -824,6 +907,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; |
@@ -886,22 +982,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 |