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

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

Issue 2786373002: memory-infra: Add peak-detector skeleton. (Closed)
Patch Set: remove seqchecker 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
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/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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698