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(); |
} |