| Index: base/trace_event/memory_dump_manager_unittest.cc
|
| diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
|
| index 65e719f00461be0ec43efd4158f18ba36d5bc743..589c4061a7f1bc83cd8bb66baa4fb032d9ba390f 100644
|
| --- a/base/trace_event/memory_dump_manager_unittest.cc
|
| +++ b/base/trace_event/memory_dump_manager_unittest.cc
|
| @@ -4,6 +4,11 @@
|
|
|
| #include "base/trace_event/memory_dump_manager.h"
|
|
|
| +#include "base/bind_helpers.h"
|
| +#include "base/memory/scoped_vector.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/threading/thread.h"
|
| #include "base/trace_event/memory_dump_provider.h"
|
| #include "base/trace_event/process_memory_dump.h"
|
| #include "testing/gmock/include/gmock/gmock.h"
|
| @@ -16,23 +21,46 @@ using testing::Return;
|
| namespace base {
|
| namespace trace_event {
|
|
|
| +// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
|
| +// instead of performing IPC dances.
|
| +class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
|
| + public:
|
| + void RequestGlobalMemoryDump(
|
| + const base::trace_event::MemoryDumpRequestArgs& args,
|
| + const MemoryDumpCallback& callback) override {
|
| + CreateProcessDump(args, callback);
|
| + }
|
| +
|
| + bool IsCoordinatorProcess() const override { return false; }
|
| +};
|
| +
|
| class MemoryDumpManagerTest : public testing::Test {
|
| public:
|
| void SetUp() override {
|
| + message_loop_.reset(new MessageLoop());
|
| mdm_.reset(new MemoryDumpManager());
|
| MemoryDumpManager::SetInstanceForTesting(mdm_.get());
|
| ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
|
| MemoryDumpManager::GetInstance()->Initialize();
|
| + MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
|
| }
|
|
|
| void TearDown() override {
|
| MemoryDumpManager::SetInstanceForTesting(nullptr);
|
| mdm_.reset();
|
| + message_loop_.reset();
|
| TraceLog::DeleteForTesting();
|
| }
|
|
|
| + void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
|
| + Closure closure,
|
| + uint64 dump_guid,
|
| + bool success) {
|
| + task_runner->PostTask(FROM_HERE, closure);
|
| + }
|
| +
|
| protected:
|
| - const char* const kTraceCategory = MemoryDumpManager::kTraceCategory;
|
| + const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;
|
|
|
| void EnableTracing(const char* category) {
|
| TraceLog::GetInstance()->SetEnabled(
|
| @@ -44,15 +72,29 @@ class MemoryDumpManagerTest : public testing::Test {
|
| scoped_ptr<MemoryDumpManager> mdm_;
|
|
|
| private:
|
| + scoped_ptr<MessageLoop> message_loop_;
|
| + MemoryDumpManagerDelegateForTesting delegate_;
|
| +
|
| // We want our singleton torn down after each test.
|
| ShadowingAtExitManager at_exit_manager_;
|
| };
|
|
|
| class MockDumpProvider : public MemoryDumpProvider {
|
| public:
|
| + MockDumpProvider() {}
|
| +
|
| + explicit MockDumpProvider(
|
| + const scoped_refptr<SingleThreadTaskRunner>& task_runner)
|
| + : MemoryDumpProvider(task_runner) {}
|
| +
|
| + // Ctor for the SharedSessionState test.
|
| + explicit MockDumpProvider(const std::string& id) {
|
| + DeclareAllocatorAttribute("allocator" + id, "attr" + id, "type" + id);
|
| + }
|
| +
|
| MOCK_METHOD1(DumpInto, bool(ProcessMemoryDump* pmd));
|
|
|
| - // DumpInto() override for the ActiveDumpProviderConsistency test,
|
| + // DumpInto() override for the ActiveDumpProviderConsistency test.
|
| bool DumpIntoAndCheckDumpProviderCurrentlyActive(ProcessMemoryDump* pmd) {
|
| EXPECT_EQ(
|
| this,
|
| @@ -60,6 +102,22 @@ class MockDumpProvider : public MemoryDumpProvider {
|
| return true;
|
| }
|
|
|
| + // DumpInto() override for the RespectTaskRunnerAffinity test.
|
| + bool DumpIntoAndCheckTaskRunner(ProcessMemoryDump* pmd) {
|
| + EXPECT_TRUE(task_runner()->RunsTasksOnCurrentThread());
|
| + return true;
|
| + }
|
| +
|
| + // DumpInto() override for the SharedSessionState test.
|
| + bool DumpIntoAndCheckSessionState(ProcessMemoryDump* pmd) {
|
| + EXPECT_TRUE(pmd->session_state());
|
| + const auto& attrs_type_info =
|
| + pmd->session_state()->allocators_attributes_type_info;
|
| + EXPECT_TRUE(attrs_type_info.Exists("allocator1", "attr1"));
|
| + EXPECT_TRUE(attrs_type_info.Exists("allocator2", "attr2"));
|
| + return true;
|
| + }
|
| +
|
| const char* GetFriendlyName() const override { return "MockDumpProvider"; }
|
| };
|
|
|
| @@ -70,7 +128,7 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
|
| // Check that the dumper is not called if the memory category is not enabled.
|
| EnableTracing("foo-and-bar-but-not-memory");
|
| EXPECT_CALL(mdp, DumpInto(_)).Times(0);
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| DisableTracing();
|
|
|
| // Now repeat enabling the memory category and check that the dumper is
|
| @@ -78,7 +136,7 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
|
| EnableTracing(kTraceCategory);
|
| EXPECT_CALL(mdp, DumpInto(_)).Times(3).WillRepeatedly(Return(true));
|
| for (int i = 0; i < 3; ++i)
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| DisableTracing();
|
|
|
| mdm_->UnregisterDumpProvider(&mdp);
|
| @@ -86,21 +144,24 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
|
| // Finally check the unregister logic (no calls to the mdp after unregister).
|
| EnableTracing(kTraceCategory);
|
| EXPECT_CALL(mdp, DumpInto(_)).Times(0);
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| TraceLog::GetInstance()->SetDisabled();
|
| }
|
|
|
| -TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileTracing) {
|
| - MockDumpProvider mdp;
|
| - mdm_->RegisterDumpProvider(&mdp);
|
| +TEST_F(MemoryDumpManagerTest, SharedSessionState) {
|
| + MockDumpProvider mdp1("1"); // Will declare an allocator property "attr1".
|
| + MockDumpProvider mdp2("2"); // Will declare an allocator property "attr2".
|
| + mdm_->RegisterDumpProvider(&mdp1);
|
| + mdm_->RegisterDumpProvider(&mdp2);
|
|
|
| EnableTracing(kTraceCategory);
|
| - EXPECT_CALL(mdp, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + EXPECT_CALL(mdp1, DumpInto(_)).Times(2).WillRepeatedly(
|
| + Invoke(&mdp1, &MockDumpProvider::DumpIntoAndCheckSessionState));
|
| + EXPECT_CALL(mdp2, DumpInto(_)).Times(2).WillRepeatedly(
|
| + Invoke(&mdp2, &MockDumpProvider::DumpIntoAndCheckSessionState));
|
|
|
| - mdm_->UnregisterDumpProvider(&mdp);
|
| - EXPECT_CALL(mdp, DumpInto(_)).Times(0);
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + for (int i = 0; i < 2; ++i)
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
|
|
| DisableTracing();
|
| }
|
| @@ -114,7 +175,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
|
| EnableTracing(kTraceCategory);
|
| EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
|
| EXPECT_CALL(mdp2, DumpInto(_)).Times(0);
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| DisableTracing();
|
|
|
| // Invert: enable mdp1 and disable mdp2.
|
| @@ -123,7 +184,7 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
|
| EnableTracing(kTraceCategory);
|
| EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
|
| EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| DisableTracing();
|
|
|
| // Enable both mdp1 and mdp2.
|
| @@ -131,7 +192,66 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
|
| EnableTracing(kTraceCategory);
|
| EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
|
| EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| + DisableTracing();
|
| +}
|
| +
|
| +// Checks that the MemoryDumpManager respects the thread affinity when a
|
| +// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
|
| +// threads and registering a MemoryDumpProvider on each of them. At each
|
| +// iteration, one thread is removed, to check the live unregistration logic.
|
| +TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
|
| + const uint32 kNumInitialThreads = 8;
|
| +
|
| + ScopedVector<Thread> threads;
|
| + ScopedVector<MockDumpProvider> mdps;
|
| +
|
| + // Create the threads and setup the expectations. Given that at each iteration
|
| + // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
|
| + // invoked a number of times equal to its index.
|
| + for (uint32 i = kNumInitialThreads; i > 0; --i) {
|
| + threads.push_back(new Thread("test thread"));
|
| + threads.back()->Start();
|
| + mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
|
| + MockDumpProvider* mdp = mdps.back();
|
| + mdm_->RegisterDumpProvider(mdp);
|
| + EXPECT_CALL(*mdp, DumpInto(_))
|
| + .Times(i)
|
| + .WillRepeatedly(
|
| + Invoke(mdp, &MockDumpProvider::DumpIntoAndCheckTaskRunner));
|
| + }
|
| +
|
| + EnableTracing(kTraceCategory);
|
| +
|
| + while (!threads.empty()) {
|
| + {
|
| + RunLoop run_loop;
|
| + MemoryDumpCallback callback =
|
| + Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
|
| + MessageLoop::current()->task_runner(), run_loop.QuitClosure());
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback);
|
| + // This nested message loop (|run_loop|) will be quit if and only if
|
| + // the RequestGlobalDump callback is invoked.
|
| + run_loop.Run();
|
| + }
|
| +
|
| + // Unregister a MDP and destroy one thread at each iteration to check the
|
| + // live unregistration logic. The unregistration needs to happen on the same
|
| + // thread the MDP belongs to.
|
| + {
|
| + RunLoop run_loop;
|
| + Closure unregistration =
|
| + Bind(&MemoryDumpManager::UnregisterDumpProvider,
|
| + Unretained(mdm_.get()), Unretained(mdps.back()));
|
| + threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
|
| + run_loop.QuitClosure());
|
| + run_loop.Run();
|
| + }
|
| + mdps.pop_back();
|
| + threads.back()->Stop();
|
| + threads.pop_back();
|
| + }
|
| +
|
| DisableTracing();
|
| }
|
|
|
| @@ -148,11 +268,11 @@ TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
|
|
|
| EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
|
| EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true));
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
|
|
| EXPECT_CALL(mdp1, DumpInto(_)).Times(0);
|
| EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(false));
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
|
|
| DisableTracing();
|
| }
|
| @@ -177,8 +297,8 @@ TEST_F(MemoryDumpManagerTest, ActiveDumpProviderConsistency) {
|
| .WillRepeatedly(Invoke(
|
| &mdp2,
|
| &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| - mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| + mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
|
| DisableTracing();
|
| }
|
|
|
|
|