summaryrefslogtreecommitdiffstats
path: root/chromium/base/win/memory_pressure_monitor_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/win/memory_pressure_monitor_unittest.cc')
-rw-r--r--chromium/base/win/memory_pressure_monitor_unittest.cc298
1 files changed, 298 insertions, 0 deletions
diff --git a/chromium/base/win/memory_pressure_monitor_unittest.cc b/chromium/base/win/memory_pressure_monitor_unittest.cc
new file mode 100644
index 00000000000..40a25a79dd8
--- /dev/null
+++ b/chromium/base/win/memory_pressure_monitor_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/memory_pressure_monitor.h"
+
+#include "base/basictypes.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct PressureSettings {
+ int phys_left_mb;
+ MemoryPressureListener::MemoryPressureLevel level;
+};
+
+} // namespace
+
+// This is outside of the anonymous namespace so that it can be seen as a friend
+// to the monitor class.
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+ using MemoryPressureMonitor::CalculateCurrentPressureLevel;
+ using MemoryPressureMonitor::CheckMemoryPressure;
+
+ static const DWORDLONG kMBBytes = 1024 * 1024;
+
+ explicit TestMemoryPressureMonitor(bool large_memory)
+ : mem_status_() {
+ // Generate a plausible amount of memory.
+ mem_status_.ullTotalPhys =
+ static_cast<DWORDLONG>(GenerateTotalMemoryMb(large_memory)) * kMBBytes;
+
+ // Rerun InferThresholds using the test fixture's GetSystemMemoryStatus.
+ InferThresholds();
+ // Stop the timer.
+ StopObserving();
+ }
+
+ TestMemoryPressureMonitor(int system_memory_mb,
+ int moderate_threshold_mb,
+ int critical_threshold_mb)
+ : MemoryPressureMonitor(moderate_threshold_mb, critical_threshold_mb),
+ mem_status_() {
+ // Set the amount of system memory.
+ mem_status_.ullTotalPhys = static_cast<DWORDLONG>(
+ system_memory_mb * kMBBytes);
+
+ // Stop the timer.
+ StopObserving();
+ }
+
+ virtual ~TestMemoryPressureMonitor() {}
+
+ MOCK_METHOD1(OnMemoryPressure,
+ void(MemoryPressureListener::MemoryPressureLevel level));
+
+ // Generates an amount of total memory that is consistent with the requested
+ // memory model.
+ int GenerateTotalMemoryMb(bool large_memory) {
+ int total_mb = 64;
+ while (total_mb < MemoryPressureMonitor::kLargeMemoryThresholdMb)
+ total_mb *= 2;
+ if (large_memory)
+ return total_mb * 2;
+ return total_mb / 2;
+ }
+
+ // Sets up the memory status to reflect the provided absolute memory left.
+ void SetMemoryFree(int phys_left_mb) {
+ // ullTotalPhys is set in the constructor and not modified.
+
+ // Set the amount of available memory.
+ mem_status_.ullAvailPhys =
+ static_cast<DWORDLONG>(phys_left_mb) * kMBBytes;
+ DCHECK_LT(mem_status_.ullAvailPhys, mem_status_.ullTotalPhys);
+
+ // These fields are unused.
+ mem_status_.dwMemoryLoad = 0;
+ mem_status_.ullTotalPageFile = 0;
+ mem_status_.ullAvailPageFile = 0;
+ mem_status_.ullTotalVirtual = 0;
+ mem_status_.ullAvailVirtual = 0;
+ }
+
+ void SetNone() {
+ SetMemoryFree(moderate_threshold_mb() + 1);
+ }
+
+ void SetModerate() {
+ SetMemoryFree(moderate_threshold_mb() - 1);
+ }
+
+ void SetCritical() {
+ SetMemoryFree(critical_threshold_mb() - 1);
+ }
+
+ private:
+ bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status) override {
+ // Simply copy the memory status set by the test fixture.
+ *mem_status = mem_status_;
+ return true;
+ }
+
+ MEMORYSTATUSEX mem_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+class WinMemoryPressureMonitorTest : public testing::Test {
+ protected:
+ void CalculateCurrentMemoryPressureLevelTest(
+ TestMemoryPressureMonitor* monitor) {
+
+ int mod = monitor->moderate_threshold_mb();
+ monitor->SetMemoryFree(mod + 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(mod);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(mod - 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->CalculateCurrentPressureLevel());
+
+ int crit = monitor->critical_threshold_mb();
+ monitor->SetMemoryFree(crit + 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(crit);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor->CalculateCurrentPressureLevel());
+
+ monitor->SetMemoryFree(crit - 1);
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor->CalculateCurrentPressureLevel());
+ }
+
+ base::MessageLoopForUI message_loop_;
+};
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// small-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelSmall) {
+ static const int kModerateMb =
+ MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb;
+ static const int kCriticalMb =
+ MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb;
+
+ TestMemoryPressureMonitor monitor(false); // Small-memory model.
+
+ EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+ EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+ ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// large-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelLarge) {
+ static const int kModerateMb =
+ MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb;
+ static const int kCriticalMb =
+ MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb;
+
+ TestMemoryPressureMonitor monitor(true); // Large-memory model.
+
+ EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+ EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+ ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with manually
+// specified threshold levels.
+TEST_F(WinMemoryPressureMonitorTest,
+ CalculateCurrentMemoryPressureLevelCustom) {
+ static const int kSystemMb = 512;
+ static const int kModerateMb = 256;
+ static const int kCriticalMb = 128;
+
+ TestMemoryPressureMonitor monitor(kSystemMb, kModerateMb, kCriticalMb);
+
+ EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+ EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+ ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// This test tests the various transition states from memory pressure, looking
+// for the correct behavior on event reposting as well as state updates.
+TEST_F(WinMemoryPressureMonitorTest, CheckMemoryPressure) {
+ // Large-memory.
+ testing::StrictMock<TestMemoryPressureMonitor> monitor(true);
+ MemoryPressureListener listener(
+ base::Bind(&TestMemoryPressureMonitor::OnMemoryPressure,
+ base::Unretained(&monitor)));
+
+ // Checking the memory pressure at 0% load should not produce any
+ // events.
+ monitor.SetNone();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ monitor.GetCurrentPressureLevel());
+
+ // Setting the memory level to 80% should produce a moderate pressure level.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ monitor.SetModerate();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // Check that the event gets reposted after a while.
+ for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+ if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ }
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+ }
+
+ // Setting the memory usage to 99% should produce critical levels.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_CRITICAL));
+ monitor.SetCritical();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // Calling it again should immediately produce a second call.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_CRITICAL));
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // When lowering the pressure again there should be a notification and the
+ // pressure should go back to moderate.
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ monitor.SetModerate();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+
+ // Check that the event gets reposted after a while.
+ for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+ if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+ EXPECT_CALL(monitor,
+ OnMemoryPressure(MemoryPressureListener::
+ MEMORY_PRESSURE_LEVEL_MODERATE));
+ }
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+ }
+
+ // Going down to no pressure should not produce an notification.
+ monitor.SetNone();
+ monitor.CheckMemoryPressure();
+ message_loop_.RunUntilIdle();
+ EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+ monitor.GetCurrentPressureLevel());
+ testing::Mock::VerifyAndClearExpectations(&monitor);
+}
+
+} // namespace win
+} // namespace base