Commit ec6a7a25 authored by Erik Chen's avatar Erik Chen Committed by Commit Bot

Speed up module dumps on macOS.

The out of process heap profiler only requires modules to be dumped, not every
single virtual memory region. This CL modifies the interface to support this,
and updates the macOS implementation to be much faster. The other OSes currently
still perform full address space dumps - this can be changed in the future if it
proves to be a performance issue.

Bug: 826913
Change-Id: Ibaa03d3dfae71a2b6d090aed0ab2ffdc4bb090a9
Reviewed-on: https://chromium-review.googlesource.com/986680
Commit-Queue: Erik Chen <erikchen@chromium.org>
Reviewed-by: default avatarPrimiano Tucci <primiano@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548731}
parent a992c363
...@@ -45,8 +45,6 @@ const char* MemoryDumpLevelOfDetailToString( ...@@ -45,8 +45,6 @@ const char* MemoryDumpLevelOfDetailToString(
return "background"; return "background";
case MemoryDumpLevelOfDetail::LIGHT: case MemoryDumpLevelOfDetail::LIGHT:
return "light"; return "light";
case MemoryDumpLevelOfDetail::VM_REGIONS_ONLY_FOR_HEAP_PROFILER:
return "vm_regions_only";
case MemoryDumpLevelOfDetail::DETAILED: case MemoryDumpLevelOfDetail::DETAILED:
return "detailed"; return "detailed";
} }
...@@ -60,8 +58,6 @@ MemoryDumpLevelOfDetail StringToMemoryDumpLevelOfDetail( ...@@ -60,8 +58,6 @@ MemoryDumpLevelOfDetail StringToMemoryDumpLevelOfDetail(
return MemoryDumpLevelOfDetail::BACKGROUND; return MemoryDumpLevelOfDetail::BACKGROUND;
if (str == "light") if (str == "light")
return MemoryDumpLevelOfDetail::LIGHT; return MemoryDumpLevelOfDetail::LIGHT;
if (str == "vm_regions_only")
return MemoryDumpLevelOfDetail::VM_REGIONS_ONLY_FOR_HEAP_PROFILER;
if (str == "detailed") if (str == "detailed")
return MemoryDumpLevelOfDetail::DETAILED; return MemoryDumpLevelOfDetail::DETAILED;
NOTREACHED(); NOTREACHED();
......
...@@ -53,9 +53,6 @@ enum class MemoryDumpLevelOfDetail : uint32_t { ...@@ -53,9 +53,6 @@ enum class MemoryDumpLevelOfDetail : uint32_t {
// Few entries, typically a fixed number, per dump. // Few entries, typically a fixed number, per dump.
LIGHT, LIGHT,
// Retrieve only memory maps. Used only for the heap profiler.
VM_REGIONS_ONLY_FOR_HEAP_PROFILER,
// Unrestricted amount of entries per dump. // Unrestricted amount of entries per dump.
DETAILED, DETAILED,
......
...@@ -50,11 +50,6 @@ void MemoryDumpScheduler::StartInternal(MemoryDumpScheduler::Config config) { ...@@ -50,11 +50,6 @@ void MemoryDumpScheduler::StartInternal(MemoryDumpScheduler::Config config) {
for (const Config::Trigger& trigger : config.triggers) { for (const Config::Trigger& trigger : config.triggers) {
DCHECK_GT(trigger.period_ms, 0u); DCHECK_GT(trigger.period_ms, 0u);
switch (trigger.level_of_detail) { switch (trigger.level_of_detail) {
case MemoryDumpLevelOfDetail::VM_REGIONS_ONLY_FOR_HEAP_PROFILER:
// There is no use case to request a periodic dump which contains
// details that are useful only for the heap-profiler.
NOTREACHED();
return;
case MemoryDumpLevelOfDetail::BACKGROUND: case MemoryDumpLevelOfDetail::BACKGROUND:
break; break;
case MemoryDumpLevelOfDetail::LIGHT: case MemoryDumpLevelOfDetail::LIGHT:
......
...@@ -168,7 +168,7 @@ class MockClientProcess : public mojom::ClientProcess { ...@@ -168,7 +168,7 @@ class MockClientProcess : public mojom::ClientProcess {
})); }));
ON_CALL(*this, RequestOSMemoryDump(_, _, _)) ON_CALL(*this, RequestOSMemoryDump(_, _, _))
.WillByDefault(Invoke([](bool want_mmaps, .WillByDefault(Invoke([](mojom::MemoryMapOption,
const std::vector<base::ProcessId> pids, const std::vector<base::ProcessId> pids,
const RequestOSMemoryDumpCallback& callback) { const RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
...@@ -183,7 +183,7 @@ class MockClientProcess : public mojom::ClientProcess { ...@@ -183,7 +183,7 @@ class MockClientProcess : public mojom::ClientProcess {
const RequestChromeMemoryDumpCallback& callback)); const RequestChromeMemoryDumpCallback& callback));
MOCK_METHOD3(RequestOSMemoryDump, MOCK_METHOD3(RequestOSMemoryDump,
void(bool want_mmaps, void(mojom::MemoryMapOption option,
const std::vector<base::ProcessId>& args, const std::vector<base::ProcessId>& args,
const RequestOSMemoryDumpCallback& callback)); const RequestOSMemoryDumpCallback& callback));
...@@ -324,7 +324,7 @@ TEST_F(CoordinatorImplTest, MissingOsDump) { ...@@ -324,7 +324,7 @@ TEST_F(CoordinatorImplTest, MissingOsDump) {
EXPECT_CALL(client_process, RequestOSMemoryDump(_, _, _)) EXPECT_CALL(client_process, RequestOSMemoryDump(_, _, _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
callback.Run(true, std::move(results)); callback.Run(true, std::move(results));
...@@ -391,7 +391,7 @@ TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) { ...@@ -391,7 +391,7 @@ TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) {
RequestOSMemoryDump( RequestOSMemoryDump(
_, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _)) _, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kBrowserPid] = FillRawOSDump(kBrowserPid); results[kBrowserPid] = FillRawOSDump(kBrowserPid);
...@@ -402,7 +402,7 @@ TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) { ...@@ -402,7 +402,7 @@ TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) {
#else #else
EXPECT_CALL(browser_client, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(browser_client, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kBrowserPid); results[0] = FillRawOSDump(kBrowserPid);
...@@ -410,7 +410,7 @@ TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) { ...@@ -410,7 +410,7 @@ TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) {
})); }));
EXPECT_CALL(renderer_client, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(renderer_client, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kRendererPid); results[0] = FillRawOSDump(kRendererPid);
...@@ -570,7 +570,7 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) { ...@@ -570,7 +570,7 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
EXPECT_CALL(browser_client, EXPECT_CALL(browser_client,
RequestOSMemoryDump(_, AllOf(Contains(1), Contains(2)), _)) RequestOSMemoryDump(_, AllOf(Contains(1), Contains(2)), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[1] = mojom::RawOSMemDump::New(); results[1] = mojom::RawOSMemDump::New();
...@@ -587,7 +587,7 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) { ...@@ -587,7 +587,7 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
#else #else
EXPECT_CALL(browser_client, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(browser_client, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = mojom::RawOSMemDump::New(); results[0] = mojom::RawOSMemDump::New();
...@@ -598,7 +598,7 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) { ...@@ -598,7 +598,7 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
})); }));
EXPECT_CALL(renderer_client, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(renderer_client, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = mojom::RawOSMemDump::New(); results[0] = mojom::RawOSMemDump::New();
...@@ -652,12 +652,11 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) { ...@@ -652,12 +652,11 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) {
// On Linux, all memory dumps come from the browser client. On all other // On Linux, all memory dumps come from the browser client. On all other
// platforms, they are expected to come from each individual client. // platforms, they are expected to come from each individual client.
#if defined(OS_LINUX) #if defined(OS_LINUX)
EXPECT_CALL( EXPECT_CALL(browser_client,
browser_client, RequestOSMemoryDump(
RequestOSMemoryDump( _, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
true, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kBrowserPid] = FillRawOSDump(kBrowserPid); results[kBrowserPid] = FillRawOSDump(kBrowserPid);
...@@ -668,7 +667,7 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) { ...@@ -668,7 +667,7 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) {
#else #else
EXPECT_CALL(browser_client, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(browser_client, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kBrowserPid); results[0] = FillRawOSDump(kBrowserPid);
...@@ -676,7 +675,7 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) { ...@@ -676,7 +675,7 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) {
})); }));
EXPECT_CALL(renderer_client, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(renderer_client, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kRendererPid); results[0] = FillRawOSDump(kRendererPid);
...@@ -819,21 +818,21 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) { ...@@ -819,21 +818,21 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) {
#if defined(OS_LINUX) #if defined(OS_LINUX)
EXPECT_CALL(client_process_1, RequestOSMemoryDump(_, _, _)) EXPECT_CALL(client_process_1, RequestOSMemoryDump(_, _, _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kBrowserPid] = FillRawOSDump(kBrowserPid); results[kBrowserPid] = FillRawOSDump(kBrowserPid);
callback.Run(true, std::move(results)); callback.Run(true, std::move(results));
})) }))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kRendererPid] = FillRawOSDump(kRendererPid); results[kRendererPid] = FillRawOSDump(kRendererPid);
callback.Run(true, std::move(results)); callback.Run(true, std::move(results));
})) }))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kGpuPid] = FillRawOSDump(kGpuPid); results[kGpuPid] = FillRawOSDump(kGpuPid);
...@@ -842,7 +841,7 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) { ...@@ -842,7 +841,7 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) {
#else #else
EXPECT_CALL(client_process_1, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(client_process_1, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kBrowserPid); results[0] = FillRawOSDump(kBrowserPid);
...@@ -850,7 +849,7 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) { ...@@ -850,7 +849,7 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) {
})); }));
EXPECT_CALL(client_process_2, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(client_process_2, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kRendererPid); results[0] = FillRawOSDump(kRendererPid);
...@@ -858,7 +857,7 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) { ...@@ -858,7 +857,7 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) {
})); }));
EXPECT_CALL(client_process_3, RequestOSMemoryDump(_, Contains(0), _)) EXPECT_CALL(client_process_3, RequestOSMemoryDump(_, Contains(0), _))
.WillOnce(Invoke( .WillOnce(Invoke(
[](bool want_mmaps, const std::vector<base::ProcessId>& pids, [](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
const MockClientProcess::RequestOSMemoryDumpCallback& callback) { const MockClientProcess::RequestOSMemoryDumpCallback& callback) {
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results; std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kGpuPid); results[0] = FillRawOSDump(kGpuPid);
......
...@@ -74,18 +74,11 @@ struct QueuedRequest { ...@@ -74,18 +74,11 @@ struct QueuedRequest {
base::trace_event::MemoryDumpRequestArgs GetRequestArgs(); base::trace_event::MemoryDumpRequestArgs GetRequestArgs();
bool wants_mmaps() const { mojom::MemoryMapOption memory_map_option() const {
return args.level_of_detail == base::trace_event::MemoryDumpLevelOfDetail:: return args.level_of_detail ==
VM_REGIONS_ONLY_FOR_HEAP_PROFILER || base::trace_event::MemoryDumpLevelOfDetail::DETAILED
args.level_of_detail == ? mojom::MemoryMapOption::FULL
base::trace_event::MemoryDumpLevelOfDetail::DETAILED; : mojom::MemoryMapOption::NONE;
}
// We always want to return chrome dumps, with exception of the special
// case below for the heap profiler, which cares only about mmaps.
bool wants_chrome_dumps() const {
return args.level_of_detail != base::trace_event::MemoryDumpLevelOfDetail::
VM_REGIONS_ONLY_FOR_HEAP_PROFILER;
} }
bool should_return_summaries() const { bool should_return_summaries() const {
......
...@@ -187,10 +187,6 @@ void QueuedRequestDispatcher::SetUpAndDispatch( ...@@ -187,10 +187,6 @@ void QueuedRequestDispatcher::SetUpAndDispatch(
DCHECK(!request->dump_in_progress); DCHECK(!request->dump_in_progress);
request->dump_in_progress = true; request->dump_in_progress = true;
// A request must be either !VM_REGIONS_ONLY or, in the special case of the
// heap profiler, must be of DETAILED type.
DCHECK(request->wants_chrome_dumps() || request->wants_mmaps());
request->start_time = base::Time::Now(); request->start_time = base::Time::Now();
TRACE_EVENT_NESTABLE_ASYNC_BEGIN2( TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
...@@ -228,17 +224,16 @@ void QueuedRequestDispatcher::SetUpAndDispatch( ...@@ -228,17 +224,16 @@ void QueuedRequestDispatcher::SetUpAndDispatch(
// OSMemoryDump until the Chrome memory dump is finished. See // OSMemoryDump until the Chrome memory dump is finished. See
// https://bugs.chromium.org/p/chromium/issues/detail?id=812346#c16 for more // https://bugs.chromium.org/p/chromium/issues/detail?id=812346#c16 for more
// details. // details.
if (request->wants_chrome_dumps()) { request->pending_responses.insert({client, ResponseType::kChromeDump});
request->pending_responses.insert({client, ResponseType::kChromeDump}); client->RequestChromeMemoryDump(request->GetRequestArgs(),
client->RequestChromeMemoryDump(request->GetRequestArgs(), base::Bind(chrome_callback, client));
base::Bind(chrome_callback, client));
}
// On most platforms each process can dump data about their own process // On most platforms each process can dump data about their own process
// so ask each process to do so Linux is special see below. // so ask each process to do so Linux is special see below.
#if !defined(OS_LINUX) #if !defined(OS_LINUX)
request->pending_responses.insert({client, ResponseType::kOSDump}); request->pending_responses.insert({client, ResponseType::kOSDump});
client->RequestOSMemoryDump(request->wants_mmaps(), {base::kNullProcessId}, client->RequestOSMemoryDump(request->memory_map_option(),
{base::kNullProcessId},
base::Bind(os_callback, client)); base::Bind(os_callback, client));
#endif // !defined(OS_LINUX) #endif // !defined(OS_LINUX)
...@@ -269,7 +264,8 @@ void QueuedRequestDispatcher::SetUpAndDispatch( ...@@ -269,7 +264,8 @@ void QueuedRequestDispatcher::SetUpAndDispatch(
if (browser_client && pids.size() > 0) { if (browser_client && pids.size() > 0) {
request->pending_responses.insert({browser_client, ResponseType::kOSDump}); request->pending_responses.insert({browser_client, ResponseType::kOSDump});
const auto callback = base::Bind(os_callback, browser_client); const auto callback = base::Bind(os_callback, browser_client);
browser_client->RequestOSMemoryDump(request->wants_mmaps(), pids, callback); browser_client->RequestOSMemoryDump(request->memory_map_option(), pids,
callback);
} }
#endif // defined(OS_LINUX) #endif // defined(OS_LINUX)
...@@ -309,8 +305,8 @@ void QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest( ...@@ -309,8 +305,8 @@ void QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest(
request->pending_responses.insert(browser_client); request->pending_responses.insert(browser_client);
request->responses[browser_client].process_id = browser_client_pid; request->responses[browser_client].process_id = browser_client_pid;
const auto callback = base::Bind(os_callback, browser_client); const auto callback = base::Bind(os_callback, browser_client);
browser_client->RequestOSMemoryDump(true /* wants_mmaps */, desired_pids, browser_client->RequestOSMemoryDump(mojom::MemoryMapOption::MODULES,
callback); desired_pids, callback);
#else #else
for (const auto& client_info : clients) { for (const auto& client_info : clients) {
if (std::find(desired_pids.begin(), desired_pids.end(), client_info.pid) != if (std::find(desired_pids.begin(), desired_pids.end(), client_info.pid) !=
...@@ -318,7 +314,7 @@ void QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest( ...@@ -318,7 +314,7 @@ void QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest(
mojom::ClientProcess* client = client_info.client; mojom::ClientProcess* client = client_info.client;
request->pending_responses.insert(client); request->pending_responses.insert(client);
request->responses[client].process_id = client_info.pid; request->responses[client].process_id = client_info.pid;
client->RequestOSMemoryDump(true /* wants_mmaps */, client->RequestOSMemoryDump(mojom::MemoryMapOption::MODULES,
{base::kNullProcessId}, {base::kNullProcessId},
base::Bind(os_callback, client)); base::Bind(os_callback, client));
} }
...@@ -500,10 +496,10 @@ void QueuedRequestDispatcher::Finalize(QueuedRequest* request, ...@@ -500,10 +496,10 @@ void QueuedRequestDispatcher::Finalize(QueuedRequest* request,
} }
// Ignore incomplete results (can happen if the client crashes/disconnects). // Ignore incomplete results (can happen if the client crashes/disconnects).
const bool valid = raw_os_dump && const bool valid =
(!request->wants_chrome_dumps() || raw_chrome_dump) && raw_os_dump && raw_chrome_dump &&
(!request->wants_mmaps() || (request->memory_map_option() == mojom::MemoryMapOption::NONE ||
(raw_os_dump && !raw_os_dump->memory_maps.empty())); (raw_os_dump && !raw_os_dump->memory_maps.empty()));
if (!valid) if (!valid)
continue; continue;
......
...@@ -136,11 +136,11 @@ void ClientProcessImpl::EnableHeapProfiling( ...@@ -136,11 +136,11 @@ void ClientProcessImpl::EnableHeapProfiling(
} }
void ClientProcessImpl::RequestOSMemoryDump( void ClientProcessImpl::RequestOSMemoryDump(
bool want_mmaps, mojom::MemoryMapOption mmap_option,
const std::vector<base::ProcessId>& pids, const std::vector<base::ProcessId>& pids,
const RequestOSMemoryDumpCallback& callback) { const RequestOSMemoryDumpCallback& callback) {
OSMemoryDumpArgs args; OSMemoryDumpArgs args;
args.want_mmaps = want_mmaps; args.mmap_option = mmap_option;
args.pids = pids; args.pids = pids;
args.callback = callback; args.callback = callback;
...@@ -166,8 +166,10 @@ void ClientProcessImpl::PerformOSMemoryDump(OSMemoryDumpArgs args) { ...@@ -166,8 +166,10 @@ void ClientProcessImpl::PerformOSMemoryDump(OSMemoryDumpArgs args) {
mojom::RawOSMemDumpPtr result = mojom::RawOSMemDump::New(); mojom::RawOSMemDumpPtr result = mojom::RawOSMemDump::New();
result->platform_private_footprint = mojom::PlatformPrivateFootprint::New(); result->platform_private_footprint = mojom::PlatformPrivateFootprint::New();
bool success = OSMetrics::FillOSMemoryDump(pid, result.get()); bool success = OSMetrics::FillOSMemoryDump(pid, result.get());
if (args.want_mmaps) if (args.mmap_option != mojom::MemoryMapOption::NONE) {
success = success && OSMetrics::FillProcessMemoryMaps(pid, result.get()); success = success && OSMetrics::FillProcessMemoryMaps(
pid, args.mmap_option, result.get());
}
if (success) if (success)
results[pid] = std::move(result); results[pid] = std::move(result);
global_success = global_success && success; global_success = global_success && success;
......
...@@ -79,7 +79,7 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ClientProcessImpl ...@@ -79,7 +79,7 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ClientProcessImpl
// mojom::ClientProcess implementation. The Coordinator calls this. // mojom::ClientProcess implementation. The Coordinator calls this.
void RequestOSMemoryDump( void RequestOSMemoryDump(
bool wants_mmaps, mojom::MemoryMapOption mmap_option,
const std::vector<base::ProcessId>& ids, const std::vector<base::ProcessId>& ids,
const RequestOSMemoryDumpCallback& callback) override; const RequestOSMemoryDumpCallback& callback) override;
...@@ -87,7 +87,7 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ClientProcessImpl ...@@ -87,7 +87,7 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ClientProcessImpl
OSMemoryDumpArgs(); OSMemoryDumpArgs();
OSMemoryDumpArgs(const OSMemoryDumpArgs&); OSMemoryDumpArgs(const OSMemoryDumpArgs&);
~OSMemoryDumpArgs(); ~OSMemoryDumpArgs();
bool want_mmaps = false; mojom::MemoryMapOption mmap_option;
std::vector<base::ProcessId> pids; std::vector<base::ProcessId> pids;
RequestOSMemoryDumpCallback callback; RequestOSMemoryDumpCallback callback;
}; };
......
...@@ -4,16 +4,32 @@ ...@@ -4,16 +4,32 @@
#include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h" #include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
#include "build/build_config.h"
namespace memory_instrumentation { namespace memory_instrumentation {
// static // static
bool OSMetrics::FillProcessMemoryMaps(base::ProcessId pid, bool OSMetrics::FillProcessMemoryMaps(base::ProcessId pid,
mojom::MemoryMapOption mmap_option,
mojom::RawOSMemDump* dump) { mojom::RawOSMemDump* dump) {
auto maps = GetProcessMemoryMaps(pid); DCHECK_NE(mmap_option, mojom::MemoryMapOption::NONE);
if (maps.empty())
std::vector<mojom::VmRegionPtr> results;
#if defined(OS_MACOSX)
// TODO: Consider implementing this optimization for other platforms as well,
// if performance becomes an issue. https://crbug.com/826913.
if (mmap_option == mojom::MemoryMapOption::MODULES)
results = GetProcessModules(pid);
#endif
if (results.empty())
results = GetProcessMemoryMaps(pid);
if (results.empty())
return false; return false;
dump->memory_maps = std::move(maps); dump->memory_maps = std::move(results);
return true; return true;
} }
......
...@@ -20,15 +20,22 @@ namespace memory_instrumentation { ...@@ -20,15 +20,22 @@ namespace memory_instrumentation {
class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT OSMetrics { class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT OSMetrics {
public: public:
static bool FillOSMemoryDump(base::ProcessId pid, mojom::RawOSMemDump* dump); static bool FillOSMemoryDump(base::ProcessId pid, mojom::RawOSMemDump* dump);
static bool FillProcessMemoryMaps(base::ProcessId, mojom::RawOSMemDump*); static bool FillProcessMemoryMaps(base::ProcessId,
mojom::MemoryMapOption,
mojom::RawOSMemDump*);
private: private:
FRIEND_TEST_ALL_PREFIXES(OSMetricsTest, ParseProcSmaps); FRIEND_TEST_ALL_PREFIXES(OSMetricsTest, ParseProcSmaps);
FRIEND_TEST_ALL_PREFIXES(OSMetricsTest, TestWinModuleReading); FRIEND_TEST_ALL_PREFIXES(OSMetricsTest, TestWinModuleReading);
FRIEND_TEST_ALL_PREFIXES(OSMetricsTest, TestMachOReading); FRIEND_TEST_ALL_PREFIXES(OSMetricsTest, TestMachOReading);
FRIEND_TEST_ALL_PREFIXES(profiling::ProfilingJsonExporterTest, MemoryMaps); FRIEND_TEST_ALL_PREFIXES(profiling::ProfilingJsonExporterTest, MemoryMaps);
static std::vector<mojom::VmRegionPtr> GetProcessMemoryMaps(base::ProcessId); static std::vector<mojom::VmRegionPtr> GetProcessMemoryMaps(base::ProcessId);
#if defined(OS_MACOSX)
static std::vector<mojom::VmRegionPtr> GetProcessModules(base::ProcessId);
#endif
#if defined(OS_LINUX) || defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_ANDROID)
static void SetProcSmapsForTesting(FILE*); static void SetProcSmapsForTesting(FILE*);
#endif // defined(OS_LINUX) #endif // defined(OS_LINUX)
......
...@@ -255,4 +255,19 @@ std::vector<mojom::VmRegionPtr> OSMetrics::GetProcessMemoryMaps( ...@@ -255,4 +255,19 @@ std::vector<mojom::VmRegionPtr> OSMetrics::GetProcessMemoryMaps(
return maps; return maps;
} }
std::vector<mojom::VmRegionPtr> OSMetrics::GetProcessModules(
base::ProcessId pid) {
std::vector<mojom::VmRegionPtr> maps;
std::vector<VMRegion> dyld_regions;
if (!GetDyldRegions(&dyld_regions))
return maps;
for (VMRegion& region : dyld_regions) {
maps.push_back(VMRegion::New(region));
}
return maps;
}
} // namespace memory_instrumentation } // namespace memory_instrumentation
...@@ -251,8 +251,9 @@ TEST(OSMetricsTest, TestWinModuleReading) { ...@@ -251,8 +251,9 @@ TEST(OSMetricsTest, TestWinModuleReading) {
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
TEST(OSMetricsTest, TestMachOReading) { namespace {
auto maps = OSMetrics::GetProcessMemoryMaps(base::kNullProcessId);
void CheckMachORegions(const std::vector<mojom::VmRegionPtr>& maps) {
uint32_t size = 100; uint32_t size = 100;
char full_path[size]; char full_path[size];
int result = _NSGetExecutablePath(full_path, &size); int result = _NSGetExecutablePath(full_path, &size);
...@@ -280,6 +281,15 @@ TEST(OSMetricsTest, TestMachOReading) { ...@@ -280,6 +281,15 @@ TEST(OSMetricsTest, TestMachOReading) {
EXPECT_TRUE(found_components_unittests); EXPECT_TRUE(found_components_unittests);
EXPECT_TRUE(found_appkit); EXPECT_TRUE(found_appkit);
} }
} // namespace
TEST(OSMetricsTest, TestMachOReading) {
auto maps = OSMetrics::GetProcessMemoryMaps(base::kNullProcessId);
CheckMachORegions(maps);
maps = OSMetrics::GetProcessModules(base::kNullProcessId);
CheckMachORegions(maps);
}
#endif // defined(OS_MACOSX) #endif // defined(OS_MACOSX)
} // namespace memory_instrumentation } // namespace memory_instrumentation
...@@ -38,6 +38,19 @@ enum HeapProfilingMode { ...@@ -38,6 +38,19 @@ enum HeapProfilingMode {
NATIVE_STACK NATIVE_STACK
}; };
enum MemoryMapOption {
// Do not fetch any information about mapped regions in the virtual address
// space.
NONE,
// Only fetch information on code modules, e.g. Chrome Binary, system
// libraries.
MODULES,
// Fetch information for every single mapped region.
FULL
};
// These structs are internal only (only for the communication between // These structs are internal only (only for the communication between
// the service and the ClientProcess library). // the service and the ClientProcess library).
// See corresponding types in //base/trace_event for comments. // See corresponding types in //base/trace_event for comments.
...@@ -213,7 +226,7 @@ interface ClientProcess { ...@@ -213,7 +226,7 @@ interface ClientProcess {
// On Linux we call this once on the browser process ClientProcess passing // On Linux we call this once on the browser process ClientProcess passing
// the pids for all processes. // the pids for all processes.
// See crbug.com/461788 // See crbug.com/461788
RequestOSMemoryDump(bool want_mmaps, array<mojo_base.mojom.ProcessId> pids) => RequestOSMemoryDump(MemoryMapOption option, array<mojo_base.mojom.ProcessId> pids) =>
(bool success, map<mojo_base.mojom.ProcessId, RawOSMemDump> dumps); (bool success, map<mojo_base.mojom.ProcessId, RawOSMemDump> dumps);
}; };
......
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