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

Unified Diff: base/metrics/persistent_histogram_allocator.cc

Issue 1738063002: Refactor histogram_persistence to be a class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: refactored (again) into PersistentHistogramAllocator class Created 4 years, 10 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/persistent_histogram_allocator.cc
diff --git a/base/metrics/histogram_persistence.cc b/base/metrics/persistent_histogram_allocator.cc
similarity index 60%
rename from base/metrics/histogram_persistence.cc
rename to base/metrics/persistent_histogram_allocator.cc
index f18d17528354329cd4995615d2451f6a52c59302..b4d1d9eb673e3593eae99119a62b23025f9dbb0b 100644
--- a/base/metrics/histogram_persistence.cc
+++ b/base/metrics/persistent_histogram_allocator.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Copyright (c) 2016 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.
-#include "base/metrics/histogram_persistence.h"
+#include "base/metrics/persistent_histogram_allocator.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -17,42 +17,6 @@ namespace base {
namespace {
-// Enumerate possible creation results for reporting.
-enum CreateHistogramResultType {
- // Everything was fine.
- CREATE_HISTOGRAM_SUCCESS = 0,
-
- // Pointer to metadata was not valid.
- CREATE_HISTOGRAM_INVALID_METADATA_POINTER,
-
- // Histogram metadata was not valid.
- CREATE_HISTOGRAM_INVALID_METADATA,
-
- // Ranges information was not valid.
- CREATE_HISTOGRAM_INVALID_RANGES_ARRAY,
-
- // Counts information was not valid.
- CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY,
-
- // Could not allocate histogram memory due to corruption.
- CREATE_HISTOGRAM_ALLOCATOR_CORRUPT,
-
- // Could not allocate histogram memory due to lack of space.
- CREATE_HISTOGRAM_ALLOCATOR_FULL,
-
- // Could not allocate histogram memory due to unknown error.
- CREATE_HISTOGRAM_ALLOCATOR_ERROR,
-
- // Histogram was of unknown type.
- CREATE_HISTOGRAM_UNKNOWN_TYPE,
-
- // Instance has detected a corrupt allocator (recorded only once).
- CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT,
-
- // Always keep this at the end.
- CREATE_HISTOGRAM_MAX
-};
-
// Name of histogram for storing results of local operations.
const char kResultHistogram[] = "UMA.CreatePersistentHistogram.Result";
@@ -62,45 +26,19 @@ const char kResultHistogram[] = "UMA.CreatePersistentHistogram.Result";
// so that, if the structure of that object changes, stored older versions
// will be safely ignored.
enum : uint32_t {
- kTypeIdHistogram = 0xF1645910 + 2, // SHA1(Histogram) v2
+ kTypeIdHistogram = 0xF1645910 + 2, // SHA1(Histogram) v2
kTypeIdRangesArray = 0xBCEA225A + 1, // SHA1(RangesArray) v1
kTypeIdCountsArray = 0x53215530 + 1, // SHA1(CountsArray) v1
};
-// This data must be held in persistent memory in order for processes to
-// locate and use histograms created elsewhere. All elements must be of a
-// fixed width to ensure 32/64-bit interoperability.
-struct PersistentHistogramData {
- int32_t histogram_type;
- int32_t flags;
- int32_t minimum;
- int32_t maximum;
- uint32_t bucket_count;
- PersistentMemoryAllocator::Reference ranges_ref;
- uint32_t ranges_checksum;
- PersistentMemoryAllocator::Reference counts_ref;
- HistogramSamples::Metadata samples_metadata;
- HistogramSamples::Metadata logged_metadata;
-
- // Space for the histogram name will be added during the actual allocation
- // request. This must be the last field of the structure. A zero-size array
- // or a "flexible" array would be preferred but is not (yet) valid C++.
- char name[1];
-};
-
-// The object held here will obviously not be destructed at process exit
-// but that's okay since PersistentMemoryAllocator objects are explicitly
-// forbidden from doing anything essential at exit anyway due to the fact
-// that they depend on data managed elsewhere and which could be destructed
-// first.
-PersistentMemoryAllocator* g_allocator = nullptr;
-
// Take an array of range boundaries and create a proper BucketRanges object
// which is returned to the caller. A return of nullptr indicates that the
// passed boundaries are invalid.
-BucketRanges* CreateRangesFromData(HistogramBase::Sample* ranges_data,
- uint32_t ranges_checksum,
- size_t count) {
+scoped_ptr<BucketRanges> CreateRangesFromData(
+ HistogramBase::Sample* ranges_data,
+ uint32_t ranges_checksum,
+ size_t count) {
+ // To avoid racy destruction at shutdown, the following may be leaked.
scoped_ptr<BucketRanges> ranges(new BucketRanges(count));
DCHECK_EQ(count, ranges->size());
for (size_t i = 0; i < count; ++i) {
@@ -113,7 +51,7 @@ BucketRanges* CreateRangesFromData(HistogramBase::Sample* ranges_data,
if (ranges->checksum() != ranges_checksum)
return nullptr;
- return ranges.release();
+ return ranges;
}
// Calculate the number of bytes required to store all of a histogram's
@@ -138,66 +76,197 @@ const Feature kPersistentHistogramsFeature{
"PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
};
-// Get the histogram in which create results are stored. This is copied almost
-// exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with added code
-// to prevent recursion (a likely occurance because the creation of a new
-// histogram can end up calling this.)
-HistogramBase* GetCreateHistogramResultHistogram() {
- static base::subtle::AtomicWord atomic_histogram_pointer = 0;
- HistogramBase* histogram_pointer(
- reinterpret_cast<HistogramBase*>(
- base::subtle::Acquire_Load(&atomic_histogram_pointer)));
- if (!histogram_pointer) {
- // It's possible for multiple threads to make it here in parallel but
- // they'll always return the same result as there is a mutex in the Get.
- // The purpose of the "initialized" variable is just to ensure that
- // the same thread doesn't recurse which is also why it doesn't have
- // to be atomic.
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- if (g_allocator) {
- DLOG(WARNING) << "Creating the results-histogram inside persistent"
- << " memory can cause future allocations to crash if"
- << " that memory is ever released (for testing).";
- }
+// This data will be held in persistent memory in order for processes to
+// locate and use histograms created elsewhere.
+struct PersistentHistogramAllocator::PersistentHistogramData {
+ int32_t histogram_type;
+ int32_t flags;
+ int32_t minimum;
+ int32_t maximum;
+ uint32_t bucket_count;
+ PersistentMemoryAllocator::Reference ranges_ref;
+ uint32_t ranges_checksum;
+ PersistentMemoryAllocator::Reference counts_ref;
+ HistogramSamples::Metadata samples_metadata;
+ HistogramSamples::Metadata logged_metadata;
- histogram_pointer = LinearHistogram::FactoryGet(
- kResultHistogram, 1, CREATE_HISTOGRAM_MAX, CREATE_HISTOGRAM_MAX + 1,
- HistogramBase::kUmaTargetedHistogramFlag);
- base::subtle::Release_Store(
- &atomic_histogram_pointer,
- reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
- }
+ // Space for the histogram name will be added during the actual allocation
+ // request. This must be the last field of the structure. A zero-size array
+ // or a "flexible" array would be preferred but is not (yet) valid C++.
+ char name[1];
+};
+
+// The object held here will obviously not be destructed at process exit
+// but that's best since PersistentMemoryAllocator objects (that underlie
+// PersistentHistogramAllocator objects) are explicitly forbidden from doing
+// anything essential at exit anyway due to the fact that they depend on data
+// managed elsewhere and which could be destructed first.
+PersistentHistogramAllocator* PersistentHistogramAllocator::g_allocator_;
Alexei Svitkine (slow) 2016/03/03 18:11:28 Can this be local to the file? (If not, the comme
bcwhite 2016/03/04 21:17:16 Done. I wasn't sure which was the best style for
+
+PersistentHistogramAllocator::PersistentHistogramAllocator(
+ scoped_ptr<PersistentMemoryAllocator> memory)
+ : memory_allocator_(std::move(memory)) {}
+
+PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
+
+scoped_ptr<HistogramBase> PersistentHistogramAllocator::GetHistogram(
+ Reference ref) {
+ // Unfortunately, the histogram "pickle" methods cannot be used as part of
+ // the persistance because the deserialization methods always create local
+ // count data (while these must reference the persistent counts) and always
+ // add it to the local list of known histograms (while these may be simple
+ // references to histograms in other processes).
+ PersistentHistogramData* histogram_data =
+ memory_allocator_->GetAsObject<PersistentHistogramData>(
+ ref, kTypeIdHistogram);
+ size_t length = memory_allocator_->GetAllocSize(ref);
+ if (!histogram_data ||
+ reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') {
+ RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA);
+ NOTREACHED();
+ return nullptr;
}
- return histogram_pointer;
+ return CreateHistogram(histogram_data);
}
-// Record the result of a histogram creation.
-void RecordCreateHistogramResult(CreateHistogramResultType result) {
- HistogramBase* result_histogram = GetCreateHistogramResultHistogram();
- if (result_histogram)
- result_histogram->Add(result);
+void PersistentHistogramAllocator::CreateIterator(Iterator* iter) {
+ memory_allocator_->CreateIterator(&iter->memory_iter);
+}
+
+scoped_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
+ HistogramType histogram_type,
+ const std::string& name,
+ int minimum,
+ int maximum,
+ const BucketRanges* bucket_ranges,
+ int32_t flags,
+ Reference* ref_ptr) {
+ // If the allocator is corrupt, don't waste time trying anything else.
+ // This also allows differentiating on the dashboard between allocations
+ // failed due to a corrupt allocator and the number of process instances
+ // with one, the latter being idicated by "newly corrupt", below.
+ if (memory_allocator_->IsCorrupt()) {
+ RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT);
+ 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);
+ 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);
+
+ // 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);
+
+ 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;
+
+ // 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
+ // statement here and serves as a double-check that everything is
+ // correct before commiting the new histogram to persistent space.
+ scoped_ptr<HistogramBase> histogram = CreateHistogram(histogram_data);
+ DCHECK(histogram);
+ if (ref_ptr != nullptr)
+ *ref_ptr = histogram_ref;
+ subtle::NoBarrier_Store(&last_created_, histogram_ref);
+ return histogram;
+ }
+
+ CreateHistogramResultType result;
+ if (memory_allocator_->IsCorrupt()) {
+ RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT);
+ result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT;
+ } else if (memory_allocator_->IsFull()) {
+ result = CREATE_HISTOGRAM_ALLOCATOR_FULL;
+ } else {
+ result = CREATE_HISTOGRAM_ALLOCATOR_ERROR;
+ }
+ RecordCreateHistogramResult(result);
+ NOTREACHED() << "error=" << result;
+
+ return nullptr;
+}
+
+void PersistentHistogramAllocator::FinalizeHistogram(
+ Reference ref,
+ bool registered) {
+ // If the created persistent histogram was registered then it needs to
+ // be marked as "iterable" in order to be found by other processes.
+ if (registered)
+ memory_allocator_->MakeIterable(ref);
+ // If it wasn't registered 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
+ memory_allocator_->SetType(ref, 0);
+}
+
+void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) {
+ memory_allocator_->CreateTrackingHistograms(name);
+}
+
+void PersistentHistogramAllocator::UpdateTrackingHistograms() {
+ memory_allocator_->UpdateTrackingHistograms();
}
-void SetPersistentHistogramMemoryAllocator(
- PersistentMemoryAllocator* allocator) {
+// static
+void PersistentHistogramAllocator::SetGlobalAllocator(
+ scoped_ptr<PersistentHistogramAllocator> allocator) {
// Releasing or changing an allocator is extremely dangerous because it
// likely has histograms stored within it. If the backing memory is also
// also released, future accesses to those histograms will seg-fault.
- CHECK(!g_allocator);
- g_allocator = allocator;
+ CHECK(!g_allocator_);
+ g_allocator_ = allocator.release();
}
-PersistentMemoryAllocator* GetPersistentHistogramMemoryAllocator() {
- return g_allocator;
+// static
+PersistentHistogramAllocator*
+PersistentHistogramAllocator::GetGlobalAllocator() {
+ return g_allocator_;
}
-PersistentMemoryAllocator*
-ReleasePersistentHistogramMemoryAllocatorForTesting() {
- PersistentMemoryAllocator* allocator = g_allocator;
- if (!allocator)
+// static
+scoped_ptr<PersistentHistogramAllocator>
+PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting() {
+ PersistentHistogramAllocator* histogram_allocator = g_allocator_;
+ if (!histogram_allocator)
return nullptr;
+ PersistentMemoryAllocator* memory_allocator =
+ histogram_allocator->memory_allocator();
// Before releasing the memory, it's necessary to have the Statistics-
// Recorder forget about the histograms contained therein; otherwise,
@@ -205,11 +274,11 @@ ReleasePersistentHistogramMemoryAllocatorForTesting() {
PersistentMemoryAllocator::Iterator iter;
PersistentMemoryAllocator::Reference ref;
uint32_t type_id;
- allocator->CreateIterator(&iter);
- while ((ref = allocator->GetNextIterable(&iter, &type_id)) != 0) {
+ memory_allocator->CreateIterator(&iter);
+ while ((ref = memory_allocator->GetNextIterable(&iter, &type_id)) != 0) {
if (type_id == kTypeIdHistogram) {
PersistentHistogramData* histogram_data =
- allocator->GetAsObject<PersistentHistogramData>(
+ memory_allocator->GetAsObject<PersistentHistogramData>(
ref, kTypeIdHistogram);
DCHECK(histogram_data);
StatisticsRecorder::ForgetHistogramForTesting(histogram_data->name);
@@ -218,19 +287,108 @@ ReleasePersistentHistogramMemoryAllocatorForTesting() {
// actively used by this code is being released back to the test.
// If that memory segment were to be deleted, future calls to create
// persistent histograms would crash. To avoid this, have the test call
- // the method GetCreateHistogramResultHistogram() *before* setting the
- // (temporary) memory allocator via SetPersistentMemoryAllocator() so
- // that the histogram is instead allocated from the process heap.
+ // the method GetCreateHistogramResultHistogram() *before* setting
+ // the (temporary) memory allocator via SetGlobalAllocator() so that
+ // histogram is instead allocated from the process heap.
DCHECK_NE(kResultHistogram, histogram_data->name);
}
}
- g_allocator = nullptr;
- return allocator;
+ g_allocator_ = nullptr;
+ return make_scoped_ptr(histogram_allocator);
};
-HistogramBase* CreatePersistentHistogram(
- PersistentMemoryAllocator* allocator,
+// static
+void PersistentHistogramAllocator::ImportGlobalHistograms() {
+ // The lock protects against concurrent access to the iterator and is created
+ // in a thread-safe manner when needed.
+ static base::LazyInstance<base::Lock>::Leaky lock = LAZY_INSTANCE_INITIALIZER;
+
+ if (g_allocator_) {
+ // TODO(bcwhite): Investigate a lock-free, thread-safe iterator.
+ base::AutoLock auto_lock(lock.Get());
+
+ // Each call resumes from where it last left off so need persistant
Alexei Svitkine (slow) 2016/03/03 18:11:28 Nit: Grammar.
bcwhite 2016/03/04 21:17:16 Done.
+ // the iterator. This class has a constructor so even the definition
+ // has to be protected by the lock in order to be thread-safe.
+ static Iterator iter;
+ if (iter.is_clear())
+ g_allocator_->CreateIterator(&iter);
+
+ // Skip the import if it's the histogram that was last created. Should a
+ // race condition cause the "last created" to be overwritten before it
+ // is recognized here then the histogram will be created and be ignored
+ // when it is detected as a duplicate by the statistics-recorder. This
+ // simple check reduces the time of creating persistent histograms by
+ // about 40%.
+ Reference last_created =
+ subtle::NoBarrier_Load(&g_allocator_->last_created_);
+
+ while (true) {
+ scoped_ptr<HistogramBase> histogram =
+ g_allocator_->GetNextHistogramWithIgnore(&iter, last_created);
+ if (!histogram)
+ break;
+ StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release());
+ }
+ }
+}
+
+// static
+HistogramBase*
+PersistentHistogramAllocator::GetCreateHistogramResultHistogram() {
+ // Get the histogram in which create-results are stored. This is copied
+ // almost exactly from the STATIC_HISTOGRAM_POINTER_BLOCK macro but with
+ // added code to prevent recursion (a likely occurance because the creation
+ // of a new a histogram can end up calling this.)
+ static base::subtle::AtomicWord atomic_histogram_pointer = 0;
+ HistogramBase* histogram_pointer =
+ reinterpret_cast<HistogramBase*>(
+ base::subtle::Acquire_Load(&atomic_histogram_pointer));
+ if (!histogram_pointer) {
+ // It's possible for multiple threads to make it here in parallel but
+ // they'll always return the same result as there is a mutex in the Get.
+ // The purpose of the "initialized" variable is just to ensure that
+ // the same thread doesn't recurse which is also why it doesn't have
+ // to be atomic.
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+ if (g_allocator_) {
+ DLOG(WARNING) << "Creating the results-histogram inside persistent"
+ << " memory can cause future allocations to crash if"
+ << " that memory is ever released (for testing).";
+ }
+
+ histogram_pointer = LinearHistogram::FactoryGet(
+ kResultHistogram, 1, CREATE_HISTOGRAM_MAX, CREATE_HISTOGRAM_MAX + 1,
+ HistogramBase::kUmaTargetedHistogramFlag);
+ base::subtle::Release_Store(
+ &atomic_histogram_pointer,
+ reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+ }
+ }
+ return histogram_pointer;
+}
+
+scoped_ptr<HistogramBase>
+PersistentHistogramAllocator::GetNextHistogramWithIgnore(
+ Iterator* iter,
+ Reference ignore) {
+ PersistentMemoryAllocator::Reference ref;
+ uint32_t type_id;
+ while ((ref = memory_allocator_->GetNextIterable(&iter->memory_iter,
+ &type_id)) != 0) {
+ if (ref == ignore)
+ continue;
+ if (type_id == kTypeIdHistogram)
+ return GetHistogram(ref);
+ }
+ return nullptr;
+}
+
+// static
+scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
PersistentHistogramData* histogram_data_ptr) {
if (!histogram_data_ptr) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER);
@@ -246,37 +404,38 @@ HistogramBase* CreatePersistentHistogram(
PersistentHistogramData histogram_data = *histogram_data_ptr;
HistogramBase::Sample* ranges_data =
- allocator->GetAsObject<HistogramBase::Sample>(histogram_data.ranges_ref,
- kTypeIdRangesArray);
+ memory_allocator_->GetAsObject<HistogramBase::Sample>(
+ histogram_data.ranges_ref, kTypeIdRangesArray);
if (!ranges_data || histogram_data.bucket_count < 2 ||
- histogram_data.bucket_count + 1 >
- std::numeric_limits<uint32_t>::max() /
- sizeof(HistogramBase::Sample) ||
- allocator->GetAllocSize(histogram_data.ranges_ref) <
+ histogram_data.bucket_count + 1 > std::numeric_limits<uint32_t>::max() /
+ sizeof(HistogramBase::Sample) ||
+ memory_allocator_->GetAllocSize(histogram_data.ranges_ref) <
(histogram_data.bucket_count + 1) * sizeof(HistogramBase::Sample)) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
NOTREACHED();
return nullptr;
}
- // To avoid racy destruction at shutdown, the following will be leaked.
- const BucketRanges* ranges = CreateRangesFromData(
- ranges_data,
- histogram_data.ranges_checksum,
- histogram_data.bucket_count + 1);
- if (!ranges) {
+
+ scoped_ptr<const BucketRanges> created_ranges =
+ CreateRangesFromData(ranges_data, histogram_data.ranges_checksum,
+ histogram_data.bucket_count + 1);
+ if (!created_ranges) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_RANGES_ARRAY);
NOTREACHED();
return nullptr;
}
- ranges = StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+ const BucketRanges* ranges =
+ StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
+ created_ranges.release());
HistogramBase::AtomicCount* counts_data =
- allocator->GetAsObject<HistogramBase::AtomicCount>(
+ memory_allocator_->GetAsObject<HistogramBase::AtomicCount>(
histogram_data.counts_ref, kTypeIdCountsArray);
size_t counts_bytes =
CalculateRequiredCountsBytes(histogram_data.bucket_count);
if (!counts_data || !counts_bytes ||
- allocator->GetAllocSize(histogram_data.counts_ref) < counts_bytes) {
+ memory_allocator_->GetAllocSize(histogram_data.counts_ref) <
+ counts_bytes) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_COUNTS_ARRAY);
NOTREACHED();
return nullptr;
@@ -289,51 +448,34 @@ HistogramBase* CreatePersistentHistogram(
counts_data + histogram_data.bucket_count;
std::string name(histogram_data_ptr->name);
- HistogramBase* histogram = nullptr;
+ scoped_ptr<HistogramBase> histogram;
switch (histogram_data.histogram_type) {
case HISTOGRAM:
- histogram = Histogram::PersistentGet(
- name,
- histogram_data.minimum,
- histogram_data.maximum,
- ranges,
- counts_data,
- logged_data,
- histogram_data.bucket_count,
+ histogram = Histogram::PersistentCreate(
+ name, histogram_data.minimum, histogram_data.maximum, ranges,
+ counts_data, logged_data, histogram_data.bucket_count,
&histogram_data_ptr->samples_metadata,
&histogram_data_ptr->logged_metadata);
DCHECK(histogram);
break;
case LINEAR_HISTOGRAM:
- histogram = LinearHistogram::PersistentGet(
- name,
- histogram_data.minimum,
- histogram_data.maximum,
- ranges,
- counts_data,
- logged_data,
- histogram_data.bucket_count,
+ histogram = LinearHistogram::PersistentCreate(
+ name, histogram_data.minimum, histogram_data.maximum, ranges,
+ counts_data, logged_data, histogram_data.bucket_count,
&histogram_data_ptr->samples_metadata,
&histogram_data_ptr->logged_metadata);
DCHECK(histogram);
break;
case BOOLEAN_HISTOGRAM:
- histogram = BooleanHistogram::PersistentGet(
- name,
- ranges,
- counts_data,
- logged_data,
+ histogram = BooleanHistogram::PersistentCreate(
+ name, ranges, counts_data, logged_data,
&histogram_data_ptr->samples_metadata,
&histogram_data_ptr->logged_metadata);
DCHECK(histogram);
break;
case CUSTOM_HISTOGRAM:
- histogram = CustomHistogram::PersistentGet(
- name,
- ranges,
- counts_data,
- logged_data,
- histogram_data.bucket_count,
+ histogram = CustomHistogram::PersistentCreate(
+ name, ranges, counts_data, logged_data, histogram_data.bucket_count,
&histogram_data_ptr->samples_metadata,
&histogram_data_ptr->logged_metadata);
DCHECK(histogram);
@@ -353,164 +495,12 @@ HistogramBase* CreatePersistentHistogram(
return histogram;
}
-HistogramBase* GetPersistentHistogram(
- PersistentMemoryAllocator* allocator,
- int32_t ref) {
- // Unfortunately, the above "pickle" methods cannot be used as part of the
- // persistance because the deserialization methods always create local
- // count data (these must referenced the persistent counts) and always add
- // it to the local list of known histograms (these may be simple references
- // to histograms in other processes).
- PersistentHistogramData* histogram_data =
- allocator->GetAsObject<PersistentHistogramData>(ref, kTypeIdHistogram);
- size_t length = allocator->GetAllocSize(ref);
- if (!histogram_data ||
- reinterpret_cast<char*>(histogram_data)[length - 1] != '\0') {
- RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA);
- NOTREACHED();
- return nullptr;
- }
- return CreatePersistentHistogram(allocator, histogram_data);
-}
-
-HistogramBase* GetNextPersistentHistogram(
- PersistentMemoryAllocator* allocator,
- PersistentMemoryAllocator::Iterator* iter) {
- PersistentMemoryAllocator::Reference ref;
- uint32_t type_id;
- while ((ref = allocator->GetNextIterable(iter, &type_id)) != 0) {
- if (type_id == kTypeIdHistogram)
- return GetPersistentHistogram(allocator, ref);
- }
- return nullptr;
-}
-
-void FinalizePersistentHistogram(PersistentMemoryAllocator::Reference ref,
- bool registered) {
- // If the created persistent histogram was registered then it needs to
- // be marked as "iterable" in order to be found by other processes.
- if (registered)
- GetPersistentHistogramMemoryAllocator()->MakeIterable(ref);
- // If it wasn't registered 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(ref, 0);
-}
-
-HistogramBase* AllocatePersistentHistogram(
- PersistentMemoryAllocator* allocator,
- HistogramType histogram_type,
- const std::string& name,
- int minimum,
- int maximum,
- const BucketRanges* bucket_ranges,
- int32_t flags,
- PersistentMemoryAllocator::Reference* ref_ptr) {
- if (!allocator)
- return nullptr;
-
- // If the allocator is corrupt, don't waste time trying anything else.
- // This also allows differentiating on the dashboard between allocations
- // failed due to a corrupt allocator and the number of process instances
- // with one, the latter being idicated by "newly corrupt", below.
- if (allocator->IsCorrupt()) {
- RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT);
- 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 =
- allocator->Allocate(ranges_bytes, kTypeIdRangesArray);
- PersistentMemoryAllocator::Reference counts_ref =
- allocator->Allocate(counts_bytes, kTypeIdCountsArray);
- PersistentMemoryAllocator::Reference histogram_ref =
- allocator->Allocate(offsetof(PersistentHistogramData, name) +
- name.length() + 1, kTypeIdHistogram);
- HistogramBase::Sample* ranges_data =
- allocator->GetAsObject<HistogramBase::Sample>(ranges_ref,
- kTypeIdRangesArray);
- PersistentHistogramData* histogram_data =
- allocator->GetAsObject<PersistentHistogramData>(histogram_ref,
- kTypeIdHistogram);
-
- // 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 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);
-
- 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;
-
- // 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
- // statement here and serves as a double-check that everything is
- // correct before commiting the new histogram to persistent space.
- HistogramBase* histogram =
- CreatePersistentHistogram(allocator, histogram_data);
- DCHECK(histogram);
- if (ref_ptr != nullptr)
- *ref_ptr = histogram_ref;
- return histogram;
- }
-
- CreateHistogramResultType result;
- if (allocator->IsCorrupt()) {
- RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT);
- result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT;
- } else if (allocator->IsFull()) {
- result = CREATE_HISTOGRAM_ALLOCATOR_FULL;
- } else {
- result = CREATE_HISTOGRAM_ALLOCATOR_ERROR;
- }
- RecordCreateHistogramResult(result);
- NOTREACHED() << "error=" << result;
-
- return nullptr;
-}
-
-void ImportPersistentHistograms() {
- // The lock protects against concurrent access to the iterator and is created
- // in a thread-safe manner when needed.
- static base::LazyInstance<base::Lock>::Leaky lock = LAZY_INSTANCE_INITIALIZER;
-
- if (g_allocator) {
- base::AutoLock auto_lock(lock.Get());
-
- // Each call resumes from where it last left off so need persistant
- // iterator. This class has a constructor so even the definition has
- // to be protected by the lock in order to be thread-safe.
- static PersistentMemoryAllocator::Iterator iter;
- if (iter.is_clear())
- g_allocator->CreateIterator(&iter);
-
- while (true) {
- HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter);
- if (!histogram)
- break;
- StatisticsRecorder::RegisterOrDeleteDuplicate(histogram);
- }
- }
+// static
+void PersistentHistogramAllocator::RecordCreateHistogramResult(
+ CreateHistogramResultType result) {
+ HistogramBase* result_histogram = GetCreateHistogramResultHistogram();
+ if (result_histogram)
+ result_histogram->Add(result);
}
} // namespace base

Powered by Google App Engine
This is Rietveld 408576698