| Index: base/metrics/persistent_histogram_allocator.cc
|
| diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
|
| index 1d5c0ef0e1c5d90175f8456469b67502f34e1d28..b38c1efa8b720ba123c51712c586b466cadcd097 100644
|
| --- a/base/metrics/persistent_histogram_allocator.cc
|
| +++ b/base/metrics/persistent_histogram_allocator.cc
|
| @@ -12,6 +12,7 @@
|
| #include "base/metrics/histogram.h"
|
| #include "base/metrics/histogram_base.h"
|
| #include "base/metrics/histogram_samples.h"
|
| +#include "base/metrics/persistent_sample_map.h"
|
| #include "base/metrics/sparse_histogram.h"
|
| #include "base/metrics/statistics_recorder.h"
|
| #include "base/synchronization/lock.h"
|
| @@ -91,6 +92,134 @@ const Feature kPersistentHistogramsFeature{
|
| "PersistentHistograms", FEATURE_DISABLED_BY_DEFAULT
|
| };
|
|
|
| +
|
| +PersistentSparseHistogramDataManager::PersistentSparseHistogramDataManager(
|
| + PersistentMemoryAllocator* allocator)
|
| + : allocator_(allocator), record_iterator_(allocator) {}
|
| +
|
| +PersistentSparseHistogramDataManager::~PersistentSparseHistogramDataManager() {}
|
| +
|
| +PersistentSampleMapRecords*
|
| +PersistentSparseHistogramDataManager::UseSampleMapRecords(uint64_t id,
|
| + const void* user) {
|
| + base::AutoLock auto_lock(lock_);
|
| + return GetSampleMapRecordsWhileLocked(id)->Acquire(user);
|
| +}
|
| +
|
| +PersistentSampleMapRecords*
|
| +PersistentSparseHistogramDataManager::GetSampleMapRecordsWhileLocked(
|
| + uint64_t id) {
|
| + lock_.AssertAcquired();
|
| +
|
| + auto found = sample_records_.find(id);
|
| + if (found != sample_records_.end())
|
| + return found->second.get();
|
| +
|
| + std::unique_ptr<PersistentSampleMapRecords>& samples = sample_records_[id];
|
| + samples = WrapUnique(new PersistentSampleMapRecords(this, id));
|
| + return samples.get();
|
| +}
|
| +
|
| +bool PersistentSparseHistogramDataManager::LoadRecords(
|
| + PersistentSampleMapRecords* sample_map_records) {
|
| + // DataManager must be locked in order to access the found_ field of any
|
| + // PersistentSampleMapRecords object.
|
| + base::AutoLock auto_lock(lock_);
|
| + bool found = false;
|
| +
|
| + // If there are already "found" entries for the passed object, move them.
|
| + if (!sample_map_records->found_.empty()) {
|
| + sample_map_records->records_.reserve(sample_map_records->records_.size() +
|
| + sample_map_records->found_.size());
|
| + sample_map_records->records_.insert(sample_map_records->records_.end(),
|
| + sample_map_records->found_.begin(),
|
| + sample_map_records->found_.end());
|
| + sample_map_records->found_.clear();
|
| + found = true;
|
| + }
|
| +
|
| + // Acquiring a lock is a semi-expensive operation so load some records with
|
| + // each call. More than this number may be loaded if it takes longer to
|
| + // find at least one matching record for the passed object.
|
| + const int kMinimumNumberToLoad = 10;
|
| + const uint64_t match_id = sample_map_records->sample_map_id_;
|
| +
|
| + // Loop while no enty is found OR we haven't yet loaded the minimum number.
|
| + // This will continue reading even after a match is found.
|
| + for (int count = 0; !found || count < kMinimumNumberToLoad; ++count) {
|
| + // Get the next sample-record. The iterator will always resume from where
|
| + // it left off even if it previously had nothing further to return.
|
| + uint64_t found_id;
|
| + PersistentMemoryAllocator::Reference ref =
|
| + PersistentSampleMap::GetNextPersistentRecord(record_iterator_,
|
| + &found_id);
|
| +
|
| + // Stop immediately if there are none.
|
| + if (!ref)
|
| + break;
|
| +
|
| + // The sample-record could be for any sparse histogram. Add the reference
|
| + // to the appropriate collection for later use.
|
| + if (found_id == match_id) {
|
| + sample_map_records->records_.push_back(ref);
|
| + found = true;
|
| + } else {
|
| + PersistentSampleMapRecords* samples =
|
| + GetSampleMapRecordsWhileLocked(found_id);
|
| + DCHECK(samples);
|
| + samples->found_.push_back(ref);
|
| + }
|
| + }
|
| +
|
| + return found;
|
| +}
|
| +
|
| +
|
| +PersistentSampleMapRecords::PersistentSampleMapRecords(
|
| + PersistentSparseHistogramDataManager* data_manager,
|
| + uint64_t sample_map_id)
|
| + : data_manager_(data_manager), sample_map_id_(sample_map_id) {}
|
| +
|
| +PersistentSampleMapRecords::~PersistentSampleMapRecords() {}
|
| +
|
| +PersistentSampleMapRecords* PersistentSampleMapRecords::Acquire(
|
| + const void* user) {
|
| + DCHECK(!user_);
|
| + user_ = user;
|
| + seen_ = 0;
|
| + return this;
|
| +}
|
| +
|
| +void PersistentSampleMapRecords::Release(const void* user) {
|
| + DCHECK_EQ(user_, user);
|
| + user_ = nullptr;
|
| +}
|
| +
|
| +PersistentMemoryAllocator::Reference PersistentSampleMapRecords::GetNext() {
|
| + DCHECK(user_);
|
| +
|
| + // If there are no unseen records, lock and swap in all the found ones.
|
| + if (records_.size() == seen_) {
|
| + if (!data_manager_->LoadRecords(this))
|
| + return false;
|
| + }
|
| +
|
| + // Return the next record. Records *must* be returned in the same order
|
| + // they are found in the persistent memory in order to ensure that all
|
| + // objects using this data always have the same state. Race conditions
|
| + // can cause duplicate records so using the "first found" is the only
|
| + // guarantee that all objects always access the same one.
|
| + DCHECK_LT(seen_, records_.size());
|
| + return records_[seen_++];
|
| +}
|
| +
|
| +PersistentMemoryAllocator::Reference PersistentSampleMapRecords::CreateNew(
|
| + HistogramBase::Sample value) {
|
| + return PersistentSampleMap::CreatePersistentRecord(data_manager_->allocator_,
|
| + sample_map_id_, value);
|
| +}
|
| +
|
| +
|
| // This data will be held in persistent memory in order for processes to
|
| // locate and use histograms created elsewhere.
|
| struct PersistentHistogramAllocator::PersistentHistogramData {
|
| @@ -125,9 +254,11 @@ PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) {
|
| return nullptr;
|
| }
|
|
|
| +
|
| PersistentHistogramAllocator::PersistentHistogramAllocator(
|
| std::unique_ptr<PersistentMemoryAllocator> memory)
|
| - : memory_allocator_(std::move(memory)) {}
|
| + : memory_allocator_(std::move(memory)),
|
| + sparse_histogram_data_manager_(memory_allocator_.get()) {}
|
|
|
| PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
|
|
|
| @@ -196,8 +327,7 @@ std::unique_ptr<HistogramBase> PersistentHistogramAllocator::CreateHistogram(
|
| // Sparse histograms are quite different so handle them as a special case.
|
| if (histogram_data_ptr->histogram_type == SPARSE_HISTOGRAM) {
|
| std::unique_ptr<HistogramBase> histogram =
|
| - SparseHistogram::PersistentCreate(memory_allocator(),
|
| - histogram_data_ptr->name,
|
| + SparseHistogram::PersistentCreate(this, histogram_data_ptr->name,
|
| &histogram_data_ptr->samples_metadata,
|
| &histogram_data_ptr->logged_metadata);
|
| DCHECK(histogram);
|
| @@ -343,6 +473,12 @@ void PersistentHistogramAllocator::FinalizeHistogram(Reference ref,
|
| memory_allocator_->SetType(ref, 0);
|
| }
|
|
|
| +PersistentSampleMapRecords* PersistentHistogramAllocator::UseSampleMapRecords(
|
| + uint64_t id,
|
| + const void* user) {
|
| + return sparse_histogram_data_manager_.UseSampleMapRecords(id, user);
|
| +}
|
| +
|
| std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
|
| HistogramType histogram_type,
|
| const std::string& name,
|
|
|