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" | 7 #include "base/bind_helpers.h" |
8 #include "base/memory/scoped_vector.h" | 8 #include "base/memory/scoped_vector.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
| 11 #include "base/strings/stringprintf.h" |
11 #include "base/test/test_io_thread.h" | 12 #include "base/test/test_io_thread.h" |
12 #include "base/thread_task_runner_handle.h" | 13 #include "base/thread_task_runner_handle.h" |
13 #include "base/threading/thread.h" | 14 #include "base/threading/thread.h" |
14 #include "base/trace_event/memory_dump_provider.h" | 15 #include "base/trace_event/memory_dump_provider.h" |
15 #include "base/trace_event/process_memory_dump.h" | 16 #include "base/trace_event/process_memory_dump.h" |
16 #include "testing/gmock/include/gmock/gmock.h" | 17 #include "testing/gmock/include/gmock/gmock.h" |
17 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
18 | 19 |
19 using testing::_; | 20 using testing::_; |
| 21 using testing::AnyNumber; |
20 using testing::AtMost; | 22 using testing::AtMost; |
21 using testing::Between; | 23 using testing::Between; |
22 using testing::Invoke; | 24 using testing::Invoke; |
23 using testing::Return; | 25 using testing::Return; |
24 | 26 |
25 namespace base { | 27 namespace base { |
26 namespace trace_event { | 28 namespace trace_event { |
27 namespace { | 29 namespace { |
28 MemoryDumpArgs g_high_detail_args = {MemoryDumpArgs::LevelOfDetail::HIGH}; | 30 MemoryDumpArgs g_high_detail_args = {MemoryDumpArgs::LevelOfDetail::HIGH}; |
29 MemoryDumpArgs g_low_detail_args = {MemoryDumpArgs::LevelOfDetail::LOW}; | 31 MemoryDumpArgs g_low_detail_args = {MemoryDumpArgs::LevelOfDetail::LOW}; |
| 32 } // namespace |
| 33 |
| 34 // GTest matchers for MemoryDumpRequestArgs arguments. |
| 35 MATCHER(IsHighDetail, "") { |
| 36 return arg.level_of_detail == MemoryDumpArgs::LevelOfDetail::HIGH; |
30 } | 37 } |
31 | 38 |
32 // Testing MemoryDumpManagerDelegate which short-circuits dump requests locally | 39 MATCHER(IsLowDetail, "") { |
33 // instead of performing IPC dances. | 40 return arg.level_of_detail == MemoryDumpArgs::LevelOfDetail::LOW; |
| 41 } |
| 42 |
| 43 // GTest matchers for MemoryDumpArgs arguments. |
| 44 MATCHER(IsHighDetailArgs, "") { |
| 45 return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::HIGH; |
| 46 } |
| 47 |
| 48 MATCHER(IsLowDetailArgs, "") { |
| 49 return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::LOW; |
| 50 } |
| 51 |
| 52 // Testing MemoryDumpManagerDelegate which, by default, short-circuits dump |
| 53 // requests locally to the MemoryDumpManager instead of performing IPC dances. |
34 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate { | 54 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate { |
35 public: | 55 public: |
36 void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args, | 56 MemoryDumpManagerDelegateForTesting() { |
37 const MemoryDumpCallback& callback) override { | 57 EXPECT_CALL(*this, IsCoordinatorProcess()).WillRepeatedly(Return(false)); |
38 CreateProcessDump(args, callback); | 58 ON_CALL(*this, RequestGlobalMemoryDump(_, _)) |
| 59 .WillByDefault(Invoke( |
| 60 this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump)); |
39 } | 61 } |
40 | 62 |
41 bool IsCoordinatorProcess() const override { return false; } | 63 MOCK_METHOD2(RequestGlobalMemoryDump, |
| 64 void(const MemoryDumpRequestArgs& args, |
| 65 const MemoryDumpCallback& callback)); |
| 66 |
| 67 MOCK_CONST_METHOD0(IsCoordinatorProcess, bool()); |
| 68 |
42 uint64 GetTracingProcessId() const override { | 69 uint64 GetTracingProcessId() const override { |
| 70 NOTREACHED(); |
43 return MemoryDumpManager::kInvalidTracingProcessId; | 71 return MemoryDumpManager::kInvalidTracingProcessId; |
44 } | 72 } |
45 }; | 73 }; |
46 | 74 |
47 class MemoryDumpManagerDelegateForPeriodicDumpTest | 75 class MockMemoryDumpProvider : public MemoryDumpProvider { |
48 : public MemoryDumpManagerDelegateForTesting { | |
49 public: | 76 public: |
50 MOCK_METHOD2(RequestGlobalMemoryDump, | 77 MOCK_METHOD2(OnMemoryDump, |
51 void(const MemoryDumpRequestArgs& args, | 78 bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd)); |
52 const MemoryDumpCallback& callback)); | |
53 | |
54 bool IsCoordinatorProcess() const override { return true; } | |
55 }; | 79 }; |
56 | 80 |
57 class MemoryDumpManagerTest : public testing::Test { | 81 class MemoryDumpManagerTest : public testing::Test { |
58 public: | 82 public: |
59 void SetUp() override { | 83 void SetUp() override { |
60 last_callback_success_ = false; | 84 last_callback_success_ = false; |
61 message_loop_.reset(new MessageLoop()); | 85 message_loop_.reset(new MessageLoop()); |
62 mdm_.reset(new MemoryDumpManager()); | 86 mdm_.reset(new MemoryDumpManager()); |
63 MemoryDumpManager::SetInstanceForTesting(mdm_.get()); | 87 MemoryDumpManager::SetInstanceForTesting(mdm_.get()); |
64 ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance()); | 88 ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance()); |
65 MemoryDumpManager::GetInstance()->Initialize(); | 89 mdm_->Initialize(); |
| 90 delegate_.reset(new MemoryDumpManagerDelegateForTesting); |
| 91 mdm_->SetDelegate(delegate_.get()); |
66 } | 92 } |
67 | 93 |
68 void TearDown() override { | 94 void TearDown() override { |
69 MemoryDumpManager::SetInstanceForTesting(nullptr); | 95 MemoryDumpManager::SetInstanceForTesting(nullptr); |
70 mdm_.reset(); | 96 mdm_.reset(); |
| 97 delegate_.reset(); |
71 message_loop_.reset(); | 98 message_loop_.reset(); |
72 TraceLog::DeleteForTesting(); | 99 TraceLog::DeleteForTesting(); |
73 } | 100 } |
74 | 101 |
75 void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner, | 102 void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner, |
76 Closure closure, | 103 Closure closure, |
77 uint64 dump_guid, | 104 uint64 dump_guid, |
78 bool success) { | 105 bool success) { |
79 last_callback_success_ = success; | 106 last_callback_success_ = success; |
80 task_runner->PostTask(FROM_HERE, closure); | 107 task_runner->PostTask(FROM_HERE, closure); |
81 } | 108 } |
82 | 109 |
83 protected: | 110 protected: |
84 void SetDelegate(scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate) { | 111 // This enables tracing using the legacy category filter string. |
85 delegate_ = delegate.Pass(); | 112 void EnableTracingWithLegacyCategories(const char* category) { |
86 MemoryDumpManager::GetInstance()->SetDelegate(delegate_.get()); | 113 TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""), |
87 } | 114 TraceLog::RECORDING_MODE); |
88 | |
89 // This enalbes tracing using the legacy category filter string. | |
90 void EnableTracing(const char* category) { | |
91 if (!delegate_) { | |
92 delegate_.reset(new MemoryDumpManagerDelegateForTesting()); | |
93 MemoryDumpManager::GetInstance()->SetDelegate(delegate_.get()); | |
94 } | |
95 TraceLog::GetInstance()->SetEnabled( | |
96 TraceConfig(category, ""), TraceLog::RECORDING_MODE); | |
97 } | 115 } |
98 | 116 |
99 void EnableTracingWithTraceConfig(const char* trace_config) { | 117 void EnableTracingWithTraceConfig(const char* trace_config) { |
100 DCHECK(delegate_); | 118 TraceLog::GetInstance()->SetEnabled(TraceConfig(trace_config), |
101 TraceConfig tc(trace_config); | 119 TraceLog::RECORDING_MODE); |
102 TraceLog::GetInstance()->SetEnabled(tc, TraceLog::RECORDING_MODE); | |
103 } | 120 } |
104 | 121 |
105 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); } | 122 void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); } |
106 | 123 |
| 124 bool IsPeriodicDumpingEnabled() const { |
| 125 return mdm_->periodic_dump_timer_.IsRunning(); |
| 126 } |
| 127 |
107 scoped_ptr<MemoryDumpManager> mdm_; | 128 scoped_ptr<MemoryDumpManager> mdm_; |
| 129 scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_; |
108 bool last_callback_success_; | 130 bool last_callback_success_; |
109 scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_; | |
110 | 131 |
111 private: | 132 private: |
112 scoped_ptr<MessageLoop> message_loop_; | 133 scoped_ptr<MessageLoop> message_loop_; |
113 | 134 |
114 // We want our singleton torn down after each test. | 135 // We want our singleton torn down after each test. |
115 ShadowingAtExitManager at_exit_manager_; | 136 ShadowingAtExitManager at_exit_manager_; |
116 }; | 137 }; |
117 | 138 |
118 class MockDumpProvider : public MemoryDumpProvider { | 139 // Basic sanity checks. Registers a memory dump provider and checks that it is |
119 public: | 140 // called, but only when memory-infra is enabled. |
120 MockDumpProvider() | |
121 : dump_provider_to_register_or_unregister(nullptr), | |
122 last_session_state_(nullptr), | |
123 level_of_detail_(MemoryDumpArgs::LevelOfDetail::HIGH) {} | |
124 | |
125 // Ctor used by the RespectTaskRunnerAffinity test. | |
126 explicit MockDumpProvider( | |
127 const scoped_refptr<SingleThreadTaskRunner>& task_runner) | |
128 : last_session_state_(nullptr), | |
129 task_runner_(task_runner), | |
130 level_of_detail_(MemoryDumpArgs::LevelOfDetail::HIGH) {} | |
131 | |
132 // Ctor used by CheckMemoryDumpArgs test. | |
133 explicit MockDumpProvider(const MemoryDumpArgs::LevelOfDetail level_of_detail) | |
134 : last_session_state_(nullptr), level_of_detail_(level_of_detail) {} | |
135 | |
136 virtual ~MockDumpProvider() {} | |
137 | |
138 MOCK_METHOD2(OnMemoryDump, | |
139 bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd)); | |
140 | |
141 // OnMemoryDump() override for the RespectTaskRunnerAffinity test. | |
142 bool OnMemoryDump_CheckTaskRunner(const MemoryDumpArgs& args, | |
143 ProcessMemoryDump* pmd) { | |
144 EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread()); | |
145 return true; | |
146 } | |
147 | |
148 // OnMemoryDump() override for the SharedSessionState test. | |
149 bool OnMemoryDump_CheckSessionState(const MemoryDumpArgs& args, | |
150 ProcessMemoryDump* pmd) { | |
151 MemoryDumpSessionState* cur_session_state = pmd->session_state().get(); | |
152 if (last_session_state_) | |
153 EXPECT_EQ(last_session_state_, cur_session_state); | |
154 last_session_state_ = cur_session_state; | |
155 return true; | |
156 } | |
157 | |
158 // OnMemoryDump() override for the RegisterDumperWhileDumping test. | |
159 bool OnMemoryDump_RegisterExtraDumpProvider(const MemoryDumpArgs& args, | |
160 ProcessMemoryDump* pmd) { | |
161 MemoryDumpManager::GetInstance()->RegisterDumpProvider( | |
162 dump_provider_to_register_or_unregister); | |
163 return true; | |
164 } | |
165 | |
166 // OnMemoryDump() override for the UnegisterDumperWhileDumping test. | |
167 bool OnMemoryDump_UnregisterDumpProvider(const MemoryDumpArgs& args, | |
168 ProcessMemoryDump* pmd) { | |
169 MemoryDumpManager::GetInstance()->UnregisterDumpProvider( | |
170 dump_provider_to_register_or_unregister); | |
171 return true; | |
172 } | |
173 | |
174 // OnMemoryDump() override for the CheckMemoryDumpArgs test. | |
175 bool OnMemoryDump_CheckMemoryDumpArgs(const MemoryDumpArgs& args, | |
176 ProcessMemoryDump* pmd) { | |
177 EXPECT_EQ(level_of_detail_, args.level_of_detail); | |
178 return true; | |
179 } | |
180 | |
181 // Used by OnMemoryDump_(Un)RegisterExtraDumpProvider. | |
182 MemoryDumpProvider* dump_provider_to_register_or_unregister; | |
183 | |
184 private: | |
185 MemoryDumpSessionState* last_session_state_; | |
186 scoped_refptr<SingleThreadTaskRunner> task_runner_; | |
187 const MemoryDumpArgs::LevelOfDetail level_of_detail_; | |
188 }; | |
189 | |
190 TEST_F(MemoryDumpManagerTest, SingleDumper) { | 141 TEST_F(MemoryDumpManagerTest, SingleDumper) { |
191 MockDumpProvider mdp; | 142 MockMemoryDumpProvider mdp; |
192 mdm_->RegisterDumpProvider(&mdp); | 143 mdm_->RegisterDumpProvider(&mdp); |
193 | 144 |
194 // Check that the dumper is not called if the memory category is not enabled. | 145 // Check that the dumper is not called if the memory category is not enabled. |
195 EnableTracing("foo-and-bar-but-not-memory"); | 146 EnableTracingWithLegacyCategories("foobar-but-not-memory"); |
| 147 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0); |
196 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); | 148 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); |
197 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 149 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
198 g_high_detail_args); | 150 g_high_detail_args); |
199 DisableTracing(); | 151 DisableTracing(); |
200 | 152 |
201 // Now repeat enabling the memory category and check that the dumper is | 153 // Now repeat enabling the memory category and check that the dumper is |
202 // invoked this time. | 154 // invoked this time. |
203 EnableTracing(MemoryDumpManager::kTraceCategory); | 155 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
| 156 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3); |
204 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true)); | 157 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true)); |
205 for (int i = 0; i < 3; ++i) | 158 for (int i = 0; i < 3; ++i) |
206 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 159 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
207 g_high_detail_args); | 160 g_high_detail_args); |
208 DisableTracing(); | 161 DisableTracing(); |
209 | 162 |
210 mdm_->UnregisterDumpProvider(&mdp); | 163 mdm_->UnregisterDumpProvider(&mdp); |
211 | 164 |
212 // Finally check the unregister logic (no calls to the mdp after unregister). | 165 // Finally check the unregister logic: the delegate will be invoked but not |
213 EnableTracing(MemoryDumpManager::kTraceCategory); | 166 // the dump provider, as it has been unregistered. |
| 167 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
| 168 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
214 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); | 169 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); |
215 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 170 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
216 g_high_detail_args); | 171 g_high_detail_args); |
217 TraceLog::GetInstance()->SetDisabled(); | 172 TraceLog::GetInstance()->SetDisabled(); |
218 } | 173 } |
219 | 174 |
| 175 // Checks that requesting dumps with high level of detail actually propagates |
| 176 // the level of the detail properly to OnMemoryDump() call on dump providers. |
220 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) { | 177 TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) { |
221 // Check that requesting dumps with high level of detail actually propagates | 178 MockMemoryDumpProvider mdp; |
222 // to OnMemoryDump() call on dump providers. | |
223 MockDumpProvider mdp_high_detail(MemoryDumpArgs::LevelOfDetail::HIGH); | |
224 mdm_->RegisterDumpProvider(&mdp_high_detail); | |
225 | 179 |
226 EnableTracing(MemoryDumpManager::kTraceCategory); | 180 mdm_->RegisterDumpProvider(&mdp); |
227 EXPECT_CALL(mdp_high_detail, OnMemoryDump(_, _)) | 181 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
228 .Times(1) | 182 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
229 .WillRepeatedly( | 183 EXPECT_CALL(mdp, OnMemoryDump(IsHighDetail(), _)).WillOnce(Return(true)); |
230 Invoke(&mdp_high_detail, | |
231 &MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs)); | |
232 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 184 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
233 g_high_detail_args); | 185 g_high_detail_args); |
234 DisableTracing(); | 186 DisableTracing(); |
235 mdm_->UnregisterDumpProvider(&mdp_high_detail); | 187 mdm_->UnregisterDumpProvider(&mdp); |
236 | 188 |
237 // Check that requesting dumps with low level of detail actually propagates to | 189 // Check that requesting dumps with low level of detail actually propagates to |
238 // OnMemoryDump() call on dump providers. | 190 // OnMemoryDump() call on dump providers. |
239 MockDumpProvider mdp_low_detail(MemoryDumpArgs::LevelOfDetail::LOW); | 191 mdm_->RegisterDumpProvider(&mdp); |
240 mdm_->RegisterDumpProvider(&mdp_low_detail); | 192 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
241 | 193 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
242 EnableTracing(MemoryDumpManager::kTraceCategory); | 194 EXPECT_CALL(mdp, OnMemoryDump(IsLowDetail(), _)).WillOnce(Return(true)); |
243 EXPECT_CALL(mdp_low_detail, OnMemoryDump(_, _)) | |
244 .Times(1) | |
245 .WillRepeatedly( | |
246 Invoke(&mdp_low_detail, | |
247 &MockDumpProvider::OnMemoryDump_CheckMemoryDumpArgs)); | |
248 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 195 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
249 g_low_detail_args); | 196 g_low_detail_args); |
250 DisableTracing(); | 197 DisableTracing(); |
251 mdm_->UnregisterDumpProvider(&mdp_low_detail); | 198 mdm_->UnregisterDumpProvider(&mdp); |
252 } | 199 } |
253 | 200 |
| 201 // Checks that the SharedSessionState object is acqually shared over time. |
254 TEST_F(MemoryDumpManagerTest, SharedSessionState) { | 202 TEST_F(MemoryDumpManagerTest, SharedSessionState) { |
255 MockDumpProvider mdp1; | 203 MockMemoryDumpProvider mdp1; |
256 MockDumpProvider mdp2; | 204 MockMemoryDumpProvider mdp2; |
257 mdm_->RegisterDumpProvider(&mdp1); | 205 mdm_->RegisterDumpProvider(&mdp1); |
258 mdm_->RegisterDumpProvider(&mdp2); | 206 mdm_->RegisterDumpProvider(&mdp2); |
259 | 207 |
260 EnableTracing(MemoryDumpManager::kTraceCategory); | 208 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
| 209 const MemoryDumpSessionState* session_state = mdm_->session_state().get(); |
| 210 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2); |
261 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) | 211 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) |
262 .Times(2) | 212 .Times(2) |
263 .WillRepeatedly( | 213 .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&, |
264 Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState)); | 214 ProcessMemoryDump* pmd) -> bool { |
| 215 EXPECT_EQ(session_state, pmd->session_state().get()); |
| 216 return true; |
| 217 })); |
265 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) | 218 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) |
266 .Times(2) | 219 .Times(2) |
267 .WillRepeatedly( | 220 .WillRepeatedly(Invoke([session_state](const MemoryDumpArgs&, |
268 Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState)); | 221 ProcessMemoryDump* pmd) -> bool { |
| 222 EXPECT_EQ(session_state, pmd->session_state().get()); |
| 223 return true; |
| 224 })); |
269 | 225 |
270 for (int i = 0; i < 2; ++i) | 226 for (int i = 0; i < 2; ++i) |
271 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 227 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
272 g_high_detail_args); | 228 g_high_detail_args); |
273 | 229 |
274 DisableTracing(); | 230 DisableTracing(); |
275 } | 231 } |
276 | 232 |
| 233 // Checks that the (Un)RegisterDumpProvider logic behaves sanely. |
277 TEST_F(MemoryDumpManagerTest, MultipleDumpers) { | 234 TEST_F(MemoryDumpManagerTest, MultipleDumpers) { |
278 MockDumpProvider mdp1; | 235 MockMemoryDumpProvider mdp1; |
279 MockDumpProvider mdp2; | 236 MockMemoryDumpProvider mdp2; |
280 | 237 |
281 // Enable only mdp1. | 238 // Enable only mdp1. |
282 mdm_->RegisterDumpProvider(&mdp1); | 239 mdm_->RegisterDumpProvider(&mdp1); |
283 EnableTracing(MemoryDumpManager::kTraceCategory); | 240 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
284 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true)); | 241 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
| 242 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true)); |
285 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0); | 243 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0); |
286 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 244 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
287 g_high_detail_args); | 245 g_high_detail_args); |
288 DisableTracing(); | 246 DisableTracing(); |
289 | 247 |
290 // Invert: enable mdp1 and disable mdp2. | 248 // Invert: enable mdp1 and disable mdp2. |
291 mdm_->UnregisterDumpProvider(&mdp1); | 249 mdm_->UnregisterDumpProvider(&mdp1); |
292 mdm_->RegisterDumpProvider(&mdp2); | 250 mdm_->RegisterDumpProvider(&mdp2); |
293 EnableTracing(MemoryDumpManager::kTraceCategory); | 251 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
| 252 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
294 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); | 253 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); |
295 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true)); | 254 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true)); |
296 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 255 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
297 g_high_detail_args); | 256 g_high_detail_args); |
298 DisableTracing(); | 257 DisableTracing(); |
299 | 258 |
300 // Enable both mdp1 and mdp2. | 259 // Enable both mdp1 and mdp2. |
301 mdm_->RegisterDumpProvider(&mdp1); | 260 mdm_->RegisterDumpProvider(&mdp1); |
302 EnableTracing(MemoryDumpManager::kTraceCategory); | 261 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
303 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true)); | 262 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
304 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true)); | 263 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true)); |
| 264 EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true)); |
305 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 265 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
306 g_high_detail_args); | 266 g_high_detail_args); |
307 DisableTracing(); | 267 DisableTracing(); |
308 } | 268 } |
309 | 269 |
310 // Verify that whether OnMemoryDump is called depends only on the current | 270 // Checks that the dump provider invocations depend only on the current |
311 // registration state and not on previous registrations and dumps. | 271 // registration state and not on previous registrations and dumps. |
312 TEST_F(MemoryDumpManagerTest, RegistrationConsistency) { | 272 TEST_F(MemoryDumpManagerTest, RegistrationConsistency) { |
313 MockDumpProvider mdp; | 273 MockMemoryDumpProvider mdp; |
314 | 274 |
315 mdm_->RegisterDumpProvider(&mdp); | 275 mdm_->RegisterDumpProvider(&mdp); |
316 | 276 |
317 { | 277 { |
318 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1); | 278 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
319 EnableTracing(MemoryDumpManager::kTraceCategory); | 279 EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true)); |
| 280 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
320 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 281 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
321 g_high_detail_args); | 282 g_high_detail_args); |
322 DisableTracing(); | 283 DisableTracing(); |
323 } | 284 } |
324 | 285 |
325 mdm_->UnregisterDumpProvider(&mdp); | 286 mdm_->UnregisterDumpProvider(&mdp); |
326 | 287 |
327 { | 288 { |
| 289 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
328 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); | 290 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); |
329 EnableTracing(MemoryDumpManager::kTraceCategory); | 291 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
330 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 292 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
331 g_high_detail_args); | 293 g_high_detail_args); |
332 DisableTracing(); | 294 DisableTracing(); |
333 } | 295 } |
334 | 296 |
335 mdm_->RegisterDumpProvider(&mdp); | 297 mdm_->RegisterDumpProvider(&mdp); |
336 mdm_->UnregisterDumpProvider(&mdp); | 298 mdm_->UnregisterDumpProvider(&mdp); |
337 | 299 |
338 { | 300 { |
| 301 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
339 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); | 302 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0); |
340 EnableTracing(MemoryDumpManager::kTraceCategory); | 303 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
341 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 304 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
342 g_high_detail_args); | 305 g_high_detail_args); |
343 DisableTracing(); | 306 DisableTracing(); |
344 } | 307 } |
345 | 308 |
346 mdm_->RegisterDumpProvider(&mdp); | 309 mdm_->RegisterDumpProvider(&mdp); |
347 mdm_->UnregisterDumpProvider(&mdp); | 310 mdm_->UnregisterDumpProvider(&mdp); |
348 mdm_->RegisterDumpProvider(&mdp); | 311 mdm_->RegisterDumpProvider(&mdp); |
349 | 312 |
350 { | 313 { |
351 EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1); | 314 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
352 EnableTracing(MemoryDumpManager::kTraceCategory); | 315 EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true)); |
| 316 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
353 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 317 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
354 g_high_detail_args); | 318 g_high_detail_args); |
355 DisableTracing(); | 319 DisableTracing(); |
356 } | 320 } |
357 } | 321 } |
358 | 322 |
359 // Checks that the MemoryDumpManager respects the thread affinity when a | 323 // Checks that the MemoryDumpManager respects the thread affinity when a |
360 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8 | 324 // MemoryDumpProvider specifies a task_runner(). The test starts creating 8 |
361 // threads and registering a MemoryDumpProvider on each of them. At each | 325 // threads and registering a MemoryDumpProvider on each of them. At each |
362 // iteration, one thread is removed, to check the live unregistration logic. | 326 // iteration, one thread is removed, to check the live unregistration logic. |
363 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) { | 327 TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) { |
364 const uint32 kNumInitialThreads = 8; | 328 const uint32 kNumInitialThreads = 8; |
365 | 329 |
366 ScopedVector<Thread> threads; | 330 ScopedVector<Thread> threads; |
367 ScopedVector<MockDumpProvider> mdps; | 331 ScopedVector<MockMemoryDumpProvider> mdps; |
368 | 332 |
369 // Create the threads and setup the expectations. Given that at each iteration | 333 // Create the threads and setup the expectations. Given that at each iteration |
370 // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be | 334 // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be |
371 // invoked a number of times equal to its index. | 335 // invoked a number of times equal to its index. |
372 for (uint32 i = kNumInitialThreads; i > 0; --i) { | 336 for (uint32 i = kNumInitialThreads; i > 0; --i) { |
373 threads.push_back(new Thread("test thread")); | 337 Thread* thread = new Thread("test thread"); |
| 338 threads.push_back(thread); |
374 threads.back()->Start(); | 339 threads.back()->Start(); |
375 mdps.push_back(new MockDumpProvider(threads.back()->task_runner())); | 340 scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner(); |
376 MockDumpProvider* mdp = mdps.back(); | 341 MockMemoryDumpProvider* mdp = new MockMemoryDumpProvider(); |
377 mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner()); | 342 mdps.push_back(mdp); |
| 343 mdm_->RegisterDumpProvider(mdp, task_runner); |
378 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) | 344 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) |
379 .Times(i) | 345 .Times(i) |
380 .WillRepeatedly( | 346 .WillRepeatedly(Invoke( |
381 Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner)); | 347 [task_runner](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { |
| 348 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread()); |
| 349 return true; |
| 350 })); |
382 } | 351 } |
383 | 352 |
384 EnableTracing(MemoryDumpManager::kTraceCategory); | 353 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
385 | 354 |
386 while (!threads.empty()) { | 355 while (!threads.empty()) { |
387 last_callback_success_ = false; | 356 last_callback_success_ = false; |
388 { | 357 { |
389 RunLoop run_loop; | 358 RunLoop run_loop; |
390 MemoryDumpCallback callback = | 359 MemoryDumpCallback callback = |
391 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), | 360 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), |
392 MessageLoop::current()->task_runner(), run_loop.QuitClosure()); | 361 MessageLoop::current()->task_runner(), run_loop.QuitClosure()); |
| 362 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1); |
393 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 363 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
394 g_high_detail_args, callback); | 364 g_high_detail_args, callback); |
395 // This nested message loop (|run_loop|) will be quit if and only if | 365 // This nested message loop (|run_loop|) will quit if and only if the |
396 // the RequestGlobalDump callback is invoked. | 366 // |callback| passed to RequestGlobalDump() is invoked. |
397 run_loop.Run(); | 367 run_loop.Run(); |
398 } | 368 } |
399 EXPECT_TRUE(last_callback_success_); | 369 EXPECT_TRUE(last_callback_success_); |
400 | 370 |
401 // Unregister a MDP and destroy one thread at each iteration to check the | 371 // Unregister a MDP and destroy one thread at each iteration to check the |
402 // live unregistration logic. The unregistration needs to happen on the same | 372 // live unregistration logic. The unregistration needs to happen on the same |
403 // thread the MDP belongs to. | 373 // thread the MDP belongs to. |
404 { | 374 { |
405 RunLoop run_loop; | 375 RunLoop run_loop; |
406 Closure unregistration = | 376 Closure unregistration = |
407 Bind(&MemoryDumpManager::UnregisterDumpProvider, | 377 Bind(&MemoryDumpManager::UnregisterDumpProvider, |
408 Unretained(mdm_.get()), Unretained(mdps.back())); | 378 Unretained(mdm_.get()), Unretained(mdps.back())); |
409 threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration, | 379 threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration, |
410 run_loop.QuitClosure()); | 380 run_loop.QuitClosure()); |
411 run_loop.Run(); | 381 run_loop.Run(); |
412 } | 382 } |
413 mdps.pop_back(); | 383 mdps.pop_back(); |
414 threads.back()->Stop(); | 384 threads.back()->Stop(); |
415 threads.pop_back(); | 385 threads.pop_back(); |
416 } | 386 } |
417 | 387 |
418 DisableTracing(); | 388 DisableTracing(); |
419 } | 389 } |
420 | 390 |
421 // Enable both dump providers, make sure that mdp gets disabled after 3 failures | 391 // Checks that providers get disabled after 3 consecutive failures, but not |
422 // and not disabled after 1. | 392 // otherwise (e.g., if interleaved). |
423 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) { | 393 TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) { |
424 MockDumpProvider mdp1; | 394 MockMemoryDumpProvider mdp1; |
425 MockDumpProvider mdp2; | 395 MockMemoryDumpProvider mdp2; |
426 | 396 |
427 mdm_->RegisterDumpProvider(&mdp1); | 397 mdm_->RegisterDumpProvider(&mdp1); |
428 mdm_->RegisterDumpProvider(&mdp2); | 398 mdm_->RegisterDumpProvider(&mdp2); |
429 EnableTracing(MemoryDumpManager::kTraceCategory); | 399 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
| 400 |
| 401 const int kNumDumps = 2 * MemoryDumpManager::kMaxConsecutiveFailuresCount; |
| 402 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(kNumDumps); |
430 | 403 |
431 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) | 404 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) |
432 .Times(MemoryDumpManager::kMaxConsecutiveFailuresCount) | 405 .Times(MemoryDumpManager::kMaxConsecutiveFailuresCount) |
433 .WillRepeatedly(Return(false)); | 406 .WillRepeatedly(Return(false)); |
434 | 407 |
435 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) | 408 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) |
436 .Times(1 + MemoryDumpManager::kMaxConsecutiveFailuresCount) | |
437 .WillOnce(Return(false)) | 409 .WillOnce(Return(false)) |
438 .WillRepeatedly(Return(true)); | 410 .WillOnce(Return(true)) |
439 for (int i = 0; i < 1 + MemoryDumpManager::kMaxConsecutiveFailuresCount; | 411 .WillOnce(Return(false)) |
440 i++) { | 412 .WillOnce(Return(false)) |
| 413 .WillOnce(Return(true)) |
| 414 .WillOnce(Return(false)); |
| 415 |
| 416 for (int i = 0; i < kNumDumps; i++) { |
441 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 417 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
442 g_high_detail_args); | 418 g_high_detail_args); |
443 } | 419 } |
444 | 420 |
445 DisableTracing(); | 421 DisableTracing(); |
446 } | 422 } |
447 | 423 |
448 // Sneakily register an extra memory dump provider while an existing one is | 424 // Sneakily registers an extra memory dump provider while an existing one is |
449 // dumping and expect it to take part in the already active tracing session. | 425 // dumping and expect it to take part in the already active tracing session. |
450 TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) { | 426 TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) { |
451 MockDumpProvider mdp1; | 427 MockMemoryDumpProvider mdp1; |
452 MockDumpProvider mdp2; | 428 MockMemoryDumpProvider mdp2; |
453 | 429 |
454 mdp1.dump_provider_to_register_or_unregister = &mdp2; | |
455 mdm_->RegisterDumpProvider(&mdp1); | 430 mdm_->RegisterDumpProvider(&mdp1); |
456 EnableTracing(MemoryDumpManager::kTraceCategory); | 431 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
| 432 |
| 433 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4); |
457 | 434 |
458 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) | 435 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) |
459 .Times(4) | 436 .Times(4) |
460 .WillOnce(Return(true)) | 437 .WillOnce(Return(true)) |
461 .WillOnce(Invoke( | 438 .WillOnce( |
462 &mdp1, &MockDumpProvider::OnMemoryDump_RegisterExtraDumpProvider)) | 439 Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { |
| 440 MemoryDumpManager::GetInstance()->RegisterDumpProvider(&mdp2); |
| 441 return true; |
| 442 })) |
463 .WillRepeatedly(Return(true)); | 443 .WillRepeatedly(Return(true)); |
464 | 444 |
465 // Depending on the insertion order (before or after mdp1), mdp2 might be | 445 // Depending on the insertion order (before or after mdp1), mdp2 might be |
466 // called also immediately after it gets registered. | 446 // called also immediately after it gets registered. |
467 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) | 447 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) |
468 .Times(Between(2, 3)) | 448 .Times(Between(2, 3)) |
469 .WillRepeatedly(Return(true)); | 449 .WillRepeatedly(Return(true)); |
470 | 450 |
471 for (int i = 0; i < 4; i++) { | 451 for (int i = 0; i < 4; i++) { |
472 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 452 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
473 g_high_detail_args); | 453 g_high_detail_args); |
474 } | 454 } |
475 | 455 |
476 DisableTracing(); | 456 DisableTracing(); |
477 } | 457 } |
478 | 458 |
479 // Like the above, but suddenly unregister the dump provider. | 459 // Like RegisterDumperWhileDumping, but unregister the dump provider instead. |
480 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) { | 460 TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) { |
481 MockDumpProvider mdp1; | 461 MockMemoryDumpProvider mdp1; |
482 MockDumpProvider mdp2; | 462 MockMemoryDumpProvider mdp2; |
483 | 463 |
484 mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get()); | 464 mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get()); |
485 mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get()); | 465 mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get()); |
486 mdp1.dump_provider_to_register_or_unregister = &mdp2; | 466 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
487 EnableTracing(MemoryDumpManager::kTraceCategory); | 467 |
| 468 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4); |
488 | 469 |
489 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) | 470 EXPECT_CALL(mdp1, OnMemoryDump(_, _)) |
490 .Times(4) | 471 .Times(4) |
491 .WillOnce(Return(true)) | 472 .WillOnce(Return(true)) |
492 .WillOnce( | 473 .WillOnce( |
493 Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_UnregisterDumpProvider)) | 474 Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool { |
| 475 MemoryDumpManager::GetInstance()->UnregisterDumpProvider(&mdp2); |
| 476 return true; |
| 477 })) |
494 .WillRepeatedly(Return(true)); | 478 .WillRepeatedly(Return(true)); |
495 | 479 |
496 // Depending on the insertion order (before or after mdp1), mdp2 might have | 480 // Depending on the insertion order (before or after mdp1), mdp2 might have |
497 // been already called when OnMemoryDump_UnregisterDumpProvider happens. | 481 // been already called when UnregisterDumpProvider happens. |
498 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) | 482 EXPECT_CALL(mdp2, OnMemoryDump(_, _)) |
499 .Times(Between(1, 2)) | 483 .Times(Between(1, 2)) |
500 .WillRepeatedly(Return(true)); | 484 .WillRepeatedly(Return(true)); |
501 | 485 |
502 for (int i = 0; i < 4; i++) { | 486 for (int i = 0; i < 4; i++) { |
503 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 487 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
504 g_high_detail_args); | 488 g_high_detail_args); |
505 } | 489 } |
506 | 490 |
507 DisableTracing(); | 491 DisableTracing(); |
508 } | 492 } |
509 | 493 |
510 // Verify that the dump does not abort when unregistering a provider while | 494 // Checks that the dump does not abort when unregistering a provider while |
511 // dumping from a different thread than the dumping thread. | 495 // dumping from a different thread than the dumping thread. |
512 TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) { | 496 TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) { |
513 ScopedVector<TestIOThread> threads; | 497 ScopedVector<TestIOThread> threads; |
514 ScopedVector<MockDumpProvider> mdps; | 498 ScopedVector<MockMemoryDumpProvider> mdps; |
515 | 499 |
516 for (int i = 0; i < 2; i++) { | 500 for (int i = 0; i < 2; i++) { |
517 threads.push_back(new TestIOThread(TestIOThread::kAutoStart)); | 501 threads.push_back(new TestIOThread(TestIOThread::kAutoStart)); |
518 mdps.push_back(new MockDumpProvider(threads.back()->task_runner())); | 502 mdps.push_back(new MockMemoryDumpProvider()); |
519 mdm_->RegisterDumpProvider(mdps.back(), threads.back()->task_runner()); | 503 mdm_->RegisterDumpProvider(mdps.back(), threads.back()->task_runner()); |
520 } | 504 } |
521 | 505 |
522 int on_memory_dump_call_count = 0; | 506 int on_memory_dump_call_count = 0; |
523 RunLoop run_loop; | 507 RunLoop run_loop; |
524 | 508 |
525 // When OnMemoryDump is called on either of the dump providers, it will | 509 // When OnMemoryDump is called on either of the dump providers, it will |
526 // unregister the other one. | 510 // unregister the other one. |
527 for (MockDumpProvider* mdp : mdps) { | 511 for (MockMemoryDumpProvider* mdp : mdps) { |
528 int other_idx = (mdps.front() == mdp); | 512 int other_idx = (mdps.front() == mdp); |
529 TestIOThread* other_thread = threads[other_idx]; | 513 TestIOThread* other_thread = threads[other_idx]; |
530 MockDumpProvider* other_mdp = mdps[other_idx]; | 514 MockMemoryDumpProvider* other_mdp = mdps[other_idx]; |
531 auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count]( | 515 auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count]( |
532 const MemoryDumpArgs& args, ProcessMemoryDump* pmd) { | 516 const MemoryDumpArgs& args, ProcessMemoryDump* pmd) { |
533 other_thread->PostTaskAndWait( | 517 other_thread->PostTaskAndWait( |
534 FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider, | 518 FROM_HERE, base::Bind(&MemoryDumpManager::UnregisterDumpProvider, |
535 base::Unretained(&*mdm_), other_mdp)); | 519 base::Unretained(&*mdm_), other_mdp)); |
536 on_memory_dump_call_count++; | 520 on_memory_dump_call_count++; |
537 return true; | 521 return true; |
538 }; | 522 }; |
539 | 523 |
540 // OnMemoryDump is called once for the provider that dumps first, and zero | 524 // OnMemoryDump is called once for the provider that dumps first, and zero |
541 // times for the other provider. | 525 // times for the other provider. |
542 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) | 526 EXPECT_CALL(*mdp, OnMemoryDump(_, _)) |
543 .Times(AtMost(1)) | 527 .Times(AtMost(1)) |
544 .WillOnce(Invoke(on_dump)); | 528 .WillOnce(Invoke(on_dump)); |
545 } | 529 } |
546 | 530 |
547 last_callback_success_ = false; | 531 last_callback_success_ = false; |
548 MemoryDumpCallback callback = | 532 MemoryDumpCallback callback = |
549 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), | 533 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), |
550 MessageLoop::current()->task_runner(), run_loop.QuitClosure()); | 534 MessageLoop::current()->task_runner(), run_loop.QuitClosure()); |
551 | 535 |
552 EnableTracing(MemoryDumpManager::kTraceCategory); | 536 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
553 MemoryDumpRequestArgs request_args = {0, MemoryDumpType::EXPLICITLY_TRIGGERED, | 537 MemoryDumpRequestArgs request_args = {0, MemoryDumpType::EXPLICITLY_TRIGGERED, |
554 g_high_detail_args}; | 538 g_high_detail_args}; |
555 mdm_->CreateProcessDump(request_args, callback); | 539 mdm_->CreateProcessDump(request_args, callback); |
556 | 540 |
557 run_loop.Run(); | 541 run_loop.Run(); |
558 | 542 |
559 ASSERT_EQ(1, on_memory_dump_call_count); | 543 ASSERT_EQ(1, on_memory_dump_call_count); |
560 ASSERT_EQ(true, last_callback_success_); | 544 ASSERT_EQ(true, last_callback_success_); |
561 | 545 |
562 DisableTracing(); | 546 DisableTracing(); |
563 } | 547 } |
564 | 548 |
565 // Ensures that a NACK callback is invoked if RequestGlobalDump is called when | 549 // Checks that a NACK callback is invoked if RequestGlobalDump() is called when |
566 // tracing is not enabled. | 550 // tracing is not enabled. |
567 TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) { | 551 TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) { |
568 MockDumpProvider mdp1; | 552 MockMemoryDumpProvider mdp1; |
| 553 mdm_->RegisterDumpProvider(&mdp1); |
569 | 554 |
570 mdm_->RegisterDumpProvider(&mdp1); | 555 EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0); |
571 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); | 556 EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0); |
572 | 557 |
573 last_callback_success_ = true; | 558 last_callback_success_ = true; |
574 { | 559 { |
575 RunLoop run_loop; | 560 RunLoop run_loop; |
576 MemoryDumpCallback callback = | 561 MemoryDumpCallback callback = |
577 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), | 562 Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this), |
578 MessageLoop::current()->task_runner(), run_loop.QuitClosure()); | 563 MessageLoop::current()->task_runner(), run_loop.QuitClosure()); |
579 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, | 564 mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, |
580 g_high_detail_args, callback); | 565 g_high_detail_args, callback); |
581 run_loop.Run(); | 566 run_loop.Run(); |
582 } | 567 } |
583 EXPECT_FALSE(last_callback_success_); | 568 EXPECT_FALSE(last_callback_success_); |
584 } | 569 } |
585 | 570 |
586 MATCHER(IsHighDetail, "") { | 571 // This test crystallizes the expectations of the chrome://tracing UI and |
587 return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::HIGH; | 572 // chrome telemetry w.r.t. periodic dumps in memory-infra, handling gracefully |
588 } | 573 // the transition between the legacy and the new-style (JSON-based) TraceConfig. |
| 574 TEST_F(MemoryDumpManagerTest, TraceConfigExpectations) { |
| 575 MemoryDumpManagerDelegateForTesting& delegate = *delegate_; |
589 | 576 |
590 MATCHER(IsLowDetail, "") { | 577 // Don't trigger the default behavior of the mock delegate in this test, |
591 return arg.dump_args.level_of_detail == MemoryDumpArgs::LevelOfDetail::LOW; | 578 // which would short-circuit the dump request to the actual |
592 } | 579 // CreateProcessDump(). |
| 580 // We don't want to create any dump in this test, only check whether the dumps |
| 581 // are requested or not. |
| 582 ON_CALL(delegate, RequestGlobalMemoryDump(_, _)).WillByDefault(Return()); |
593 | 583 |
594 TEST_F(MemoryDumpManagerTest, SchedulePeriodicDumpsFromTraceConfig) { | 584 // Enabling memory-infra in a non-coordinator process should not trigger any |
595 const char kMemoryDumpTraceConfigString[] = | 585 // periodic dumps. |
596 "{" | 586 EXPECT_CALL(delegate, IsCoordinatorProcess()).WillRepeatedly(Return(false)); |
597 "\"included_categories\":[" | 587 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
598 "\"disabled-by-default-memory-infra\"" | 588 EXPECT_FALSE(IsPeriodicDumpingEnabled()); |
599 "]," | 589 DisableTracing(); |
600 "\"memory_dump_config\":{" | 590 |
| 591 // Enabling memory-infra with the legacy TraceConfig (category filter) in |
| 592 // a coordinator process should enable periodic dumps. |
| 593 EXPECT_CALL(delegate, IsCoordinatorProcess()).WillRepeatedly(Return(true)); |
| 594 EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory); |
| 595 EXPECT_TRUE(IsPeriodicDumpingEnabled()); |
| 596 DisableTracing(); |
| 597 |
| 598 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator |
| 599 // process without specifying any "memory_dump_config" section should enable |
| 600 // periodic dumps. This is to preserve the behavior chrome://tracing UI, that |
| 601 // is: ticking memory-infra should dump periodically with the default config. |
| 602 EXPECT_CALL(delegate, IsCoordinatorProcess()).WillRepeatedly(Return(true)); |
| 603 const std::string kTraceConfigWithNoMemorDumpConfig = StringPrintf( |
| 604 "{\"included_categories\":[\"%s\"]}", MemoryDumpManager::kTraceCategory); |
| 605 EnableTracingWithTraceConfig(kTraceConfigWithNoMemorDumpConfig.c_str()); |
| 606 EXPECT_TRUE(IsPeriodicDumpingEnabled()); |
| 607 DisableTracing(); |
| 608 |
| 609 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator |
| 610 // process with an empty "memory_dump_config" should NOT enable periodic |
| 611 // dumps. This is the way telemetry is supposed to use memory-infra with |
| 612 // only explicitly triggered dumps. |
| 613 EXPECT_CALL(delegate, IsCoordinatorProcess()).WillRepeatedly(Return(true)); |
| 614 const std::string kTraceConfigWithNoTriggers = StringPrintf( |
| 615 "{\"included_categories\":[\"%s\"], \"memory_dump_config\":{}", |
| 616 MemoryDumpManager::kTraceCategory); |
| 617 EnableTracingWithTraceConfig(kTraceConfigWithNoTriggers.c_str()); |
| 618 EXPECT_FALSE(IsPeriodicDumpingEnabled()); |
| 619 DisableTracing(); |
| 620 |
| 621 // Enabling memory-infra with the new (JSON) TraceConfig in a non-coordinator |
| 622 // process with a fully defined trigger config should NOT enable any periodic |
| 623 // dumps. |
| 624 EXPECT_CALL(delegate, IsCoordinatorProcess()).WillRepeatedly(Return(false)); |
| 625 const std::string kTraceConfigWithTriggers = StringPrintf( |
| 626 "{\"included_categories\":[\"%s\"]," |
| 627 "\"memory_dump_config\":{" |
601 "\"triggers\":[" | 628 "\"triggers\":[" |
602 "{" | 629 "{\"mode\":\"light\", \"periodic_interval_ms\":1}," |
603 "\"mode\":\"light\"," | 630 "{\"mode\":\"detailed\", \"periodic_interval_ms\":5}" |
604 "\"periodic_interval_ms\":1" | |
605 "}," | |
606 "{" | |
607 "\"mode\":\"detailed\"," | |
608 "\"periodic_interval_ms\":3" | |
609 "}" | |
610 "]" | 631 "]" |
611 "}" | 632 "}" |
612 "}"; | 633 "}", MemoryDumpManager::kTraceCategory); |
| 634 EnableTracingWithTraceConfig(kTraceConfigWithTriggers.c_str()); |
| 635 EXPECT_FALSE(IsPeriodicDumpingEnabled()); |
| 636 DisableTracing(); |
| 637 |
| 638 // Enabling memory-infra with the new (JSON) TraceConfig in a coordinator |
| 639 // process with a fully defined trigger config should cause periodic dumps to |
| 640 // be performed in the correct order. |
| 641 EXPECT_CALL(delegate, IsCoordinatorProcess()).WillRepeatedly(Return(true)); |
613 | 642 |
614 RunLoop run_loop; | 643 RunLoop run_loop; |
615 scoped_ptr<MemoryDumpManagerDelegateForPeriodicDumpTest> delegate( | 644 auto quit_closure = run_loop.QuitClosure(); |
616 new MemoryDumpManagerDelegateForPeriodicDumpTest()); | |
617 | 645 |
618 auto quit_closure = run_loop.QuitClosure(); | 646 // The expected sequence with config of light=1ms, heavy=5ms is H,L,L,L,H,... |
619 testing::InSequence sequence; | 647 testing::InSequence sequence; |
620 EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsHighDetail(), _)) | 648 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsHighDetailArgs(), _)); |
621 .Times(1); | 649 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLowDetailArgs(), _)).Times(3); |
622 EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsLowDetail(), _)) | 650 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsHighDetailArgs(), _)); |
623 .Times(2); | 651 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLowDetailArgs(), _)).Times(2); |
624 EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsHighDetail(), _)) | 652 EXPECT_CALL(delegate, RequestGlobalMemoryDump(IsLowDetailArgs(), _)) |
625 .Times(1); | |
626 EXPECT_CALL(*delegate.get(), RequestGlobalMemoryDump(IsLowDetail(), _)) | |
627 .Times(1) | |
628 .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args, | 653 .WillOnce(Invoke([quit_closure](const MemoryDumpRequestArgs& args, |
629 const MemoryDumpCallback& callback) { | 654 const MemoryDumpCallback& callback) { |
630 TraceLog::GetInstance()->SetDisabled(); | |
631 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure); | 655 ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure); |
632 })); | 656 })); |
633 | 657 |
634 SetDelegate(delegate.Pass()); | 658 // Swallow all the final spurious calls until tracing gets disabled. |
635 EnableTracingWithTraceConfig(kMemoryDumpTraceConfigString); | 659 EXPECT_CALL(delegate, RequestGlobalMemoryDump(_, _)).Times(AnyNumber()); |
636 | 660 |
| 661 EnableTracingWithTraceConfig(kTraceConfigWithTriggers.c_str()); |
637 run_loop.Run(); | 662 run_loop.Run(); |
| 663 DisableTracing(); |
638 } | 664 } |
639 | 665 |
640 } // namespace trace_event | 666 } // namespace trace_event |
641 } // namespace base | 667 } // namespace base |
OLD | NEW |