summaryrefslogtreecommitdiffstats
path: root/base/metrics/sparse_histogram.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/metrics/sparse_histogram.cc')
-rw-r--r--base/metrics/sparse_histogram.cc102
1 files changed, 87 insertions, 15 deletions
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
index 485f179..ee18cfa 100644
--- a/base/metrics/sparse_histogram.cc
+++ b/base/metrics/sparse_histogram.cc
@@ -7,6 +7,8 @@
#include <utility>
#include "base/metrics/metrics_hashes.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_sample_map.h"
#include "base/metrics/sample_map.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
@@ -21,26 +23,75 @@ typedef HistogramBase::Sample Sample;
// static
HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
int32_t flags) {
- HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+ // Import histograms from known persistent storage. Histograms could have
+ // 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.
+ PersistentHistogramAllocator::ImportGlobalHistograms();
+ HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
if (!histogram) {
- // To avoid racy destruction at shutdown, the following will be leaked.
- HistogramBase* tentative_histogram = new SparseHistogram(name);
- tentative_histogram->SetFlags(flags);
- histogram =
- StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+ // Try to create the histogram using a "persistent" allocator. As of
+ // 2016-02-25, the availability of such is controlled by a base::Feature
+ // 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;
+ scoped_ptr<HistogramBase> tentative_histogram;
+ PersistentHistogramAllocator* allocator =
+ PersistentHistogramAllocator::GetGlobalAllocator();
+ if (allocator) {
+ tentative_histogram = allocator->AllocateHistogram(
+ SPARSE_HISTOGRAM, name, 0, 0, nullptr, flags, &histogram_ref);
+ }
+
+ // Handle the case where no persistent allocator is present or the
+ // persistent allocation fails (perhaps because it is full).
+ if (!tentative_histogram) {
+ DCHECK(!histogram_ref); // Should never have been set.
+ DCHECK(!allocator); // Shouldn't have failed.
+ flags &= ~HistogramBase::kIsPersistent;
+ tentative_histogram.reset(new SparseHistogram(name));
+ tentative_histogram->SetFlags(flags);
+ }
+
+ // 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) {
+ allocator->FinalizeHistogram(histogram_ref,
+ histogram == tentative_histogram_ptr);
+ }
+
ReportHistogramActivity(*histogram, HISTOGRAM_CREATED);
} else {
ReportHistogramActivity(*histogram, HISTOGRAM_LOOKUP);
}
+
DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
return histogram;
}
+// static
+scoped_ptr<HistogramBase> SparseHistogram::PersistentCreate(
+ PersistentMemoryAllocator* allocator,
+ const std::string& name,
+ HistogramSamples::Metadata* meta,
+ HistogramSamples::Metadata* logged_meta) {
+ return make_scoped_ptr(
+ new SparseHistogram(allocator, name, meta, logged_meta));
+}
+
SparseHistogram::~SparseHistogram() {}
uint64_t SparseHistogram::name_hash() const {
- return samples_.id();
+ return samples_->id();
}
HistogramType SparseHistogram::GetHistogramType() const {
@@ -66,7 +117,7 @@ void SparseHistogram::AddCount(Sample value, int count) {
}
{
base::AutoLock auto_lock(lock_);
- samples_.Accumulate(value, count);
+ samples_->Accumulate(value, count);
}
FindAndRunCallback(value);
@@ -76,29 +127,29 @@ scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
scoped_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
base::AutoLock auto_lock(lock_);
- snapshot->Add(samples_);
+ snapshot->Add(*samples_);
return std::move(snapshot);
}
scoped_ptr<HistogramSamples> SparseHistogram::SnapshotDelta() {
scoped_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
base::AutoLock auto_lock(lock_);
- snapshot->Add(samples_);
+ snapshot->Add(*samples_);
// Subtract what was previously logged and update that information.
- snapshot->Subtract(logged_samples_);
- logged_samples_.Add(*snapshot);
+ snapshot->Subtract(*logged_samples_);
+ logged_samples_->Add(*snapshot);
return std::move(snapshot);
}
void SparseHistogram::AddSamples(const HistogramSamples& samples) {
base::AutoLock auto_lock(lock_);
- samples_.Add(samples);
+ samples_->Add(samples);
}
bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
base::AutoLock auto_lock(lock_);
- return samples_.AddFromPickle(iter);
+ return samples_->AddFromPickle(iter);
}
void SparseHistogram::WriteHTMLGraph(std::string* output) const {
@@ -117,7 +168,28 @@ bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
SparseHistogram::SparseHistogram(const std::string& name)
: HistogramBase(name),
- samples_(HashMetricName(name)) {}
+ samples_(new SampleMap(HashMetricName(name))),
+ logged_samples_(new SampleMap(samples_->id())) {}
+
+SparseHistogram::SparseHistogram(PersistentMemoryAllocator* allocator,
+ const std::string& name,
+ HistogramSamples::Metadata* meta,
+ HistogramSamples::Metadata* logged_meta)
+ : HistogramBase(name),
+ // While other histogram types maintain a static vector of values with
+ // sufficient space for both "active" and "logged" samples, with each
+ // SampleVector being given the appropriate half, sparse histograms
+ // have no such initial allocation. Each sample has its own record
+ // attached to a single PersistentSampleMap by a common 64-bit identifier.
+ // Since a sparse histogram has two sample maps (active and logged),
+ // there must be two sets of sample records with diffent IDs. The
+ // "active" samples use, for convenience purposes, an ID matching
+ // that of the histogram while the "logged" samples use that number
+ // plus 1.
+ samples_(new PersistentSampleMap(HashMetricName(name), allocator, meta)),
+ logged_samples_(
+ new PersistentSampleMap(samples_->id() + 1, allocator, logged_meta)) {
+}
HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
std::string histogram_name;