summaryrefslogtreecommitdiff
path: root/chromium/components/metrics/content
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/metrics/content
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/metrics/content')
-rw-r--r--chromium/components/metrics/content/DEPS4
-rw-r--r--chromium/components/metrics/content/gpu_metrics_provider.cc33
-rw-r--r--chromium/components/metrics/content/gpu_metrics_provider.h29
-rw-r--r--chromium/components/metrics/content/rendering_perf_metrics_provider.cc20
-rw-r--r--chromium/components/metrics/content/rendering_perf_metrics_provider.h30
-rw-r--r--chromium/components/metrics/content/subprocess_metrics_provider.cc210
-rw-r--r--chromium/components/metrics/content/subprocess_metrics_provider.h116
-rw-r--r--chromium/components/metrics/content/subprocess_metrics_provider_unittest.cc161
8 files changed, 603 insertions, 0 deletions
diff --git a/chromium/components/metrics/content/DEPS b/chromium/components/metrics/content/DEPS
new file mode 100644
index 00000000000..c2ff8a0af67
--- /dev/null
+++ b/chromium/components/metrics/content/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+content/public/browser",
+ "+gpu/config",
+]
diff --git a/chromium/components/metrics/content/gpu_metrics_provider.cc b/chromium/components/metrics/content/gpu_metrics_provider.cc
new file mode 100644
index 00000000000..baa1e770e92
--- /dev/null
+++ b/chromium/components/metrics/content/gpu_metrics_provider.cc
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/content/gpu_metrics_provider.h"
+
+#include "content/public/browser/gpu_data_manager.h"
+#include "gpu/config/gpu_info.h"
+#include "third_party/metrics_proto/system_profile.pb.h"
+
+namespace metrics {
+
+GPUMetricsProvider::GPUMetricsProvider() {}
+
+GPUMetricsProvider::~GPUMetricsProvider() {}
+
+void GPUMetricsProvider::ProvideSystemProfileMetrics(
+ SystemProfileProto* system_profile_proto) {
+ SystemProfileProto::Hardware* hardware =
+ system_profile_proto->mutable_hardware();
+
+ const gpu::GPUInfo& gpu_info =
+ content::GpuDataManager::GetInstance()->GetGPUInfo();
+ const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
+ SystemProfileProto::Hardware::Graphics* gpu = hardware->mutable_gpu();
+ gpu->set_vendor_id(active_gpu.vendor_id);
+ gpu->set_device_id(active_gpu.device_id);
+ gpu->set_driver_version(active_gpu.driver_version);
+ gpu->set_gl_vendor(gpu_info.gl_vendor);
+ gpu->set_gl_renderer(gpu_info.gl_renderer);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/content/gpu_metrics_provider.h b/chromium/components/metrics/content/gpu_metrics_provider.h
new file mode 100644
index 00000000000..d429be83cf5
--- /dev/null
+++ b/chromium/components/metrics/content/gpu_metrics_provider.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_CONTENT_GPU_METRICS_PROVIDER_H_
+#define COMPONENTS_METRICS_CONTENT_GPU_METRICS_PROVIDER_H_
+
+#include "base/macros.h"
+#include "components/metrics/metrics_provider.h"
+
+namespace metrics {
+
+// GPUMetricsProvider provides GPU-related metrics.
+class GPUMetricsProvider : public MetricsProvider {
+ public:
+ GPUMetricsProvider();
+ ~GPUMetricsProvider() override;
+
+ // MetricsProvider:
+ void ProvideSystemProfileMetrics(
+ SystemProfileProto* system_profile_proto) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GPUMetricsProvider);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CONTENT_GPU_METRICS_PROVIDER_H_
diff --git a/chromium/components/metrics/content/rendering_perf_metrics_provider.cc b/chromium/components/metrics/content/rendering_perf_metrics_provider.cc
new file mode 100644
index 00000000000..c914f38df01
--- /dev/null
+++ b/chromium/components/metrics/content/rendering_perf_metrics_provider.cc
@@ -0,0 +1,20 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/content/rendering_perf_metrics_provider.h"
+
+#include "gpu/config/gpu_util.h"
+
+namespace metrics {
+
+RenderingPerfMetricsProvider::RenderingPerfMetricsProvider() = default;
+
+RenderingPerfMetricsProvider::~RenderingPerfMetricsProvider() = default;
+
+void RenderingPerfMetricsProvider::ProvideCurrentSessionData(
+ ChromeUserMetricsExtension* uma_proto) {
+ gpu::RecordDevicePerfInfoHistograms();
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/content/rendering_perf_metrics_provider.h b/chromium/components/metrics/content/rendering_perf_metrics_provider.h
new file mode 100644
index 00000000000..90ac73b02c2
--- /dev/null
+++ b/chromium/components/metrics/content/rendering_perf_metrics_provider.h
@@ -0,0 +1,30 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_CONTENT_RENDERING_PERF_METRICS_PROVIDER_H_
+#define COMPONENTS_METRICS_CONTENT_RENDERING_PERF_METRICS_PROVIDER_H_
+
+#include "base/macros.h"
+#include "components/metrics/metrics_provider.h"
+
+namespace metrics {
+
+// RenderingPerfMetricsProvider provides metrics related to rendering
+// performance.
+class RenderingPerfMetricsProvider : public MetricsProvider {
+ public:
+ RenderingPerfMetricsProvider();
+ ~RenderingPerfMetricsProvider() override;
+
+ // MetricsProvider:
+ void ProvideCurrentSessionData(
+ metrics::ChromeUserMetricsExtension* uma_proto) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderingPerfMetricsProvider);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CONTENT_RENDERING_PERF_METRICS_PROVIDER_H_
diff --git a/chromium/components/metrics/content/subprocess_metrics_provider.cc b/chromium/components/metrics/content/subprocess_metrics_provider.cc
new file mode 100644
index 00000000000..9af900d3421
--- /dev/null
+++ b/chromium/components/metrics/content/subprocess_metrics_provider.cc
@@ -0,0 +1,210 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/content/subprocess_metrics_provider.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "components/metrics/metrics_service.h"
+#include "content/public/browser/browser_child_process_host.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_data.h"
+
+namespace metrics {
+namespace {
+
+// This is used by tests that don't have an easy way to access the global
+// instance of this class.
+SubprocessMetricsProvider* g_subprocess_metrics_provider_for_testing;
+
+} // namespace
+
+SubprocessMetricsProvider::SubprocessMetricsProvider() {
+ base::StatisticsRecorder::RegisterHistogramProvider(
+ weak_ptr_factory_.GetWeakPtr());
+ content::BrowserChildProcessObserver::Add(this);
+ g_subprocess_metrics_provider_for_testing = this;
+}
+
+SubprocessMetricsProvider::~SubprocessMetricsProvider() {
+ // Safe even if this object has never been added as an observer.
+ content::BrowserChildProcessObserver::Remove(this);
+ g_subprocess_metrics_provider_for_testing = nullptr;
+}
+
+// static
+void SubprocessMetricsProvider::MergeHistogramDeltasForTesting() {
+ DCHECK(g_subprocess_metrics_provider_for_testing);
+ g_subprocess_metrics_provider_for_testing->MergeHistogramDeltas();
+}
+
+void SubprocessMetricsProvider::RegisterSubprocessAllocator(
+ int id,
+ std::unique_ptr<base::PersistentHistogramAllocator> allocator) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!allocators_by_id_.Lookup(id));
+
+ // Stop now if this was called without an allocator, typically because
+ // GetSubprocessHistogramAllocatorOnIOThread exited early and returned
+ // null.
+ if (!allocator)
+ return;
+
+ // Map is "MapOwnPointer" so transfer ownership to it.
+ allocators_by_id_.AddWithID(std::move(allocator), id);
+}
+
+void SubprocessMetricsProvider::DeregisterSubprocessAllocator(int id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (!allocators_by_id_.Lookup(id))
+ return;
+
+ // Extract the matching allocator from the list of active ones. It will
+ // be automatically released when this method exits.
+ std::unique_ptr<base::PersistentHistogramAllocator> allocator(
+ allocators_by_id_.Replace(id, nullptr));
+ allocators_by_id_.Remove(id);
+ DCHECK(allocator);
+
+ // Merge the last deltas from the allocator before it is released.
+ MergeHistogramDeltasFromAllocator(id, allocator.get());
+}
+
+void SubprocessMetricsProvider::MergeHistogramDeltasFromAllocator(
+ int id,
+ base::PersistentHistogramAllocator* allocator) {
+ DCHECK(allocator);
+
+ int histogram_count = 0;
+ base::PersistentHistogramAllocator::Iterator hist_iter(allocator);
+ while (true) {
+ std::unique_ptr<base::HistogramBase> histogram = hist_iter.GetNext();
+ if (!histogram)
+ break;
+ allocator->MergeHistogramDeltaToStatisticsRecorder(histogram.get());
+ ++histogram_count;
+ }
+
+ DVLOG(1) << "Reported " << histogram_count << " histograms from subprocess #"
+ << id;
+}
+
+void SubprocessMetricsProvider::MergeHistogramDeltas() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ for (AllocatorByIdMap::iterator iter(&allocators_by_id_); !iter.IsAtEnd();
+ iter.Advance()) {
+ MergeHistogramDeltasFromAllocator(iter.GetCurrentKey(),
+ iter.GetCurrentValue());
+ }
+}
+
+void SubprocessMetricsProvider::BrowserChildProcessHostConnected(
+ const content::ChildProcessData& data) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // It's necessary to access the BrowserChildProcessHost object that is
+ // managing the child in order to extract the metrics memory from it.
+ // Unfortunately, the required lookup can only be performed on the IO
+ // thread so do the necessary dance.
+ content::GetIOThreadTaskRunner({})->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(
+ &SubprocessMetricsProvider::GetSubprocessHistogramAllocatorOnIOThread,
+ data.id),
+ base::BindOnce(&SubprocessMetricsProvider::RegisterSubprocessAllocator,
+ weak_ptr_factory_.GetWeakPtr(), data.id));
+}
+
+void SubprocessMetricsProvider::BrowserChildProcessHostDisconnected(
+ const content::ChildProcessData& data) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DeregisterSubprocessAllocator(data.id);
+}
+
+void SubprocessMetricsProvider::BrowserChildProcessCrashed(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DeregisterSubprocessAllocator(data.id);
+}
+
+void SubprocessMetricsProvider::BrowserChildProcessKilled(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DeregisterSubprocessAllocator(data.id);
+}
+
+void SubprocessMetricsProvider::OnRenderProcessHostCreated(
+ content::RenderProcessHost* host) {
+ // Sometimes, the same host will cause multiple notifications in tests so
+ // could possibly do the same in a release build.
+ if (!scoped_observer_.IsObserving(host))
+ scoped_observer_.Add(host);
+}
+
+void SubprocessMetricsProvider::RenderProcessReady(
+ content::RenderProcessHost* host) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // If the render-process-host passed a persistent-memory-allocator to the
+ // renderer process, extract it and register it here.
+ std::unique_ptr<base::PersistentMemoryAllocator> allocator =
+ host->TakeMetricsAllocator();
+ if (allocator) {
+ RegisterSubprocessAllocator(
+ host->GetID(), std::make_unique<base::PersistentHistogramAllocator>(
+ std::move(allocator)));
+ }
+}
+
+void SubprocessMetricsProvider::RenderProcessExited(
+ content::RenderProcessHost* host,
+ const content::ChildProcessTerminationInfo& info) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ DeregisterSubprocessAllocator(host->GetID());
+}
+
+void SubprocessMetricsProvider::RenderProcessHostDestroyed(
+ content::RenderProcessHost* host) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // It's possible for a Renderer to terminate without RenderProcessExited
+ // (above) being called so it's necessary to de-register also upon the
+ // destruction of the host. If both get called, no harm is done.
+
+ DeregisterSubprocessAllocator(host->GetID());
+ scoped_observer_.Remove(host);
+}
+
+// static
+std::unique_ptr<base::PersistentHistogramAllocator>
+SubprocessMetricsProvider::GetSubprocessHistogramAllocatorOnIOThread(int id) {
+ // See if the new process has a memory allocator and take control of it if so.
+ // This call can only be made on the browser's IO thread.
+ content::BrowserChildProcessHost* host =
+ content::BrowserChildProcessHost::FromID(id);
+ if (!host)
+ return nullptr;
+
+ std::unique_ptr<base::PersistentMemoryAllocator> allocator =
+ host->TakeMetricsAllocator();
+ if (!allocator)
+ return nullptr;
+
+ return std::make_unique<base::PersistentHistogramAllocator>(
+ std::move(allocator));
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/content/subprocess_metrics_provider.h b/chromium/components/metrics/content/subprocess_metrics_provider.h
new file mode 100644
index 00000000000..cac37d5ca47
--- /dev/null
+++ b/chromium/components/metrics/content/subprocess_metrics_provider.h
@@ -0,0 +1,116 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_
+#define COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_
+
+#include <memory>
+#include <set>
+
+#include "base/containers/id_map.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/scoped_observer.h"
+#include "base/threading/thread_checker.h"
+#include "components/metrics/metrics_provider.h"
+#include "content/public/browser/browser_child_process_observer.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_process_host_creation_observer.h"
+#include "content/public/browser/render_process_host_observer.h"
+
+namespace base {
+class PersistentHistogramAllocator;
+}
+
+namespace metrics {
+
+// SubprocessMetricsProvider gathers and merges histograms stored in shared
+// memory segments between processes. Merging occurs when a process exits,
+// when metrics are being collected for upload, or when something else needs
+// combined metrics (such as the chrome://histograms page).
+class SubprocessMetricsProvider
+ : public MetricsProvider,
+ public base::StatisticsRecorder::HistogramProvider,
+ public content::BrowserChildProcessObserver,
+ public content::RenderProcessHostCreationObserver,
+ public content::RenderProcessHostObserver {
+ public:
+ SubprocessMetricsProvider();
+ ~SubprocessMetricsProvider() override;
+
+ // Merge histograms for all subprocesses. This is used by tests that don't
+ // have access to the internal instance of this class.
+ static void MergeHistogramDeltasForTesting();
+
+ private:
+ friend class SubprocessMetricsProviderTest;
+
+ // Indicates subprocess to be monitored with unique id for later reference.
+ // Metrics reporting will read histograms from it and upload them to UMA.
+ void RegisterSubprocessAllocator(
+ int id,
+ std::unique_ptr<base::PersistentHistogramAllocator> allocator);
+
+ // Indicates that a subprocess has exited and is thus finished with the
+ // allocator it was using.
+ void DeregisterSubprocessAllocator(int id);
+
+ // Merge all histograms of a given allocator to the global StatisticsRecorder.
+ // This is called periodically during UMA metrics collection (if enabled) and
+ // possibly on-demand for other purposes.
+ void MergeHistogramDeltasFromAllocator(
+ int id,
+ base::PersistentHistogramAllocator* allocator);
+
+ // MetricsProvider:
+ void MergeHistogramDeltas() override;
+
+ // content::BrowserChildProcessObserver:
+ void BrowserChildProcessHostConnected(
+ const content::ChildProcessData& data) override;
+ void BrowserChildProcessHostDisconnected(
+ const content::ChildProcessData& data) override;
+ void BrowserChildProcessCrashed(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) override;
+ void BrowserChildProcessKilled(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) override;
+
+ // content::RenderProcessHostCreationObserver:
+ void OnRenderProcessHostCreated(
+ content::RenderProcessHost* process_host) override;
+
+ // content::RenderProcessHostObserver:
+ void RenderProcessReady(content::RenderProcessHost* host) override;
+ void RenderProcessExited(
+ content::RenderProcessHost* host,
+ const content::ChildProcessTerminationInfo& info) override;
+ void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
+
+ // Gets a histogram allocator from a subprocess. This must be called on
+ // the IO thread.
+ static std::unique_ptr<base::PersistentHistogramAllocator>
+ GetSubprocessHistogramAllocatorOnIOThread(int id);
+
+ THREAD_CHECKER(thread_checker_);
+
+ // All of the shared-persistent-allocators for known sub-processes.
+ using AllocatorByIdMap =
+ base::IDMap<std::unique_ptr<base::PersistentHistogramAllocator>, int>;
+ AllocatorByIdMap allocators_by_id_;
+
+ // Track all observed render processes to un-observe them on exit.
+ ScopedObserver<content::RenderProcessHost, content::RenderProcessHostObserver>
+ scoped_observer_{this};
+
+ base::WeakPtrFactory<SubprocessMetricsProvider> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(SubprocessMetricsProvider);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CONTENT_SUBPROCESS_METRICS_PROVIDER_H_
diff --git a/chromium/components/metrics/content/subprocess_metrics_provider_unittest.cc b/chromium/components/metrics/content/subprocess_metrics_provider_unittest.cc
new file mode 100644
index 00000000000..26a3a6e640e
--- /dev/null
+++ b/chromium/components/metrics/content/subprocess_metrics_provider_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/content/subprocess_metrics_provider.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+#include "base/metrics/persistent_histogram_allocator.h"
+#include "base/metrics/persistent_memory_allocator.h"
+#include "base/metrics/statistics_recorder.h"
+#include "content/public/test/browser_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::IsEmpty;
+using ::testing::UnorderedElementsAre;
+
+namespace metrics {
+namespace {
+
+const uint32_t TEST_MEMORY_SIZE = 64 << 10; // 64 KiB
+
+class HistogramFlattenerDeltaRecorder : public base::HistogramFlattener {
+ public:
+ HistogramFlattenerDeltaRecorder() {}
+
+ void RecordDelta(const base::HistogramBase& histogram,
+ const base::HistogramSamples& snapshot) override {
+ recorded_delta_histogram_names_.push_back(histogram.histogram_name());
+ }
+
+ std::vector<std::string> GetRecordedDeltaHistogramNames() {
+ return recorded_delta_histogram_names_;
+ }
+
+ private:
+ std::vector<std::string> recorded_delta_histogram_names_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistogramFlattenerDeltaRecorder);
+};
+
+} // namespace
+
+class SubprocessMetricsProviderTest : public testing::Test {
+ protected:
+ SubprocessMetricsProviderTest() {
+ // MergeHistogramDeltas needs to be called beause it uses a histogram
+ // macro which caches a pointer to a histogram. If not done before setting
+ // a persistent global allocator, then it would point into memory that
+ // will go away.
+ provider_.MergeHistogramDeltas();
+
+ // Create a dedicated StatisticsRecorder for this test.
+ test_recorder_ = base::StatisticsRecorder::CreateTemporaryForTesting();
+
+ // Create a global allocator using a block of memory from the heap.
+ base::GlobalHistogramAllocator::CreateWithLocalMemory(TEST_MEMORY_SIZE, 0,
+ "");
+ }
+
+ ~SubprocessMetricsProviderTest() override {
+ base::GlobalHistogramAllocator::ReleaseForTesting();
+ }
+
+ SubprocessMetricsProvider* provider() { return &provider_; }
+
+ std::unique_ptr<base::PersistentHistogramAllocator> CreateDuplicateAllocator(
+ base::PersistentHistogramAllocator* allocator) {
+ // Just wrap around the data segment in-use by the passed allocator.
+ return std::make_unique<base::PersistentHistogramAllocator>(
+ std::make_unique<base::PersistentMemoryAllocator>(
+ const_cast<void*>(allocator->data()), allocator->length(), 0, 0,
+ std::string(), false));
+ }
+
+ std::vector<std::string> GetSnapshotHistogramNames() {
+ // Merge the data from the allocator into the StatisticsRecorder.
+ provider_.MergeHistogramDeltas();
+
+ // Flatten what is known to see what has changed since the last time.
+ HistogramFlattenerDeltaRecorder flattener;
+ base::HistogramSnapshotManager snapshot_manager(&flattener);
+ // "true" to the begin() includes histograms held in persistent storage.
+ base::StatisticsRecorder::PrepareDeltas(true, base::Histogram::kNoFlags,
+ base::Histogram::kNoFlags,
+ &snapshot_manager);
+ return flattener.GetRecordedDeltaHistogramNames();
+ }
+
+ void EnableRecording() { provider_.OnRecordingEnabled(); }
+ void DisableRecording() { provider_.OnRecordingDisabled(); }
+
+ void RegisterSubprocessAllocator(
+ int id,
+ std::unique_ptr<base::PersistentHistogramAllocator> allocator) {
+ provider_.RegisterSubprocessAllocator(id, std::move(allocator));
+ }
+
+ void DeregisterSubprocessAllocator(int id) {
+ provider_.DeregisterSubprocessAllocator(id);
+ }
+
+ private:
+ // A thread-bundle makes the tests appear on the UI thread, something that is
+ // checked in methods called from the SubprocessMetricsProvider class under
+ // test. This must be constructed before the |provider_| field.
+ content::BrowserTaskEnvironment task_environment_;
+
+ SubprocessMetricsProvider provider_;
+ std::unique_ptr<base::StatisticsRecorder> test_recorder_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubprocessMetricsProviderTest);
+};
+
+TEST_F(SubprocessMetricsProviderTest, SnapshotMetrics) {
+ base::HistogramBase* foo = base::Histogram::FactoryGet("foo", 1, 100, 10, 0);
+ base::HistogramBase* bar = base::Histogram::FactoryGet("bar", 1, 100, 10, 0);
+ base::HistogramBase* baz = base::Histogram::FactoryGet("baz", 1, 100, 10, 0);
+ foo->Add(42);
+ bar->Add(84);
+
+ // Detach the global allocator but keep it around until this method exits
+ // so that the memory holding histogram data doesn't get released. Register
+ // a new allocator that duplicates the global one.
+ std::unique_ptr<base::GlobalHistogramAllocator> global_allocator(
+ base::GlobalHistogramAllocator::ReleaseForTesting());
+ RegisterSubprocessAllocator(123,
+ CreateDuplicateAllocator(global_allocator.get()));
+
+ // Recording should find the two histograms created in persistent memory.
+ EXPECT_THAT(GetSnapshotHistogramNames(), UnorderedElementsAre("foo", "bar"));
+
+ // A second run should have nothing to produce.
+ EXPECT_THAT(GetSnapshotHistogramNames(), IsEmpty());
+
+ // Create a new histogram and update existing ones. Should now report 3 items.
+ baz->Add(1969);
+ foo->Add(10);
+ bar->Add(20);
+ EXPECT_THAT(GetSnapshotHistogramNames(),
+ UnorderedElementsAre("foo", "bar", "baz"));
+
+ // Ensure that deregistering does a final merge of the data.
+ foo->Add(10);
+ bar->Add(20);
+ DeregisterSubprocessAllocator(123);
+ EXPECT_THAT(GetSnapshotHistogramNames(), UnorderedElementsAre("foo", "bar"));
+
+ // Further snapshots should be empty even if things have changed.
+ foo->Add(10);
+ bar->Add(20);
+ EXPECT_THAT(GetSnapshotHistogramNames(), IsEmpty());
+}
+
+} // namespace metrics