0

[memory-infra] Don't report PSS or mapping count for footprint requests

The CLs https://crrev.com/c/6148597 and https://crrev.com/c/6347824
added additional metrics to the RawOSMemDump and populated them on the
Linux platform. These metrics are populated for all requests to
OSMetrics::FillOSMemoryDump even if they are totally ignored by the
caller. This code path is used not only for metrics collection, but also
the generation of the private memory footprint for the TaskManagerImpl
which does not require such information.

The TaskManagerImpl polls for RequestPrivateMemoryFootprint which issues
a memory_footprint_only request to MemoryInstrumentation. We now take an
additional vector of flags which determine which parts of the
RawOSMemDump are populated. When memory_footprint_only is true this
vector is empty and when it's true we add all of the enum options which
populates the count_mappings and pss fields.

In the future this set of flags may be extended to support more options
such as native_library_pages_bitmap. Then these can be used to
standardize the request for memory dumps (see
https://crbug.com/417455299).

Bug: 417080394
Change-Id: Iab9a4705b42dd2d571e1ff6370a73235d5e0f843
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6535692
Reviewed-by: Joe Mason <joenotcharles@google.com>
Reviewed-by: Francois Pierre Doray <fdoray@chromium.org>
Commit-Queue: Joe Mason <joenotcharles@google.com>
Cr-Commit-Position: refs/heads/main@{#1460382}
This commit is contained in:
Chris Staite
2025-05-14 14:48:27 -07:00
committed by Chromium LUCI CQ
parent a3a4cac570
commit b26436faa4
14 changed files with 216 additions and 105 deletions

@ -5291,11 +5291,11 @@ uint64_t RenderProcessHostImpl::GetPrivateMemoryFootprint() {
memory_instrumentation::mojom::PlatformPrivateFootprint::New();
#if BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_IOS_TVOS)
bool success = memory_instrumentation::OSMetrics::FillOSMemoryDump(
GetProcess().Handle(), ChildProcessTaskPortProvider::GetInstance(),
GetProcess().Handle(), {}, ChildProcessTaskPortProvider::GetInstance(),
dump.get());
#else
bool success = memory_instrumentation::OSMetrics::FillOSMemoryDump(
GetProcess().Handle(), dump.get());
GetProcess().Handle(), {}, dump.get());
#endif
// Failed to get private memory for the process, e.g. the process has died.

@ -178,8 +178,9 @@ class MockClientProcess : public mojom::ClientProcess {
std::move(callback).Run(true, args.dump_guid, std::move(pmd));
}));
ON_CALL(*this, RequestOSMemoryDumpMock(_, _, _))
ON_CALL(*this, RequestOSMemoryDumpMock(_, _, _, _))
.WillByDefault(Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId> pids,
RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
@ -194,8 +195,9 @@ class MockClientProcess : public mojom::ClientProcess {
MOCK_METHOD2(RequestChromeMemoryDumpMock,
void(const MemoryDumpRequestArgs& args,
RequestChromeMemoryDumpCallback& callback));
MOCK_METHOD3(RequestOSMemoryDumpMock,
MOCK_METHOD4(RequestOSMemoryDumpMock,
void(mojom::MemoryMapOption option,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& args,
RequestOSMemoryDumpCallback& callback));
@ -205,9 +207,10 @@ class MockClientProcess : public mojom::ClientProcess {
RequestChromeMemoryDumpMock(args, callback);
}
void RequestOSMemoryDump(mojom::MemoryMapOption option,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& args,
RequestOSMemoryDumpCallback callback) override {
RequestOSMemoryDumpMock(option, args, callback);
RequestOSMemoryDumpMock(option, flags, args, callback);
}
private:
@ -389,10 +392,12 @@ TEST_F(CoordinatorImplTest, MissingOsDump) {
NiceMock<MockClientProcess> client_process(this, 1,
mojom::ProcessType::BROWSER);
EXPECT_CALL(client_process, RequestOSMemoryDumpMock(_, _, _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(client_process, RequestOSMemoryDumpMock(_, _, _, _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
std::move(callback).Run(true, std::move(results));
}));
@ -455,31 +460,38 @@ TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) {
// On Linux, all memory dumps come from the browser client. On all other
// platforms, they are expected to come from each individual client.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_CALL(browser_client,
RequestOSMemoryDumpMock(
_, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(
browser_client,
RequestOSMemoryDumpMock(
_, _, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kBrowserPid] = FillRawOSDump(kBrowserPid);
results[kRendererPid] = FillRawOSDump(kRendererPid);
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _)).Times(0);
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _, _)).Times(0);
#else
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kBrowserPid);
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kRendererPid);
std::move(callback).Run(true, std::move(results));
@ -633,10 +645,12 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
}));
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_CALL(browser_client,
RequestOSMemoryDumpMock(_, AllOf(Contains(1), Contains(2)), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
RequestOSMemoryDumpMock(_, _, AllOf(Contains(1), Contains(2)), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[1] = mojom::RawOSMemDump::New();
results[1]->resident_set_kb = 1;
@ -648,12 +662,14 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
results[2]->resident_set_kb = 2;
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _)).Times(0);
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _, _)).Times(0);
#else
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = mojom::RawOSMemDump::New();
results[0]->platform_private_footprint =
@ -661,10 +677,12 @@ TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
results[0]->resident_set_kb = 1;
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = mojom::RawOSMemDump::New();
results[0]->platform_private_footprint =
@ -717,31 +735,38 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) {
// On Linux, all memory dumps come from the browser client. On all other
// platforms, they are expected to come from each individual client.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_CALL(browser_client,
RequestOSMemoryDumpMock(
_, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(
browser_client,
RequestOSMemoryDumpMock(
_, _, AllOf(Contains(kBrowserPid), Contains(kRendererPid)), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kBrowserPid] = FillRawOSDump(kBrowserPid);
results[kRendererPid] = FillRawOSDump(kRendererPid);
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _)).Times(0);
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, _, _)).Times(0);
#else
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kBrowserPid);
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(renderer_client, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kRendererPid);
std::move(callback).Run(true, std::move(results));
@ -881,49 +906,61 @@ TEST_F(CoordinatorImplTest, DumpByPidSuccess) {
// On Linux, all memory dumps come from the browser client. On all other
// platforms, they are expected to come from each individual client.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_CALL(client_process_1, RequestOSMemoryDumpMock(_, _, _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(client_process_1, RequestOSMemoryDumpMock(_, _, _, _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kBrowserPid] = FillRawOSDump(kBrowserPid);
std::move(callback).Run(true, std::move(results));
}))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kRendererPid] = FillRawOSDump(kRendererPid);
std::move(callback).Run(true, std::move(results));
}))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[kGpuPid] = FillRawOSDump(kGpuPid);
std::move(callback).Run(true, std::move(results));
}));
#else
EXPECT_CALL(client_process_1, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(client_process_1, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kBrowserPid);
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(client_process_2, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(client_process_2, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kRendererPid);
std::move(callback).Run(true, std::move(results));
}));
EXPECT_CALL(client_process_3, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(client_process_3, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = FillRawOSDump(kGpuPid);
std::move(callback).Run(true, std::move(results));
@ -1009,10 +1046,12 @@ TEST_F(CoordinatorImplTest, GlobalDumpWithSubTrees) {
std::move(callback).Run(true, args.dump_guid, std::move(pmd));
}));
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(1), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, _, Contains(1), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[1] = mojom::RawOSMemDump::New();
results[1]->resident_set_kb = 1;
@ -1021,10 +1060,12 @@ TEST_F(CoordinatorImplTest, GlobalDumpWithSubTrees) {
std::move(callback).Run(true, std::move(results));
}));
#else
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
.WillOnce(Invoke(
[](mojom::MemoryMapOption, const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, _, Contains(0), _))
.WillOnce(
Invoke([](mojom::MemoryMapOption,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
MockClientProcess::RequestOSMemoryDumpCallback& callback) {
base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
results[0] = mojom::RawOSMemDump::New();
results[0]->platform_private_footprint =

@ -4,6 +4,9 @@
#include "services/resource_coordinator/memory_instrumentation/queued_request.h"
#include "base/containers/to_vector.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
namespace memory_instrumentation {
QueuedRequest::Args::Args(MemoryDumpType dump_type,
@ -51,6 +54,13 @@ base::trace_event::MemoryDumpRequestArgs QueuedRequest::GetRequestArgs() {
return request_args;
}
std::vector<mojom::MemDumpFlags> QueuedRequest::memory_dump_flags() const {
if (!args.memory_footprint_only) {
return base::ToVector(OSMetrics::MemDumpFlagSet::All());
}
return {};
}
QueuedVmRegionRequest::Response::Response() = default;
QueuedVmRegionRequest::Response::~Response() = default;

@ -93,6 +93,8 @@ struct QueuedRequest {
: mojom::MemoryMapOption::NONE;
}
std::vector<mojom::MemDumpFlags> memory_dump_flags() const;
bool should_return_summaries() const {
return args.dump_type == base::trace_event::MemoryDumpType::kSummaryOnly;
}

@ -224,9 +224,9 @@ void QueuedRequestDispatcher::SetUpAndDispatch(
// so ask each process to do so Linux is special see below.
#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
request->pending_responses.insert({client_info.pid, ResponseType::kOSDump});
client->RequestOSMemoryDump(request->memory_map_option(),
{base::kNullProcessId},
base::BindOnce(os_callback, client_info.pid));
client->RequestOSMemoryDump(
request->memory_map_option(), request->memory_dump_flags(),
{base::kNullProcessId}, base::BindOnce(os_callback, client_info.pid));
#endif // !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS)
// If we are in the single pid case, then we've already found the only
@ -259,7 +259,8 @@ void QueuedRequestDispatcher::SetUpAndDispatch(
request->pending_responses.insert(
{browser_client_pid, ResponseType::kOSDump});
auto callback = base::BindOnce(os_callback, browser_client_pid);
browser_client->RequestOSMemoryDump(request->memory_map_option(), pids,
browser_client->RequestOSMemoryDump(request->memory_map_option(),
request->memory_dump_flags(), pids,
std::move(callback));
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
@ -302,7 +303,7 @@ void QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest(
request->pending_responses.insert(browser_client_pid);
request->responses[browser_client_pid].process_id = browser_client_pid;
auto callback = base::BindOnce(os_callback, browser_client_pid);
browser_client->RequestOSMemoryDump(mojom::MemoryMapOption::MODULES,
browser_client->RequestOSMemoryDump(mojom::MemoryMapOption::MODULES, {},
desired_pids, std::move(callback));
#else
for (const auto& client_info : clients) {
@ -312,7 +313,7 @@ void QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest(
request->responses[client_info.pid].process_id = client_info.pid;
request->responses[client_info.pid].service_name =
client_info.service_name;
client->RequestOSMemoryDump(mojom::MemoryMapOption::MODULES,
client->RequestOSMemoryDump(mojom::MemoryMapOption::MODULES, {},
{base::kNullProcessId},
base::BindOnce(os_callback, client_info.pid));
}

@ -20,6 +20,16 @@
namespace memory_instrumentation {
struct ClientProcessImpl::OSMemoryDumpArgs {
OSMemoryDumpArgs();
OSMemoryDumpArgs(OSMemoryDumpArgs&&);
~OSMemoryDumpArgs();
mojom::MemoryMapOption mmap_option;
OSMetrics::MemDumpFlagSet flags;
std::vector<base::ProcessId> pids;
RequestOSMemoryDumpCallback callback;
};
// static
void ClientProcessImpl::CreateInstance(
mojo::PendingReceiver<mojom::ClientProcess> receiver,
@ -144,12 +154,16 @@ void ClientProcessImpl::RequestGlobalMemoryDump_NoCallback(
void ClientProcessImpl::RequestOSMemoryDump(
mojom::MemoryMapOption mmap_option,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& pids,
RequestOSMemoryDumpCallback callback) {
OSMemoryDumpArgs args;
args.mmap_option = mmap_option;
args.pids = pids;
args.callback = std::move(callback);
for (const auto& flag : flags) {
args.flags.Put(flag);
}
#if BUILDFLAG(IS_MAC)
// If the most recent chrome memory dump hasn't finished, wait for that to
@ -173,7 +187,8 @@ void ClientProcessImpl::PerformOSMemoryDump(OSMemoryDumpArgs args) {
auto handle = base::Process::Open(pid).Handle();
mojom::RawOSMemDumpPtr result = mojom::RawOSMemDump::New();
result->platform_private_footprint = mojom::PlatformPrivateFootprint::New();
bool success = OSMetrics::FillOSMemoryDump(handle, result.get());
bool success =
OSMetrics::FillOSMemoryDump(handle, args.flags, result.get());
if (args.mmap_option != mojom::MemoryMapOption::NONE) {
success = success && OSMetrics::FillProcessMemoryMaps(
handle, args.mmap_option, result.get());

@ -67,17 +67,11 @@ class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION)
// mojom::ClientProcess implementation. The Coordinator calls this.
void RequestOSMemoryDump(mojom::MemoryMapOption mmap_option,
const std::vector<mojom::MemDumpFlags>& flags,
const std::vector<base::ProcessId>& ids,
RequestOSMemoryDumpCallback callback) override;
struct OSMemoryDumpArgs {
OSMemoryDumpArgs();
OSMemoryDumpArgs(OSMemoryDumpArgs&&);
~OSMemoryDumpArgs();
mojom::MemoryMapOption mmap_option;
std::vector<base::ProcessId> pids;
RequestOSMemoryDumpCallback callback;
};
struct OSMemoryDumpArgs;
void PerformOSMemoryDump(OSMemoryDumpArgs args);
// Map containing pending chrome memory callbacks indexed by dump guid.

@ -7,6 +7,7 @@
#include <vector>
#include "base/component_export.h"
#include "base/containers/enum_set.h"
#include "base/gtest_prod_util.h"
#include "base/process/process_handle.h"
#include "base/process/process_metrics.h"
@ -40,14 +41,21 @@ namespace memory_instrumentation {
class COMPONENT_EXPORT(
RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) OSMetrics {
public:
using MemDumpFlagSet =
base::EnumSet<mojom::MemDumpFlags,
mojom::MemDumpFlags::MEM_DUMP_COUNT_MAPPINGS,
mojom::MemDumpFlags::kMaxValue>;
// Fills |dump| with memory information about |handle|. See class comments for
// restrictions on |handle|. |dump.platform_private_footprint| must be
// allocated before calling this function. If |handle| is null, the handle of
// the current process is used
static bool FillOSMemoryDump(base::ProcessHandle handle,
const MemDumpFlagSet& flags,
mojom::RawOSMemDump* dump);
#if BUILDFLAG(IS_APPLE)
static bool FillOSMemoryDump(base::ProcessHandle handle,
const MemDumpFlagSet& flags,
base::PortProvider* port_provider,
mojom::RawOSMemDump* dump);
#endif

@ -19,6 +19,7 @@ namespace memory_instrumentation {
// static
bool OSMetrics::FillOSMemoryDump(base::ProcessHandle handle,
const MemDumpFlagSet& flags,
mojom::RawOSMemDump* dump) {
auto info = GetMemoryInfo(handle);
if (!info.has_value()) {

@ -329,6 +329,7 @@ void OSMetrics::SetProcSmapsForTesting(FILE* f) {
// static
bool OSMetrics::FillOSMemoryDump(base::ProcessHandle handle,
const MemDumpFlagSet& flags,
mojom::RawOSMemDump* dump) {
auto info = GetMemoryInfo(handle);
if (!info.has_value()) {
@ -341,8 +342,12 @@ bool OSMetrics::FillOSMemoryDump(base::ProcessHandle handle,
base::saturated_cast<uint32_t>(info->resident_set_bytes / 1024);
dump->peak_resident_set_kb = GetPeakResidentSetSize(handle);
dump->is_peak_rss_resettable = ResetPeakRSSIfPossible(handle);
dump->mappings_count = CountMappings(handle);
GetSmapsRollup(&dump->pss_kb, &dump->swap_pss_kb);
if (flags.Has(mojom::MemDumpFlags::MEM_DUMP_COUNT_MAPPINGS)) {
dump->mappings_count = CountMappings(handle);
}
if (flags.Has(mojom::MemDumpFlags::MEM_DUMP_PSS)) {
GetSmapsRollup(&dump->pss_kb, &dump->swap_pss_kb);
}
#if BUILDFLAG(IS_ANDROID)
#if BUILDFLAG(SUPPORTS_CODE_ORDERING)

@ -227,16 +227,18 @@ void AddRegionByteStats(VMRegion* dest, const VMRegion& source) {
// static
bool OSMetrics::FillOSMemoryDump(base::ProcessHandle handle,
const MemDumpFlagSet& flags,
mojom::RawOSMemDump* dump) {
auto current_handle = base::GetCurrentProcessHandle();
if (handle != base::kNullProcessId && handle != current_handle) {
return false;
}
return FillOSMemoryDump(current_handle, nullptr, dump);
return FillOSMemoryDump(current_handle, flags, nullptr, dump);
}
// static
bool OSMetrics::FillOSMemoryDump(base::ProcessHandle handle,
const MemDumpFlagSet& flags,
base::PortProvider* port_provider,
mojom::RawOSMemDump* dump) {
auto process_metrics =

@ -164,7 +164,8 @@ TEST(OSMetricsTest, GivesNonZeroResults) {
base::ProcessHandle handle = base::kNullProcessHandle;
mojom::RawOSMemDump dump;
dump.platform_private_footprint = mojom::PlatformPrivateFootprint::New();
EXPECT_TRUE(OSMetrics::FillOSMemoryDump(handle, &dump));
OSMetrics::MemDumpFlagSet flags = OSMetrics::MemDumpFlagSet::All();
EXPECT_TRUE(OSMetrics::FillOSMemoryDump(handle, flags, &dump));
EXPECT_TRUE(dump.platform_private_footprint);
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
BUILDFLAG(IS_FUCHSIA)
@ -286,7 +287,10 @@ TEST(OSMetricsTest, GetMappedAndResidentPages) {
TEST(OSMetricsTest, CountMappings) {
mojom::RawOSMemDump dump;
dump.platform_private_footprint = mojom::PlatformPrivateFootprint::New();
ASSERT_TRUE(OSMetrics::FillOSMemoryDump(base::kNullProcessHandle, &dump));
OSMetrics::MemDumpFlagSet flags = {
mojom::MemDumpFlags::MEM_DUMP_COUNT_MAPPINGS};
ASSERT_TRUE(
OSMetrics::FillOSMemoryDump(base::kNullProcessHandle, flags, &dump));
uint32_t mappings_count = dump.mappings_count;
EXPECT_GT(dump.mappings_count, 0u);
@ -306,12 +310,20 @@ TEST(OSMetricsTest, CountMappings) {
mprotect(reinterpret_cast<void*>(start), page_size, PROT_NONE));
}
ASSERT_TRUE(OSMetrics::FillOSMemoryDump(base::kNullProcessHandle, &dump));
ASSERT_TRUE(
OSMetrics::FillOSMemoryDump(base::kNullProcessHandle, flags, &dump));
EXPECT_GT(dump.mappings_count, mappings_count);
munmap(addr, kPageCount * page_size);
}
TEST(OSMetricsTest, CountMappingsDisabled) {
mojom::RawOSMemDump dump;
dump.platform_private_footprint = mojom::PlatformPrivateFootprint::New();
ASSERT_TRUE(OSMetrics::FillOSMemoryDump(base::kNullProcessHandle, {}, &dump));
EXPECT_EQ(dump.mappings_count, 0u);
}
TEST(OSMetricsTest, Pss) {
// Some older Android devices may not support this, so skip the test in those
// cases.
@ -321,13 +333,22 @@ TEST(OSMetricsTest, Pss) {
mojom::RawOSMemDump dump;
dump.platform_private_footprint = mojom::PlatformPrivateFootprint::New();
ASSERT_TRUE(OSMetrics::FillOSMemoryDump(base::kNullProcessHandle, &dump));
ASSERT_TRUE(OSMetrics::FillOSMemoryDump(
base::kNullProcessHandle, {mojom::MemDumpFlags::MEM_DUMP_PSS}, &dump));
uint32_t pss = dump.pss_kb;
// We don't know the exact value here, but it should be greater than 0.
EXPECT_GT(pss, 0u);
}
TEST(OSMetricsTest, PssDisabled) {
mojom::RawOSMemDump dump;
dump.platform_private_footprint = mojom::PlatformPrivateFootprint::New();
ASSERT_TRUE(OSMetrics::FillOSMemoryDump(base::kNullProcessHandle, {}, &dump));
EXPECT_EQ(dump.pss_kb, 0u);
EXPECT_EQ(dump.swap_pss_kb, 0u);
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) ||
// BUILDFLAG(IS_ANDROID)

@ -41,6 +41,7 @@ std::string MakeDebugID(const GUID& guid, DWORD age) {
// static
bool OSMetrics::FillOSMemoryDump(base::ProcessHandle handle,
const MemDumpFlagSet& flags,
mojom::RawOSMemDump* dump) {
auto info = GetMemoryInfo(handle);
if (!info.has_value()) {

@ -51,6 +51,14 @@ enum MemoryMapOption {
FULL,
};
enum MemDumpFlags {
// On Linux platforms, populate the mappings_count field of RawOSMemDump.
MEM_DUMP_COUNT_MAPPINGS = 0,
// On Linux platforms, populate the pss_kb and swap_pss_kb fields of
// RawOSMemDump.
MEM_DUMP_PSS = 1,
};
// These structs are internal only (only for the communication between
// the service and the ClientProcess library).
// See corresponding types in //base/trace_event for comments.
@ -295,7 +303,9 @@ interface ClientProcess {
// the pids for all processes.
// See crbug.com/461788
RequestOSMemoryDump(
MemoryMapOption option, array<mojo_base.mojom.ProcessId> pids)
MemoryMapOption option,
array<MemDumpFlags> flags,
array<mojo_base.mojom.ProcessId> pids)
=> (bool success, map<mojo_base.mojom.ProcessId, RawOSMemDump> dumps);
};