summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorbcwhite <bcwhite@chromium.org>2016-03-15 19:37:45 -0700
committerCommit bot <commit-bot@chromium.org>2016-03-16 02:38:44 +0000
commit33d95806addac4c84a88eb8561ea424ef2097b6d (patch)
tree393f1029aa624f83d61ebe8c4cc88bd379824fb9 /base
parentab4d700467b65a395a64c02d1a7d2777950ec0cd (diff)
downloadchromium_src-33d95806addac4c84a88eb8561ea424ef2097b6d.zip
chromium_src-33d95806addac4c84a88eb8561ea424ef2097b6d.tar.gz
chromium_src-33d95806addac4c84a88eb8561ea424ef2097b6d.tar.bz2
Refactor histogram_persistence to be a class.
The number of top-level functions was getting too large and impeding development of other features due to the previous lack of OO design. The code is largely unchanged, just moved into a stateful class and reordered to match the public/private sections of the class. Two other CLs are included here because they fit well with the refactoring: https://codereview.chromium.org/1689833002/ Add ownership-transfer to histogram management calls. This CL changes the interface to use scoped_ptr to explicitly document, with std::move, when the transfer of ownership is taking place. https://codereview.chromium.org/1731453002/ Reduce histogram creation time by avoiding import of those just created. Attempting to import histograms in the persistent memory segment is necessary because it could be shared and thus have other processes creating objects within it. However, there's no need to import those objects that this process created. The simple method remembering the "reference" of the last histogram created in the allocator catches almost all cases and reduces histogram creation time by 40%. BUG=546019 TBR=grt,thakis grt: setup/installer_metrics.cc (no logic changes) thakis: gn & gyp changes for new files Review URL: https://codereview.chromium.org/1738063002 Cr-Commit-Position: refs/heads/master@{#381386}
Diffstat (limited to 'base')
-rw-r--r--base/BUILD.gn5
-rw-r--r--base/base.gyp1
-rw-r--r--base/base.gypi4
-rw-r--r--base/metrics/histogram.cc74
-rw-r--r--base/metrics/histogram.h78
-rw-r--r--base/metrics/histogram_persistence.h91
-rw-r--r--base/metrics/histogram_samples.h2
-rw-r--r--base/metrics/histogram_unittest.cc117
-rw-r--r--base/metrics/persistent_histogram_allocator.cc (renamed from base/metrics/histogram_persistence.cc)414
-rw-r--r--base/metrics/persistent_histogram_allocator.h212
-rw-r--r--base/metrics/persistent_histogram_allocator_unittest.cc126
-rw-r--r--base/metrics/statistics_recorder_unittest.cc10
12 files changed, 672 insertions, 462 deletions
diff --git a/base/BUILD.gn b/base/BUILD.gn
index cfe258b..1fcd718 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -526,14 +526,14 @@ component("base") {
"metrics/histogram_delta_serialization.h",
"metrics/histogram_flattener.h",
"metrics/histogram_macros.h",
- "metrics/histogram_persistence.cc",
- "metrics/histogram_persistence.h",
"metrics/histogram_samples.cc",
"metrics/histogram_samples.h",
"metrics/histogram_snapshot_manager.cc",
"metrics/histogram_snapshot_manager.h",
"metrics/metrics_hashes.cc",
"metrics/metrics_hashes.h",
+ "metrics/persistent_histogram_allocator.cc",
+ "metrics/persistent_histogram_allocator.h",
"metrics/persistent_memory_allocator.cc",
"metrics/persistent_memory_allocator.h",
"metrics/sample_map.cc",
@@ -1738,6 +1738,7 @@ test("base_unittests") {
"metrics/histogram_snapshot_manager_unittest.cc",
"metrics/histogram_unittest.cc",
"metrics/metrics_hashes_unittest.cc",
+ "metrics/persistent_histogram_allocator_unittest.cc",
"metrics/persistent_memory_allocator_unittest.cc",
"metrics/sample_map_unittest.cc",
"metrics/sample_vector_unittest.cc",
diff --git a/base/base.gyp b/base/base.gyp
index 3f03dd8..d4e5be3 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -490,6 +490,7 @@
'metrics/histogram_snapshot_manager_unittest.cc',
'metrics/histogram_unittest.cc',
'metrics/metrics_hashes_unittest.cc',
+ 'metrics/persistent_histogram_allocator_unittest.cc',
'metrics/persistent_memory_allocator_unittest.cc',
'metrics/sample_map_unittest.cc',
'metrics/sample_vector_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index efcd8a3..4bf8ae6 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -406,14 +406,14 @@
'metrics/histogram_delta_serialization.h',
'metrics/histogram_flattener.h',
'metrics/histogram_macros.h',
- 'metrics/histogram_persistence.cc',
- 'metrics/histogram_persistence.h',
'metrics/histogram_samples.cc',
'metrics/histogram_samples.h',
'metrics/histogram_snapshot_manager.cc',
'metrics/histogram_snapshot_manager.h',
'metrics/metrics_hashes.cc',
'metrics/metrics_hashes.h',
+ 'metrics/persistent_histogram_allocator.cc',
+ 'metrics/persistent_histogram_allocator.h',
'metrics/persistent_memory_allocator.cc',
'metrics/persistent_memory_allocator.h',
'metrics/sample_map.cc',
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index ea4f816..e8d851b 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -19,8 +19,8 @@
#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_histogram_allocator.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
@@ -122,8 +122,8 @@ class Histogram::Factory {
// 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);
+ virtual scoped_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) {
+ return make_scoped_ptr(new Histogram(name_, minimum_, maximum_, ranges));
}
// Perform any required datafill on the just-created histogram. If
@@ -151,7 +151,7 @@ HistogramBase* Histogram::Factory::Build() {
// 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();
+ PersistentHistogramAllocator::ImportGlobalHistograms();
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name_);
if (!histogram) {
@@ -176,14 +176,13 @@ HistogramBase* Histogram::Factory::Build() {
// 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();
+ PersistentHistogramAllocator::Reference histogram_ref = 0;
+ scoped_ptr<HistogramBase> tentative_histogram;
+ PersistentHistogramAllocator* allocator =
+ PersistentHistogramAllocator::GetGlobalAllocator();
if (allocator) {
flags_ |= HistogramBase::kIsPersistent;
- tentative_histogram = AllocatePersistentHistogram(
- allocator,
+ tentative_histogram = allocator->AllocateHistogram(
histogram_type_,
name_,
minimum_,
@@ -202,14 +201,20 @@ HistogramBase* Histogram::Factory::Build() {
tentative_histogram = HeapAlloc(registered_ranges);
}
- FillHistogram(tentative_histogram);
- histogram =
- StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+ FillHistogram(tentative_histogram.get());
+
+ // Register this histogram with the StatisticsRecorder. Keep a copy of
+ // the pointer value to tell later whether the locally created histogram
+ // was registered or deleted. The type is "void" because it could point
+ // to released memory after the following line.
+ const void* tentative_histogram_ptr = tentative_histogram.get();
+ histogram = StatisticsRecorder::RegisterOrDeleteDuplicate(
+ tentative_histogram.release());
// Persistent histograms need some follow-up processing.
if (histogram_ref) {
- FinalizePersistentHistogram(histogram_ref,
- histogram == tentative_histogram);
+ allocator->FinalizeHistogram(histogram_ref,
+ histogram == tentative_histogram_ptr);
}
}
@@ -267,7 +272,7 @@ HistogramBase* Histogram::FactoryTimeGet(const char* name,
flags);
}
-HistogramBase* Histogram::PersistentGet(
+scoped_ptr<HistogramBase> Histogram::PersistentCreate(
const std::string& name,
Sample minimum,
Sample maximum,
@@ -277,8 +282,9 @@ HistogramBase* Histogram::PersistentGet(
uint32_t counts_size,
HistogramSamples::Metadata* meta,
HistogramSamples::Metadata* logged_meta) {
- return new Histogram(name, minimum, maximum, ranges, counts, logged_counts,
- counts_size, meta, logged_meta);
+ return make_scoped_ptr(new Histogram(
+ name, minimum, maximum, ranges, counts, logged_counts, counts_size,
+ meta, logged_meta));
}
// Calculate what range of values are held in each bucket.
@@ -732,8 +738,9 @@ class LinearHistogram::Factory : public Histogram::Factory {
return ranges;
}
- HistogramBase* HeapAlloc(const BucketRanges* ranges) override {
- return new LinearHistogram(name_, minimum_, maximum_, ranges);
+ scoped_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) override {
+ return make_scoped_ptr(
+ new LinearHistogram(name_, minimum_, maximum_, ranges));
}
void FillHistogram(HistogramBase* base_histogram) override {
@@ -792,7 +799,7 @@ HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
flags);
}
-HistogramBase* LinearHistogram::PersistentGet(
+scoped_ptr<HistogramBase> LinearHistogram::PersistentCreate(
const std::string& name,
Sample minimum,
Sample maximum,
@@ -802,8 +809,9 @@ HistogramBase* LinearHistogram::PersistentGet(
uint32_t counts_size,
HistogramSamples::Metadata* meta,
HistogramSamples::Metadata* logged_meta) {
- return new LinearHistogram(name, minimum, maximum, ranges, counts,
- logged_counts, counts_size, meta, logged_meta);
+ return make_scoped_ptr(new LinearHistogram(
+ name, minimum, maximum, ranges, counts, logged_counts, counts_size,
+ meta, logged_meta));
}
HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
@@ -921,8 +929,8 @@ class BooleanHistogram::Factory : public Histogram::Factory {
return ranges;
}
- HistogramBase* HeapAlloc(const BucketRanges* ranges) override {
- return new BooleanHistogram(name_, ranges);
+ scoped_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) override {
+ return make_scoped_ptr(new BooleanHistogram(name_, ranges));
}
private:
@@ -938,15 +946,15 @@ HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
return FactoryGet(std::string(name), flags);
}
-HistogramBase* BooleanHistogram::PersistentGet(
+scoped_ptr<HistogramBase> BooleanHistogram::PersistentCreate(
const std::string& name,
const BucketRanges* ranges,
HistogramBase::AtomicCount* counts,
HistogramBase::AtomicCount* logged_counts,
HistogramSamples::Metadata* meta,
HistogramSamples::Metadata* logged_meta) {
- return new BooleanHistogram(name, ranges, counts, logged_counts, meta,
- logged_meta);
+ return make_scoped_ptr(new BooleanHistogram(
+ name, ranges, counts, logged_counts, meta, logged_meta));
}
HistogramType BooleanHistogram::GetHistogramType() const {
@@ -1018,8 +1026,8 @@ class CustomHistogram::Factory : public Histogram::Factory {
return bucket_ranges;
}
- HistogramBase* HeapAlloc(const BucketRanges* ranges) override {
- return new CustomHistogram(name_, ranges);
+ scoped_ptr<HistogramBase> HeapAlloc(const BucketRanges* ranges) override {
+ return make_scoped_ptr(new CustomHistogram(name_, ranges));
}
private:
@@ -1044,7 +1052,7 @@ HistogramBase* CustomHistogram::FactoryGet(
return FactoryGet(std::string(name), custom_ranges, flags);
}
-HistogramBase* CustomHistogram::PersistentGet(
+scoped_ptr<HistogramBase> CustomHistogram::PersistentCreate(
const std::string& name,
const BucketRanges* ranges,
HistogramBase::AtomicCount* counts,
@@ -1052,8 +1060,8 @@ HistogramBase* CustomHistogram::PersistentGet(
uint32_t counts_size,
HistogramSamples::Metadata* meta,
HistogramSamples::Metadata* logged_meta) {
- return new CustomHistogram(name, ranges, counts, logged_counts, counts_size,
- meta, logged_meta);
+ return make_scoped_ptr(new CustomHistogram(
+ name, ranges, counts, logged_counts, counts_size, meta, logged_meta));
}
HistogramType CustomHistogram::GetHistogramType() const {
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index ea59de6..5111b8f 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -104,6 +104,8 @@ class BASE_EXPORT Histogram : public HistogramBase {
typedef std::vector<Count> Counts;
+ ~Histogram() override;
+
//----------------------------------------------------------------------------
// For a valid histogram, input should follow these restrictions:
// minimum > 0 (if a minimum below 1 is specified, it will implicitly be
@@ -139,16 +141,17 @@ class BASE_EXPORT Histogram : public HistogramBase {
uint32_t bucket_count,
int32_t flags);
- // Get a histogram using data in persistent storage.
- static HistogramBase* PersistentGet(const std::string& name,
- Sample minimum,
- Sample maximum,
- const BucketRanges* ranges,
- HistogramBase::AtomicCount* counts,
- HistogramBase::AtomicCount* logged_counts,
- uint32_t counts_size,
- HistogramSamples::Metadata* meta,
- HistogramSamples::Metadata* logged_meta);
+ // Create a histogram using data in persistent storage.
+ static scoped_ptr<HistogramBase> PersistentCreate(
+ const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ HistogramBase::AtomicCount* logged_counts,
+ uint32_t counts_size,
+ HistogramSamples::Metadata* meta,
+ HistogramSamples::Metadata* logged_meta);
static void InitializeBucketRanges(Sample minimum,
Sample maximum,
@@ -237,8 +240,6 @@ class BASE_EXPORT Histogram : public HistogramBase {
HistogramSamples::Metadata* meta,
HistogramSamples::Metadata* logged_meta);
- ~Histogram() override;
-
// HistogramBase implementation:
bool SerializeInfoImpl(base::Pickle* pickle) const override;
@@ -350,16 +351,17 @@ class BASE_EXPORT LinearHistogram : public Histogram {
uint32_t bucket_count,
int32_t flags);
- // Get a histogram using data in persistent storage.
- static HistogramBase* PersistentGet(const std::string& name,
- Sample minimum,
- Sample maximum,
- const BucketRanges* ranges,
- HistogramBase::AtomicCount* counts,
- HistogramBase::AtomicCount* logged_counts,
- uint32_t counts_size,
- HistogramSamples::Metadata* meta,
- HistogramSamples::Metadata* logged_meta);
+ // Create a histogram using data in persistent storage.
+ static scoped_ptr<HistogramBase> PersistentCreate(
+ const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ HistogramBase::AtomicCount* logged_counts,
+ uint32_t counts_size,
+ HistogramSamples::Metadata* meta,
+ HistogramSamples::Metadata* logged_meta);
struct DescriptionPair {
Sample sample;
@@ -440,13 +442,14 @@ class BASE_EXPORT BooleanHistogram : public LinearHistogram {
// call sites.
static HistogramBase* FactoryGet(const char* name, int32_t flags);
- // Get a histogram using data in persistent storage.
- static HistogramBase* PersistentGet(const std::string& name,
- const BucketRanges* ranges,
- HistogramBase::AtomicCount* counts,
- HistogramBase::AtomicCount* logged_counts,
- HistogramSamples::Metadata* meta,
- HistogramSamples::Metadata* logged_meta);
+ // Create a histogram using data in persistent storage.
+ static scoped_ptr<HistogramBase> PersistentCreate(
+ const std::string& name,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ HistogramBase::AtomicCount* logged_counts,
+ HistogramSamples::Metadata* meta,
+ HistogramSamples::Metadata* logged_meta);
HistogramType GetHistogramType() const override;
@@ -489,14 +492,15 @@ class BASE_EXPORT CustomHistogram : public Histogram {
const std::vector<Sample>& custom_ranges,
int32_t flags);
- // Get a histogram using data in persistent storage.
- static HistogramBase* PersistentGet(const std::string& name,
- const BucketRanges* ranges,
- HistogramBase::AtomicCount* counts,
- HistogramBase::AtomicCount* logged_counts,
- uint32_t counts_size,
- HistogramSamples::Metadata* meta,
- HistogramSamples::Metadata* logged_meta);
+ // Create a histogram using data in persistent storage.
+ static scoped_ptr<HistogramBase> PersistentCreate(
+ const std::string& name,
+ const BucketRanges* ranges,
+ HistogramBase::AtomicCount* counts,
+ HistogramBase::AtomicCount* logged_counts,
+ uint32_t counts_size,
+ HistogramSamples::Metadata* meta,
+ HistogramSamples::Metadata* logged_meta);
// Overridden from Histogram:
HistogramType GetHistogramType() const override;
diff --git a/base/metrics/histogram_persistence.h b/base/metrics/histogram_persistence.h
deleted file mode 100644
index 95f4878..0000000
--- a/base/metrics/histogram_persistence.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) 2015 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.
-
-#ifndef BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
-#define BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
-
-#include "base/base_export.h"
-#include "base/feature_list.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram_base.h"
-#include "base/metrics/persistent_memory_allocator.h"
-
-namespace base {
-
-// Feature definition for enabling histogram persistence.
-BASE_EXPORT extern const Feature kPersistentHistogramsFeature;
-
-// Histogram containing creation results. Visible for testing.
-BASE_EXPORT HistogramBase* GetCreateHistogramResultHistogram();
-
-// Access a PersistentMemoryAllocator for storing histograms in space that
-// can be persisted or shared between processes. There is only ever one
-// allocator for all such histograms created by a single process though one
-// process may access the histograms created by other processes if it has a
-// handle on its memory segment. This takes ownership of the object and
-// should not be changed without great care as it is likely that there will
-// be pointers to data held in that space. It should be called as soon as
-// possible during startup to capture as many histograms as possible and
-// while operating single-threaded so there are no race-conditions.
-BASE_EXPORT void SetPersistentHistogramMemoryAllocator(
- PersistentMemoryAllocator* allocator);
-BASE_EXPORT PersistentMemoryAllocator* GetPersistentHistogramMemoryAllocator();
-
-// This access to the persistent allocator is only for testing; it extracts
-// the current allocator completely. This allows easy creation of histograms
-// within persistent memory segments which can then be extracted and used
-// in other ways.
-BASE_EXPORT PersistentMemoryAllocator*
-ReleasePersistentHistogramMemoryAllocatorForTesting();
-
-// Recreate a Histogram from data held in persistent memory. Though this
-// object will be local to the current process, the sample data will be
-// shared with all other threads referencing it. This method takes a |ref|
-// to the top- level histogram data and the |allocator| on which it is found.
-// This method will return nullptr if any problem is detected with the data.
-// The |allocator| may or may not be the same as the PersistentMemoryAllocator
-// set for general use so that this method can be used to extract Histograms
-// from persistent memory segments other than the default place that this
-// process is creating its own histograms. The caller must take ownership of
-// the returned object and destroy it when no longer needed.
-BASE_EXPORT HistogramBase* GetPersistentHistogram(
- PersistentMemoryAllocator* allocator,
- int32_t ref);
-
-// Get the next histogram in persistent data based on iterator. The caller
-// must take ownership of the returned object and destroy it when no longer
-// needed.
-BASE_EXPORT HistogramBase* GetNextPersistentHistogram(
- PersistentMemoryAllocator* allocator,
- PersistentMemoryAllocator::Iterator* iter);
-
-// Finalize the creation of the histogram, making it available to other
-// processes if it is the registered instance.
-void FinalizePersistentHistogram(PersistentMemoryAllocator::Reference ref,
- bool register);
-
-// Allocate a new persistent histogram. This does *not* make the object
-// iterable in the allocator; call MakeIterable(ref) directly if that is
-// desired.
-BASE_EXPORT 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);
-
-// Import new histograms from attached PersistentMemoryAllocator. It's
-// possible for other processes to create histograms in the attached memory
-// segment; this adds those to the internal list of known histograms to
-// avoid creating duplicates that would have to merged during reporting.
-// Every call to this method resumes from the last entry it saw so it costs
-// nothing if nothing new has been added.
-void ImportPersistentHistograms();
-
-} // namespace base
-
-#endif // BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
index 29fbe17..30bff84 100644
--- a/base/metrics/histogram_samples.h
+++ b/base/metrics/histogram_samples.h
@@ -22,7 +22,7 @@ class SampleCountIterator;
// HistogramSamples is a container storing all samples of a histogram. All
// elements must be of a fixed width to ensure 32/64-bit interoperability.
// If this structure changes, bump the version number for kTypeIdHistogram
-// in histogram_persistence.cc.
+// in persistent_histogram_allocator.cc.
class BASE_EXPORT HistogramSamples {
public:
struct Metadata {
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
index beb6a71..f621ec5 100644
--- a/base/metrics/histogram_unittest.cc
+++ b/base/metrics/histogram_unittest.cc
@@ -16,7 +16,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/histogram_macros.h"
-#include "base/metrics/histogram_persistence.h"
+#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
@@ -41,7 +41,7 @@ class HistogramTest : public testing::TestWithParam<bool> {
// registered).
InitializeStatisticsRecorder();
if (use_persistent_histogram_allocator_)
- CreatePersistentMemoryAllocator();
+ CreatePersistentHistogramAllocator();
}
void TearDown() override {
@@ -50,7 +50,7 @@ class HistogramTest : public testing::TestWithParam<bool> {
ASSERT_FALSE(allocator_->IsCorrupt());
}
UninitializeStatisticsRecorder();
- DestroyPersistentMemoryAllocator();
+ DestroyPersistentHistogramAllocator();
}
void InitializeStatisticsRecorder() {
@@ -63,27 +63,27 @@ class HistogramTest : public testing::TestWithParam<bool> {
statistics_recorder_ = NULL;
}
- void CreatePersistentMemoryAllocator() {
+ void CreatePersistentHistogramAllocator() {
// By getting the results-histogram before any persistent allocator
// is attached, that histogram is guaranteed not to be stored in
// any persistent memory segment (which simplifies some tests).
- GetCreateHistogramResultHistogram();
+ PersistentHistogramAllocator::GetCreateHistogramResultHistogram();
if (!allocator_memory_)
allocator_memory_.reset(new char[kAllocatorMemorySize]);
- delete ReleasePersistentHistogramMemoryAllocatorForTesting();
+ PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting();
memset(allocator_memory_.get(), 0, kAllocatorMemorySize);
- SetPersistentHistogramMemoryAllocator(
- new PersistentMemoryAllocator(
- allocator_memory_.get(), kAllocatorMemorySize, 0,
- 0, "HistogramAllocatorTest", false));
- allocator_ = GetPersistentHistogramMemoryAllocator();
+ PersistentHistogramAllocator::CreateGlobalAllocatorOnPersistentMemory(
+ allocator_memory_.get(), kAllocatorMemorySize, 0, 0,
+ "HistogramAllocatorTest");
+ allocator_ =
+ PersistentHistogramAllocator::GetGlobalAllocator()->memory_allocator();
}
- void DestroyPersistentMemoryAllocator() {
+ void DestroyPersistentHistogramAllocator() {
allocator_ = nullptr;
- delete ReleasePersistentHistogramMemoryAllocatorForTesting();
+ PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting();
}
const bool use_persistent_histogram_allocator_;
@@ -97,8 +97,7 @@ class HistogramTest : public testing::TestWithParam<bool> {
};
// Run all HistogramTest cases with both heap and persistent memory.
-INSTANTIATE_TEST_CASE_P(HeapAndPersistent, HistogramTest,
- testing::Bool());
+INSTANTIATE_TEST_CASE_P(HeapAndPersistent, HistogramTest, testing::Bool());
// Check for basic syntax and use.
@@ -126,94 +125,6 @@ TEST_P(HistogramTest, BasicTest) {
LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
}
-// Check for basic syntax and use with persistent allocator.
-TEST_P(HistogramTest, PersistentTest) {
- if (!use_persistent_histogram_allocator_)
- return;
-
- PersistentMemoryAllocator::MemoryInfo meminfo0;
- allocator_->GetMemoryInfo(&meminfo0);
-
- // Try basic construction
- HistogramBase* histogram = Histogram::FactoryGet(
- "TestHistogram", 1, 1000, 10,
- HistogramBase::kIsPersistent);
- EXPECT_TRUE(histogram);
- histogram->CheckName("TestHistogram");
- PersistentMemoryAllocator::MemoryInfo meminfo1;
- allocator_->GetMemoryInfo(&meminfo1);
- EXPECT_GT(meminfo0.free, meminfo1.free);
-
- HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
- "TestLinearHistogram", 1, 1000, 10,
- HistogramBase::kIsPersistent);
- EXPECT_TRUE(linear_histogram);
- linear_histogram->CheckName("TestLinearHistogram");
- PersistentMemoryAllocator::MemoryInfo meminfo2;
- allocator_->GetMemoryInfo(&meminfo2);
- EXPECT_GT(meminfo1.free, meminfo2.free);
-
- HistogramBase* boolean_histogram = BooleanHistogram::FactoryGet(
- "TestBooleanHistogram", HistogramBase::kIsPersistent);
- EXPECT_TRUE(boolean_histogram);
- boolean_histogram->CheckName("TestBooleanHistogram");
- PersistentMemoryAllocator::MemoryInfo meminfo3;
- allocator_->GetMemoryInfo(&meminfo3);
- EXPECT_GT(meminfo2.free, meminfo3.free);
-
- std::vector<int> custom_ranges;
- custom_ranges.push_back(1);
- custom_ranges.push_back(5);
- HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
- "TestCustomHistogram", custom_ranges,
- HistogramBase::kIsPersistent);
- EXPECT_TRUE(custom_histogram);
- custom_histogram->CheckName("TestCustomHistogram");
- PersistentMemoryAllocator::MemoryInfo meminfo4;
- allocator_->GetMemoryInfo(&meminfo4);
- EXPECT_GT(meminfo3.free, meminfo4.free);
-
- PersistentMemoryAllocator::Iterator iter;
- uint32_t type;
- allocator_->CreateIterator(&iter);
- EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // Histogram
- EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // LinearHistogram
- EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // BooleanHistogram
- EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // CustomHistogram
- EXPECT_EQ(0U, allocator_->GetNextIterable(&iter, &type));
-
- // Create a second allocator and have it access the memory of the first.
- scoped_ptr<HistogramBase> recovered;
- PersistentMemoryAllocator recovery(
- allocator_memory_.get(), kAllocatorMemorySize, 0,
- 0, std::string(), false);
- recovery.CreateIterator(&iter);
-
- recovered.reset(GetNextPersistentHistogram(&recovery, &iter));
- ASSERT_TRUE(recovered);
- recovered->CheckName("TestHistogram");
-
- recovered.reset(GetNextPersistentHistogram(&recovery, &iter));
- ASSERT_TRUE(recovered);
- recovered->CheckName("TestLinearHistogram");
-
- recovered.reset(GetNextPersistentHistogram(&recovery, &iter));
- ASSERT_TRUE(recovered);
- recovered->CheckName("TestBooleanHistogram");
-
- recovered.reset(GetNextPersistentHistogram(&recovery, &iter));
- ASSERT_TRUE(recovered);
- recovered->CheckName("TestCustomHistogram");
-
- recovered.reset(GetNextPersistentHistogram(&recovery, &iter));
- EXPECT_FALSE(recovered);
-
- // Use standard macros (but with fixed samples)
- LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
- LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30);
- LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
-}
-
// Check that the macro correctly matches histograms by name and records their
// data together.
TEST_P(HistogramTest, NameMatchTest) {
diff --git a/base/metrics/histogram_persistence.cc b/base/metrics/persistent_histogram_allocator.cc
index f18d175..1929060 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 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"
@@ -13,46 +13,14 @@
#include "base/metrics/statistics_recorder.h"
#include "base/synchronization/lock.h"
+// TODO(bcwhite): Order these methods to match the header file. The current
+// order is only temporary in order to aid review of the transition from
+// a non-class implementation.
+
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 +30,27 @@ 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 current globally-active persistent allocator for all new histograms.
// 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;
+// 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* g_allocator;
// 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 +63,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,15 +88,55 @@ 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() {
+// 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;
+
+ // 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];
+};
+
+PersistentHistogramAllocator::PersistentHistogramAllocator(
+ scoped_ptr<PersistentMemoryAllocator> memory)
+ : memory_allocator_(std::move(memory)) {}
+
+PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
+
+void PersistentHistogramAllocator::CreateIterator(Iterator* iter) {
+ memory_allocator_->CreateIterator(&iter->memory_iter);
+}
+
+void PersistentHistogramAllocator::CreateTrackingHistograms(StringPiece name) {
+ memory_allocator_->CreateTrackingHistograms(name);
+}
+
+void PersistentHistogramAllocator::UpdateTrackingHistograms() {
+ memory_allocator_->UpdateTrackingHistograms();
+}
+
+// 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(
+ HistogramBase* histogram_pointer =
reinterpret_cast<HistogramBase*>(
- base::subtle::Acquire_Load(&atomic_histogram_pointer)));
+ 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.
@@ -173,31 +163,38 @@ HistogramBase* GetCreateHistogramResultHistogram() {
return histogram_pointer;
}
-// Record the result of a histogram creation.
-void RecordCreateHistogramResult(CreateHistogramResultType result) {
+// static
+void PersistentHistogramAllocator::RecordCreateHistogramResult(
+ CreateHistogramResultType result) {
HistogramBase* result_histogram = GetCreateHistogramResultHistogram();
if (result_histogram)
result_histogram->Add(result);
}
-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;
+ g_allocator = allocator.release();
}
-PersistentMemoryAllocator* GetPersistentHistogramMemoryAllocator() {
+// 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 +202,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 +215,55 @@ 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;
+ return make_scoped_ptr(histogram_allocator);
};
-HistogramBase* CreatePersistentHistogram(
- PersistentMemoryAllocator* allocator,
+// static
+void PersistentHistogramAllocator::CreateGlobalAllocatorOnPersistentMemory(
+ void* base,
+ size_t size,
+ size_t page_size,
+ uint64_t id,
+ StringPiece name) {
+ SetGlobalAllocator(make_scoped_ptr(new PersistentHistogramAllocator(
+ make_scoped_ptr(new PersistentMemoryAllocator(
+ base, size, page_size, id, name, false)))));
+}
+
+// static
+void PersistentHistogramAllocator::CreateGlobalAllocatorOnLocalMemory(
+ size_t size,
+ uint64_t id,
+ StringPiece name) {
+ SetGlobalAllocator(make_scoped_ptr(new PersistentHistogramAllocator(
+ make_scoped_ptr(new LocalPersistentMemoryAllocator(size, id, name)))));
+}
+
+// static
+void PersistentHistogramAllocator::CreateGlobalAllocatorOnSharedMemory(
+ size_t size,
+ const SharedMemoryHandle& handle) {
+ scoped_ptr<SharedMemory> shm(new SharedMemory(handle, /*readonly=*/false));
+ if (!shm->Map(size)) {
+ NOTREACHED();
+ return;
+ }
+
+ SetGlobalAllocator(make_scoped_ptr(new PersistentHistogramAllocator(
+ make_scoped_ptr(new SharedPersistentMemoryAllocator(
+ std::move(shm), 0, StringPiece(), /*readonly=*/false)))));
+}
+
+// static
+scoped_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
PersistentHistogramData* histogram_data_ptr) {
if (!histogram_data_ptr) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_INVALID_METADATA_POINTER);
@@ -246,37 +279,43 @@ 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);
+
+ const uint32_t max_buckets =
+ std::numeric_limits<uint32_t>::max() / sizeof(HistogramBase::Sample);
+ size_t required_bytes =
+ (histogram_data.bucket_count + 1) * sizeof(HistogramBase::Sample);
+ size_t allocated_bytes =
+ memory_allocator_->GetAllocSize(histogram_data.ranges_ref);
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) * sizeof(HistogramBase::Sample)) {
+ histogram_data.bucket_count >= max_buckets ||
+ allocated_bytes < required_bytes) {
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 +328,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,68 +375,67 @@ 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).
+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 =
- allocator->GetAsObject<PersistentHistogramData>(ref, kTypeIdHistogram);
- size_t length = allocator->GetAllocSize(ref);
+ 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 CreatePersistentHistogram(allocator, histogram_data);
+ return CreateHistogram(histogram_data);
}
-HistogramBase* GetNextPersistentHistogram(
- PersistentMemoryAllocator* allocator,
- PersistentMemoryAllocator::Iterator* iter) {
+scoped_ptr<HistogramBase>
+PersistentHistogramAllocator::GetNextHistogramWithIgnore(Iterator* iter,
+ Reference ignore) {
PersistentMemoryAllocator::Reference ref;
uint32_t type_id;
- while ((ref = allocator->GetNextIterable(iter, &type_id)) != 0) {
+ while ((ref = memory_allocator_->GetNextIterable(&iter->memory_iter,
+ &type_id)) != 0) {
+ if (ref == ignore)
+ continue;
if (type_id == kTypeIdHistogram)
- return GetPersistentHistogram(allocator, ref);
+ return GetHistogram(ref);
}
return nullptr;
}
-void FinalizePersistentHistogram(PersistentMemoryAllocator::Reference ref,
- bool registered) {
+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)
- GetPersistentHistogramMemoryAllocator()->MakeIterable(ref);
+ 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
- GetPersistentHistogramMemoryAllocator()->SetType(ref, 0);
+ memory_allocator_->SetType(ref, 0);
}
-HistogramBase* AllocatePersistentHistogram(
- PersistentMemoryAllocator* allocator,
+scoped_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
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;
-
+ 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 (allocator->IsCorrupt()) {
+ if (memory_allocator_->IsCorrupt()) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_CORRUPT);
return nullptr;
}
@@ -430,23 +451,24 @@ HistogramBase* AllocatePersistentHistogram(
size_t ranges_bytes = (bucket_count + 1) * sizeof(HistogramBase::Sample);
PersistentMemoryAllocator::Reference ranges_ref =
- allocator->Allocate(ranges_bytes, kTypeIdRangesArray);
+ memory_allocator_->Allocate(ranges_bytes, kTypeIdRangesArray);
PersistentMemoryAllocator::Reference counts_ref =
- allocator->Allocate(counts_bytes, kTypeIdCountsArray);
+ memory_allocator_->Allocate(counts_bytes, kTypeIdCountsArray);
PersistentMemoryAllocator::Reference histogram_ref =
- allocator->Allocate(offsetof(PersistentHistogramData, name) +
- name.length() + 1, kTypeIdHistogram);
+ memory_allocator_->Allocate(
+ offsetof(PersistentHistogramData, name) + name.length() + 1,
+ kTypeIdHistogram);
HistogramBase::Sample* ranges_data =
- allocator->GetAsObject<HistogramBase::Sample>(ranges_ref,
- kTypeIdRangesArray);
+ memory_allocator_->GetAsObject<HistogramBase::Sample>(ranges_ref,
+ kTypeIdRangesArray);
PersistentHistogramData* histogram_data =
- allocator->GetAsObject<PersistentHistogramData>(histogram_ref,
- kTypeIdHistogram);
+ memory_allocator_->GetAsObject<PersistentHistogramData>(histogram_ref,
+ kTypeIdHistogram);
- // Only continue here if all allocations were successful. If they weren't
+ // 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.
+ // 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)
@@ -466,19 +488,23 @@ HistogramBase* AllocatePersistentHistogram(
// 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);
+ scoped_ptr<HistogramBase> histogram = CreateHistogram(histogram_data);
DCHECK(histogram);
if (ref_ptr != nullptr)
*ref_ptr = histogram_ref;
+
+ // By storing the reference within the allocator to this histogram, the
+ // next import (which will happen before the next histogram creation)
+ // will know to skip it. See also the comment in ImportGlobalHistograms().
+ subtle::NoBarrier_Store(&last_created_, histogram_ref);
return histogram;
}
CreateHistogramResultType result;
- if (allocator->IsCorrupt()) {
+ if (memory_allocator_->IsCorrupt()) {
RecordCreateHistogramResult(CREATE_HISTOGRAM_ALLOCATOR_NEWLY_CORRUPT);
result = CREATE_HISTOGRAM_ALLOCATOR_CORRUPT;
- } else if (allocator->IsFull()) {
+ } else if (memory_allocator_->IsFull()) {
result = CREATE_HISTOGRAM_ALLOCATOR_FULL;
} else {
result = CREATE_HISTOGRAM_ALLOCATOR_ERROR;
@@ -489,26 +515,38 @@ HistogramBase* AllocatePersistentHistogram(
return nullptr;
}
-void ImportPersistentHistograms() {
+// 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
- // 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;
+ // Each call resumes from where it last left off so a persistant iterator
+ // is needed. 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) {
- HistogramBase* histogram = GetNextPersistentHistogram(g_allocator, &iter);
+ scoped_ptr<HistogramBase> histogram =
+ g_allocator->GetNextHistogramWithIgnore(&iter, last_created);
if (!histogram)
break;
- StatisticsRecorder::RegisterOrDeleteDuplicate(histogram);
+ StatisticsRecorder::RegisterOrDeleteDuplicate(histogram.release());
}
}
}
diff --git a/base/metrics/persistent_histogram_allocator.h b/base/metrics/persistent_histogram_allocator.h
new file mode 100644
index 0000000..cc8d023
--- /dev/null
+++ b/base/metrics/persistent_histogram_allocator.h
@@ -0,0 +1,212 @@
+// Copyright 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.
+
+#ifndef BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
+#define BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/feature_list.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Feature definition for enabling histogram persistence.
+BASE_EXPORT extern const Feature kPersistentHistogramsFeature;
+
+// This class manages histograms created within a PersistentMemoryAllocator.
+class BASE_EXPORT PersistentHistogramAllocator {
+ public:
+ // This iterator is used for fetching persistent histograms from an allocator.
+ class Iterator {
+ public:
+ bool is_clear() { return memory_iter.is_clear(); }
+
+ private:
+ friend class PersistentHistogramAllocator;
+
+ // The iterator used for stepping through persistent memory iterables.
+ PersistentMemoryAllocator::Iterator memory_iter;
+ };
+
+ using Reference = PersistentMemoryAllocator::Reference;
+
+ // A PersistentHistogramAllocator is constructed from a PersistentMemory-
+ // Allocator object of which it takes ownership.
+ PersistentHistogramAllocator(scoped_ptr<PersistentMemoryAllocator> memory);
+ ~PersistentHistogramAllocator();
+
+ // Direct access to underlying memory allocator. If the segment is shared
+ // across threads or processes, reading data through these values does
+ // not guarantee consistency. Use with care. Do not write.
+ PersistentMemoryAllocator* memory_allocator() {
+ return memory_allocator_.get();
+ }
+
+ // Implement the "metadata" API of a PersistentMemoryAllocator, forwarding
+ // those requests to the real one.
+ uint64_t Id() const { return memory_allocator_->Id(); }
+ const char* Name() const { return memory_allocator_->Name(); }
+ const void* data() const { return memory_allocator_->data(); }
+ size_t length() const { return memory_allocator_->length(); }
+ size_t used() const { return memory_allocator_->used(); }
+
+ // Recreate a Histogram from data held in persistent memory. Though this
+ // object will be local to the current process, the sample data will be
+ // shared with all other threads referencing it. This method takes a |ref|
+ // to where the top-level histogram data may be found in this allocator.
+ // This method will return null if any problem is detected with the data.
+ scoped_ptr<HistogramBase> GetHistogram(Reference ref);
+
+ // Get the next histogram in persistent data based on iterator.
+ scoped_ptr<HistogramBase> GetNextHistogram(Iterator* iter) {
+ return GetNextHistogramWithIgnore(iter, 0);
+ }
+
+ // Create an iterator for going through all histograms in an allocator.
+ void CreateIterator(Iterator* iter);
+
+ // Allocate a new persistent histogram. The returned histogram will not
+ // be able to be located by other allocators until it is "finalized".
+ scoped_ptr<HistogramBase> AllocateHistogram(
+ HistogramType histogram_type,
+ const std::string& name,
+ int minimum,
+ int maximum,
+ const BucketRanges* bucket_ranges,
+ int32_t flags,
+ Reference* ref_ptr);
+
+ // Finalize the creation of the histogram, making it available to other
+ // processes if |registered| (as in: added to the StatisticsRecorder) is
+ // True, forgetting it otherwise.
+ void FinalizeHistogram(Reference ref, bool registered);
+
+ // Create internal histograms for tracking memory use and allocation sizes
+ // for allocator of |name| (which can simply be the result of Name()). This
+ // is done seperately from construction for situations such as when the
+ // histograms will be backed by memory provided by this very allocator.
+ //
+ // IMPORTANT: Callers must update tools/metrics/histograms/histograms.xml
+ // with the following histograms:
+ // UMA.PersistentAllocator.name.Allocs
+ // UMA.PersistentAllocator.name.UsedPct
+ void CreateTrackingHistograms(StringPiece name);
+ void UpdateTrackingHistograms();
+
+ // Manage a PersistentHistogramAllocator for globally storing histograms in
+ // a space that can be persisted or shared between processes. There is only
+ // ever one allocator for all such histograms created by a single process.
+ // This takes ownership of the object and should be called as soon as
+ // possible during startup to capture as many histograms as possible and
+ // while operating single-threaded so there are no race-conditions.
+ static void SetGlobalAllocator(
+ scoped_ptr<PersistentHistogramAllocator> allocator);
+ static PersistentHistogramAllocator* GetGlobalAllocator();
+
+ // This access to the persistent allocator is only for testing; it extracts
+ // the current allocator completely. This allows easy creation of histograms
+ // within persistent memory segments which can then be extracted and used
+ // in other ways.
+ static scoped_ptr<PersistentHistogramAllocator>
+ ReleaseGlobalAllocatorForTesting();
+
+ // These helper methods perform SetGlobalAllocator() calls with allocators
+ // of the specified type and parameters.
+ static void CreateGlobalAllocatorOnPersistentMemory(
+ void* base,
+ size_t size,
+ size_t page_size,
+ uint64_t id,
+ StringPiece name);
+ static void CreateGlobalAllocatorOnLocalMemory(
+ size_t size,
+ uint64_t id,
+ StringPiece name);
+ static void CreateGlobalAllocatorOnSharedMemory(
+ size_t size,
+ const SharedMemoryHandle& handle);
+
+ // Import new histograms from the global PersistentHistogramAllocator. It's
+ // possible for other processes to create histograms in the active memory
+ // segment; this adds those to the internal list of known histograms to
+ // avoid creating duplicates that would have to be merged during reporting.
+ // Every call to this method resumes from the last entry it saw; it costs
+ // nothing if nothing new has been added.
+ static void ImportGlobalHistograms();
+
+ // Histogram containing creation results. Visible for testing.
+ static HistogramBase* GetCreateHistogramResultHistogram();
+
+ private:
+ // 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
+ };
+
+ // The structure used to hold histogram data in persistent memory. It is
+ // defined and used entirely within the .cc file.
+ struct PersistentHistogramData;
+
+ // Get the next histogram in persistent data based on iterator while
+ // ignoring a particular reference if it is found.
+ scoped_ptr<HistogramBase> GetNextHistogramWithIgnore(
+ Iterator* iter,
+ Reference ignore);
+
+ // Create a histogram based on saved (persistent) information about it.
+ scoped_ptr<HistogramBase> CreateHistogram(
+ PersistentHistogramData* histogram_data_ptr);
+
+ // Record the result of a histogram creation.
+ static void RecordCreateHistogramResult(CreateHistogramResultType result);
+
+ // The memory allocator that provides the actual histogram storage.
+ scoped_ptr<PersistentMemoryAllocator> memory_allocator_;
+
+ // A reference to the last-created histogram in the allocator, used to avoid
+ // trying to import what was just created.
+ subtle::AtomicWord last_created_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocator);
+};
+
+} // namespace base
+
+#endif // BASE_METRICS_HISTOGRAM_PERSISTENCE_H_
diff --git a/base/metrics/persistent_histogram_allocator_unittest.cc b/base/metrics/persistent_histogram_allocator_unittest.cc
new file mode 100644
index 0000000..64abdec
--- /dev/null
+++ b/base/metrics/persistent_histogram_allocator_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright 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/persistent_histogram_allocator.h"
+
+#include "base/logging.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class PersistentHistogramAllocatorTest : public testing::Test {
+ protected:
+ const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB
+
+ PersistentHistogramAllocatorTest() { CreatePersistentHistogramAllocator(); }
+ ~PersistentHistogramAllocatorTest() override {
+ DestroyPersistentHistogramAllocator();
+ }
+
+ void CreatePersistentHistogramAllocator() {
+ allocator_memory_.reset(new char[kAllocatorMemorySize]);
+
+ PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting();
+ memset(allocator_memory_.get(), 0, kAllocatorMemorySize);
+ PersistentHistogramAllocator::GetCreateHistogramResultHistogram();
+ PersistentHistogramAllocator::CreateGlobalAllocatorOnPersistentMemory(
+ allocator_memory_.get(), kAllocatorMemorySize, 0, 0,
+ "PersistentHistogramAllocatorTest");
+ allocator_ =
+ PersistentHistogramAllocator::GetGlobalAllocator()->memory_allocator();
+ }
+
+ void DestroyPersistentHistogramAllocator() {
+ allocator_ = nullptr;
+ PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting();
+ }
+
+ scoped_ptr<char[]> allocator_memory_;
+ PersistentMemoryAllocator* allocator_ = nullptr;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PersistentHistogramAllocatorTest);
+};
+
+TEST_F(PersistentHistogramAllocatorTest, CreateAndIterateTest) {
+ PersistentMemoryAllocator::MemoryInfo meminfo0;
+ allocator_->GetMemoryInfo(&meminfo0);
+
+ // Try basic construction
+ HistogramBase* histogram = Histogram::FactoryGet(
+ "TestHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
+ EXPECT_TRUE(histogram);
+ histogram->CheckName("TestHistogram");
+ PersistentMemoryAllocator::MemoryInfo meminfo1;
+ allocator_->GetMemoryInfo(&meminfo1);
+ EXPECT_GT(meminfo0.free, meminfo1.free);
+
+ HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+ "TestLinearHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
+ EXPECT_TRUE(linear_histogram);
+ linear_histogram->CheckName("TestLinearHistogram");
+ PersistentMemoryAllocator::MemoryInfo meminfo2;
+ allocator_->GetMemoryInfo(&meminfo2);
+ EXPECT_GT(meminfo1.free, meminfo2.free);
+
+ HistogramBase* boolean_histogram = BooleanHistogram::FactoryGet(
+ "TestBooleanHistogram", HistogramBase::kIsPersistent);
+ EXPECT_TRUE(boolean_histogram);
+ boolean_histogram->CheckName("TestBooleanHistogram");
+ PersistentMemoryAllocator::MemoryInfo meminfo3;
+ allocator_->GetMemoryInfo(&meminfo3);
+ EXPECT_GT(meminfo2.free, meminfo3.free);
+
+ std::vector<int> custom_ranges;
+ custom_ranges.push_back(1);
+ custom_ranges.push_back(5);
+ HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+ "TestCustomHistogram", custom_ranges, HistogramBase::kIsPersistent);
+ EXPECT_TRUE(custom_histogram);
+ custom_histogram->CheckName("TestCustomHistogram");
+ PersistentMemoryAllocator::MemoryInfo meminfo4;
+ allocator_->GetMemoryInfo(&meminfo4);
+ EXPECT_GT(meminfo3.free, meminfo4.free);
+
+ PersistentMemoryAllocator::Iterator iter;
+ uint32_t type;
+ allocator_->CreateIterator(&iter);
+ EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // Histogram
+ EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // LinearHistogram
+ EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // BooleanHistogram
+ EXPECT_NE(0U, allocator_->GetNextIterable(&iter, &type)); // CustomHistogram
+ EXPECT_EQ(0U, allocator_->GetNextIterable(&iter, &type));
+
+ // Create a second allocator and have it access the memory of the first.
+ scoped_ptr<HistogramBase> recovered;
+ PersistentHistogramAllocator recovery(
+ make_scoped_ptr(new PersistentMemoryAllocator(
+ allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false)));
+ PersistentHistogramAllocator::Iterator histogram_iter;
+ recovery.CreateIterator(&histogram_iter);
+
+ recovered = recovery.GetNextHistogram(&histogram_iter);
+ ASSERT_TRUE(recovered);
+ recovered->CheckName("TestHistogram");
+
+ recovered = recovery.GetNextHistogram(&histogram_iter);
+ ASSERT_TRUE(recovered);
+ recovered->CheckName("TestLinearHistogram");
+
+ recovered = recovery.GetNextHistogram(&histogram_iter);
+ ASSERT_TRUE(recovered);
+ recovered->CheckName("TestBooleanHistogram");
+
+ recovered = recovery.GetNextHistogram(&histogram_iter);
+ ASSERT_TRUE(recovered);
+ recovered->CheckName("TestCustomHistogram");
+
+ recovered = recovery.GetNextHistogram(&histogram_iter);
+ EXPECT_FALSE(recovered);
+}
+
+} // namespace base
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
index 17511a4..073cbb1 100644
--- a/base/metrics/statistics_recorder_unittest.cc
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -10,7 +10,7 @@
#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_macros.h"
-#include "base/metrics/histogram_persistence.h"
+#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/sparse_histogram.h"
#include "base/metrics/statistics_recorder.h"
#include "base/values.h"
@@ -23,7 +23,7 @@ class StatisticsRecorderTest : public testing::Test {
void SetUp() override {
// Get this first so it never gets created in persistent storage and will
// not appear in the StatisticsRecorder after it is re-initialized.
- GetCreateHistogramResultHistogram();
+ PersistentHistogramAllocator::GetCreateHistogramResultHistogram();
// Each test will have a clean state (no Histogram / BucketRanges
// registered).
InitializeStatisticsRecorder();
@@ -31,7 +31,7 @@ class StatisticsRecorderTest : public testing::Test {
void TearDown() override {
UninitializeStatisticsRecorder();
- delete ReleasePersistentHistogramMemoryAllocatorForTesting();
+ PersistentHistogramAllocator::ReleaseGlobalAllocatorForTesting();
}
void InitializeStatisticsRecorder() {
@@ -325,8 +325,8 @@ TEST_F(StatisticsRecorderTest, ToJSON) {
TEST_F(StatisticsRecorderTest, IterationTest) {
StatisticsRecorder::Histograms registered_histograms;
LOCAL_HISTOGRAM_COUNTS("TestHistogram.IterationTest1", 30);
- SetPersistentHistogramMemoryAllocator(
- new LocalPersistentMemoryAllocator(64 << 10, 0, std::string()));
+ PersistentHistogramAllocator::CreateGlobalAllocatorOnLocalMemory(
+ 64 << 10 /* 64 KiB */, 0, "");
LOCAL_HISTOGRAM_COUNTS("TestHistogram.IterationTest2", 30);
StatisticsRecorder::HistogramIterator i1 = StatisticsRecorder::begin(true);