1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075 |
- // Copyright 2017 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 "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
- #include <memory>
- #include "base/bind.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/test/gmock_callback_support.h"
- #include "base/test/task_environment.h"
- #include "base/test/test_future.h"
- #include "base/test/trace_test_utils.h"
- #include "base/threading/platform_thread.h"
- #include "base/time/time.h"
- #include "base/trace_event/memory_dump_request_args.h"
- #include "build/build_config.h"
- #include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer_proto.h"
- #include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
- #include "services/tracing/public/cpp/perfetto/producer_test_utils.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using base::test::RunOnceClosure;
- using ::testing::_;
- using ::testing::AllOf;
- using ::testing::Contains;
- using ::testing::Eq;
- using ::testing::Field;
- using ::testing::Invoke;
- using ::testing::IsEmpty;
- using ::testing::Ne;
- using ::testing::NiceMock;
- using ::testing::NotNull;
- using ::testing::Pointee;
- using ::testing::Property;
- using ::testing::Return;
- using ::testing::UnorderedElementsAre;
- using GetVmRegionsForHeapProfilerCallback = memory_instrumentation::
- CoordinatorImpl::GetVmRegionsForHeapProfilerCallback;
- using RequestGlobalMemoryDumpAndAppendToTraceCallback = memory_instrumentation::
- CoordinatorImpl::RequestGlobalMemoryDumpAndAppendToTraceCallback;
- using RequestGlobalMemoryDumpCallback =
- memory_instrumentation::CoordinatorImpl::RequestGlobalMemoryDumpCallback;
- using RequestGlobalMemoryDumpForPidCallback = memory_instrumentation::
- CoordinatorImpl::RequestGlobalMemoryDumpForPidCallback;
- using base::trace_event::MemoryAllocatorDump;
- using base::trace_event::MemoryDumpArgs;
- using base::trace_event::MemoryDumpLevelOfDetail;
- using base::trace_event::MemoryDumpManager;
- using base::trace_event::MemoryDumpRequestArgs;
- using base::trace_event::MemoryDumpType;
- using base::trace_event::ProcessMemoryDump;
- using base::trace_event::TraceLog;
- using memory_instrumentation::mojom::GlobalMemoryDump;
- using memory_instrumentation::mojom::GlobalMemoryDumpPtr;
- namespace memory_instrumentation {
- class FakeCoordinatorImpl : public CoordinatorImpl {
- public:
- FakeCoordinatorImpl() = default;
- ~FakeCoordinatorImpl() override = default;
- MOCK_CONST_METHOD0(ComputePidToServiceNamesMap,
- std::map<base::ProcessId, std::vector<std::string>>());
- };
- class CoordinatorImplTest : public testing::Test {
- public:
- CoordinatorImplTest() = default;
- void SetUp() override {
- TracingObserverProto::RegisterForTesting();
- coordinator_ = std::make_unique<NiceMock<FakeCoordinatorImpl>>();
- tracing::PerfettoTracedProcess::GetTaskRunner()->ResetTaskRunnerForTesting(
- base::ThreadTaskRunnerHandle::Get());
- }
- void TearDown() override {
- coordinator_.reset();
- }
- void RegisterClientProcess(
- mojo::PendingReceiver<mojom::Coordinator> receiver,
- mojo::PendingRemote<mojom::ClientProcess> client_process,
- mojom::ProcessType process_type,
- base::ProcessId pid) {
- coordinator_->RegisterClientProcess(
- std::move(receiver), std::move(client_process), process_type, pid,
- /*service_name=*/absl::nullopt);
- }
- void RequestGlobalMemoryDump(RequestGlobalMemoryDumpCallback callback) {
- RequestGlobalMemoryDump(
- MemoryDumpType::SUMMARY_ONLY, MemoryDumpLevelOfDetail::BACKGROUND,
- MemoryDumpDeterminism::NONE, {}, std::move(callback));
- }
- void RequestGlobalMemoryDump(
- MemoryDumpType dump_type,
- MemoryDumpLevelOfDetail level_of_detail,
- MemoryDumpDeterminism determinism,
- const std::vector<std::string>& allocator_dump_names,
- RequestGlobalMemoryDumpCallback callback) {
- coordinator_->RequestGlobalMemoryDump(dump_type, level_of_detail,
- determinism, allocator_dump_names,
- std::move(callback));
- }
- void RequestGlobalMemoryDumpForPid(
- base::ProcessId pid,
- const std::vector<std::string>& allocator_dump_names,
- RequestGlobalMemoryDumpForPidCallback callback) {
- coordinator_->RequestGlobalMemoryDumpForPid(pid, allocator_dump_names,
- std::move(callback));
- }
- void RequestGlobalMemoryDumpAndAppendToTrace(
- RequestGlobalMemoryDumpAndAppendToTraceCallback callback) {
- coordinator_->RequestGlobalMemoryDumpAndAppendToTrace(
- MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED,
- MemoryDumpDeterminism::NONE, std::move(callback));
- }
- void GetVmRegionsForHeapProfiler(
- const std::vector<base::ProcessId>& pids,
- GetVmRegionsForHeapProfilerCallback callback) {
- coordinator_->GetVmRegionsForHeapProfiler(pids, std::move(callback));
- }
- void ReduceCoordinatorClientProcessTimeout() {
- coordinator_->set_client_process_timeout(base::Milliseconds(5));
- }
- protected:
- // Note that |coordinator_| must outlive |task_environment_|, because
- // otherwise a worker thread owned by the task environment may try to access
- // the coordinator after it has been destroyed.
- std::unique_ptr<NiceMock<FakeCoordinatorImpl>> coordinator_;
- base::test::TaskEnvironment task_environment_{
- base::test::SingleThreadTaskEnvironment::TimeSource::MOCK_TIME};
- base::test::TracingEnvironment tracing_environment_;
- };
- class MockClientProcess : public mojom::ClientProcess {
- public:
- MockClientProcess(CoordinatorImplTest* test_coordinator)
- : MockClientProcess(test_coordinator,
- base::GetCurrentProcId(),
- mojom::ProcessType::OTHER) {}
- MockClientProcess(CoordinatorImplTest* test_coordinator,
- base::ProcessId pid,
- mojom::ProcessType process_type) {
- // Register to the coordinator.
- mojo::Remote<mojom::Coordinator> remote_coordinator;
- mojo::PendingRemote<mojom::ClientProcess> client_process;
- receiver_.Bind(client_process.InitWithNewPipeAndPassReceiver());
- test_coordinator->RegisterClientProcess(
- remote_coordinator.BindNewPipeAndPassReceiver(),
- std::move(client_process), process_type, pid);
- ON_CALL(*this, RequestChromeMemoryDumpMock(_, _))
- .WillByDefault(Invoke([pid](const MemoryDumpRequestArgs& args,
- RequestChromeMemoryDumpCallback& callback) {
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- auto* mad = pmd->CreateAllocatorDump(
- "malloc", base::trace_event::MemoryAllocatorDumpGuid(pid));
- mad->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, 1024);
- std::move(callback).Run(true, args.dump_guid, std::move(pmd));
- }));
- ON_CALL(*this, RequestOSMemoryDumpMock(_, _, _))
- .WillByDefault(Invoke([](mojom::MemoryMapOption,
- const std::vector<base::ProcessId> pids,
- RequestOSMemoryDumpCallback& callback) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- std::move(callback).Run(true, std::move(results));
- }));
- }
- ~MockClientProcess() override = default;
- // TODO(crbug.com/729950): Remove non const reference here once GMock is
- // updated to support move-only types.
- MOCK_METHOD2(RequestChromeMemoryDumpMock,
- void(const MemoryDumpRequestArgs& args,
- RequestChromeMemoryDumpCallback& callback));
- MOCK_METHOD3(RequestOSMemoryDumpMock,
- void(mojom::MemoryMapOption option,
- const std::vector<base::ProcessId>& args,
- RequestOSMemoryDumpCallback& callback));
- void RequestChromeMemoryDump(
- const MemoryDumpRequestArgs& args,
- RequestChromeMemoryDumpCallback callback) override {
- RequestChromeMemoryDumpMock(args, callback);
- }
- void RequestOSMemoryDump(mojom::MemoryMapOption option,
- const std::vector<base::ProcessId>& args,
- RequestOSMemoryDumpCallback callback) override {
- RequestOSMemoryDumpMock(option, args, callback);
- }
- private:
- mojo::Receiver<mojom::ClientProcess> receiver_{this};
- };
- class MockGlobalMemoryDumpCallback {
- public:
- MockGlobalMemoryDumpCallback() = default;
- MOCK_METHOD2(OnCall, void(bool, GlobalMemoryDump*));
- void Run(bool success, GlobalMemoryDumpPtr ptr) {
- OnCall(success, ptr.get());
- }
- RequestGlobalMemoryDumpCallback Get() {
- return base::BindOnce(&MockGlobalMemoryDumpCallback::Run,
- base::Unretained(this));
- }
- };
- class MockGlobalMemoryDumpAndAppendToTraceCallback {
- public:
- MockGlobalMemoryDumpAndAppendToTraceCallback() = default;
- MOCK_METHOD2(OnCall, void(bool, uint64_t));
- void Run(bool success, uint64_t dump_guid) { OnCall(success, dump_guid); }
- RequestGlobalMemoryDumpAndAppendToTraceCallback Get() {
- return base::BindOnce(&MockGlobalMemoryDumpAndAppendToTraceCallback::Run,
- base::Unretained(this));
- }
- };
- class MockGetVmRegionsForHeapProfilerCallback {
- public:
- MockGetVmRegionsForHeapProfilerCallback() = default;
- MOCK_METHOD1(OnCall,
- void(const base::flat_map<base::ProcessId,
- std::vector<mojom::VmRegionPtr>>&));
- void Run(base::flat_map<base::ProcessId, std::vector<mojom::VmRegionPtr>>
- results) {
- OnCall(results);
- }
- GetVmRegionsForHeapProfilerCallback Get() {
- return base::BindOnce(&MockGetVmRegionsForHeapProfilerCallback::Run,
- base::Unretained(this));
- }
- };
- uint64_t GetFakeAddrForVmRegion(int pid, int region_index) {
- return 0x100000ul * pid * (region_index + 1);
- }
- uint64_t GetFakeSizeForVmRegion(int pid, int region_index) {
- return 4096 * pid * (region_index + 1);
- }
- mojom::RawOSMemDumpPtr FillRawOSDump(int pid) {
- mojom::RawOSMemDumpPtr raw_os_dump = mojom::RawOSMemDump::New();
- raw_os_dump->platform_private_footprint =
- mojom::PlatformPrivateFootprint::New();
- raw_os_dump->resident_set_kb = pid;
- for (int i = 0; i < 3; i++) {
- mojom::VmRegionPtr vm_region = mojom::VmRegion::New();
- vm_region->start_address = GetFakeAddrForVmRegion(pid, i);
- vm_region->size_in_bytes = GetFakeSizeForVmRegion(pid, i);
- raw_os_dump->memory_maps.push_back(std::move(vm_region));
- }
- return raw_os_dump;
- }
- // Tests that the global dump is acked even in absence of clients.
- TEST_F(CoordinatorImplTest, NoClients) {
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(true, NotNull()));
- RequestGlobalMemoryDump(callback.Get());
- }
- // Nominal behavior: several clients contributing to the global dump.
- TEST_F(CoordinatorImplTest, SeveralClients) {
- base::RunLoop run_loop;
- NiceMock<MockClientProcess> client_process_1(this, 1,
- mojom::ProcessType::BROWSER);
- NiceMock<MockClientProcess> client_process_2(this);
- EXPECT_CALL(client_process_1, RequestChromeMemoryDumpMock(_, _)).Times(1);
- EXPECT_CALL(client_process_2, RequestChromeMemoryDumpMock(_, _)).Times(1);
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(true, NotNull()))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- // Issuing two requests will cause the second one to be queued.
- TEST_F(CoordinatorImplTest, QueuedRequest) {
- base::RunLoop run_loop;
- // This variable to be static as the lambda below has to convert to a function
- // pointer rather than a functor.
- static base::test::TaskEnvironment* task_environment = nullptr;
- task_environment = &task_environment_;
- NiceMock<MockClientProcess> client_process_1(this, 1,
- mojom::ProcessType::BROWSER);
- NiceMock<MockClientProcess> client_process_2(this);
- // Each request will invoke on both processes.
- EXPECT_CALL(client_process_1, RequestChromeMemoryDumpMock(_, _)).Times(2);
- EXPECT_CALL(client_process_2, RequestChromeMemoryDumpMock(_, _))
- .Times(2)
- .WillRepeatedly(Invoke(
- [](const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- // Skip the wall clock time-ticks forward to make sure start_time
- // is strictly increasing.
- task_environment->FastForwardBy(base::Milliseconds(10));
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- std::move(callback).Run(true, args.dump_guid, std::move(pmd));
- }));
- MockGlobalMemoryDumpCallback callback1;
- MockGlobalMemoryDumpCallback callback2;
- // Verify that the start time of subsequent dumps is monotonically
- // increasing.
- base::TimeTicks before = base::TimeTicks::Now();
- base::TimeTicks first_dump_time;
- EXPECT_CALL(callback1, OnCall(true, NotNull()))
- .WillOnce(Invoke([&](bool success, GlobalMemoryDump* global_dump) {
- EXPECT_LE(before, global_dump->start_time);
- first_dump_time = global_dump->start_time;
- }));
- EXPECT_CALL(callback2, OnCall(true, NotNull()))
- .WillOnce(Invoke([&](bool success, GlobalMemoryDump* global_dump) {
- EXPECT_LT(before, global_dump->start_time);
- EXPECT_LT(first_dump_time, global_dump->start_time);
- run_loop.Quit();
- }));
- RequestGlobalMemoryDump(callback1.Get());
- RequestGlobalMemoryDump(callback2.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, MissingChromeDump) {
- base::RunLoop run_loop;
- NiceMock<MockClientProcess> client_process(this, 1,
- mojom::ProcessType::BROWSER);
- EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke(
- [](const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- std::move(callback).Run(true, args.dump_guid, std::move(pmd));
- }));
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(
- callback,
- OnCall(true, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
- IsEmpty()))))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, MissingOsDump) {
- base::RunLoop run_loop;
- 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- std::move(callback).Run(true, std::move(results));
- }));
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(
- callback,
- OnCall(true, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
- IsEmpty()))))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, TimeOutStuckChild) {
- base::RunLoop run_loop;
- // |stuck_callback| should be destroyed after |client_process| or mojo
- // will complain about the callback being destoyed before the binding.
- MockClientProcess::RequestChromeMemoryDumpCallback stuck_callback;
- NiceMock<MockClientProcess> client_process(this, 1,
- mojom::ProcessType::BROWSER);
- // Store a reference to the callback passed to RequestChromeMemoryDump
- // to emulate "stuck" behaviour.
- EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke(
- [&stuck_callback](
- const MemoryDumpRequestArgs&,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- stuck_callback = std::move(callback);
- }));
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(
- callback,
- OnCall(false, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
- IsEmpty()))))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- ReduceCoordinatorClientProcessTimeout();
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, TimeOutStuckChildMultiProcess) {
- base::RunLoop run_loop;
- static constexpr base::ProcessId kBrowserPid = 1;
- static constexpr base::ProcessId kRendererPid = 2;
- // |stuck_callback| should be destroyed after |renderer_client| or mojo
- // will complain about the callback being destoyed before the binding.
- MockClientProcess::RequestChromeMemoryDumpCallback stuck_callback;
- MockClientProcess browser_client(this, kBrowserPid,
- mojom::ProcessType::BROWSER);
- MockClientProcess renderer_client(this, kRendererPid,
- mojom::ProcessType::RENDERER);
- // This ifdef is here to match the sandboxing behavior of the client.
- // 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) {
- 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);
- #else
- EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
- .WillOnce(Invoke(
- [](mojom::MemoryMapOption, 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[0] = FillRawOSDump(kRendererPid);
- std::move(callback).Run(true, std::move(results));
- }));
- #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- // Make the browser respond correctly but pretend the renderer is "stuck"
- // by storing a callback.
- EXPECT_CALL(renderer_client, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke(
- [&stuck_callback](
- const MemoryDumpRequestArgs&,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- stuck_callback = std::move(callback);
- }));
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(false, _))
- .WillOnce(
- Invoke([&run_loop](bool success, GlobalMemoryDump* global_dump) {
- EXPECT_EQ(1U, global_dump->process_dumps.size());
- run_loop.Quit();
- }));
- ReduceCoordinatorClientProcessTimeout();
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- // Tests that a global dump is completed even if a client disconnects (e.g. due
- // to a crash) while a global dump is happening.
- TEST_F(CoordinatorImplTest, ClientCrashDuringGlobalDump) {
- base::RunLoop run_loop;
- auto client_process_1 = std::make_unique<NiceMock<MockClientProcess>>(
- this, 1, mojom::ProcessType::BROWSER);
- auto client_process_2 = std::make_unique<NiceMock<MockClientProcess>>(this);
- // One of the client processes dies after a global dump is requested and
- // before it receives the corresponding process dump request. The coordinator
- // should detect that one of its clients is disconnected and claim the global
- // dump attempt has failed.
- // Whichever client is called first destroys the other client.
- ON_CALL(*client_process_1, RequestChromeMemoryDumpMock(_, _))
- .WillByDefault(Invoke(
- [&client_process_2](
- const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- client_process_2.reset();
- std::move(callback).Run(true, args.dump_guid, nullptr);
- }));
- ON_CALL(*client_process_2, RequestChromeMemoryDumpMock(_, _))
- .WillByDefault(Invoke(
- [&client_process_1](
- const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- client_process_1.reset();
- std::move(callback).Run(true, args.dump_guid, nullptr);
- }));
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(false, NotNull()))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- // Like ClientCrashDuringGlobalDump but covers the case of having only one
- // client. Regression testing for crbug.com/742265.
- TEST_F(CoordinatorImplTest, SingleClientCrashDuringGlobalDump) {
- base::RunLoop run_loop;
- auto client_process = std::make_unique<NiceMock<MockClientProcess>>(
- this, 1, mojom::ProcessType::BROWSER);
- ON_CALL(*client_process, RequestChromeMemoryDumpMock(_, _))
- .WillByDefault(Invoke(
- [&client_process](
- const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- // The dtor here will cause mojo to post an UnregisterClient call to
- // the coordinator.
- client_process.reset();
- std::move(callback).Run(true, args.dump_guid, nullptr);
- }));
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(false, NotNull()))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, GlobalMemoryDumpStruct) {
- base::RunLoop run_loop;
- MockClientProcess browser_client(this, 1, mojom::ProcessType::BROWSER);
- MockClientProcess renderer_client(this, 2, mojom::ProcessType::RENDERER);
- EXPECT_CALL(browser_client, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke([](const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback&
- callback) {
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- auto* size = MemoryAllocatorDump::kNameSize;
- auto* bytes = MemoryAllocatorDump::kUnitsBytes;
- const uint32_t kB = 1024;
- pmd->CreateAllocatorDump("malloc",
- base::trace_event::MemoryAllocatorDumpGuid(1))
- ->AddScalar(size, bytes, 1 * kB);
- pmd->CreateAllocatorDump("malloc/ignored")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("blink_gc")->AddScalar(size, bytes, 2 * kB);
- pmd->CreateAllocatorDump("blink_gc/ignored")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("v8/foo")->AddScalar(size, bytes, 1 * kB);
- pmd->CreateAllocatorDump("v8/bar")->AddScalar(size, bytes, 2 * kB);
- pmd->CreateAllocatorDump("v8")->AddScalar(size, bytes, 99 * kB);
- // All the 99 KB values here are expected to be ignored.
- pmd->CreateAllocatorDump("partition_alloc")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("partition_alloc/allocated_objects")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("partition_alloc/allocated_objects/ignored")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("partition_alloc/partitions")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_1")
- ->AddScalar(size, bytes, 2 * kB);
- pmd->CreateAllocatorDump("partition_alloc/partitions/not_ignored_2")
- ->AddScalar(size, bytes, 2 * kB);
- std::move(callback).Run(true, args.dump_guid, std::move(pmd));
- }));
- EXPECT_CALL(renderer_client, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke(
- [](const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- auto* mad = pmd->CreateAllocatorDump(
- "malloc", base::trace_event::MemoryAllocatorDumpGuid(2));
- mad->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, 1024 * 2);
- std::move(callback).Run(true, args.dump_guid, std::move(pmd));
- }));
- #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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[1] = mojom::RawOSMemDump::New();
- results[1]->resident_set_kb = 1;
- results[1]->platform_private_footprint =
- mojom::PlatformPrivateFootprint::New();
- results[2] = mojom::RawOSMemDump::New();
- results[2]->platform_private_footprint =
- mojom::PlatformPrivateFootprint::New();
- results[2]->resident_set_kb = 2;
- std::move(callback).Run(true, std::move(results));
- }));
- 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[0] = mojom::RawOSMemDump::New();
- results[0]->platform_private_footprint =
- mojom::PlatformPrivateFootprint::New();
- 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[0] = mojom::RawOSMemDump::New();
- results[0]->platform_private_footprint =
- mojom::PlatformPrivateFootprint::New();
- results[0]->resident_set_kb = 2;
- std::move(callback).Run(true, std::move(results));
- }));
- #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(true, NotNull()))
- .WillOnce(Invoke([&run_loop](bool success,
- GlobalMemoryDump* global_dump) {
- EXPECT_TRUE(success);
- EXPECT_EQ(2U, global_dump->process_dumps.size());
- mojom::ProcessMemoryDumpPtr browser_dump = nullptr;
- mojom::ProcessMemoryDumpPtr renderer_dump = nullptr;
- for (mojom::ProcessMemoryDumpPtr& dump : global_dump->process_dumps) {
- if (dump->process_type == mojom::ProcessType::BROWSER) {
- browser_dump = std::move(dump);
- } else if (dump->process_type == mojom::ProcessType::RENDERER) {
- renderer_dump = std::move(dump);
- }
- }
- EXPECT_EQ(browser_dump->os_dump->resident_set_kb, 1u);
- EXPECT_EQ(renderer_dump->os_dump->resident_set_kb, 2u);
- run_loop.Quit();
- }));
- RequestGlobalMemoryDump(callback.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) {
- base::RunLoop run_loop;
- // Not using a constexpr base::ProcessId because std:unordered_map<>
- // and friends makes it too easy to accidentally odr-use this variable
- // causing all sorts of compiler-toolchain divergent fun when trying
- // to decide of the lambda capture is necessary.
- static constexpr base::ProcessId kBrowserPid = 1;
- static constexpr base::ProcessId kRendererPid = 2;
- MockClientProcess browser_client(this, kBrowserPid,
- mojom::ProcessType::BROWSER);
- MockClientProcess renderer_client(this, kRendererPid,
- mojom::ProcessType::RENDERER);
- // This ifdef is here to match the sandboxing behavior of the client.
- // 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) {
- 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);
- #else
- EXPECT_CALL(browser_client, RequestOSMemoryDumpMock(_, Contains(0), _))
- .WillOnce(Invoke(
- [](mojom::MemoryMapOption, 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[0] = FillRawOSDump(kRendererPid);
- std::move(callback).Run(true, std::move(results));
- }));
- #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- MockGetVmRegionsForHeapProfilerCallback callback;
- EXPECT_CALL(callback, OnCall(_))
- .WillOnce(Invoke(
- [&run_loop](
- const base::flat_map<base::ProcessId,
- std::vector<mojom::VmRegionPtr>>& results) {
- ASSERT_EQ(2U, results.size());
- auto browser_it = results.find(kBrowserPid);
- ASSERT_TRUE(browser_it != results.end());
- auto renderer_it = results.find(kRendererPid);
- ASSERT_TRUE(renderer_it != results.end());
- const std::vector<mojom::VmRegionPtr>& browser_mmaps =
- browser_it->second;
- ASSERT_EQ(3u, browser_mmaps.size());
- for (int i = 0; i < 3; i++) {
- EXPECT_EQ(GetFakeAddrForVmRegion(kBrowserPid, i),
- browser_mmaps[i]->start_address);
- }
- const std::vector<mojom::VmRegionPtr>& renderer_mmaps =
- renderer_it->second;
- ASSERT_EQ(3u, renderer_mmaps.size());
- for (int i = 0; i < 3; i++) {
- EXPECT_EQ(GetFakeAddrForVmRegion(kRendererPid, i),
- renderer_mmaps[i]->start_address);
- }
- run_loop.Quit();
- }));
- std::vector<base::ProcessId> pids;
- pids.push_back(kBrowserPid);
- pids.push_back(kRendererPid);
- GetVmRegionsForHeapProfiler(pids, callback.Get());
- run_loop.Run();
- }
- // RequestGlobalMemoryDump, as opposite to RequestGlobalMemoryDumpAndAddToTrace,
- // shouldn't add anything into the trace
- TEST_F(CoordinatorImplTest, DumpsArentAddedToTraceUnlessRequested) {
- CoordinatorImpl* coordinator = CoordinatorImpl::GetInstance();
- ASSERT_TRUE(coordinator->use_proto_writer_);
- tracing::DataSourceTester data_source_tester(
- reinterpret_cast<TracingObserverProto*>(
- coordinator->tracing_observer_.get()));
- base::RunLoop run_loop;
- NiceMock<MockClientProcess> client_process(this, 1,
- mojom::ProcessType::BROWSER);
- EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke(
- [](const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- std::move(callback).Run(true, args.dump_guid, std::move(pmd));
- }));
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(
- callback,
- OnCall(true, Pointee(Field(&mojom::GlobalMemoryDump::process_dumps,
- IsEmpty()))))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- base::trace_event::TraceConfig trace_config(
- std::string(MemoryDumpManager::kTraceCategory) + ",-*",
- base::trace_event::RECORD_UNTIL_FULL);
- data_source_tester.BeginTrace(trace_config);
- RequestGlobalMemoryDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED,
- MemoryDumpDeterminism::NONE, {}, callback.Get());
- run_loop.Run();
- data_source_tester.EndTracing();
- for (size_t i = 0; i < data_source_tester.GetFinalizedPacketCount(); i++) {
- EXPECT_FALSE(data_source_tester.GetFinalizedPacket(i)
- ->has_memory_tracker_snapshot());
- }
- }
- // crbug.com: 1238428: flaky on Linux.
- #if BUILDFLAG(IS_LINUX)
- #define MAYBE_DumpsAreAddedToTraceWhenRequested \
- DISABLED_DumpsAreAddedToTraceWhenRequested
- #else
- #define MAYBE_DumpsAreAddedToTraceWhenRequested \
- DumpsAreAddedToTraceWhenRequested
- #endif
- TEST_F(CoordinatorImplTest, MAYBE_DumpsAreAddedToTraceWhenRequested) {
- CoordinatorImpl* coordinator = CoordinatorImpl::GetInstance();
- ASSERT_TRUE(coordinator->use_proto_writer_);
- tracing::DataSourceTester data_source_tester(
- reinterpret_cast<TracingObserverProto*>(
- coordinator->tracing_observer_.get()));
- base::RunLoop run_loop;
- NiceMock<MockClientProcess> client_process(this, 1,
- mojom::ProcessType::BROWSER);
- EXPECT_CALL(client_process, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke(
- [](const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- std::move(callback).Run(true, args.dump_guid, std::move(pmd));
- }));
- MockGlobalMemoryDumpAndAppendToTraceCallback callback;
- EXPECT_CALL(callback, OnCall(true, Ne(0ul)))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- base::trace_event::TraceConfig trace_config(
- std::string(MemoryDumpManager::kTraceCategory) + ",-*",
- base::trace_event::RECORD_UNTIL_FULL);
- data_source_tester.BeginTrace(trace_config);
- RequestGlobalMemoryDumpAndAppendToTrace(callback.Get());
- run_loop.Run();
- data_source_tester.EndTracing();
- EXPECT_GE(data_source_tester.GetFinalizedPacketCount(), 1u);
- const auto* packet = data_source_tester.GetFinalizedPacket();
- EXPECT_EQ(packet->memory_tracker_snapshot().level_of_detail(),
- perfetto::protos::MemoryTrackerSnapshot::DETAIL_FULL);
- }
- TEST_F(CoordinatorImplTest, DumpByPidSuccess) {
- static constexpr base::ProcessId kBrowserPid = 1;
- static constexpr base::ProcessId kRendererPid = 2;
- static constexpr base::ProcessId kGpuPid = 3;
- NiceMock<MockClientProcess> client_process_1(this, kBrowserPid,
- mojom::ProcessType::BROWSER);
- NiceMock<MockClientProcess> client_process_2(this, kRendererPid,
- mojom::ProcessType::RENDERER);
- NiceMock<MockClientProcess> client_process_3(this, kGpuPid,
- mojom::ProcessType::GPU);
- // This ifdef is here to match the sandboxing behavior of the client.
- // 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) {
- 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) {
- 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) {
- 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) {
- 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) {
- 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[0] = FillRawOSDump(kGpuPid);
- std::move(callback).Run(true, std::move(results));
- }));
- #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- base::RunLoop run_loop;
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(true, Ne(nullptr)))
- .WillOnce(Invoke([](bool success, GlobalMemoryDump* global_dump) {
- EXPECT_EQ(1U, global_dump->process_dumps.size());
- EXPECT_EQ(global_dump->process_dumps[0]->pid, kBrowserPid);
- }))
- .WillOnce(Invoke([](bool success, GlobalMemoryDump* global_dump) {
- EXPECT_EQ(1U, global_dump->process_dumps.size());
- EXPECT_EQ(global_dump->process_dumps[0]->pid, kRendererPid);
- }))
- .WillOnce(
- Invoke([&run_loop](bool success, GlobalMemoryDump* global_dump) {
- EXPECT_EQ(1U, global_dump->process_dumps.size());
- EXPECT_EQ(global_dump->process_dumps[0]->pid, kGpuPid);
- run_loop.Quit();
- }));
- RequestGlobalMemoryDumpForPid(kBrowserPid, {}, callback.Get());
- RequestGlobalMemoryDumpForPid(kRendererPid, {}, callback.Get());
- RequestGlobalMemoryDumpForPid(kGpuPid, {}, callback.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, DumpByPidFailure) {
- NiceMock<MockClientProcess> client_process_1(this, 1,
- mojom::ProcessType::BROWSER);
- base::RunLoop run_loop;
- MockGlobalMemoryDumpCallback callback;
- EXPECT_CALL(callback, OnCall(false, nullptr))
- .WillOnce(RunOnceClosure(run_loop.QuitClosure()));
- RequestGlobalMemoryDumpForPid(2, {}, callback.Get());
- run_loop.Run();
- }
- TEST_F(CoordinatorImplTest, GlobalDumpWithSubTrees) {
- base::RunLoop run_loop;
- static constexpr base::ProcessId kBrowserPid = 1;
- MockClientProcess browser_client(this, kBrowserPid,
- mojom::ProcessType::BROWSER);
- EXPECT_CALL(browser_client, RequestChromeMemoryDumpMock(_, _))
- .WillOnce(Invoke(
- [](const MemoryDumpRequestArgs& args,
- MockClientProcess::RequestChromeMemoryDumpCallback& callback) {
- MemoryDumpArgs dump_args{MemoryDumpLevelOfDetail::DETAILED};
- auto pmd = std::make_unique<ProcessMemoryDump>(dump_args);
- auto* size = MemoryAllocatorDump::kNameSize;
- auto* bytes = MemoryAllocatorDump::kUnitsBytes;
- const uint32_t kB = 1024;
- // None of these dumps should appear in the output.
- pmd->CreateAllocatorDump(
- "malloc", base::trace_event::MemoryAllocatorDumpGuid(1))
- ->AddScalar(size, bytes, 1 * kB);
- pmd->CreateAllocatorDump("v8/foo")->AddScalar(size, bytes, 1 * kB);
- pmd->CreateAllocatorDump("v8/bar")->AddScalar(size, bytes, 2 * kB);
- pmd->CreateAllocatorDump("v8")->AddScalar(size, bytes, 99 * kB);
- // This "tree" of dumps should be included.
- pmd->CreateAllocatorDump("partition_alloc")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("partition_alloc/allocated_objects")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("partition_alloc/partitions")
- ->AddScalar(size, bytes, 99 * kB);
- pmd->CreateAllocatorDump("partition_alloc/partitions/1")
- ->AddScalar(size, bytes, 2 * kB);
- pmd->CreateAllocatorDump("partition_alloc/partitions/2")
- ->AddScalar(size, bytes, 2 * kB);
- 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[1] = mojom::RawOSMemDump::New();
- results[1]->resident_set_kb = 1;
- results[1]->platform_private_footprint =
- mojom::PlatformPrivateFootprint::New();
- 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) {
- base::flat_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
- results[0] = mojom::RawOSMemDump::New();
- results[0]->platform_private_footprint =
- mojom::PlatformPrivateFootprint::New();
- results[0]->resident_set_kb = 1;
- std::move(callback).Run(true, std::move(results));
- }));
- #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- base::test::TestFuture<bool,
- memory_instrumentation::mojom::GlobalMemoryDumpPtr>
- result;
- RequestGlobalMemoryDump(
- MemoryDumpType::SUMMARY_ONLY, MemoryDumpLevelOfDetail::BACKGROUND,
- MemoryDumpDeterminism::NONE, {"partition_alloc/*"}, result.GetCallback());
- // Expect that the dump request succeeds.
- ASSERT_TRUE(std::get<bool>(result.Get()));
- // Verify that the dump has a single "partition_alloc" top-level node, and
- // that the top level dump has children.
- const auto& global_dump =
- std::get<memory_instrumentation::mojom::GlobalMemoryDumpPtr>(
- result.Get());
- ASSERT_EQ(global_dump->process_dumps.size(), 1u);
- const auto& process_dump = *global_dump->process_dumps.begin();
- EXPECT_EQ(process_dump->pid, kBrowserPid);
- const auto& allocator_dumps = process_dump->chrome_allocator_dumps;
- ASSERT_EQ(allocator_dumps.size(), 1u);
- EXPECT_EQ(allocator_dumps.begin()->first, "partition_alloc");
- EXPECT_EQ(allocator_dumps.begin()->second->children.size(), 2u);
- }
- } // namespace memory_instrumentation
|