OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/trace_event/memory_dump_manager.h" | 5 #include "base/trace_event/memory_dump_manager.h" |
6 | 6 |
| 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/threading/thread.h" |
7 #include "base/trace_event/memory_dump_provider.h" | 12 #include "base/trace_event/memory_dump_provider.h" |
8 #include "base/trace_event/process_memory_dump.h" | 13 #include "base/trace_event/process_memory_dump.h" |
9 #include "testing/gmock/include/gmock/gmock.h" | 14 #include "testing/gmock/include/gmock/gmock.h" |
10 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
11 | 16 |
12 using testing::_; | 17 using testing::_; |
13 using testing::Invoke; | 18 using testing::Invoke; |
14 using testing::Return; | 19 using testing::Return; |
15 | 20 |
16 namespace base { | 21 namespace base { |
17 namespace trace_event { | 22 namespace trace_event { |
18 | 23 |
| 24 // Testing MemoryDumpManagerDelegate which short-circuits dump requests locally |
| 25 // instead of performing IPC dances. |
| 26 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate { |
| 27 public: |
| 28 void RequestGlobalMemoryDump( |
| 29 const base::trace_event::MemoryDumpRequestArgs& args, |
| 30 const MemoryDumpCallback& callback) override { |
| 31 CreateProcessDump(args, callback); |
| 32 } |
| 33 |
| 34 bool IsCoordinatorProcess() const override { return false; } |
| 35 }; |
| 36 |
19 class MemoryDumpManagerTest : public testing::Test { | 37 class MemoryDumpManagerTest : public testing::Test { |
20 public: | 38 public: |
21 void SetUp() override { | 39 void SetUp() override { |
| 40 message_loop_.reset(new MessageLoop()); |
22 mdm_.reset(new MemoryDumpManager()); | 41 mdm_.reset(new MemoryDumpManager()); |
23 MemoryDumpManager::SetInstanceForTesting(mdm_.get()); | 42 MemoryDumpManager::SetInstanceForTesting(mdm_.get()); |
24 ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance()); | 43 ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance()); |
25 MemoryDumpManager::GetInstance()->Initialize(); | 44 MemoryDumpManager::GetInstance()->Initialize(); |
| 45 MemoryDumpManager::GetInstance()->SetDelegate(&delegate_); |
26 } | 46 } |
27 | 47 |
28 void TearDown() override { | 48 void TearDown() override { |
29 MemoryDumpManager::SetInstanceForTesting(nullptr); | 49 MemoryDumpManager::SetInstanceForTesting(nullptr); |
30 mdm_.reset(); | 50 mdm_.reset(); |
| 51 message_loop_.reset(); |
31 TraceLog::DeleteForTesting(); | 52 TraceLog::DeleteForTesting(); |
32 } | 53 } |
33 | 54 |
| 55 void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner, |
| 56 Closure closure, |
| 57 uint64 dump_guid, |
| 58 bool success) { |
| 59 task_runner->PostTask(FROM_HERE, closure); |
| 60 } |
| 61 |
34 protected: | 62 protected: |
35 const char* const kTraceCategory = MemoryDumpManager::kTraceCategory; | 63 const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting; |
36 | 64 |
37 void EnableTracing(const char* category) { | 65 void EnableTracing(const char* category) { |
38 TraceLog::GetInstance()->SetEnabled( | 66 TraceLog::GetInstance()->SetEnabled( |
39 CategoryFilter(category), TraceLog::RECORDING_MODE, TraceOptions()); | 67 CategoryFilter(category), TraceLog::RECORDING_MODE, TraceOptions()); |
40 } | 68 } |
41 | 69 |
42 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); } | 70 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); } |
43 | 71 |
44 scoped_ptr<MemoryDumpManager> mdm_; | 72 scoped_ptr<MemoryDumpManager> mdm_; |
45 | 73 |
46 private: | 74 private: |
| 75 scoped_ptr<MessageLoop> message_loop_; |
| 76 MemoryDumpManagerDelegateForTesting delegate_; |
| 77 |
47 // We want our singleton torn down after each test. | 78 // We want our singleton torn down after each test. |
48 ShadowingAtExitManager at_exit_manager_; | 79 ShadowingAtExitManager at_exit_manager_; |
49 }; | 80 }; |
50 | 81 |
51 class MockDumpProvider : public MemoryDumpProvider { | 82 class MockDumpProvider : public MemoryDumpProvider { |
52 public: | 83 public: |
| 84 MockDumpProvider() {} |
| 85 |
| 86 explicit MockDumpProvider( |
| 87 const scoped_refptr<SingleThreadTaskRunner>& task_runner) |
| 88 : MemoryDumpProvider(task_runner) {} |
| 89 |
| 90 // Ctor for the SharedSessionState test. |
| 91 explicit MockDumpProvider(const std::string& id) { |
| 92 DeclareAllocatorAttribute("allocator" + id, "attr" + id, "type" + id); |
| 93 } |
| 94 |
53 MOCK_METHOD1(DumpInto, bool(ProcessMemoryDump* pmd)); | 95 MOCK_METHOD1(DumpInto, bool(ProcessMemoryDump* pmd)); |
54 | 96 |
55 // DumpInto() override for the ActiveDumpProviderConsistency test, | 97 // DumpInto() override for the ActiveDumpProviderConsistency test. |
56 bool DumpIntoAndCheckDumpProviderCurrentlyActive(ProcessMemoryDump* pmd) { | 98 bool DumpIntoAndCheckDumpProviderCurrentlyActive(ProcessMemoryDump* pmd) { |
57 EXPECT_EQ( | 99 EXPECT_EQ( |
58 this, | 100 this, |
59 MemoryDumpManager::GetInstance()->dump_provider_currently_active()); | 101 MemoryDumpManager::GetInstance()->dump_provider_currently_active()); |
60 return true; | 102 return true; |
61 } | 103 } |
62 | 104 |
| 105 // DumpInto() override for the RespectTaskRunnerAffinity test. |
| 106 bool DumpIntoAndCheckTaskRunner(ProcessMemoryDump* pmd) { |
| 107 EXPECT_TRUE(task_runner()->RunsTasksOnCurrentThread()); |
| 108 return true; |
| 109 } |
| 110 |
| 111 // DumpInto() override for the SharedSessionState test. |
| 112 bool DumpIntoAndCheckSessionState(ProcessMemoryDump* pmd) { |
| 113 EXPECT_TRUE(pmd->session_state()); |
| 114 const auto& attrs_type_info = |
| 115 pmd->session_state()->allocators_attributes_type_info; |
| 116 EXPECT_TRUE(attrs_type_info.Exists("allocator1", "attr1")); |
| 117 EXPECT_TRUE(attrs_type_info.Exists("allocator2", "attr2")); |
| 118 return true; |
| 119 } |
| 120 |
63 const char* GetFriendlyName() const override { return "MockDumpProvider"; } | 121 const char* GetFriendlyName() const override { return "MockDumpProvider"; } |
64 }; | 122 }; |
65 | 123 |
66 TEST_F(MemoryDumpManagerTest, SingleDumper) { | 124 TEST_F(MemoryDumpManagerTest, SingleDumper) { |
67 MockDumpProvider mdp; | 125 MockDumpProvider mdp; |
68 mdm_->RegisterDumpProvider(&mdp); | 126 mdm_->RegisterDumpProvider(&mdp); |
69 | 127 |
70 // Check that the dumper is not called if the memory category is not enabled. | 128 // Check that the dumper is not called if the memory category is not enabled. |
71 EnableTracing("foo-and-bar-but-not-memory"); | 129 EnableTracing("foo-and-bar-but-not-memory"); |
72 EXPECT_CALL(mdp, DumpInto(_)).Times(0); | 130 EXPECT_CALL(mdp, DumpInto(_)).Times(0); |
73 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 131 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
74 DisableTracing(); | 132 DisableTracing(); |
75 | 133 |
76 // Now repeat enabling the memory category and check that the dumper is | 134 // Now repeat enabling the memory category and check that the dumper is |
77 // invoked this time. | 135 // invoked this time. |
78 EnableTracing(kTraceCategory); | 136 EnableTracing(kTraceCategory); |
79 EXPECT_CALL(mdp, DumpInto(_)).Times(3).WillRepeatedly(Return(true)); | 137 EXPECT_CALL(mdp, DumpInto(_)).Times(3).WillRepeatedly(Return(true)); |
80 for (int i = 0; i < 3; ++i) | 138 for (int i = 0; i < 3; ++i) |
81 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 139 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
82 DisableTracing(); | 140 DisableTracing(); |
83 | 141 |
84 mdm_->UnregisterDumpProvider(&mdp); | 142 mdm_->UnregisterDumpProvider(&mdp); |
85 | 143 |
86 // Finally check the unregister logic (no calls to the mdp after unregister). | 144 // Finally check the unregister logic (no calls to the mdp after unregister). |
87 EnableTracing(kTraceCategory); | 145 EnableTracing(kTraceCategory); |
88 EXPECT_CALL(mdp, DumpInto(_)).Times(0); | 146 EXPECT_CALL(mdp, DumpInto(_)).Times(0); |
89 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 147 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
90 TraceLog::GetInstance()->SetDisabled(); | 148 TraceLog::GetInstance()->SetDisabled(); |
91 } | 149 } |
92 | 150 |
93 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileTracing) { | 151 TEST_F(MemoryDumpManagerTest, SharedSessionState) { |
94 MockDumpProvider mdp; | 152 MockDumpProvider mdp1("1"); // Will declare an allocator property "attr1". |
95 mdm_->RegisterDumpProvider(&mdp); | 153 MockDumpProvider mdp2("2"); // Will declare an allocator property "attr2". |
| 154 mdm_->RegisterDumpProvider(&mdp1); |
| 155 mdm_->RegisterDumpProvider(&mdp2); |
96 | 156 |
97 EnableTracing(kTraceCategory); | 157 EnableTracing(kTraceCategory); |
98 EXPECT_CALL(mdp, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); | 158 EXPECT_CALL(mdp1, DumpInto(_)).Times(2).WillRepeatedly( |
99 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 159 Invoke(&mdp1, &MockDumpProvider::DumpIntoAndCheckSessionState)); |
| 160 EXPECT_CALL(mdp2, DumpInto(_)).Times(2).WillRepeatedly( |
| 161 Invoke(&mdp2, &MockDumpProvider::DumpIntoAndCheckSessionState)); |
100 | 162 |
101 mdm_->UnregisterDumpProvider(&mdp); | 163 for (int i = 0; i < 2; ++i) |
102 EXPECT_CALL(mdp, DumpInto(_)).Times(0); | 164 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
103 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | |
104 | 165 |
105 DisableTracing(); | 166 DisableTracing(); |
106 } | 167 } |
107 | 168 |
108 TEST_F(MemoryDumpManagerTest, MultipleDumpers) { | 169 TEST_F(MemoryDumpManagerTest, MultipleDumpers) { |
109 MockDumpProvider mdp1; | 170 MockDumpProvider mdp1; |
110 MockDumpProvider mdp2; | 171 MockDumpProvider mdp2; |
111 | 172 |
112 // Enable only mdp1. | 173 // Enable only mdp1. |
113 mdm_->RegisterDumpProvider(&mdp1); | 174 mdm_->RegisterDumpProvider(&mdp1); |
114 EnableTracing(kTraceCategory); | 175 EnableTracing(kTraceCategory); |
115 EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); | 176 EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); |
116 EXPECT_CALL(mdp2, DumpInto(_)).Times(0); | 177 EXPECT_CALL(mdp2, DumpInto(_)).Times(0); |
117 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 178 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
118 DisableTracing(); | 179 DisableTracing(); |
119 | 180 |
120 // Invert: enable mdp1 and disable mdp2. | 181 // Invert: enable mdp1 and disable mdp2. |
121 mdm_->UnregisterDumpProvider(&mdp1); | 182 mdm_->UnregisterDumpProvider(&mdp1); |
122 mdm_->RegisterDumpProvider(&mdp2); | 183 mdm_->RegisterDumpProvider(&mdp2); |
123 EnableTracing(kTraceCategory); | 184 EnableTracing(kTraceCategory); |
124 EXPECT_CALL(mdp1, DumpInto(_)).Times(0); | 185 EXPECT_CALL(mdp1, DumpInto(_)).Times(0); |
125 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); | 186 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); |
126 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 187 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
127 DisableTracing(); | 188 DisableTracing(); |
128 | 189 |
129 // Enable both mdp1 and mdp2. | 190 // Enable both mdp1 and mdp2. |
130 mdm_->RegisterDumpProvider(&mdp1); | 191 mdm_->RegisterDumpProvider(&mdp1); |
131 EnableTracing(kTraceCategory); | 192 EnableTracing(kTraceCategory); |
132 EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); | 193 EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); |
133 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); | 194 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); |
134 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 195 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
135 DisableTracing(); | 196 DisableTracing(); |
136 } | 197 } |
137 | 198 |
| 199 // Checks that the MemoryDumpManager respects the thread affinity when a |
| 200 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8 |
| 201 // threads and registering a MemoryDumpProvider on each of them. At each |
| 202 // iteration, one thread is removed, to check the live unregistration logic. |
| 203 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) { |
| 204 const uint32 kNumInitialThreads = 8; |
| 205 |
| 206 ScopedVector<Thread> threads; |
| 207 ScopedVector<MockDumpProvider> mdps; |
| 208 |
| 209 // Create the threads and setup the expectations. Given that at each iteration |
| 210 // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be |
| 211 // invoked a number of times equal to its index. |
| 212 for (uint32 i = kNumInitialThreads; i > 0; --i) { |
| 213 threads.push_back(new Thread("test thread")); |
| 214 threads.back()->Start(); |
| 215 mdps.push_back(new MockDumpProvider(threads.back()->task_runner())); |
| 216 MockDumpProvider* mdp = mdps.back(); |
| 217 mdm_->RegisterDumpProvider(mdp); |
| 218 EXPECT_CALL(*mdp, DumpInto(_)) |
| 219 .Times(i) |
| 220 .WillRepeatedly( |
| 221 Invoke(mdp, &MockDumpProvider::DumpIntoAndCheckTaskRunner)); |
| 222 } |
| 223 |
| 224 EnableTracing(kTraceCategory); |
| 225 |
| 226 while (!threads.empty()) { |
| 227 { |
| 228 RunLoop run_loop; |
| 229 MemoryDumpCallback callback = |
| 230 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), |
| 231 MessageLoop::current()->task_runner(), run_loop.QuitClosure()); |
| 232 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback); |
| 233 // This nested message loop (|run_loop|) will be quit if and only if |
| 234 // the RequestGlobalDump callback is invoked. |
| 235 run_loop.Run(); |
| 236 } |
| 237 |
| 238 // Unregister a MDP and destroy one thread at each iteration to check the |
| 239 // live unregistration logic. The unregistration needs to happen on the same |
| 240 // thread the MDP belongs to. |
| 241 { |
| 242 RunLoop run_loop; |
| 243 Closure unregistration = |
| 244 Bind(&MemoryDumpManager::UnregisterDumpProvider, |
| 245 Unretained(mdm_.get()), Unretained(mdps.back())); |
| 246 threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration, |
| 247 run_loop.QuitClosure()); |
| 248 run_loop.Run(); |
| 249 } |
| 250 mdps.pop_back(); |
| 251 threads.back()->Stop(); |
| 252 threads.pop_back(); |
| 253 } |
| 254 |
| 255 DisableTracing(); |
| 256 } |
| 257 |
138 // Enable both dump providers, make mdp1 fail and assert that only mdp2 is | 258 // Enable both dump providers, make mdp1 fail and assert that only mdp2 is |
139 // invoked the 2nd time. | 259 // invoked the 2nd time. |
140 // FIXME(primiano): remove once crbug.com/461788 gets fixed. | 260 // FIXME(primiano): remove once crbug.com/461788 gets fixed. |
141 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) { | 261 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) { |
142 MockDumpProvider mdp1; | 262 MockDumpProvider mdp1; |
143 MockDumpProvider mdp2; | 263 MockDumpProvider mdp2; |
144 | 264 |
145 mdm_->RegisterDumpProvider(&mdp1); | 265 mdm_->RegisterDumpProvider(&mdp1); |
146 mdm_->RegisterDumpProvider(&mdp2); | 266 mdm_->RegisterDumpProvider(&mdp2); |
147 EnableTracing(kTraceCategory); | 267 EnableTracing(kTraceCategory); |
148 | 268 |
149 EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(false)); | 269 EXPECT_CALL(mdp1, DumpInto(_)).Times(1).WillRepeatedly(Return(false)); |
150 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); | 270 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(true)); |
151 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 271 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
152 | 272 |
153 EXPECT_CALL(mdp1, DumpInto(_)).Times(0); | 273 EXPECT_CALL(mdp1, DumpInto(_)).Times(0); |
154 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(false)); | 274 EXPECT_CALL(mdp2, DumpInto(_)).Times(1).WillRepeatedly(Return(false)); |
155 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 275 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
156 | 276 |
157 DisableTracing(); | 277 DisableTracing(); |
158 } | 278 } |
159 | 279 |
160 // TODO(primiano): remove once crbug.com/466121 gets fixed. | 280 // TODO(primiano): remove once crbug.com/466121 gets fixed. |
161 // Ascertains that calls to MDM::dump_provider_currently_active() actually | 281 // Ascertains that calls to MDM::dump_provider_currently_active() actually |
162 // returns the MemoryDumpProvider currently active during the DumpInto() call. | 282 // returns the MemoryDumpProvider currently active during the DumpInto() call. |
163 TEST_F(MemoryDumpManagerTest, ActiveDumpProviderConsistency) { | 283 TEST_F(MemoryDumpManagerTest, ActiveDumpProviderConsistency) { |
164 MockDumpProvider mdp1; | 284 MockDumpProvider mdp1; |
165 MockDumpProvider mdp2; | 285 MockDumpProvider mdp2; |
166 | 286 |
167 mdm_->RegisterDumpProvider(&mdp1); | 287 mdm_->RegisterDumpProvider(&mdp1); |
168 mdm_->RegisterDumpProvider(&mdp2); | 288 mdm_->RegisterDumpProvider(&mdp2); |
169 EnableTracing(kTraceCategory); | 289 EnableTracing(kTraceCategory); |
170 EXPECT_CALL(mdp1, DumpInto(_)) | 290 EXPECT_CALL(mdp1, DumpInto(_)) |
171 .Times(2) | 291 .Times(2) |
172 .WillRepeatedly(Invoke( | 292 .WillRepeatedly(Invoke( |
173 &mdp1, | 293 &mdp1, |
174 &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive)); | 294 &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive)); |
175 EXPECT_CALL(mdp2, DumpInto(_)) | 295 EXPECT_CALL(mdp2, DumpInto(_)) |
176 .Times(2) | 296 .Times(2) |
177 .WillRepeatedly(Invoke( | 297 .WillRepeatedly(Invoke( |
178 &mdp2, | 298 &mdp2, |
179 &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive)); | 299 &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive)); |
180 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 300 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
181 mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED); | 301 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED); |
182 DisableTracing(); | 302 DisableTracing(); |
183 } | 303 } |
184 | 304 |
185 } // namespace trace_event | 305 } // namespace trace_event |
186 } // namespace base | 306 } // namespace base |
OLD | NEW |