| 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 |