Commit 6c3cc295 authored by Sigurdur Asgeirsson's avatar Sigurdur Asgeirsson Committed by Commit Bot

RC: Add memory measurement to render process probe.

Bug: 755840
Change-Id: I96af63e817abe9bdefb0916da4d652e97c620a2c
Reviewed-on: https://chromium-review.googlesource.com/1037631
Commit-Queue: Chris Hamilton <chrisha@chromium.org>
Reviewed-by: default avatarChris Hamilton <chrisha@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#555844}
parent e35026fa
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
#include "base/values.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
...@@ -27,9 +26,6 @@ namespace { ...@@ -27,9 +26,6 @@ namespace {
constexpr base::TimeDelta kDefaultMeasurementInterval = constexpr base::TimeDelta kDefaultMeasurementInterval =
base::TimeDelta::FromMinutes(10); base::TimeDelta::FromMinutes(10);
base::LazyInstance<ResourceCoordinatorRenderProcessProbe>::DestructorAtExit
g_probe = LAZY_INSTANCE_INITIALIZER;
} // namespace } // namespace
ResourceCoordinatorRenderProcessProbe::RenderProcessInfo::RenderProcessInfo() = ResourceCoordinatorRenderProcessProbe::RenderProcessInfo::RenderProcessInfo() =
...@@ -49,7 +45,8 @@ ResourceCoordinatorRenderProcessProbe:: ...@@ -49,7 +45,8 @@ ResourceCoordinatorRenderProcessProbe::
// static // static
ResourceCoordinatorRenderProcessProbe* ResourceCoordinatorRenderProcessProbe*
ResourceCoordinatorRenderProcessProbe::GetInstance() { ResourceCoordinatorRenderProcessProbe::GetInstance() {
return g_probe.Pointer(); static base::NoDestructor<ResourceCoordinatorRenderProcessProbe> probe;
return probe.get();
} }
// static // static
...@@ -132,16 +129,24 @@ void ResourceCoordinatorRenderProcessProbe:: ...@@ -132,16 +129,24 @@ void ResourceCoordinatorRenderProcessProbe::
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&ResourceCoordinatorRenderProcessProbe:: base::BindOnce(
CollectAndDispatchRenderProcessMetricsOnIOThread, &ResourceCoordinatorRenderProcessProbe::
base::Unretained(this))); CollectRenderProcessMetricsAndStartMemoryDumpOnIOThread,
base::Unretained(this)));
} }
void ResourceCoordinatorRenderProcessProbe:: void ResourceCoordinatorRenderProcessProbe::
CollectAndDispatchRenderProcessMetricsOnIOThread() { CollectRenderProcessMetricsAndStartMemoryDumpOnIOThread() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
DCHECK(is_gathering_); DCHECK(is_gathering_);
// Dispatch the memory collection request.
memory_instrumentation::MemoryInstrumentation::GetInstance()
->RequestGlobalDump(
base::BindRepeating(&ResourceCoordinatorRenderProcessProbe::
ProcessGlobalMemoryDumpAndDispatchOnIOThread,
base::Unretained(this)));
RenderProcessInfoMap::iterator iter = render_process_info_map_.begin(); RenderProcessInfoMap::iterator iter = render_process_info_map_.begin();
while (iter != render_process_info_map_.end()) { while (iter != render_process_info_map_.end()) {
auto& render_process_info = iter->second; auto& render_process_info = iter->second;
...@@ -157,12 +162,21 @@ void ResourceCoordinatorRenderProcessProbe:: ...@@ -157,12 +162,21 @@ void ResourceCoordinatorRenderProcessProbe::
continue; continue;
} }
} }
}
void ResourceCoordinatorRenderProcessProbe::
ProcessGlobalMemoryDumpAndDispatchOnIOThread(
bool global_success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump) {
// Create the measurement batch. // Create the measurement batch.
mojom::ProcessResourceMeasurementBatchPtr batch = mojom::ProcessResourceMeasurementBatchPtr batch =
mojom::ProcessResourceMeasurementBatch::New(); mojom::ProcessResourceMeasurementBatch::New();
for (auto& render_process_info_map_entry : render_process_info_map_) { // TODO(siggi): Add start/end times. This will need some support from
// the memory_instrumentation code.
// Start by adding the render process hosts we know about to the batch.
for (const auto& render_process_info_map_entry : render_process_info_map_) {
auto& render_process_info = render_process_info_map_entry.second; auto& render_process_info = render_process_info_map_entry.second;
// TODO(oysteine): Move the multiplier used to avoid precision loss // TODO(oysteine): Move the multiplier used to avoid precision loss
// into a shared location, when this property gets used. // into a shared location, when this property gets used.
...@@ -171,13 +185,35 @@ void ResourceCoordinatorRenderProcessProbe:: ...@@ -171,13 +185,35 @@ void ResourceCoordinatorRenderProcessProbe::
measurement->pid = render_process_info.process.Pid(); measurement->pid = render_process_info.process.Pid();
measurement->cpu_usage = render_process_info.cpu_usage; measurement->cpu_usage = render_process_info.cpu_usage;
// TODO(siggi): Add the private footprint.
batch->measurements.push_back(std::move(measurement)); batch->measurements.push_back(std::move(measurement));
} }
bool should_restart = DispatchMetrics(std::move(batch)); if (dump) {
// Then amend the ones we have memory metrics for with their private
// footprint. The global dump may contain non-renderer processes, it may
// contain renderer processes we didn't capture at the start of the cycle,
// and it may not contain all the renderer processes we know about.
// This may happen due to the inherent race between the request and
// starting/stopping renderers, or because of other failures
// This may therefore provide incomplete information.
for (const auto& dump_entry : dump->process_dumps()) {
base::ProcessId pid = dump_entry.pid();
for (const auto& measurement : batch->measurements) {
if (measurement->pid == pid) {
measurement->private_footprint_kb =
dump_entry.os_dump().private_footprint_kb;
break;
}
}
}
} else {
// We should only get a nullptr in case of failure.
DCHECK(!global_success);
}
bool should_restart = DispatchMetrics(std::move(batch));
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE, content::BrowserThread::UI, FROM_HERE,
base::BindOnce( base::BindOnce(
......
...@@ -9,11 +9,12 @@ ...@@ -9,11 +9,12 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "base/lazy_instance.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/no_destructor.h"
#include "base/process/process.h" #include "base/process/process.h"
#include "base/process/process_metrics.h" #include "base/process/process_metrics.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/resource_coordinator/public/cpp/system_resource_coordinator.h" #include "services/resource_coordinator/public/cpp/system_resource_coordinator.h"
namespace resource_coordinator { namespace resource_coordinator {
...@@ -41,6 +42,7 @@ class ResourceCoordinatorRenderProcessProbe { ...@@ -41,6 +42,7 @@ class ResourceCoordinatorRenderProcessProbe {
void StartSingleGather(); void StartSingleGather();
protected: protected:
// Internal state protected for testing.
struct RenderProcessInfo { struct RenderProcessInfo {
RenderProcessInfo(); RenderProcessInfo();
~RenderProcessInfo(); ~RenderProcessInfo();
...@@ -51,9 +53,7 @@ class ResourceCoordinatorRenderProcessProbe { ...@@ -51,9 +53,7 @@ class ResourceCoordinatorRenderProcessProbe {
}; };
using RenderProcessInfoMap = std::map<int, RenderProcessInfo>; using RenderProcessInfoMap = std::map<int, RenderProcessInfo>;
// Internal state protected for testing. friend class base::NoDestructor<ResourceCoordinatorRenderProcessProbe>;
friend struct base::LazyInstanceTraitsBase<
ResourceCoordinatorRenderProcessProbe>;
ResourceCoordinatorRenderProcessProbe(); ResourceCoordinatorRenderProcessProbe();
virtual ~ResourceCoordinatorRenderProcessProbe(); virtual ~ResourceCoordinatorRenderProcessProbe();
...@@ -61,10 +61,13 @@ class ResourceCoordinatorRenderProcessProbe { ...@@ -61,10 +61,13 @@ class ResourceCoordinatorRenderProcessProbe {
// (1) Identify all of the render processes that are active to measure. // (1) Identify all of the render processes that are active to measure.
// Child render processes can only be discovered in the browser's UI thread. // Child render processes can only be discovered in the browser's UI thread.
void RegisterAliveRenderProcessesOnUIThread(); void RegisterAliveRenderProcessesOnUIThread();
// (2) Collect and dispatch the render process metrics to the system // (2) Collect the render process CPU metrics and initiate a memory dump.
// coordination unit. void CollectRenderProcessMetricsAndStartMemoryDumpOnIOThread();
void CollectAndDispatchRenderProcessMetricsOnIOThread(); // (3) Process the results of the memory dump and dispatch the results.
// (3) Initiate the next render process metrics collection cycle if the void ProcessGlobalMemoryDumpAndDispatchOnIOThread(
bool success,
std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump);
// (4) Initiate the next render process metrics collection cycle if the
// cycle has been started and |restart_cycle| is true, which consists of a // cycle has been started and |restart_cycle| is true, which consists of a
// delayed call to perform (1) via a timer. // delayed call to perform (1) via a timer.
// Virtual for testing. // Virtual for testing.
......
...@@ -135,8 +135,10 @@ IN_PROC_BROWSER_TEST_F(ResourceCoordinatorRenderProcessProbeBrowserTest, ...@@ -135,8 +135,10 @@ IN_PROC_BROWSER_TEST_F(ResourceCoordinatorRenderProcessProbeBrowserTest,
EXPECT_EQ(initial_size, probe.last_measurement_batch()->measurements.size()); EXPECT_EQ(initial_size, probe.last_measurement_batch()->measurements.size());
// A quirk of the process_metrics implementation is that the first CPU // A quirk of the process_metrics implementation is that the first CPU
// measurement returns zero. // measurement returns zero.
for (const auto& measurement : probe.last_measurement_batch()->measurements) for (const auto& measurement : probe.last_measurement_batch()->measurements) {
EXPECT_EQ(0.0, measurement->cpu_usage); EXPECT_EQ(0.0, measurement->cpu_usage);
EXPECT_NE(0u, measurement->private_footprint_kb);
}
// Open a second tab and complete a navigation. // Open a second tab and complete a navigation.
ui_test_utils::NavigateToURLWithDisposition( ui_test_utils::NavigateToURLWithDisposition(
...@@ -164,8 +166,10 @@ IN_PROC_BROWSER_TEST_F(ResourceCoordinatorRenderProcessProbeBrowserTest, ...@@ -164,8 +166,10 @@ IN_PROC_BROWSER_TEST_F(ResourceCoordinatorRenderProcessProbeBrowserTest,
size_t info_map_size = info_map.size(); size_t info_map_size = info_map.size();
probe.StartGatherCycleAndWait(); probe.StartGatherCycleAndWait();
// The second and subsequent CPU measurements should return some data. // The second and subsequent CPU measurements should return some data.
for (const auto& measurement : probe.last_measurement_batch()->measurements) for (const auto& measurement : probe.last_measurement_batch()->measurements) {
EXPECT_LE(0.0, measurement->cpu_usage); EXPECT_LE(0.0, measurement->cpu_usage);
EXPECT_NE(0u, measurement->private_footprint_kb);
}
EXPECT_EQ(info_map_size, info_map.size()); EXPECT_EQ(info_map_size, info_map.size());
for (const auto& entry : probe.render_process_info_map()) { for (const auto& entry : probe.render_process_info_map()) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment