OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "components/memory_pressure/memory_pressure_monitor.h" | |
6 | |
7 #include <memory> | |
8 #include <utility> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/task_runner.h" | |
12 #include "base/test/simple_test_tick_clock.h" | |
13 #include "base/tracked_objects.h" | |
14 #include "components/memory_pressure/memory_pressure_stats_collector.h" | |
15 #include "components/memory_pressure/test_memory_pressure_calculator.h" | |
16 #include "testing/gmock/include/gmock/gmock.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 namespace memory_pressure { | |
20 | |
21 namespace { | |
22 | |
23 using MemoryPressureLevel = MemoryPressureMonitor::MemoryPressureLevel; | |
24 const MemoryPressureLevel MEMORY_PRESSURE_LEVEL_NONE = | |
25 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE; | |
26 const MemoryPressureLevel MEMORY_PRESSURE_LEVEL_MODERATE = | |
27 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE; | |
28 const MemoryPressureLevel MEMORY_PRESSURE_LEVEL_CRITICAL = | |
29 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL; | |
30 | |
31 using testing::_; | |
32 | |
33 } // namespace | |
34 | |
35 // A mock task runner. This isn't directly a TaskRunner as the reference | |
36 // counting confuses gmock. | |
37 class LenientMockTaskRunner { | |
38 public: | |
39 MOCK_METHOD2(PostDelayedTask, | |
40 bool(const tracked_objects::Location&, base::TimeDelta)); | |
41 }; | |
42 using MockTaskRunner = testing::StrictMock<LenientMockTaskRunner>; | |
43 | |
44 // A TaskRunner implementation that wraps a MockTaskRunner. | |
45 class TaskRunnerProxy : public base::TaskRunner { | |
46 public: | |
47 // The provided |mock| must outlive this object. | |
48 explicit TaskRunnerProxy(MockTaskRunner* mock) : mock_(mock) {} | |
49 bool RunsTasksInCurrentSequence() const override { return true; } | |
50 bool PostDelayedTask(const tracked_objects::Location& location, | |
51 base::OnceClosure closure, | |
52 base::TimeDelta delta) override { | |
53 return mock_->PostDelayedTask(location, delta); | |
54 } | |
55 | |
56 private: | |
57 MockTaskRunner* mock_; | |
58 ~TaskRunnerProxy() override {} | |
59 }; | |
60 | |
61 class TestMemoryPressureMonitor : public MemoryPressureMonitor { | |
62 public: | |
63 // Expose the callback that is used for scheduled checks. | |
64 using MemoryPressureMonitor::CheckPressureAndUpdateStats; | |
65 | |
66 #if !defined(MEMORY_PRESSURE_IS_POLLING) | |
67 using MemoryPressureMonitor::OnMemoryPressureChanged; | |
68 #endif | |
69 | |
70 #if defined(MEMORY_PRESSURE_IS_POLLING) | |
71 TestMemoryPressureMonitor(scoped_refptr<base::TaskRunner> task_runner, | |
72 base::TickClock* tick_clock, | |
73 MemoryPressureStatsCollector* stats_collector, | |
74 MemoryPressureCalculator* calculator, | |
75 DispatchCallback dispatch_callback) | |
76 : MemoryPressureMonitor(task_runner, | |
77 tick_clock, | |
78 stats_collector, | |
79 calculator, | |
80 dispatch_callback) {} | |
81 #else // MEMORY_PRESSURE_IS_POLLING | |
82 TestMemoryPressureMonitor(scoped_refptr<base::TaskRunner> task_runner, | |
83 base::TickClock* tick_clock, | |
84 MemoryPressureStatsCollector* stats_collector, | |
85 DispatchCallback dispatch_callback, | |
86 MemoryPressureLevel initial_level) | |
87 : MemoryPressureMonitor(task_runner, | |
88 tick_clock, | |
89 stats_collector, | |
90 dispatch_callback, | |
91 initial_level) {} | |
92 #endif // !MEMORY_PRESSURE_IS_POLLING | |
93 | |
94 // A handful of accessors for unittesting. | |
95 MemoryPressureLevel current_memory_pressure_level() const { | |
96 return current_memory_pressure_level_; | |
97 } | |
98 const std::map<int, base::TimeTicks>& scheduled_checks() const { | |
99 return scheduled_checks_; | |
100 } | |
101 int serial_number() const { return serial_number_; } | |
102 }; | |
103 | |
104 // A mock dispatch class. | |
105 class LenientMockDispatch { | |
106 public: | |
107 MOCK_METHOD1(Dispatch, void(MemoryPressureLevel)); | |
108 }; | |
109 using MockDispatch = testing::StrictMock<LenientMockDispatch>; | |
110 | |
111 class MemoryPressureMonitorTest : public testing::Test { | |
112 public: | |
113 MemoryPressureMonitorTest() | |
114 : task_runner_proxy_(new TaskRunnerProxy(&mock_task_runner_)), | |
115 stats_collector_(&tick_clock_) {} | |
116 | |
117 #if defined(MEMORY_PRESSURE_IS_POLLING) | |
118 // Creates a monitor in the given initial pressure level and validates its | |
119 // state. | |
120 void CreateMonitor(MemoryPressureLevel initial_level) { | |
121 calculator_.SetLevel(initial_level); | |
122 Tick(1); // Advance the clock so it doesn't return zero. | |
123 | |
124 // Determine the delay with which we expect the task to be posted. | |
125 int delay = MemoryPressureMonitor::kDefaultPollingIntervalMs; | |
126 if (initial_level == MEMORY_PRESSURE_LEVEL_MODERATE) | |
127 delay = MemoryPressureMonitor::kNotificationIntervalPressureModerateMs; | |
128 else if (initial_level == MEMORY_PRESSURE_LEVEL_CRITICAL) | |
129 delay = MemoryPressureMonitor::kNotificationIntervalPressureCriticalMs; | |
130 | |
131 // The monitor will make one call to the task runner during construction. | |
132 ExpectTaskPosted(delay); | |
133 monitor_.reset(new TestMemoryPressureMonitor( | |
134 task_runner_proxy_, &tick_clock_, &stats_collector_, &calculator_, | |
135 base::Bind(&MockDispatch::Dispatch, | |
136 base::Unretained(&mock_dispatch_)))); | |
137 VerifyAndClearExpectations(); | |
138 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
139 | |
140 // The monitor should have made one call immediately to the calculator_. | |
141 EXPECT_EQ(1, calculator_.calls()); | |
142 ExpectPressure(initial_level); | |
143 calculator_.ResetCalls(); | |
144 } | |
145 #else // MEMORY_PRESSURE_IS_POLLING | |
146 void CreateMonitor(MemoryPressureLevel initial_level) { | |
147 Tick(1); // Advance the clock so it doesn't return zero. | |
148 | |
149 // The monitor will make one call to the task runner during construction. | |
150 ExpectTaskPosted(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
151 monitor_.reset(new TestMemoryPressureMonitor( | |
152 task_runner_proxy_, &tick_clock_, &stats_collector_, | |
153 base::Bind(&MockDispatch::Dispatch, base::Unretained(&mock_dispatch_)), | |
154 initial_level)); | |
155 VerifyAndClearExpectations(); | |
156 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
157 | |
158 // The monitor should have made one call immediately to the calculator_. | |
159 ExpectPressure(initial_level); | |
160 } | |
161 #endif // !MEMORY_PRESSURE_IS_POLLING | |
162 | |
163 // Advances the tick clock by the given number of milliseconds. | |
164 void Tick(int ms) { | |
165 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(ms)); | |
166 } | |
167 | |
168 // Sets expectations for tasks scheduled via |mock_task_runner_|. | |
169 void ExpectTaskPosted(int delay_ms) { | |
170 base::TimeDelta delay = base::TimeDelta::FromMilliseconds(delay_ms); | |
171 EXPECT_CALL(mock_task_runner_, PostDelayedTask(_, delay)) | |
172 .WillOnce(testing::Return(true)); | |
173 } | |
174 | |
175 // Sets up expectations for calls to |mock_dispatch_|. | |
176 void ExpectDispatch(MemoryPressureLevel level) { | |
177 EXPECT_CALL(mock_dispatch_, Dispatch(level)); | |
178 } | |
179 void ExpectDispatchModerate() { | |
180 EXPECT_CALL(mock_dispatch_, Dispatch(MEMORY_PRESSURE_LEVEL_MODERATE)); | |
181 } | |
182 void ExpectDispatchCritical() { | |
183 EXPECT_CALL(mock_dispatch_, Dispatch(MEMORY_PRESSURE_LEVEL_CRITICAL)); | |
184 } | |
185 | |
186 // Verifies and clears expectations for both |mock_task_runner_| and | |
187 // |mock_dispatch_|. | |
188 void VerifyAndClearExpectations() { | |
189 testing::Mock::VerifyAndClearExpectations(&mock_task_runner_); | |
190 testing::Mock::VerifyAndClearExpectations(&mock_dispatch_); | |
191 } | |
192 | |
193 // Checks expectations on |monitor_->current_memory_pressure_level()|. | |
194 void ExpectPressure(MemoryPressureLevel level) { | |
195 EXPECT_EQ(level, monitor_->current_memory_pressure_level()); | |
196 } | |
197 void ExpectNone() { | |
198 EXPECT_EQ(MEMORY_PRESSURE_LEVEL_NONE, | |
199 monitor_->current_memory_pressure_level()); | |
200 } | |
201 void ExpectModerate() { | |
202 EXPECT_EQ(MEMORY_PRESSURE_LEVEL_MODERATE, | |
203 monitor_->current_memory_pressure_level()); | |
204 } | |
205 void ExpectCritical() { | |
206 EXPECT_EQ(MEMORY_PRESSURE_LEVEL_CRITICAL, | |
207 monitor_->current_memory_pressure_level()); | |
208 } | |
209 | |
210 MockTaskRunner mock_task_runner_; | |
211 scoped_refptr<TaskRunnerProxy> task_runner_proxy_; | |
212 base::SimpleTestTickClock tick_clock_; | |
213 MemoryPressureStatsCollector stats_collector_; | |
214 | |
215 #if defined(MEMORY_PRESSURE_IS_POLLING) | |
216 TestMemoryPressureCalculator calculator_; | |
217 #endif | |
218 | |
219 MockDispatch mock_dispatch_; | |
220 std::unique_ptr<TestMemoryPressureMonitor> monitor_; | |
221 }; | |
222 | |
223 TEST_F(MemoryPressureMonitorTest, NormalScheduling) { | |
224 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
225 | |
226 Tick(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
227 ExpectTaskPosted(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
228 monitor_->CheckPressureAndUpdateStats(monitor_->serial_number()); | |
229 VerifyAndClearExpectations(); | |
230 | |
231 Tick(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
232 ExpectTaskPosted(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
233 monitor_->CheckPressureAndUpdateStats(monitor_->serial_number()); | |
234 VerifyAndClearExpectations(); | |
235 } | |
236 | |
237 #if defined(MEMORY_PRESSURE_IS_POLLING) | |
238 | |
239 TEST_F(MemoryPressureMonitorTest, CalculatorNotAlwaysInvoked) { | |
240 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
241 | |
242 // Callback into the monitor too soon and expect nothing to happen. | |
243 Tick(1); | |
244 EXPECT_EQ(MEMORY_PRESSURE_LEVEL_NONE, monitor_->GetCurrentPressureLevel()); | |
245 VerifyAndClearExpectations(); | |
246 EXPECT_EQ(0, calculator_.calls()); | |
247 ExpectNone(); | |
248 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
249 | |
250 // Pass sufficient time that the rate limiter will allow another calculation. | |
251 // Don't expect another scheduled call because there's already one pending. | |
252 Tick(MemoryPressureMonitor::kMinimumTimeBetweenSamplesMs); | |
253 EXPECT_EQ(MEMORY_PRESSURE_LEVEL_NONE, monitor_->GetCurrentPressureLevel()); | |
254 VerifyAndClearExpectations(); | |
255 EXPECT_EQ(1, calculator_.calls()); | |
256 ExpectNone(); | |
257 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
258 } | |
259 | |
260 TEST_F(MemoryPressureMonitorTest, NoPressureScheduling) { | |
261 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
262 | |
263 // Step forward by a polling interval. This should cause another scheduled | |
264 // check to be posted. | |
265 Tick(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
266 ExpectTaskPosted(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
267 monitor_->CheckPressureAndUpdateStats(monitor_->serial_number()); | |
268 VerifyAndClearExpectations(); | |
269 ExpectNone(); | |
270 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
271 } | |
272 | |
273 TEST_F(MemoryPressureMonitorTest, NoPressureToModerateViaScheduling) { | |
274 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
275 | |
276 // Step forward by a polling interval. This should cause another scheduled | |
277 // check to be posted. | |
278 calculator_.SetModerate(); | |
279 Tick(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
280 ExpectTaskPosted( | |
281 MemoryPressureMonitor::kNotificationIntervalPressureModerateMs); | |
282 ExpectDispatchModerate(); | |
283 monitor_->CheckPressureAndUpdateStats(monitor_->serial_number()); | |
284 VerifyAndClearExpectations(); | |
285 ExpectModerate(); | |
286 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
287 } | |
288 | |
289 TEST_F(MemoryPressureMonitorTest, NoPressureToCriticalViaScheduling) { | |
290 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
291 | |
292 // Step forward by a polling interval. This should cause another scheduled | |
293 // check to be posted. | |
294 calculator_.SetCritical(); | |
295 Tick(MemoryPressureMonitor::kDefaultPollingIntervalMs); | |
296 ExpectTaskPosted( | |
297 MemoryPressureMonitor::kNotificationIntervalPressureCriticalMs); | |
298 ExpectDispatchCritical(); | |
299 monitor_->CheckPressureAndUpdateStats(monitor_->serial_number()); | |
300 VerifyAndClearExpectations(); | |
301 ExpectCritical(); | |
302 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
303 } | |
304 | |
305 TEST_F(MemoryPressureMonitorTest, ModeratePressureToCriticalViaScheduling) { | |
306 CreateMonitor(MEMORY_PRESSURE_LEVEL_MODERATE); | |
307 | |
308 // Step forward by a polling interval. This should cause another scheduled | |
309 // check to be posted. | |
310 calculator_.SetCritical(); | |
311 Tick(MemoryPressureMonitor::kNotificationIntervalPressureModerateMs); | |
312 ExpectTaskPosted( | |
313 MemoryPressureMonitor::kNotificationIntervalPressureCriticalMs); | |
314 ExpectDispatchCritical(); | |
315 monitor_->CheckPressureAndUpdateStats(monitor_->serial_number()); | |
316 VerifyAndClearExpectations(); | |
317 ExpectCritical(); | |
318 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
319 } | |
320 | |
321 TEST_F(MemoryPressureMonitorTest, UnscheduledStateChange) { | |
322 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
323 | |
324 // Callback into the monitor directly. This will change the memory pressure | |
325 // and cause a new call to be scheduled as the higher memory pressure has a | |
326 // higher renotification frequency. | |
327 // NOTE: This test relies implicitly on the following facts: | |
328 // kMinimumTimeBetweenSamplesMs < kDefaultPollingIntervalMs / 2 | |
329 // kNotificationIntervalPressureCriticalMs < kDefaultPollingIntervalMs / 2 | |
330 calculator_.SetCritical(); | |
331 Tick(MemoryPressureMonitor::kDefaultPollingIntervalMs / 2); | |
332 ExpectTaskPosted( | |
333 MemoryPressureMonitor::kNotificationIntervalPressureCriticalMs); | |
334 ExpectDispatchCritical(); | |
335 EXPECT_EQ(MEMORY_PRESSURE_LEVEL_CRITICAL, | |
336 monitor_->GetCurrentPressureLevel()); | |
337 VerifyAndClearExpectations(); | |
338 EXPECT_EQ(1, calculator_.calls()); | |
339 ExpectCritical(); | |
340 EXPECT_EQ(2u, monitor_->scheduled_checks().size()); | |
341 } | |
342 | |
343 #else // MEMORY_PRESSURE_IS_POLLING | |
344 | |
345 TEST_F(MemoryPressureMonitorTest, PressureChangeNop) { | |
346 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
347 | |
348 // The pressure hasn't changed so this should be a nop. | |
349 Tick(1); | |
350 monitor_->OnMemoryPressureChanged(MEMORY_PRESSURE_LEVEL_NONE); | |
351 VerifyAndClearExpectations(); | |
352 ExpectNone(); | |
353 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
354 } | |
355 | |
356 TEST_F(MemoryPressureMonitorTest, PressureChangeNoNewScheduledTask) { | |
357 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
358 | |
359 // The pressure is increasing and the renotification frequency has changed. | |
360 // However, a pending event is already scheduled soon enough so no new one | |
361 // should be scheduled. | |
362 Tick(MemoryPressureMonitor::kDefaultPollingIntervalMs - | |
363 MemoryPressureMonitor::kNotificationIntervalPressureModerateMs / 2); | |
364 ExpectDispatchModerate(); | |
365 monitor_->OnMemoryPressureChanged(MEMORY_PRESSURE_LEVEL_MODERATE); | |
366 VerifyAndClearExpectations(); | |
367 ExpectModerate(); | |
368 EXPECT_EQ(1u, monitor_->scheduled_checks().size()); | |
369 } | |
370 | |
371 TEST_F(MemoryPressureMonitorTest, PressureChangeNewScheduledTask) { | |
372 CreateMonitor(MEMORY_PRESSURE_LEVEL_NONE); | |
373 | |
374 // The pressure is increasing and the renotification frequency has changed. | |
375 // The already scheduled event is too far in the future so a new event should | |
376 // be scheduled. | |
377 Tick(1); | |
378 ExpectTaskPosted( | |
379 MemoryPressureMonitor::kNotificationIntervalPressureCriticalMs); | |
380 ExpectDispatchCritical(); | |
381 monitor_->OnMemoryPressureChanged(MEMORY_PRESSURE_LEVEL_CRITICAL); | |
382 VerifyAndClearExpectations(); | |
383 ExpectCritical(); | |
384 EXPECT_EQ(2u, monitor_->scheduled_checks().size()); | |
385 } | |
386 | |
387 #endif // !MEMORY_PRESSURE_IS_POLLING | |
388 | |
389 } // namespace memory_pressure | |
OLD | NEW |