OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/trace_event/memory_peak_detector.h" | |
6 | |
7 #include <memory> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/logging.h" | |
11 #include "base/run_loop.h" | |
12 #include "base/synchronization/waitable_event.h" | |
13 #include "base/test/test_timeouts.h" | |
14 #include "base/threading/platform_thread.h" | |
15 #include "base/threading/thread.h" | |
16 #include "base/threading/thread_task_runner_handle.h" | |
17 #include "base/trace_event/memory_dump_provider.h" | |
18 #include "base/trace_event/memory_dump_provider_info.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 namespace base { | |
22 namespace trace_event { | |
23 | |
24 namespace { | |
25 class MockMemoryDumpProvider : public MemoryDumpProvider { | |
26 public: | |
27 MockMemoryDumpProvider(WaitableEvent* evt) : evt_(evt) {} | |
28 bool OnMemoryDump(const MemoryDumpArgs&, ProcessMemoryDump*) override { | |
29 NOTREACHED(); | |
30 return true; | |
31 } | |
32 | |
33 void PollFastMemoryTotal(uint64_t* memory_total) override { evt_->Signal(); } | |
34 | |
35 WaitableEvent* const evt_; | |
36 }; | |
37 } // namespace | |
38 | |
39 class MemoryPeakDetectorTest : public testing::Test { | |
40 public: | |
41 MemoryPeakDetectorTest() : testing::Test() {} | |
42 | |
43 void RestartThreadAndReinitializePeakDetector() { | |
44 if (bg_thread_) | |
45 bg_thread_->Stop(); | |
46 bg_thread_.reset(new Thread("Peak Detector Test Thread")); | |
47 bg_thread_->Start(); | |
48 peak_detector_->Initialize( | |
49 Bind(&MemoryPeakDetectorTest::MockGetDumpProviders, Unretained(this)), | |
50 bg_thread_->task_runner(), | |
51 Bind(&MemoryPeakDetectorTest::OnPeakDetectedCallback, | |
52 Unretained(this))); | |
53 } | |
54 | |
55 void SetUp() override { | |
56 peak_detector_ = MemoryPeakDetector::GetInstance(); | |
hjd
2017/04/03 13:25:30
Maybe it would be better if each test constructed
Primiano Tucci (use gerrit)
2017/04/03 15:51:17
Hmm It's a singleton, so in order to construct it
Primiano Tucci (use gerrit)
2017/04/03 20:28:16
Okay you made very good arguments. Using an actual
| |
57 get_mdp_call_count = 0; | |
58 if (initialize_peak_detector_during_setup()) | |
59 RestartThreadAndReinitializePeakDetector(); | |
60 } | |
61 | |
62 void TearDown() override { | |
63 dump_providers.clear(); | |
64 peak_detector_->TearDownForTesting(); | |
65 bg_thread_->Stop(); | |
66 bg_thread_.reset(); | |
67 } | |
68 | |
69 // Calls MemoryPeakDetector::state_for_testing() on the bg thread and returns | |
70 // the result on the current thread. | |
71 MemoryPeakDetector::State GetPeakDetectorState() { | |
72 MemoryPeakDetector::State res = MemoryPeakDetector::NOT_INITIALIZED; | |
73 auto get_fn = [](MemoryPeakDetector* peak_detector, WaitableEvent* evt, | |
74 MemoryPeakDetector::State* res) { | |
75 *res = peak_detector->state_for_testing(); | |
76 evt->Signal(); | |
77 }; | |
78 | |
79 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, | |
80 WaitableEvent::InitialState::NOT_SIGNALED); | |
81 bg_thread_->task_runner()->PostTask( | |
82 FROM_HERE, Bind(get_fn, Unretained(peak_detector_), Unretained(&evt), | |
83 Unretained(&res))); | |
84 evt.Wait(); | |
85 return res; | |
86 } | |
87 | |
88 // Calls MemoryPeakDetector::poll_tasks_count_for_testing() on the bg thread | |
89 // and returns the result on the current thread. | |
90 uint32_t GetNumPollingTasksRan() { | |
91 uint32_t res = 0; | |
92 auto get_fn = [](MemoryPeakDetector* peak_detector, WaitableEvent* evt, | |
93 uint32_t* res) { | |
94 *res = peak_detector->poll_tasks_count_for_testing(); | |
95 evt->Signal(); | |
96 }; | |
97 | |
98 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, | |
99 WaitableEvent::InitialState::NOT_SIGNALED); | |
100 bg_thread_->task_runner()->PostTask( | |
101 FROM_HERE, Bind(get_fn, Unretained(peak_detector_), Unretained(&evt), | |
102 Unretained(&res))); | |
103 evt.Wait(); | |
104 return res; | |
105 } | |
106 | |
107 void MockGetDumpProviders(MemoryPeakDetector::DumpProvidersList* mdps) { | |
108 get_mdp_call_count++; | |
109 *mdps = dump_providers; | |
110 } | |
111 | |
112 void OnPeakDetectedCallback() { | |
113 // TODO(primiano): use in upcoming CLs. | |
114 } | |
115 | |
116 scoped_refptr<MemoryDumpProviderInfo> CreateMockDumpProvider( | |
117 WaitableEvent* evt) { | |
118 std::unique_ptr<MemoryDumpProvider> mdp(new MockMemoryDumpProvider(evt)); | |
119 MemoryDumpProvider::Options opt; | |
120 opt.is_fast_polling_supported = true; | |
121 scoped_refptr<MemoryDumpProviderInfo> mdp_info( | |
122 new MemoryDumpProviderInfo(mdp.get(), "Mock MDP", nullptr, opt, false)); | |
123 | |
124 // The |mdp| instance will be destroyed together with the |mdp_info|. | |
125 mdp_info->owned_dump_provider = std::move(mdp); | |
126 return mdp_info; | |
127 } | |
128 | |
129 protected: | |
130 virtual bool initialize_peak_detector_during_setup() const { return true; } | |
131 | |
132 MemoryPeakDetector::DumpProvidersList dump_providers; | |
133 uint32_t get_mdp_call_count; | |
134 MemoryPeakDetector* peak_detector_; | |
135 std::unique_ptr<Thread> bg_thread_; | |
136 }; | |
137 | |
138 class MemoryPeakDetectorTestNoAutoInitialize : public MemoryPeakDetectorTest { | |
139 bool initialize_peak_detector_during_setup() const override { return false; } | |
140 }; | |
141 | |
142 TEST_F(MemoryPeakDetectorTest, GetDumpProvidersFunctionCalled) { | |
143 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); | |
144 peak_detector_->Start(); | |
145 bg_thread_->FlushForTesting(); | |
146 EXPECT_EQ(1u, get_mdp_call_count); | |
147 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); | |
148 | |
149 peak_detector_->Stop(); | |
150 bg_thread_->FlushForTesting(); | |
151 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); | |
152 EXPECT_EQ(0u, GetNumPollingTasksRan()); | |
153 } | |
154 | |
155 TEST_F(MemoryPeakDetectorTestNoAutoInitialize, NotifyBeforeInitialize) { | |
156 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, | |
157 WaitableEvent::InitialState::NOT_SIGNALED); | |
158 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(&evt); | |
159 dump_providers.push_back(mdp); | |
160 peak_detector_->NotifyMemoryDumpProvidersChanged(); | |
ssid
2017/04/03 17:55:28
Can you add a
EXPECT_EQ(MemoryPeakDetector::NOT_I
Primiano Tucci (use gerrit)
2017/04/03 20:28:16
Good point, done
| |
161 RestartThreadAndReinitializePeakDetector(); | |
162 | |
163 peak_detector_->Start(); | |
164 bg_thread_->FlushForTesting(); | |
165 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); | |
166 evt.Wait(); // Wait for a PollFastMemoryTotal() call. | |
167 | |
168 peak_detector_->Stop(); | |
169 bg_thread_->FlushForTesting(); | |
170 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); | |
171 EXPECT_EQ(1u, get_mdp_call_count); | |
172 EXPECT_GE(GetNumPollingTasksRan(), 1u); | |
173 } | |
174 | |
175 TEST_F(MemoryPeakDetectorTest, DoubleStop) { | |
176 peak_detector_->Start(); | |
177 bg_thread_->FlushForTesting(); | |
178 | |
179 peak_detector_->Stop(); | |
180 bg_thread_->FlushForTesting(); | |
181 | |
182 peak_detector_->Stop(); | |
183 bg_thread_->FlushForTesting(); | |
184 | |
185 EXPECT_EQ(1u, get_mdp_call_count); | |
186 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); | |
187 EXPECT_EQ(0u, GetNumPollingTasksRan()); | |
188 } | |
189 | |
190 TEST_F(MemoryPeakDetectorTest, OneDumpProviderRegisteredBeforeStart) { | |
191 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, | |
192 WaitableEvent::InitialState::NOT_SIGNALED); | |
193 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(&evt); | |
194 dump_providers.push_back(mdp); | |
195 | |
196 peak_detector_->Start(); | |
197 bg_thread_->FlushForTesting(); | |
198 evt.Wait(); // Signaled when PollFastMemoryTotal() is called on the MockMDP. | |
199 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); | |
200 | |
201 peak_detector_->Stop(); | |
202 bg_thread_->FlushForTesting(); | |
203 | |
204 EXPECT_EQ(1u, get_mdp_call_count); | |
205 EXPECT_GT(GetNumPollingTasksRan(), 0u); | |
206 } | |
207 | |
208 TEST_F(MemoryPeakDetectorTest, ReInitializeAndRebindToNewThread) { | |
209 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, | |
210 WaitableEvent::InitialState::NOT_SIGNALED); | |
211 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(&evt); | |
212 dump_providers.push_back(mdp); | |
213 | |
214 for (int i = 0; i < 5; ++i) { | |
215 evt.Reset(); | |
216 peak_detector_->Start(); | |
217 bg_thread_->FlushForTesting(); | |
218 evt.Wait(); // Wait for a PollFastMemoryTotal() call. | |
219 peak_detector_->Stop(); | |
220 | |
221 // Reinitialize and re-bind to a new task runner. | |
222 RestartThreadAndReinitializePeakDetector(); | |
223 } | |
224 } | |
225 | |
226 TEST_F(MemoryPeakDetectorTest, OneDumpProviderRegisteredOutOfBand) { | |
227 peak_detector_->Start(); | |
228 bg_thread_->FlushForTesting(); | |
229 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); | |
230 EXPECT_EQ(1u, get_mdp_call_count); | |
231 | |
232 // Check that no poll tasks are posted before any dump provider is registered. | |
233 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | |
234 EXPECT_EQ(0u, GetNumPollingTasksRan()); | |
235 | |
236 // Registed the MDP After Start() has been issued and expect that the | |
237 // PeakDetector transitions ENABLED -> RUNNING on the next | |
238 // NotifyMemoryDumpProvidersChanged() call. | |
239 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL, | |
240 WaitableEvent::InitialState::NOT_SIGNALED); | |
241 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider(&evt); | |
242 dump_providers.push_back(mdp); | |
243 peak_detector_->NotifyMemoryDumpProvidersChanged(); | |
244 | |
245 evt.Wait(); // Signaled when PollFastMemoryTotal() is called on the MockMDP. | |
246 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); | |
247 EXPECT_EQ(2u, get_mdp_call_count); | |
248 | |
249 // Now simulate the unregisration and expect that the PeakDetector transitions | |
250 // back to ENABLED. | |
251 dump_providers.clear(); | |
252 peak_detector_->NotifyMemoryDumpProvidersChanged(); | |
253 bg_thread_->FlushForTesting(); | |
ssid
2017/04/03 17:55:28
There is FlushForTesting calls in all the tests. I
Primiano Tucci (use gerrit)
2017/04/03 20:28:16
I removed all of them but two. Most of them where
| |
254 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); | |
255 EXPECT_EQ(3u, get_mdp_call_count); | |
256 uint32_t num_poll_tasks = GetNumPollingTasksRan(); | |
257 EXPECT_GT(num_poll_tasks, 0u); | |
258 | |
259 // At this point, no more polling tasks should be posted. | |
260 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | |
261 peak_detector_->Stop(); | |
262 bg_thread_->FlushForTesting(); | |
263 EXPECT_EQ(num_poll_tasks, GetNumPollingTasksRan()); | |
264 } | |
265 | |
266 TEST_F(MemoryPeakDetectorTest, RegisterAndUnregisterTwoDumpProviders) { | |
267 WaitableEvent evt1(WaitableEvent::ResetPolicy::MANUAL, | |
268 WaitableEvent::InitialState::NOT_SIGNALED); | |
269 WaitableEvent evt2(WaitableEvent::ResetPolicy::MANUAL, | |
270 WaitableEvent::InitialState::NOT_SIGNALED); | |
271 scoped_refptr<MemoryDumpProviderInfo> mdp1 = CreateMockDumpProvider(&evt1); | |
272 scoped_refptr<MemoryDumpProviderInfo> mdp2 = CreateMockDumpProvider(&evt2); | |
273 | |
274 // Register only one MDP and start the detector. | |
275 dump_providers.push_back(mdp1); | |
276 peak_detector_->Start(); | |
277 bg_thread_->FlushForTesting(); | |
278 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); | |
279 | |
280 // Wait for one poll task and then register also the other one. | |
281 evt1.Wait(); | |
282 dump_providers.push_back(mdp2); | |
283 peak_detector_->NotifyMemoryDumpProvidersChanged(); | |
284 evt2.Wait(); | |
285 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); | |
286 | |
287 // Now unregister the first MDP and check that everything is still running. | |
288 dump_providers.erase(dump_providers.begin()); | |
289 peak_detector_->NotifyMemoryDumpProvidersChanged(); | |
290 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); | |
291 | |
292 // Now unregister both and check that the detector goes to idle. | |
293 dump_providers.clear(); | |
294 peak_detector_->NotifyMemoryDumpProvidersChanged(); | |
295 bg_thread_->FlushForTesting(); | |
296 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); | |
297 | |
298 // Now re-register both and check that the detector re-activates posting | |
299 // new polling tasks. | |
300 uint32_t num_poll_tasks = GetNumPollingTasksRan(); | |
301 evt1.Reset(); | |
302 evt2.Reset(); | |
303 dump_providers.push_back(mdp1); | |
304 dump_providers.push_back(mdp2); | |
305 peak_detector_->NotifyMemoryDumpProvidersChanged(); | |
306 bg_thread_->FlushForTesting(); | |
307 evt1.Wait(); | |
308 evt2.Wait(); | |
309 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState()); | |
310 EXPECT_GT(GetNumPollingTasksRan(), num_poll_tasks); | |
311 | |
312 // Stop everything, tear down the MDPs, restart the detector and check that | |
313 // it detector doesn't accidentally try to re-access them. | |
314 peak_detector_->Stop(); | |
315 bg_thread_->FlushForTesting(); | |
316 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); | |
317 dump_providers.clear(); | |
318 mdp1 = nullptr; | |
319 mdp2 = nullptr; | |
320 | |
321 num_poll_tasks = GetNumPollingTasksRan(); | |
322 peak_detector_->Start(); | |
323 bg_thread_->FlushForTesting(); | |
324 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState()); | |
325 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | |
326 peak_detector_->Stop(); | |
327 bg_thread_->FlushForTesting(); | |
328 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState()); | |
329 EXPECT_EQ(num_poll_tasks, GetNumPollingTasksRan()); | |
330 | |
331 EXPECT_EQ(6u, get_mdp_call_count); | |
332 } | |
333 | |
334 } // namespace trace_event | |
335 } // namespace base | |
OLD | NEW |