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

Unified Diff: base/metrics/persistent_histogram_allocator.cc

Issue 1840843004: Improve efficiency of persistent sparse histograms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@improved-pma-iterator
Patch Set: rebased Created 4 years, 8 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/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
index 1d5c0ef0e1c5d90175f8456469b67502f34e1d28..5b45f9042a6b41db8ddbc4b437d12ba542ee0cea 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"
@@ -125,9 +126,15 @@ PersistentHistogramAllocator::Iterator::GetNextWithIgnore(Reference ignore) {
return nullptr;
}
+
PersistentHistogramAllocator::PersistentHistogramAllocator(
std::unique_ptr<PersistentMemoryAllocator> memory)
- : memory_allocator_(std::move(memory)) {}
+ : memory_allocator_(std::move(memory)) {
+ // Need to allocate this in a thread-safe manner so do it during the
+ // initial construction of the object.
+ sparse_histogram_helper_.reset(
+ new PersistentSparseHistogramHelper(memory_allocator()));
+}
PersistentHistogramAllocator::~PersistentHistogramAllocator() {}
@@ -196,8 +203,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 +349,11 @@ void PersistentHistogramAllocator::FinalizeHistogram(Reference ref,
memory_allocator_->SetType(ref, 0);
}
+PersistentSampleMapRecords* PersistentHistogramAllocator::GetSampleMapRecords(
+ uint64_t id) {
+ return sparse_histogram_helper_->GetSampleMapRecords(id);
+}
+
std::unique_ptr<HistogramBase> PersistentHistogramAllocator::AllocateHistogram(
HistogramType histogram_type,
const std::string& name,
@@ -589,4 +600,104 @@ void GlobalHistogramAllocator::ImportHistogramsToStatisticsRecorder() {
}
}
+
+PersistentSparseHistogramHelper::PersistentSparseHistogramHelper(
+ PersistentMemoryAllocator* allocator)
+ : allocator_(allocator), record_iterator_(allocator) {}
+
+PersistentSparseHistogramHelper::~PersistentSparseHistogramHelper() {}
+
+PersistentSampleMapRecords*
+PersistentSparseHistogramHelper::GetSampleMapRecords(uint64_t id) {
+ base::AutoLock auto_lock(lock_);
+ return GetSampleMapRecordsWhileLocked(id);
+}
+
+PersistentSampleMapRecords*
+PersistentSparseHistogramHelper::GetSampleMapRecordsWhileLocked(uint64_t id) {
+ PersistentSampleMapRecords* samples = sample_records_.Lookup(id);
+ if (samples)
+ return samples;
+
+ samples = new PersistentSampleMapRecords(this, id);
+ sample_records_.AddWithID(samples, id); // Ownership is transferred.
+ return samples;
+}
+
+bool PersistentSparseHistogramHelper::LoadRecordsForSampleMapWhileLocked(
+ uint64_t load_id) {
Alexei Svitkine (slow) 2016/04/13 15:53:50 Nit: Add lock_.AssertAcquired()
bcwhite 2016/04/13 22:45:03 Done.
+ // Acquiring a lock is a semi-expensive operation so try to load more than
+ // a single record with each call. More than this number may be loaded if
+ // the next record for the specified histogram is further out.
+ const int kMinimumNumberToLoad = 10;
+ bool found = false;
+
+ for (int count = 0; !found || count < kMinimumNumberToLoad; ++count) {
Alexei Svitkine (slow) 2016/04/13 15:53:50 Nit: I would just remove the found var and return
bcwhite 2016/04/13 22:45:03 For performance reasons, I want to load a minimum
Alexei Svitkine (slow) 2016/04/14 19:30:03 I understand that, I was not suggesting here to re
bcwhite 2016/04/15 02:36:18 That would stop loading when the first match was f
Alexei Svitkine (slow) 2016/04/15 15:05:07 Ah. I had missed the fact that you're using || in
bcwhite 2016/04/15 18:23:01 Done.
+ // Get the next sample-record.
+ uint64_t sample_map_id;
+ PersistentMemoryAllocator::Reference ref =
+ PersistentSampleMap::GetNextPersistentRecord(record_iterator_,
Alexei Svitkine (slow) 2016/04/13 15:53:50 In the previous code, you had a comment about the
bcwhite 2016/04/13 22:45:03 Done.
+ &sample_map_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.
+ PersistentSampleMapRecords* samples =
+ GetSampleMapRecordsWhileLocked(sample_map_id);
+ DCHECK(samples);
+ samples->found_.push_back(ref);
+ if (sample_map_id == load_id)
+ found = true;
+ }
+
+ return found;
+}
+
+
+PersistentSampleMapRecords::PersistentSampleMapRecords(
+ PersistentSparseHistogramHelper* helper,
+ uint64_t sample_map_id)
+ : helper_(helper), sample_map_id_(sample_map_id) {}
+
+PersistentSampleMapRecords::~PersistentSampleMapRecords() {}
+
+void PersistentSampleMapRecords::Reset() {
+ seen_ = 0;
+}
+
+PersistentMemoryAllocator::Reference PersistentSampleMapRecords::GetNext() {
+ // If there are no unseen records, lock and swap in all the found ones.
+ if (records_.size() == seen_) {
+ base::AutoLock auto_lock(helper_->lock_);
+
+ // If there are no found records either, load some for this histogram.
+ if (found_.empty()) {
+ if (!helper_->LoadRecordsForSampleMapWhileLocked(sample_map_id_))
Alexei Svitkine (slow) 2016/04/13 15:53:50 So the function you call will give up after not fi
bcwhite 2016/04/13 22:45:03 It loads 10 records. If it hasn't found one for t
Alexei Svitkine (slow) 2016/04/14 19:30:03 Where does it continue? I don't see a loop inside
bcwhite 2016/04/15 02:36:18 "!found" in the "for" condition. LoadRecordsForSa
+ return 0;
Alexei Svitkine (slow) 2016/04/13 15:53:50 Hmm, can we expose kReferenceNull to be public and
bcwhite 2016/04/13 22:45:03 Done.
+ }
+
+ DCHECK(!found_.empty());
+ records_.reserve(records_.size() + found_.size());
Alexei Svitkine (slow) 2016/04/13 15:53:50 Seems wasteful to copy this stuff twice. How about
bcwhite 2016/04/13 22:45:03 Done but I think this makes the code more confusin
+ records_.insert(records_.end(), found_.begin(), found_.end());
+ found_.clear();
+ }
+
+ // 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_++];
Alexei Svitkine (slow) 2016/04/13 15:53:50 Shouldn't this code also be locked?
bcwhite 2016/04/13 22:45:03 No need. records_ is only ever accessed by a sing
Alexei Svitkine (slow) 2016/04/14 19:30:03 I see. So it's only the helper that needs the lock
bcwhite 2016/04/15 02:36:18 Hmmm... Let me think about it. I worry that the
bcwhite 2016/04/15 14:12:57 Done.
+}
+
+PersistentMemoryAllocator::Reference PersistentSampleMapRecords::CreateNew(
+ HistogramBase::Sample value) {
+ return PersistentSampleMap::CreatePersistentRecord(helper_->allocator_,
+ sample_map_id_, value);
+}
+
} // namespace base

Powered by Google App Engine
This is Rietveld 408576698