1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/trace_event/memory_dump_manager.h"
7 #include "base/bind_helpers.h"
8 #include "base/memory/scoped_vector.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/test/test_io_thread.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/threading/thread.h"
15 #include "base/trace_event/memory_dump_provider.h"
16 #include "base/trace_event/process_memory_dump.h"
17 #include "base/trace_event/trace_config_memory_test_util.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
22 using testing::AnyNumber
;
23 using testing::AtMost
;
24 using testing::Between
;
25 using testing::Invoke
;
26 using testing::Return
;
29 namespace trace_event
{
31 // GTest matchers for MemoryDumpRequestArgs arguments.
32 MATCHER(IsDetailedDump
, "") {
33 return arg
.level_of_detail
== MemoryDumpLevelOfDetail::DETAILED
;
36 MATCHER(IsLightDump
, "") {
37 return arg
.level_of_detail
== MemoryDumpLevelOfDetail::LIGHT
;
40 // Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
41 // requests locally to the MemoryDumpManager instead of performing IPC dances.
42 class MemoryDumpManagerDelegateForTesting
: public MemoryDumpManagerDelegate
{
44 MemoryDumpManagerDelegateForTesting() {
45 ON_CALL(*this, RequestGlobalMemoryDump(_
, _
))
46 .WillByDefault(Invoke(
47 this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump
));
50 MOCK_METHOD2(RequestGlobalMemoryDump
,
51 void(const MemoryDumpRequestArgs
& args
,
52 const MemoryDumpCallback
& callback
));
54 uint64
GetTracingProcessId() const override
{
56 return MemoryDumpManager::kInvalidTracingProcessId
;
60 class MockMemoryDumpProvider
: public MemoryDumpProvider
{
62 MOCK_METHOD2(OnMemoryDump
,
63 bool(const MemoryDumpArgs
& args
, ProcessMemoryDump
* pmd
));
66 class MemoryDumpManagerTest
: public testing::Test
{
68 void SetUp() override
{
69 last_callback_success_
= false;
70 message_loop_
.reset(new MessageLoop());
71 mdm_
.reset(new MemoryDumpManager());
72 MemoryDumpManager::SetInstanceForTesting(mdm_
.get());
73 ASSERT_EQ(mdm_
, MemoryDumpManager::GetInstance());
74 delegate_
.reset(new MemoryDumpManagerDelegateForTesting
);
77 void TearDown() override
{
78 MemoryDumpManager::SetInstanceForTesting(nullptr);
81 message_loop_
.reset();
82 TraceLog::DeleteForTesting();
85 void DumpCallbackAdapter(scoped_refptr
<SingleThreadTaskRunner
> task_runner
,
89 last_callback_success_
= success
;
90 task_runner
->PostTask(FROM_HERE
, closure
);
94 void InitializeMemoryDumpManager(bool is_coordinator
) {
95 mdm_
->Initialize(delegate_
.get(), is_coordinator
);
98 void EnableTracingWithLegacyCategories(const char* category
) {
99 TraceLog::GetInstance()->SetEnabled(TraceConfig(category
, ""),
100 TraceLog::RECORDING_MODE
);
103 void EnableTracingWithTraceConfig(const std::string
& trace_config
) {
104 TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config
),
105 TraceLog::RECORDING_MODE
);
108 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
110 bool IsPeriodicDumpingEnabled() const {
111 return mdm_
->periodic_dump_timer_
.IsRunning();
114 int GetMaxConsecutiveFailuresCount() const {
115 return MemoryDumpManager::kMaxConsecutiveFailuresCount
;
118 scoped_ptr
<MemoryDumpManager
> mdm_
;
119 scoped_ptr
<MemoryDumpManagerDelegateForTesting
> delegate_
;
120 bool last_callback_success_
;
123 scoped_ptr
<MessageLoop
> message_loop_
;
125 // We want our singleton torn down after each test.
126 ShadowingAtExitManager at_exit_manager_
;
129 // Basic sanity checks. Registers a memory dump provider and checks that it is
130 // called, but only when memory-infra is enabled.
131 TEST_F(MemoryDumpManagerTest
, SingleDumper
) {
132 InitializeMemoryDumpManager(false /* is_coordinator */);
133 MockMemoryDumpProvider mdp
;
134 mdm_
->RegisterDumpProvider(&mdp
);
136 // Check that the dumper is not called if the memory category is not enabled.
137 EnableTracingWithLegacyCategories("foobar-but-not-memory");
138 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(0);
139 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).Times(0);
140 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
141 MemoryDumpLevelOfDetail::DETAILED
);
144 // Now repeat enabling the memory category and check that the dumper is
145 // invoked this time.
146 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
147 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(3);
148 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).Times(3).WillRepeatedly(Return(true));
149 for (int i
= 0; i
< 3; ++i
)
150 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
151 MemoryDumpLevelOfDetail::DETAILED
);
154 mdm_
->UnregisterDumpProvider(&mdp
);
156 // Finally check the unregister logic: the delegate will be invoked but not
157 // the dump provider, as it has been unregistered.
158 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
159 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
160 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).Times(0);
161 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
162 MemoryDumpLevelOfDetail::DETAILED
);
163 TraceLog::GetInstance()->SetDisabled();
166 // Checks that requesting dumps with high level of detail actually propagates
167 // the level of the detail properly to OnMemoryDump() call on dump providers.
168 TEST_F(MemoryDumpManagerTest
, CheckMemoryDumpArgs
) {
169 InitializeMemoryDumpManager(false /* is_coordinator */);
170 MockMemoryDumpProvider mdp
;
172 mdm_
->RegisterDumpProvider(&mdp
);
173 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
174 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
175 EXPECT_CALL(mdp
, OnMemoryDump(IsDetailedDump(), _
)).WillOnce(Return(true));
176 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
177 MemoryDumpLevelOfDetail::DETAILED
);
179 mdm_
->UnregisterDumpProvider(&mdp
);
181 // Check that requesting dumps with low level of detail actually propagates to
182 // OnMemoryDump() call on dump providers.
183 mdm_
->RegisterDumpProvider(&mdp
);
184 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
185 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
186 EXPECT_CALL(mdp
, OnMemoryDump(IsLightDump(), _
)).WillOnce(Return(true));
187 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
188 MemoryDumpLevelOfDetail::LIGHT
);
190 mdm_
->UnregisterDumpProvider(&mdp
);
193 // Checks that the SharedSessionState object is acqually shared over time.
194 TEST_F(MemoryDumpManagerTest
, SharedSessionState
) {
195 InitializeMemoryDumpManager(false /* is_coordinator */);
196 MockMemoryDumpProvider mdp1
;
197 MockMemoryDumpProvider mdp2
;
198 mdm_
->RegisterDumpProvider(&mdp1
);
199 mdm_
->RegisterDumpProvider(&mdp2
);
201 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
202 const MemoryDumpSessionState
* session_state
= mdm_
->session_state().get();
203 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(2);
204 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
))
206 .WillRepeatedly(Invoke([session_state
](const MemoryDumpArgs
&,
207 ProcessMemoryDump
* pmd
) -> bool {
208 EXPECT_EQ(session_state
, pmd
->session_state().get());
211 EXPECT_CALL(mdp2
, OnMemoryDump(_
, _
))
213 .WillRepeatedly(Invoke([session_state
](const MemoryDumpArgs
&,
214 ProcessMemoryDump
* pmd
) -> bool {
215 EXPECT_EQ(session_state
, pmd
->session_state().get());
219 for (int i
= 0; i
< 2; ++i
)
220 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
221 MemoryDumpLevelOfDetail::DETAILED
);
226 // Checks that the (Un)RegisterDumpProvider logic behaves sanely.
227 TEST_F(MemoryDumpManagerTest
, MultipleDumpers
) {
228 InitializeMemoryDumpManager(false /* is_coordinator */);
229 MockMemoryDumpProvider mdp1
;
230 MockMemoryDumpProvider mdp2
;
233 mdm_
->RegisterDumpProvider(&mdp1
);
234 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
235 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
236 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
)).WillOnce(Return(true));
237 EXPECT_CALL(mdp2
, OnMemoryDump(_
, _
)).Times(0);
238 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
239 MemoryDumpLevelOfDetail::DETAILED
);
242 // Invert: enable mdp1 and disable mdp2.
243 mdm_
->UnregisterDumpProvider(&mdp1
);
244 mdm_
->RegisterDumpProvider(&mdp2
);
245 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
246 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
247 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
)).Times(0);
248 EXPECT_CALL(mdp2
, OnMemoryDump(_
, _
)).WillOnce(Return(true));
249 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
250 MemoryDumpLevelOfDetail::DETAILED
);
253 // Enable both mdp1 and mdp2.
254 mdm_
->RegisterDumpProvider(&mdp1
);
255 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
256 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
257 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
)).WillOnce(Return(true));
258 EXPECT_CALL(mdp2
, OnMemoryDump(_
, _
)).WillOnce(Return(true));
259 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
260 MemoryDumpLevelOfDetail::DETAILED
);
264 // Checks that the dump provider invocations depend only on the current
265 // registration state and not on previous registrations and dumps.
266 TEST_F(MemoryDumpManagerTest
, RegistrationConsistency
) {
267 InitializeMemoryDumpManager(false /* is_coordinator */);
268 MockMemoryDumpProvider mdp
;
270 mdm_
->RegisterDumpProvider(&mdp
);
273 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
274 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).WillOnce(Return(true));
275 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
276 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
277 MemoryDumpLevelOfDetail::DETAILED
);
281 mdm_
->UnregisterDumpProvider(&mdp
);
284 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
285 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).Times(0);
286 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
287 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
288 MemoryDumpLevelOfDetail::DETAILED
);
292 mdm_
->RegisterDumpProvider(&mdp
);
293 mdm_
->UnregisterDumpProvider(&mdp
);
296 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
297 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).Times(0);
298 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
299 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
300 MemoryDumpLevelOfDetail::DETAILED
);
304 mdm_
->RegisterDumpProvider(&mdp
);
305 mdm_
->UnregisterDumpProvider(&mdp
);
306 mdm_
->RegisterDumpProvider(&mdp
);
309 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
310 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).WillOnce(Return(true));
311 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
312 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
313 MemoryDumpLevelOfDetail::DETAILED
);
318 // Checks that the MemoryDumpManager respects the thread affinity when a
319 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8
320 // threads and registering a MemoryDumpProvider on each of them. At each
321 // iteration, one thread is removed, to check the live unregistration logic.
322 TEST_F(MemoryDumpManagerTest
, RespectTaskRunnerAffinity
) {
323 InitializeMemoryDumpManager(false /* is_coordinator */);
324 const uint32 kNumInitialThreads
= 8;
326 ScopedVector
<Thread
> threads
;
327 ScopedVector
<MockMemoryDumpProvider
> mdps
;
329 // Create the threads and setup the expectations. Given that at each iteration
330 // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
331 // invoked a number of times equal to its index.
332 for (uint32 i
= kNumInitialThreads
; i
> 0; --i
) {
333 Thread
* thread
= new Thread("test thread");
334 threads
.push_back(thread
);
335 threads
.back()->Start();
336 scoped_refptr
<SingleThreadTaskRunner
> task_runner
= thread
->task_runner();
337 MockMemoryDumpProvider
* mdp
= new MockMemoryDumpProvider();
339 mdm_
->RegisterDumpProvider(mdp
, task_runner
);
340 EXPECT_CALL(*mdp
, OnMemoryDump(_
, _
))
342 .WillRepeatedly(Invoke(
343 [task_runner
](const MemoryDumpArgs
&, ProcessMemoryDump
*) -> bool {
344 EXPECT_TRUE(task_runner
->RunsTasksOnCurrentThread());
349 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
351 while (!threads
.empty()) {
352 last_callback_success_
= false;
355 MemoryDumpCallback callback
=
356 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter
, Unretained(this),
357 MessageLoop::current()->task_runner(), run_loop
.QuitClosure());
358 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
359 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
360 MemoryDumpLevelOfDetail::DETAILED
, callback
);
361 // This nested message loop (|run_loop|) will quit if and only if the
362 // |callback| passed to RequestGlobalDump() is invoked.
365 EXPECT_TRUE(last_callback_success_
);
367 // Unregister a MDP and destroy one thread at each iteration to check the
368 // live unregistration logic. The unregistration needs to happen on the same
369 // thread the MDP belongs to.
372 Closure unregistration
=
373 Bind(&MemoryDumpManager::UnregisterDumpProvider
,
374 Unretained(mdm_
.get()), Unretained(mdps
.back()));
375 threads
.back()->task_runner()->PostTaskAndReply(FROM_HERE
, unregistration
,
376 run_loop
.QuitClosure());
380 threads
.back()->Stop();
387 // Checks that providers get disabled after 3 consecutive failures, but not
388 // otherwise (e.g., if interleaved).
389 TEST_F(MemoryDumpManagerTest
, DisableFailingDumpers
) {
390 InitializeMemoryDumpManager(false /* is_coordinator */);
391 MockMemoryDumpProvider mdp1
;
392 MockMemoryDumpProvider mdp2
;
394 mdm_
->RegisterDumpProvider(&mdp1
);
395 mdm_
->RegisterDumpProvider(&mdp2
);
396 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
398 const int kNumDumps
= 2 * GetMaxConsecutiveFailuresCount();
399 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(kNumDumps
);
401 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
))
402 .Times(GetMaxConsecutiveFailuresCount())
403 .WillRepeatedly(Return(false));
405 EXPECT_CALL(mdp2
, OnMemoryDump(_
, _
))
406 .WillOnce(Return(false))
407 .WillOnce(Return(true))
408 .WillOnce(Return(false))
409 .WillOnce(Return(false))
410 .WillOnce(Return(true))
411 .WillOnce(Return(false));
413 for (int i
= 0; i
< kNumDumps
; i
++) {
414 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
415 MemoryDumpLevelOfDetail::DETAILED
);
421 // Sneakily registers an extra memory dump provider while an existing one is
422 // dumping and expect it to take part in the already active tracing session.
423 TEST_F(MemoryDumpManagerTest
, RegisterDumperWhileDumping
) {
424 InitializeMemoryDumpManager(false /* is_coordinator */);
425 MockMemoryDumpProvider mdp1
;
426 MockMemoryDumpProvider mdp2
;
428 mdm_
->RegisterDumpProvider(&mdp1
);
429 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
431 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(4);
433 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
))
435 .WillOnce(Return(true))
437 Invoke([&mdp2
](const MemoryDumpArgs
&, ProcessMemoryDump
*) -> bool {
438 MemoryDumpManager::GetInstance()->RegisterDumpProvider(&mdp2
);
441 .WillRepeatedly(Return(true));
443 // Depending on the insertion order (before or after mdp1), mdp2 might be
444 // called also immediately after it gets registered.
445 EXPECT_CALL(mdp2
, OnMemoryDump(_
, _
))
446 .Times(Between(2, 3))
447 .WillRepeatedly(Return(true));
449 for (int i
= 0; i
< 4; i
++) {
450 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
451 MemoryDumpLevelOfDetail::DETAILED
);
457 // Like RegisterDumperWhileDumping, but unregister the dump provider instead.
458 TEST_F(MemoryDumpManagerTest
, UnregisterDumperWhileDumping
) {
459 InitializeMemoryDumpManager(false /* is_coordinator */);
460 MockMemoryDumpProvider mdp1
;
461 MockMemoryDumpProvider mdp2
;
463 mdm_
->RegisterDumpProvider(&mdp1
, ThreadTaskRunnerHandle::Get());
464 mdm_
->RegisterDumpProvider(&mdp2
, ThreadTaskRunnerHandle::Get());
465 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
467 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(4);
469 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
))
471 .WillOnce(Return(true))
473 Invoke([&mdp2
](const MemoryDumpArgs
&, ProcessMemoryDump
*) -> bool {
474 MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2
);
477 .WillRepeatedly(Return(true));
479 // Depending on the insertion order (before or after mdp1), mdp2 might have
480 // been already called when UnregisterDumpProvider happens.
481 EXPECT_CALL(mdp2
, OnMemoryDump(_
, _
))
482 .Times(Between(1, 2))
483 .WillRepeatedly(Return(true));
485 for (int i
= 0; i
< 4; i
++) {
486 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
487 MemoryDumpLevelOfDetail::DETAILED
);
493 // Checks that the dump does not abort when unregistering a provider while
494 // dumping from a different thread than the dumping thread.
495 TEST_F(MemoryDumpManagerTest
, UnregisterDumperFromThreadWhileDumping
) {
496 InitializeMemoryDumpManager(false /* is_coordinator */);
497 ScopedVector
<TestIOThread
> threads
;
498 ScopedVector
<MockMemoryDumpProvider
> mdps
;
500 for (int i
= 0; i
< 2; i
++) {
501 threads
.push_back(new TestIOThread(TestIOThread::kAutoStart
));
502 mdps
.push_back(new MockMemoryDumpProvider());
503 mdm_
->RegisterDumpProvider(mdps
.back(), threads
.back()->task_runner());
506 int on_memory_dump_call_count
= 0;
509 // When OnMemoryDump is called on either of the dump providers, it will
510 // unregister the other one.
511 for (MockMemoryDumpProvider
* mdp
: mdps
) {
512 int other_idx
= (mdps
.front() == mdp
);
513 TestIOThread
* other_thread
= threads
[other_idx
];
514 MockMemoryDumpProvider
* other_mdp
= mdps
[other_idx
];
515 auto on_dump
= [this, other_thread
, other_mdp
, &on_memory_dump_call_count
](
516 const MemoryDumpArgs
& args
, ProcessMemoryDump
* pmd
) {
517 other_thread
->PostTaskAndWait(
518 FROM_HERE
, base::Bind(&MemoryDumpManager::UnregisterDumpProvider
,
519 base::Unretained(&*mdm_
), other_mdp
));
520 on_memory_dump_call_count
++;
524 // OnMemoryDump is called once for the provider that dumps first, and zero
525 // times for the other provider.
526 EXPECT_CALL(*mdp
, OnMemoryDump(_
, _
))
528 .WillOnce(Invoke(on_dump
));
531 last_callback_success_
= false;
532 MemoryDumpCallback callback
=
533 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter
, Unretained(this),
534 MessageLoop::current()->task_runner(), run_loop
.QuitClosure());
536 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
538 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
539 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
540 MemoryDumpLevelOfDetail::DETAILED
, callback
);
544 ASSERT_EQ(1, on_memory_dump_call_count
);
545 ASSERT_EQ(true, last_callback_success_
);
550 // Checks that a NACK callback is invoked if RequestGlobalDump() is called when
551 // tracing is not enabled.
552 TEST_F(MemoryDumpManagerTest
, CallbackCalledOnFailure
) {
553 InitializeMemoryDumpManager(false /* is_coordinator */);
554 MockMemoryDumpProvider mdp1
;
555 mdm_
->RegisterDumpProvider(&mdp1
);
557 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(0);
558 EXPECT_CALL(mdp1
, OnMemoryDump(_
, _
)).Times(0);
560 last_callback_success_
= true;
563 MemoryDumpCallback callback
=
564 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter
, Unretained(this),
565 MessageLoop::current()->task_runner(), run_loop
.QuitClosure());
566 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
567 MemoryDumpLevelOfDetail::DETAILED
, callback
);
570 EXPECT_FALSE(last_callback_success_
);
573 // Checks that is the MemoryDumpManager is initialized after tracing already
574 // began, it will still late-join the party (real use case: startup tracing).
575 TEST_F(MemoryDumpManagerTest
, InitializedAfterStartOfTracing
) {
576 MockMemoryDumpProvider mdp
;
577 mdm_
->RegisterDumpProvider(&mdp
);
578 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
580 // First check that a RequestGlobalDump() issued before the MemoryDumpManager
581 // initialization gets NACK-ed cleanly.
583 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).Times(0);
584 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(0);
586 MemoryDumpCallback callback
=
587 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter
, Unretained(this),
588 MessageLoop::current()->task_runner(), run_loop
.QuitClosure());
589 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
590 MemoryDumpLevelOfDetail::DETAILED
, callback
);
592 EXPECT_FALSE(last_callback_success_
);
595 // Now late-initialize the MemoryDumpManager and check that the
596 // RequestGlobalDump completes successfully.
598 EXPECT_CALL(mdp
, OnMemoryDump(_
, _
)).Times(1);
599 EXPECT_CALL(*delegate_
, RequestGlobalMemoryDump(_
, _
)).Times(1);
600 InitializeMemoryDumpManager(false /* is_coordinator */);
602 MemoryDumpCallback callback
=
603 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter
, Unretained(this),
604 MessageLoop::current()->task_runner(), run_loop
.QuitClosure());
605 mdm_
->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED
,
606 MemoryDumpLevelOfDetail::DETAILED
, callback
);
608 EXPECT_TRUE(last_callback_success_
);
613 // This test (and the MemoryDumpManagerTestCoordinator below) crystallizes the
614 // expectations of the chrome://tracing UI and chrome telemetry w.r.t. periodic
615 // dumps in memory-infra, handling gracefully the transition between the legacy
616 // and the new-style (JSON-based) TraceConfig.
617 TEST_F(MemoryDumpManagerTest
, TraceConfigExpectations
) {
618 InitializeMemoryDumpManager(false /* is_coordinator */);
619 MemoryDumpManagerDelegateForTesting
& delegate
= *delegate_
;
621 // Don't trigger the default behavior of the mock delegate in this test,
622 // which would short-circuit the dump request to the actual
623 // CreateProcessDump().
624 // We don't want to create any dump in this test, only check whether the dumps
625 // are requested or not.
626 ON_CALL(delegate
, RequestGlobalMemoryDump(_
, _
)).WillByDefault(Return());
628 // Enabling memory-infra in a non-coordinator process should not trigger any
630 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
631 EXPECT_FALSE(IsPeriodicDumpingEnabled());
634 // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator
635 // process with a fully defined trigger config should NOT enable any periodic
637 EnableTracingWithTraceConfig(
638 TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(1, 5));
639 EXPECT_FALSE(IsPeriodicDumpingEnabled());
643 TEST_F(MemoryDumpManagerTest
, TraceConfigExpectationsWhenIsCoordinator
) {
644 InitializeMemoryDumpManager(true /* is_coordinator */);
645 MemoryDumpManagerDelegateForTesting
& delegate
= *delegate_
;
646 ON_CALL(delegate
, RequestGlobalMemoryDump(_
, _
)).WillByDefault(Return());
648 // Enabling memory-infra with the legacy TraceConfig (category filter) in
649 // a coordinator process should enable periodic dumps.
650 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory
);
651 EXPECT_TRUE(IsPeriodicDumpingEnabled());
654 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
655 // process without specifying any "memory_dump_config" section should enable
656 // periodic dumps. This is to preserve the behavior chrome://tracing UI, that
657 // is: ticking memory-infra should dump periodically with the default config.
658 EnableTracingWithTraceConfig(
659 TraceConfigMemoryTestUtil::GetTraceConfig_NoTriggers());
660 EXPECT_TRUE(IsPeriodicDumpingEnabled());
663 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
664 // process with an empty "memory_dump_config" should NOT enable periodic
665 // dumps. This is the way telemetry is supposed to use memory-infra with
666 // only explicitly triggered dumps.
667 EnableTracingWithTraceConfig(
668 TraceConfigMemoryTestUtil::GetTraceConfig_EmptyTriggers());
669 EXPECT_FALSE(IsPeriodicDumpingEnabled());
672 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator
673 // process with a fully defined trigger config should cause periodic dumps to
674 // be performed in the correct order.
676 auto quit_closure
= run_loop
.QuitClosure();
678 const int kHeavyDumpRate
= 5;
679 const int kLightDumpPeriodMs
= 1;
680 const int kHeavyDumpPeriodMs
= kHeavyDumpRate
* kLightDumpPeriodMs
;
681 // The expected sequence with light=1ms, heavy=5ms is H,L,L,L,L,H,...
682 testing::InSequence sequence
;
683 EXPECT_CALL(delegate
, RequestGlobalMemoryDump(IsDetailedDump(), _
));
684 EXPECT_CALL(delegate
, RequestGlobalMemoryDump(IsLightDump(), _
))
685 .Times(kHeavyDumpRate
- 1);
686 EXPECT_CALL(delegate
, RequestGlobalMemoryDump(IsDetailedDump(), _
));
687 EXPECT_CALL(delegate
, RequestGlobalMemoryDump(IsLightDump(), _
))
688 .Times(kHeavyDumpRate
- 2);
689 EXPECT_CALL(delegate
, RequestGlobalMemoryDump(IsLightDump(), _
))
690 .WillOnce(Invoke([quit_closure
](const MemoryDumpRequestArgs
& args
,
691 const MemoryDumpCallback
& callback
) {
692 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, quit_closure
);
695 // Swallow all the final spurious calls until tracing gets disabled.
696 EXPECT_CALL(delegate
, RequestGlobalMemoryDump(_
, _
)).Times(AnyNumber());
698 EnableTracingWithTraceConfig(
699 TraceConfigMemoryTestUtil::GetTraceConfig_PeriodicTriggers(
700 kLightDumpPeriodMs
, kHeavyDumpPeriodMs
));
705 } // namespace trace_event