| Index: base/metrics/sparse_histogram.cc
|
| diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
|
| index 485f1796e98ab74eabf3c6bb4ab2294779b552a4..ee18cfa6b15ffb0b69b56604ac17529cddd1a9bb 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;
|
|
|