summaryrefslogtreecommitdiff
path: root/chromium/base/metrics/statistics_recorder.cc
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-01-31 16:33:43 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-02-06 16:33:22 +0000
commitda51f56cc21233c2d30f0fe0d171727c3102b2e0 (patch)
tree4e579ab70ce4b19bee7984237f3ce05a96d59d83 /chromium/base/metrics/statistics_recorder.cc
parentc8c2d1901aec01e934adf561a9fdf0cc776cdef8 (diff)
downloadqtwebengine-chromium-da51f56cc21233c2d30f0fe0d171727c3102b2e0.tar.gz
BASELINE: Update Chromium to 65.0.3525.40
Also imports missing submodules Change-Id: I36901b7c6a325cda3d2c10cedb2186c25af3b79b Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
Diffstat (limited to 'chromium/base/metrics/statistics_recorder.cc')
-rw-r--r--chromium/base/metrics/statistics_recorder.cc544
1 files changed, 205 insertions, 339 deletions
diff --git a/chromium/base/metrics/statistics_recorder.cc b/chromium/base/metrics/statistics_recorder.cc
index a21adc09a0c..60e430eb72a 100644
--- a/chromium/base/metrics/statistics_recorder.cc
+++ b/chromium/base/metrics/statistics_recorder.cc
@@ -20,184 +20,138 @@
#include "base/strings/stringprintf.h"
#include "base/values.h"
+namespace base {
namespace {
-// Initialize histogram statistics gathering system.
-base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ =
- LAZY_INSTANCE_INITIALIZER;
-
bool HistogramNameLesser(const base::HistogramBase* a,
const base::HistogramBase* b) {
- return a->histogram_name() < b->histogram_name();
+ return strcmp(a->histogram_name(), b->histogram_name()) < 0;
}
} // namespace
-namespace base {
+// static
+LazyInstance<Lock>::Leaky StatisticsRecorder::lock_;
-StatisticsRecorder::~StatisticsRecorder() {
- DCHECK(histograms_);
- DCHECK(ranges_);
+// static
+StatisticsRecorder* StatisticsRecorder::top_ = nullptr;
- // Clean out what this object created and then restore what existed before.
- Reset();
- base::AutoLock auto_lock(lock_.Get());
- histograms_ = existing_histograms_.release();
- callbacks_ = existing_callbacks_.release();
- ranges_ = existing_ranges_.release();
- providers_ = existing_providers_.release();
- record_checker_ = existing_record_checker_.release();
+// static
+bool StatisticsRecorder::is_vlog_initialized_ = false;
+
+size_t StatisticsRecorder::BucketRangesHash::operator()(
+ const BucketRanges* const a) const {
+ return a->checksum();
}
-// static
-void StatisticsRecorder::Initialize() {
- // Tests sometimes create local StatisticsRecorders in order to provide a
- // contained environment of histograms that can be later discarded. If a
- // true global instance gets created in this environment then it will
- // eventually get disconnected when the local instance destructs and
- // restores the previous state, resulting in no StatisticsRecorder at all.
- // The global lazy instance, however, will remain valid thus ensuring that
- // another never gets installed via this method. If a |histograms_| map
- // exists then assume the StatisticsRecorder is already "initialized".
- if (histograms_)
- return;
+bool StatisticsRecorder::BucketRangesEqual::operator()(
+ const BucketRanges* const a,
+ const BucketRanges* const b) const {
+ return a->Equals(b);
+}
- // Ensure that an instance of the StatisticsRecorder object is created.
- g_statistics_recorder_.Get();
+StatisticsRecorder::~StatisticsRecorder() {
+ const AutoLock auto_lock(lock_.Get());
+ DCHECK_EQ(this, top_);
+ top_ = previous_;
}
// static
-bool StatisticsRecorder::IsActive() {
- base::AutoLock auto_lock(lock_.Get());
- return histograms_ != nullptr;
+void StatisticsRecorder::EnsureGlobalRecorderWhileLocked() {
+ lock_.Get().AssertAcquired();
+ if (top_)
+ return;
+
+ const StatisticsRecorder* const p = new StatisticsRecorder;
+ // The global recorder is never deleted.
+ ANNOTATE_LEAKING_OBJECT_PTR(p);
+ DCHECK_EQ(p, top_);
}
// static
void StatisticsRecorder::RegisterHistogramProvider(
const WeakPtr<HistogramProvider>& provider) {
- providers_->push_back(provider);
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ top_->providers_.push_back(provider);
}
// static
HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
HistogramBase* histogram) {
- HistogramBase* histogram_to_delete = nullptr;
- HistogramBase* histogram_to_return = nullptr;
- {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_) {
- histogram_to_return = histogram;
-
- // As per crbug.com/79322 the histograms are intentionally leaked, so we
- // need to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used
- // only once for an object, the duplicates should not be annotated.
- // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
- // twice |if (!histograms_)|.
- ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
- } else {
- const char* name = histogram->histogram_name();
- StringPiece name_piece(name);
- HistogramMap::iterator it = histograms_->find(name_piece);
- if (histograms_->end() == it) {
- // |name_piece| is guaranteed to never change or be deallocated so long
- // as the histogram is alive (which is forever).
- (*histograms_)[name_piece] = histogram;
- ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
- // If there are callbacks for this histogram, we set the kCallbackExists
- // flag.
- auto callback_iterator = callbacks_->find(name);
- if (callback_iterator != callbacks_->end()) {
- if (!callback_iterator->second.is_null())
- histogram->SetFlags(HistogramBase::kCallbackExists);
- else
- histogram->ClearFlags(HistogramBase::kCallbackExists);
- }
- histogram_to_return = histogram;
- } else if (histogram == it->second) {
- // The histogram was registered before.
- histogram_to_return = histogram;
- } else {
- // We already have one histogram with this name.
- DCHECK_EQ(StringPiece(histogram->histogram_name()),
- StringPiece(it->second->histogram_name()))
- << "hash collision";
- histogram_to_return = it->second;
- histogram_to_delete = histogram;
- }
+ // Declared before |auto_lock| to ensure correct destruction order.
+ std::unique_ptr<HistogramBase> histogram_deleter;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+
+ const char* const name = histogram->histogram_name();
+ HistogramBase*& registered = top_->histograms_[name];
+
+ if (!registered) {
+ // |name| is guaranteed to never change or be deallocated so long
+ // as the histogram is alive (which is forever).
+ registered = histogram;
+ ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
+ // If there are callbacks for this histogram, we set the kCallbackExists
+ // flag.
+ const auto callback_iterator = top_->callbacks_.find(name);
+ if (callback_iterator != top_->callbacks_.end()) {
+ if (!callback_iterator->second.is_null())
+ histogram->SetFlags(HistogramBase::kCallbackExists);
+ else
+ histogram->ClearFlags(HistogramBase::kCallbackExists);
}
+ return histogram;
+ }
+
+ if (histogram == registered) {
+ // The histogram was registered before.
+ return histogram;
}
- delete histogram_to_delete;
- return histogram_to_return;
+
+ // We already have one histogram with this name.
+ histogram_deleter.reset(histogram);
+ return registered;
}
// static
const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
const BucketRanges* ranges) {
DCHECK(ranges->HasValidChecksum());
+
+ // Declared before |auto_lock| to ensure correct destruction order.
std::unique_ptr<const BucketRanges> ranges_deleter;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- base::AutoLock auto_lock(lock_.Get());
- if (!ranges_) {
+ const BucketRanges* const registered = *top_->ranges_.insert(ranges).first;
+ if (registered == ranges) {
ANNOTATE_LEAKING_OBJECT_PTR(ranges);
- return ranges;
- }
-
- std::list<const BucketRanges*>* checksum_matching_list;
- RangesMap::iterator ranges_it = ranges_->find(ranges->checksum());
- if (ranges_->end() == ranges_it) {
- // Add a new matching list to map.
- checksum_matching_list = new std::list<const BucketRanges*>();
- ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
- (*ranges_)[ranges->checksum()] = checksum_matching_list;
} else {
- checksum_matching_list = ranges_it->second;
+ ranges_deleter.reset(ranges);
}
- for (const BucketRanges* existing_ranges : *checksum_matching_list) {
- if (existing_ranges->Equals(ranges)) {
- if (existing_ranges == ranges) {
- return ranges;
- } else {
- ranges_deleter.reset(ranges);
- return existing_ranges;
- }
- }
- }
- // We haven't found a BucketRanges which has the same ranges. Register the
- // new BucketRanges.
- checksum_matching_list->push_front(ranges);
- return ranges;
+ return registered;
}
// static
void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
std::string* output) {
- if (!IsActive())
- return;
-
- Histograms snapshot;
- GetSnapshot(query, &snapshot);
- std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
- for (const HistogramBase* histogram : snapshot) {
+ for (const HistogramBase* const histogram : GetSnapshot(query)) {
histogram->WriteHTMLGraph(output);
- output->append("<br><hr><br>");
+ *output += "<br><hr><br>";
}
}
// static
void StatisticsRecorder::WriteGraph(const std::string& query,
std::string* output) {
- if (!IsActive())
- return;
if (query.length())
StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
else
output->append("Collections of all histograms\n");
- Histograms snapshot;
- GetSnapshot(query, &snapshot);
- std::sort(snapshot.begin(), snapshot.end(), &HistogramNameLesser);
- for (const HistogramBase* histogram : snapshot) {
+ for (const HistogramBase* const histogram : GetSnapshot(query)) {
histogram->WriteAscii(output);
output->append("\n");
}
@@ -205,19 +159,11 @@ void StatisticsRecorder::WriteGraph(const std::string& query,
// static
std::string StatisticsRecorder::ToJSON(JSONVerbosityLevel verbosity_level) {
- if (!IsActive())
- return std::string();
-
- std::string output("{");
- Histograms snapshot;
- GetSnapshot(std::string(), &snapshot);
- output += "\"histograms\":[";
- bool first_histogram = true;
- for (const HistogramBase* histogram : snapshot) {
- if (first_histogram)
- first_histogram = false;
- else
- output += ",";
+ std::string output = "{\"histograms\":[";
+ const char* sep = "";
+ for (const HistogramBase* const histogram : GetHistograms()) {
+ output += sep;
+ sep = ",";
std::string json;
histogram->WriteJSON(&json, verbosity_level);
output += json;
@@ -227,28 +173,13 @@ std::string StatisticsRecorder::ToJSON(JSONVerbosityLevel verbosity_level) {
}
// static
-void StatisticsRecorder::GetHistograms(Histograms* output) {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return;
-
- for (const auto& entry : *histograms_) {
- output->push_back(entry.second);
- }
-}
-
-// static
-void StatisticsRecorder::GetBucketRanges(
- std::vector<const BucketRanges*>* output) {
- base::AutoLock auto_lock(lock_.Get());
- if (!ranges_)
- return;
-
- for (const auto& entry : *ranges_) {
- for (auto* range_entry : *entry.second) {
- output->push_back(range_entry);
- }
- }
+std::vector<const BucketRanges*> StatisticsRecorder::GetBucketRanges() {
+ std::vector<const BucketRanges*> out;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ out.reserve(top_->ranges_.size());
+ out.assign(top_->ranges_.begin(), top_->ranges_.end());
+ return out;
}
// static
@@ -258,23 +189,25 @@ HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
// will acquire the lock at that time.
ImportGlobalPersistentHistograms();
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return nullptr;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- HistogramMap::iterator it = histograms_->find(name);
- if (histograms_->end() == it)
- return nullptr;
- return it->second;
+ const HistogramMap::const_iterator it = top_->histograms_.find(name);
+ return it != top_->histograms_.end() ? it->second : nullptr;
}
// static
-void StatisticsRecorder::ImportProvidedHistograms() {
- if (!providers_)
- return;
+StatisticsRecorder::HistogramProviders
+StatisticsRecorder::GetHistogramProviders() {
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ return top_->providers_;
+}
+// static
+void StatisticsRecorder::ImportProvidedHistograms() {
// Merge histogram data from each provider in turn.
- for (const WeakPtr<HistogramProvider>& provider : *providers_) {
+ for (const WeakPtr<HistogramProvider>& provider : GetHistogramProviders()) {
// Weak-pointer may be invalid if the provider was destructed, though they
// generally never are.
if (provider)
@@ -288,42 +221,14 @@ void StatisticsRecorder::PrepareDeltas(
HistogramBase::Flags flags_to_set,
HistogramBase::Flags required_flags,
HistogramSnapshotManager* snapshot_manager) {
- if (include_persistent)
- ImportGlobalPersistentHistograms();
-
- auto known = GetKnownHistograms(include_persistent);
- snapshot_manager->PrepareDeltas(known.begin(), known.end(), flags_to_set,
- required_flags);
+ snapshot_manager->PrepareDeltas(GetKnownHistograms(include_persistent),
+ flags_to_set, required_flags);
}
// static
void StatisticsRecorder::InitLogOnShutdown() {
- if (!histograms_)
- return;
-
- base::AutoLock auto_lock(lock_.Get());
- g_statistics_recorder_.Get().InitLogOnShutdownWithoutLock();
-}
-
-// static
-void StatisticsRecorder::GetSnapshot(const std::string& query,
- Histograms* snapshot) {
- // This must be called *before* the lock is acquired below because it will
- // call back into this object to register histograms. Those called methods
- // will acquire the lock at that time.
- ImportGlobalPersistentHistograms();
-
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return;
-
- // Need a c-string query for comparisons against c-string histogram name.
- const char* query_string = query.c_str();
-
- for (const auto& entry : *histograms_) {
- if (strstr(entry.second->histogram_name(), query_string) != nullptr)
- snapshot->push_back(entry.second);
- }
+ const AutoLock auto_lock(lock_.Get());
+ InitLogOnShutdownWhileLocked();
}
// static
@@ -331,16 +236,14 @@ bool StatisticsRecorder::SetCallback(
const std::string& name,
const StatisticsRecorder::OnSampleCallback& cb) {
DCHECK(!cb.is_null());
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return false;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- if (ContainsKey(*callbacks_, name))
+ if (!top_->callbacks_.insert({name, cb}).second)
return false;
- callbacks_->insert(std::make_pair(name, cb));
- auto it = histograms_->find(name);
- if (it != histograms_->end())
+ const HistogramMap::const_iterator it = top_->histograms_.find(name);
+ if (it != top_->histograms_.end())
it->second->SetFlags(HistogramBase::kCallbackExists);
return true;
@@ -348,199 +251,162 @@ bool StatisticsRecorder::SetCallback(
// static
void StatisticsRecorder::ClearCallback(const std::string& name) {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- callbacks_->erase(name);
+ top_->callbacks_.erase(name);
// We also clear the flag from the histogram (if it exists).
- auto it = histograms_->find(name);
- if (it != histograms_->end())
+ const HistogramMap::const_iterator it = top_->histograms_.find(name);
+ if (it != top_->histograms_.end())
it->second->ClearFlags(HistogramBase::kCallbackExists);
}
// static
StatisticsRecorder::OnSampleCallback StatisticsRecorder::FindCallback(
const std::string& name) {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return OnSampleCallback();
-
- auto callback_iterator = callbacks_->find(name);
- return callback_iterator != callbacks_->end() ? callback_iterator->second
- : OnSampleCallback();
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ const auto it = top_->callbacks_.find(name);
+ return it != top_->callbacks_.end() ? it->second : OnSampleCallback();
}
// static
size_t StatisticsRecorder::GetHistogramCount() {
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_)
- return 0;
- return histograms_->size();
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ return top_->histograms_.size();
}
// static
void StatisticsRecorder::ForgetHistogramForTesting(base::StringPiece name) {
- if (!histograms_)
- return;
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
- HistogramMap::iterator found = histograms_->find(name);
- if (found == histograms_->end())
+ const HistogramMap::iterator found = top_->histograms_.find(name);
+ if (found == top_->histograms_.end())
return;
- HistogramBase* base = found->second;
+ HistogramBase* const base = found->second;
if (base->GetHistogramType() != SPARSE_HISTOGRAM) {
// When forgetting a histogram, it's likely that other information is
// also becoming invalid. Clear the persistent reference that may no
// longer be valid. There's no danger in this as, at worst, duplicates
// will be created in persistent memory.
- Histogram* histogram = static_cast<Histogram*>(base);
- histogram->bucket_ranges()->set_persistent_reference(0);
+ static_cast<Histogram*>(base)->bucket_ranges()->set_persistent_reference(0);
}
- histograms_->erase(found);
+ top_->histograms_.erase(found);
}
// static
std::unique_ptr<StatisticsRecorder>
StatisticsRecorder::CreateTemporaryForTesting() {
+ const AutoLock auto_lock(lock_.Get());
return WrapUnique(new StatisticsRecorder());
}
// static
-void StatisticsRecorder::UninitializeForTesting() {
- // Stop now if it's never been initialized.
- if (!histograms_)
- return;
-
- // Get the global instance and destruct it. It's held in static memory so
- // can't "delete" it; call the destructor explicitly.
- DCHECK(g_statistics_recorder_.private_instance_);
- g_statistics_recorder_.Get().~StatisticsRecorder();
-
- // Now the ugly part. There's no official way to release a LazyInstance once
- // created so it's necessary to clear out an internal variable which
- // shouldn't be publicly visible but is for initialization reasons.
- g_statistics_recorder_.private_instance_ = 0;
-}
-
-// static
void StatisticsRecorder::SetRecordChecker(
std::unique_ptr<RecordHistogramChecker> record_checker) {
- record_checker_ = record_checker.release();
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ top_->record_checker_ = std::move(record_checker);
}
// static
bool StatisticsRecorder::ShouldRecordHistogram(uint64_t histogram_hash) {
- return !record_checker_ || record_checker_->ShouldRecord(histogram_hash);
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ return !top_->record_checker_ ||
+ top_->record_checker_->ShouldRecord(histogram_hash);
}
// static
-std::vector<HistogramBase*> StatisticsRecorder::GetKnownHistograms(
- bool include_persistent) {
- std::vector<HistogramBase*> known;
- base::AutoLock auto_lock(lock_.Get());
- if (!histograms_ || histograms_->empty())
- return known;
-
- known.reserve(histograms_->size());
- for (const auto& h : *histograms_) {
- if (!include_persistent &&
- (h.second->flags() & HistogramBase::kIsPersistent)) {
- continue;
+template <typename Predicate>
+StatisticsRecorder::Histograms StatisticsRecorder::GetHistogramsWithPredicate(
+ const Predicate predicate) {
+ // This must be called *before* the lock is acquired below because it will
+ // call back into this object to register histograms. Those called methods
+ // will acquire the lock at that time.
+ ImportGlobalPersistentHistograms();
+
+ Histograms out;
+
+ {
+ const AutoLock auto_lock(lock_.Get());
+ EnsureGlobalRecorderWhileLocked();
+ out.reserve(top_->histograms_.size());
+ for (const auto& entry : top_->histograms_) {
+ const HistogramBase* const histogram = entry.second;
+ DCHECK(histogram);
+ if (predicate(*histogram))
+ out.push_back(entry.second);
}
- known.push_back(h.second);
}
- return known;
+ std::sort(out.begin(), out.end(), &HistogramNameLesser);
+ return out;
}
// static
-void StatisticsRecorder::ImportGlobalPersistentHistograms() {
- if (!histograms_)
- return;
-
- // Import histograms from known persistent storage. Histograms could have
- // been added by other processes and they must be fetched and recognized
- // locally. If the persistent memory segment is not shared between processes,
- // this call does nothing.
- GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
- if (allocator)
- allocator->ImportHistogramsToStatisticsRecorder();
+StatisticsRecorder::Histograms StatisticsRecorder::GetHistograms() {
+ return GetHistogramsWithPredicate([](const HistogramBase&) { return true; });
}
-// This singleton instance should be started during the single threaded portion
-// of main(), and hence it is not thread safe. It initializes globals to
-// provide support for all future calls.
-StatisticsRecorder::StatisticsRecorder() {
- base::AutoLock auto_lock(lock_.Get());
-
- existing_histograms_.reset(histograms_);
- existing_callbacks_.reset(callbacks_);
- existing_ranges_.reset(ranges_);
- existing_providers_.reset(providers_);
- existing_record_checker_.reset(record_checker_);
-
- histograms_ = new HistogramMap;
- callbacks_ = new CallbackMap;
- ranges_ = new RangesMap;
- providers_ = new HistogramProviders;
- record_checker_ = nullptr;
-
- InitLogOnShutdownWithoutLock();
-}
-
-void StatisticsRecorder::InitLogOnShutdownWithoutLock() {
- if (!vlog_initialized_ && VLOG_IS_ON(1)) {
- vlog_initialized_ = true;
- AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this);
- }
+// static
+StatisticsRecorder::Histograms StatisticsRecorder::GetKnownHistograms(
+ bool include_persistent) {
+ return GetHistogramsWithPredicate(
+ [include_persistent](const HistogramBase& histogram) {
+ return include_persistent ||
+ (histogram.flags() & HistogramBase::kIsPersistent) == 0;
+ });
}
// static
-void StatisticsRecorder::Reset() {
- std::unique_ptr<HistogramMap> histograms_deleter;
- std::unique_ptr<CallbackMap> callbacks_deleter;
- std::unique_ptr<RangesMap> ranges_deleter;
- std::unique_ptr<HistogramProviders> providers_deleter;
- std::unique_ptr<RecordHistogramChecker> record_checker_deleter;
- {
- base::AutoLock auto_lock(lock_.Get());
- histograms_deleter.reset(histograms_);
- callbacks_deleter.reset(callbacks_);
- ranges_deleter.reset(ranges_);
- providers_deleter.reset(providers_);
- record_checker_deleter.reset(record_checker_);
- histograms_ = nullptr;
- callbacks_ = nullptr;
- ranges_ = nullptr;
- providers_ = nullptr;
- record_checker_ = nullptr;
- }
- // We are going to leak the histograms and the ranges.
+StatisticsRecorder::Histograms StatisticsRecorder::GetSnapshot(
+ const std::string& query) {
+ // Need a C-string query for comparisons against C-string histogram name.
+ const char* const query_string = query.c_str();
+ return GetHistogramsWithPredicate(
+ [query_string](const HistogramBase& histogram) {
+ return strstr(histogram.histogram_name(), query_string) != nullptr;
+ });
}
// static
-void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
- std::string output;
- StatisticsRecorder::WriteGraph(std::string(), &output);
- VLOG(1) << output;
+void StatisticsRecorder::ImportGlobalPersistentHistograms() {
+ // Import histograms from known persistent storage. Histograms could have been
+ // added by other processes and they must be fetched and recognized locally.
+ // If the persistent memory segment is not shared between processes, this call
+ // does nothing.
+ if (GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get())
+ allocator->ImportHistogramsToStatisticsRecorder();
}
-
-// static
-StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = nullptr;
-// static
-StatisticsRecorder::CallbackMap* StatisticsRecorder::callbacks_ = nullptr;
-// static
-StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = nullptr;
-// static
-StatisticsRecorder::HistogramProviders* StatisticsRecorder::providers_;
-// static
-RecordHistogramChecker* StatisticsRecorder::record_checker_ = nullptr;
-// static
-base::LazyInstance<base::Lock>::Leaky StatisticsRecorder::lock_ =
- LAZY_INSTANCE_INITIALIZER;
+// This singleton instance should be started during the single threaded portion
+// of main(), and hence it is not thread safe. It initializes globals to provide
+// support for all future calls.
+StatisticsRecorder::StatisticsRecorder() {
+ lock_.Get().AssertAcquired();
+ previous_ = top_;
+ top_ = this;
+ InitLogOnShutdownWhileLocked();
+}
+
+// static
+void StatisticsRecorder::InitLogOnShutdownWhileLocked() {
+ lock_.Get().AssertAcquired();
+ if (!is_vlog_initialized_ && VLOG_IS_ON(1)) {
+ is_vlog_initialized_ = true;
+ const auto dump_to_vlog = [](void*) {
+ std::string output;
+ WriteGraph("", &output);
+ VLOG(1) << output;
+ };
+ AtExitManager::RegisterCallback(dump_to_vlog, nullptr);
+ }
+}
} // namespace base