Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Side by Side Diff: base/trace_event/memory_peak_detector_unittest.cc

Issue 2786373002: memory-infra: Add peak-detector skeleton. (Closed)
Patch Set: minor typos Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/trace_event/memory_peak_detector.cc ('k') | tools/gn/bootstrap/bootstrap.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 using ::testing::_;
23 using ::testing::Invoke;
24 using ::testing::Return;
25
26 namespace base {
27 namespace trace_event {
28
29 namespace {
30
31 class MockMemoryDumpProvider : public MemoryDumpProvider {
32 public:
33 bool OnMemoryDump(const MemoryDumpArgs&, ProcessMemoryDump*) override {
34 NOTREACHED();
35 return true;
36 }
37
38 MOCK_METHOD1(PollFastMemoryTotal, void(uint64_t*));
39 };
40
41 // Wrapper to use gmock on a callback.
42 struct OnPeakDetectedWrapper {
43 MOCK_METHOD0(OnPeak, void());
44 };
45
46 } // namespace
47
48 class MemoryPeakDetectorTest : public testing::Test {
49 public:
50 struct FriendDeleter {
51 void operator()(MemoryPeakDetector* inst) { delete inst; }
52 };
53
54 MemoryPeakDetectorTest() : testing::Test() {}
55
56 std::unique_ptr<MemoryPeakDetector, FriendDeleter> NewInstance() {
57 return std::unique_ptr<MemoryPeakDetector, FriendDeleter>(
58 new MemoryPeakDetector());
59 }
60
61 void RestartThreadAndReinitializePeakDetector() {
62 bg_thread_.reset(new Thread("Peak Detector Test Thread"));
63 bg_thread_->Start();
64 peak_detector_ = NewInstance();
65 peak_detector_->Setup(
66 Bind(&MemoryPeakDetectorTest::MockGetDumpProviders, Unretained(this)),
67 bg_thread_->task_runner(),
68 Bind(&OnPeakDetectedWrapper::OnPeak, Unretained(&on_peak_callback_)));
69 }
70
71 void SetUp() override {
72 get_mdp_call_count_ = 0;
73 RestartThreadAndReinitializePeakDetector();
74 }
75
76 void TearDown() override {
77 peak_detector_->TearDown();
78 bg_thread_->FlushForTesting();
79 EXPECT_EQ(MemoryPeakDetector::NOT_INITIALIZED, GetPeakDetectorState());
80 dump_providers_.clear();
81 }
82
83 // Calls MemoryPeakDetector::state_for_testing() on the bg thread and returns
84 // the result on the current thread.
85 MemoryPeakDetector::State GetPeakDetectorState() {
86 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
87 WaitableEvent::InitialState::NOT_SIGNALED);
88 MemoryPeakDetector::State res = MemoryPeakDetector::NOT_INITIALIZED;
89 auto get_fn = [](MemoryPeakDetector* peak_detector, WaitableEvent* evt,
90 MemoryPeakDetector::State* res) {
91 *res = peak_detector->state_for_testing();
92 evt->Signal();
93 };
94 bg_thread_->task_runner()->PostTask(
95 FROM_HERE, Bind(get_fn, Unretained(&*peak_detector_), Unretained(&evt),
96 Unretained(&res)));
97 evt.Wait();
98 return res;
99 }
100
101 // Calls MemoryPeakDetector::poll_tasks_count_for_testing() on the bg thread
102 // and returns the result on the current thread.
103 uint32_t GetNumPollingTasksRan() {
104 uint32_t res = 0;
105 auto get_fn = [](MemoryPeakDetector* peak_detector, WaitableEvent* evt,
106 uint32_t* res) {
107 *res = peak_detector->poll_tasks_count_for_testing();
108 evt->Signal();
109 };
110
111 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
112 WaitableEvent::InitialState::NOT_SIGNALED);
113 bg_thread_->task_runner()->PostTask(
114 FROM_HERE, Bind(get_fn, Unretained(&*peak_detector_), Unretained(&evt),
115 Unretained(&res)));
116 evt.Wait();
117 return res;
118 }
119
120 // Called on the |bg_thread_|.
121 void MockGetDumpProviders(MemoryPeakDetector::DumpProvidersList* mdps) {
122 get_mdp_call_count_++;
123 *mdps = dump_providers_;
124 }
125
126 uint32_t GetNumGetDumpProvidersCalls() {
127 bg_thread_->FlushForTesting();
128 return get_mdp_call_count_;
129 }
130
131 scoped_refptr<MemoryDumpProviderInfo> CreateMockDumpProvider() {
132 std::unique_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider());
133 MemoryDumpProvider::Options opt;
134 opt.is_fast_polling_supported = true;
135 scoped_refptr<MemoryDumpProviderInfo> mdp_info(
136 new MemoryDumpProviderInfo(mdp.get(), "Mock MDP", nullptr, opt, false));
137
138 // The |mdp| instance will be destroyed together with the |mdp_info|.
139 mdp_info->owned_dump_provider = std::move(mdp);
140 return mdp_info;
141 }
142
143 static MockMemoryDumpProvider& GetMockMDP(
144 const scoped_refptr<MemoryDumpProviderInfo>& mdp_info) {
145 return *static_cast<MockMemoryDumpProvider*>(mdp_info->dump_provider);
146 }
147
148 protected:
149 MemoryPeakDetector::DumpProvidersList dump_providers_;
150 uint32_t get_mdp_call_count_;
151 std::unique_ptr<MemoryPeakDetector, FriendDeleter> peak_detector_;
152 std::unique_ptr<Thread> bg_thread_;
153 OnPeakDetectedWrapper on_peak_callback_;
154 };
155
156 TEST_F(MemoryPeakDetectorTest, GetDumpProvidersFunctionCalled) {
157 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
158 peak_detector_->Start();
159 EXPECT_EQ(1u, GetNumGetDumpProvidersCalls());
160 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState());
161
162 peak_detector_->Stop();
163 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
164 EXPECT_EQ(0u, GetNumPollingTasksRan());
165 }
166
167 TEST_F(MemoryPeakDetectorTest, NotifyBeforeInitialize) {
168 peak_detector_->TearDown();
169
170 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
171 WaitableEvent::InitialState::NOT_SIGNALED);
172 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider();
173 EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_))
174 .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); }));
175 dump_providers_.push_back(mdp);
176 peak_detector_->NotifyMemoryDumpProvidersChanged();
177 EXPECT_EQ(MemoryPeakDetector::NOT_INITIALIZED, GetPeakDetectorState());
178 RestartThreadAndReinitializePeakDetector();
179
180 peak_detector_->Start();
181 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
182 evt.Wait(); // Wait for a PollFastMemoryTotal() call.
183
184 peak_detector_->Stop();
185 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
186 EXPECT_EQ(1u, GetNumGetDumpProvidersCalls());
187 EXPECT_GE(GetNumPollingTasksRan(), 1u);
188 }
189
190 TEST_F(MemoryPeakDetectorTest, DoubleStop) {
191 peak_detector_->Start();
192 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState());
193
194 peak_detector_->Stop();
195 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
196
197 peak_detector_->Stop();
198 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
199
200 EXPECT_EQ(1u, GetNumGetDumpProvidersCalls());
201 EXPECT_EQ(0u, GetNumPollingTasksRan());
202 }
203
204 TEST_F(MemoryPeakDetectorTest, OneDumpProviderRegisteredBeforeStart) {
205 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
206 WaitableEvent::InitialState::NOT_SIGNALED);
207 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider();
208 EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_))
209 .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); }));
210 dump_providers_.push_back(mdp);
211
212 peak_detector_->Start();
213 evt.Wait(); // Signaled when PollFastMemoryTotal() is called on the MockMDP.
214 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
215
216 peak_detector_->Stop();
217 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
218 EXPECT_EQ(1u, GetNumGetDumpProvidersCalls());
219 EXPECT_GT(GetNumPollingTasksRan(), 0u);
220 }
221
222 TEST_F(MemoryPeakDetectorTest, ReInitializeAndRebindToNewThread) {
223 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
224 WaitableEvent::InitialState::NOT_SIGNALED);
225 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider();
226 EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_))
227 .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); }));
228 dump_providers_.push_back(mdp);
229
230 for (int i = 0; i < 5; ++i) {
231 evt.Reset();
232 peak_detector_->Start();
233 evt.Wait(); // Wait for a PollFastMemoryTotal() call.
234 // Check that calling TearDown implicitly does a Stop().
235 peak_detector_->TearDown();
236
237 // Reinitialize and re-bind to a new task runner.
238 RestartThreadAndReinitializePeakDetector();
239 }
240 }
241
242 TEST_F(MemoryPeakDetectorTest, OneDumpProviderRegisteredOutOfBand) {
243 peak_detector_->Start();
244 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState());
245 EXPECT_EQ(1u, GetNumGetDumpProvidersCalls());
246
247 // Check that no poll tasks are posted before any dump provider is registered.
248 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
249 EXPECT_EQ(0u, GetNumPollingTasksRan());
250
251 // Registed the MDP After Start() has been issued and expect that the
252 // PeakDetector transitions ENABLED -> RUNNING on the next
253 // NotifyMemoryDumpProvidersChanged() call.
254 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
255 WaitableEvent::InitialState::NOT_SIGNALED);
256 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider();
257 EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_))
258 .WillRepeatedly(Invoke([&evt](uint64_t*) { evt.Signal(); }));
259 dump_providers_.push_back(mdp);
260 peak_detector_->NotifyMemoryDumpProvidersChanged();
261
262 evt.Wait(); // Signaled when PollFastMemoryTotal() is called on the MockMDP.
263 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
264 EXPECT_EQ(2u, GetNumGetDumpProvidersCalls());
265
266 // Now simulate the unregisration and expect that the PeakDetector transitions
267 // back to ENABLED.
268 dump_providers_.clear();
269 peak_detector_->NotifyMemoryDumpProvidersChanged();
270 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState());
271 EXPECT_EQ(3u, GetNumGetDumpProvidersCalls());
272 uint32_t num_poll_tasks = GetNumPollingTasksRan();
273 EXPECT_GT(num_poll_tasks, 0u);
274
275 // At this point, no more polling tasks should be posted.
276 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
277 peak_detector_->Stop();
278 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
279 EXPECT_EQ(num_poll_tasks, GetNumPollingTasksRan());
280 }
281
282 // Test that a sequence of Start()/Stop() back-to-back doesn't end up creating
283 // several outstanding timer tasks and instead respects the polling_interval_ms.
284 TEST_F(MemoryPeakDetectorTest, StartStopQuickly) {
285 WaitableEvent evt(WaitableEvent::ResetPolicy::MANUAL,
286 WaitableEvent::InitialState::NOT_SIGNALED);
287 scoped_refptr<MemoryDumpProviderInfo> mdp = CreateMockDumpProvider();
288 dump_providers_.push_back(mdp);
289 const uint32_t kNumPolls = 20;
290 uint32_t polls_done = 0;
291 EXPECT_CALL(GetMockMDP(mdp), PollFastMemoryTotal(_))
292 .WillRepeatedly(Invoke([&polls_done, &evt, kNumPolls](uint64_t*) {
293 if (++polls_done == kNumPolls)
294 evt.Signal();
295 }));
296
297 const TimeTicks tstart = TimeTicks::Now();
298 for (int i = 0; i < 5; i++) {
299 peak_detector_->Start();
300 peak_detector_->Stop();
301 }
302 peak_detector_->Start();
303 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
304 evt.Wait(); // Wait for kNumPolls.
305 const double time_ms = (TimeTicks::Now() - tstart).InMillisecondsF();
306
307 // TODO(primiano): this will become config.polling_interval_ms in the next CL.
308 const uint32_t polling_interval_ms = 1;
309 EXPECT_GE(time_ms, kNumPolls * polling_interval_ms);
310 peak_detector_->Stop();
311 }
312
313 TEST_F(MemoryPeakDetectorTest, RegisterAndUnregisterTwoDumpProviders) {
314 WaitableEvent evt1(WaitableEvent::ResetPolicy::MANUAL,
315 WaitableEvent::InitialState::NOT_SIGNALED);
316 WaitableEvent evt2(WaitableEvent::ResetPolicy::MANUAL,
317 WaitableEvent::InitialState::NOT_SIGNALED);
318 scoped_refptr<MemoryDumpProviderInfo> mdp1 = CreateMockDumpProvider();
319 scoped_refptr<MemoryDumpProviderInfo> mdp2 = CreateMockDumpProvider();
320 EXPECT_CALL(GetMockMDP(mdp1), PollFastMemoryTotal(_))
321 .WillRepeatedly(Invoke([&evt1](uint64_t*) { evt1.Signal(); }));
322 EXPECT_CALL(GetMockMDP(mdp2), PollFastMemoryTotal(_))
323 .WillRepeatedly(Invoke([&evt2](uint64_t*) { evt2.Signal(); }));
324
325 // Register only one MDP and start the detector.
326 dump_providers_.push_back(mdp1);
327 peak_detector_->Start();
328 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
329
330 // Wait for one poll task and then register also the other one.
331 evt1.Wait();
332 dump_providers_.push_back(mdp2);
333 peak_detector_->NotifyMemoryDumpProvidersChanged();
334 evt2.Wait();
335 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
336
337 // Now unregister the first MDP and check that everything is still running.
338 dump_providers_.erase(dump_providers_.begin());
339 peak_detector_->NotifyMemoryDumpProvidersChanged();
340 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
341
342 // Now unregister both and check that the detector goes to idle.
343 dump_providers_.clear();
344 peak_detector_->NotifyMemoryDumpProvidersChanged();
345 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState());
346
347 // Now re-register both and check that the detector re-activates posting
348 // new polling tasks.
349 uint32_t num_poll_tasks = GetNumPollingTasksRan();
350 evt1.Reset();
351 evt2.Reset();
352 dump_providers_.push_back(mdp1);
353 dump_providers_.push_back(mdp2);
354 peak_detector_->NotifyMemoryDumpProvidersChanged();
355 evt1.Wait();
356 evt2.Wait();
357 EXPECT_EQ(MemoryPeakDetector::RUNNING, GetPeakDetectorState());
358 EXPECT_GT(GetNumPollingTasksRan(), num_poll_tasks);
359
360 // Stop everything, tear down the MDPs, restart the detector and check that
361 // it detector doesn't accidentally try to re-access them.
362 peak_detector_->Stop();
363 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
364 dump_providers_.clear();
365 mdp1 = nullptr;
366 mdp2 = nullptr;
367
368 num_poll_tasks = GetNumPollingTasksRan();
369 peak_detector_->Start();
370 EXPECT_EQ(MemoryPeakDetector::ENABLED, GetPeakDetectorState());
371 PlatformThread::Sleep(TestTimeouts::tiny_timeout());
372
373 peak_detector_->Stop();
374 EXPECT_EQ(MemoryPeakDetector::DISABLED, GetPeakDetectorState());
375 EXPECT_EQ(num_poll_tasks, GetNumPollingTasksRan());
376
377 EXPECT_EQ(6u, GetNumGetDumpProvidersCalls());
378 }
379
380 } // namespace trace_event
381 } // namespace base
OLDNEW
« no previous file with comments | « base/trace_event/memory_peak_detector.cc ('k') | tools/gn/bootstrap/bootstrap.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698