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

Unified Diff: base/metrics/persistent_histogram_allocator.cc

Issue 1734033003: Add support for persistent sparse histograms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 9 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_unittest.cc ('k') | base/metrics/persistent_sample_map.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/metrics/persistent_histogram_allocator.cc
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
index 2e4029ef6a60e7f2bd68e67c42f1ad861e9851cf..6006d31fbee70031acb901fb6a0f04a944f5ff04 100644
--- a/base/metrics/persistent_histogram_allocator.cc
+++ b/base/metrics/persistent_histogram_allocator.cc
@@ -10,6 +10,7 @@
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
+#include "base/metrics/sparse_histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/synchronization/lock.h"
@@ -71,12 +72,12 @@ scoped_ptr<BucketRanges> CreateRangesFromData(
size_t CalculateRequiredCountsBytes(size_t bucket_count) {
// 2 because each "sample count" also requires a backup "logged count"
// used for calculating the delta during snapshot operations.
- const unsigned kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount);
+ const size_t kBytesPerBucket = 2 * sizeof(HistogramBase::AtomicCount);
// If the |bucket_count| is such that it would overflow the return type,
// perhaps as the result of a malicious actor, then return zero to
// indicate the problem to the caller.
- if (bucket_count > std::numeric_limits<uint32_t>::max() / kBytesPerBucket)
+ if (bucket_count > std::numeric_limits<size_t>::max() / kBytesPerBucket)
return 0;
return bucket_count * kBytesPerBucket;
@@ -276,6 +277,18 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
return nullptr;
}
+ // Sparse histograms are quite different so handle them as a special case.
+ if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) {
+ scoped_ptr<HistogramBase> histogram = SparseHistogram::PersistentCreate(
+ memory_allocator(), histogram_data_ptr->name,
+ &histogram_data_ptr->samples_metadata,
+ &histogram_data_ptr->logged_metadata);
+ DCHECK(histogram);
+ histogram->SetFlags(histogram_data_ptr->flags);
+ RecordCreateHistogramResult(CREATE_HISTOGRAM_SUCCESS);
+ return histogram;
+ }
+
// Copy the histogram_data to local storage because anything in persistent
// memory cannot be trusted as it could be changed at any moment by a
// malicious actor that shares access. The contents of histogram_data are
@@ -318,7 +331,7 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
histogram_data.counts_ref, kTypeIdCountsArray);
size_t counts_bytes =
CalculateRequiredCountsBytes(histogram_data.bucket_count);
- if (!counts_data || !counts_bytes ||
+ if (!counts_data || counts_bytes == 0 ||
memory_allocator_->GetAllocSize(histogram_data.counts_ref) <
counts_bytes) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY);
@@ -445,49 +458,64 @@ scoped_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
return nullptr;
}
- // If CalculateRequiredCountsBytes() returns zero then the bucket_count
- // was not valid.
- size_t bucket_count = bucket_ranges->bucket_count();
- size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count);
- if (!counts_bytes) {
- NOTREACHED();
- return nullptr;
- }
-
- size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample);
- PersistentMemoryAllocator::Reference ranges_ref =
- memory_allocator_->Allocate(ranges_bytes, kTypeIdRangesArray);
- PersistentMemoryAllocator::Reference counts_ref =
- memory_allocator_->Allocate(counts_bytes, kTypeIdCountsArray);
+ // Create the metadata necessary for a persistent sparse histogram. This
+ // is done first because it is a small subset of what is required for
+ // other histograms.
PersistentMemoryAllocator::Reference histogram_ref =
memory_allocator_->Allocate(
offsetof(PersistentHistogramData, name) + name.length() + 1,
kTypeIdHistogram);
- HistogramBase::Sample* ranges_data =
- memory_allocator_->GetAsObject<HistogramBase::Sample>(ranges_ref,
- kTypeIdRangesArray);
PersistentHistogramData* histogram_data =
memory_allocator_->GetAsObject<PersistentHistogramData>(histogram_ref,
kTypeIdHistogram);
+ if (histogram_data) {
+ memcpy(histogram_data->name, name.c_str(), name.size() + 1);
+ histogram_data->histogram_type = histogram_type;
+ histogram_data->flags = flags | HistogramBase::kIsPersistent;
+ }
- // Only continue here if all allocations were successful. If they weren't,
- // there is no way to free the space but that's not really a problem since
- // the allocations only fail because the space is full or corrupt and so
- // any future attempts will also fail.
- if (counts_ref && ranges_data && histogram_data) {
- strcpy(histogram_data->name, name.c_str());
- for (size_t i = 0; i < bucket_ranges->size(); ++i)
- ranges_data[i] = bucket_ranges->range(i);
+ // Create the remaining metadata necessary for regular histograms.
+ if (histogram_type != SPARSE_HISTOGRAM) {
+ size_t bucket_count = bucket_ranges->bucket_count();
+ size_t counts_bytes = CalculateRequiredCountsBytes(bucket_count);
+ if (counts_bytes == 0) {
+ // |bucket_count| was out-of-range.
+ NOTREACHED();
+ return nullptr;
+ }
- histogram_data->histogram_type = histogram_type;
- histogram_data->flags = flags;
- histogram_data->minimum = minimum;
- histogram_data->maximum = maximum;
- histogram_data->bucket_count = static_cast<uint32_t>(bucket_count);
- histogram_data->ranges_ref = ranges_ref;
- histogram_data->ranges_checksum = bucket_ranges->checksum();
- histogram_data->counts_ref = counts_ref;
+ size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample);
+ PersistentMemoryAllocator::Reference counts_ref =
+ memory_allocator_->Allocate(counts_bytes, kTypeIdCountsArray);
+ PersistentMemoryAllocator::Reference ranges_ref =
+ memory_allocator_->Allocate(ranges_bytes, kTypeIdRangesArray);
+ HistogramBase::Sample* ranges_data =
+ memory_allocator_->GetAsObject<HistogramBase::Sample>(
+ ranges_ref, kTypeIdRangesArray);
+
+ // Only continue here if all allocations were successful. If they weren't,
+ // there is no way to free the space but that's not really a problem since
+ // the allocations only fail because the space is full or corrupt and so
+ // any future attempts will also fail.
+ if (counts_ref && ranges_data && histogram_data) {
+ for (size_t i = 0; i < bucket_ranges->size(); ++i)
+ ranges_data[i] = bucket_ranges->range(i);
+
+ histogram_data->minimum = minimum;
+ histogram_data->maximum = maximum;
+ // |bucket_count| must fit within 32-bits or the allocation of the counts
+ // array would have failed for being too large; the allocator supports
+ // less than 4GB total size.
+ histogram_data->bucket_count = static_cast<uint32_t>(bucket_count);
+ histogram_data->ranges_ref = ranges_ref;
+ histogram_data->ranges_checksum = bucket_ranges->checksum();
+ histogram_data->counts_ref = counts_ref;
+ } else {
+ histogram_data = nullptr; // Clear this for proper handling below.
+ }
+ }
+ if (histogram_data) {
// Create the histogram using resources in persistent memory. This ends up
// resolving the "ref" values stored in histogram_data instad of just
// using what is already known above but avoids duplicating the switch
« no previous file with comments | « base/metrics/histogram_unittest.cc ('k') | base/metrics/persistent_sample_map.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698