| Index: base/memory/memory_pressure_monitor_mac_unittest.cc
|
| diff --git a/base/memory/memory_pressure_monitor_mac_unittest.cc b/base/memory/memory_pressure_monitor_mac_unittest.cc
|
| index b7c29cd13cb59025ae230c7007a937f81badc456..9d251f011e9959d1ea5f52482546e382155e993e 100644
|
| --- a/base/memory/memory_pressure_monitor_mac_unittest.cc
|
| +++ b/base/memory/memory_pressure_monitor_mac_unittest.cc
|
| @@ -4,7 +4,11 @@
|
|
|
| #include "base/memory/memory_pressure_monitor_mac.h"
|
|
|
| +#include "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/mac/scoped_cftyperef.h"
|
| #include "base/macros.h"
|
| +#include "base/test/histogram_tester.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| namespace base {
|
| @@ -12,43 +16,87 @@ namespace mac {
|
|
|
| class TestMemoryPressureMonitor : public MemoryPressureMonitor {
|
| public:
|
| - using MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure;
|
| + using MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel;
|
| +
|
| + // A HistogramTester for verifying correct UMA stat generation.
|
| + base::HistogramTester tester;
|
|
|
| TestMemoryPressureMonitor() { }
|
|
|
| + // Clears the next run loop update time so that the next pass of the run
|
| + // loop checks the memory pressure level immediately. Normally there's a
|
| + // 5 second delay between pressure readings.
|
| + void ResetRunLoopUpdateTime() { next_run_loop_update_time_ = 0; }
|
| +
|
| + // Access to the last-recorded memory pressure level.
|
| + MemoryPressureListener::MemoryPressureLevel LastPressureLevel() {
|
| + return last_pressure_level_;
|
| + }
|
| +
|
| + // Sets the last UMA stat report time. Time spent in memory pressure is
|
| + // recorded in 5-second "ticks" from the last time statistics were recorded.
|
| + void SetLastStatisticReportTime(CFTimeInterval time) {
|
| + last_statistic_report_time_ = time;
|
| + }
|
| +
|
| + // Sets the raw macOS memory pressure level read by the memory pressure
|
| + // monitor.
|
| + int macos_pressure_level_for_testing_;
|
| +
|
| + // Exposes the UpdatePressureLevel() method for testing.
|
| + void UpdatePressureLevel() { MemoryPressureMonitor::UpdatePressureLevel(); }
|
| +
|
| + // Returns the number of seconds left over from the last UMA tick
|
| + // calculation.
|
| + int SubTickSeconds() { return subtick_seconds_; }
|
| +
|
| + // Returns the number of seconds per UMA tick.
|
| + static int GetSecondsPerUMATick() {
|
| + return MemoryPressureMonitor::GetSecondsPerUMATick();
|
| + }
|
| +
|
| private:
|
| DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
|
| +
|
| + int GetMacMemoryPressureLevel() override {
|
| + return macos_pressure_level_for_testing_;
|
| + }
|
| };
|
|
|
| TEST(MacMemoryPressureMonitorTest, MemoryPressureFromMacMemoryPressure) {
|
| - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| - TestMemoryPressureMonitor::
|
| - MemoryPressureLevelForMacMemoryPressure(
|
| - DISPATCH_MEMORYPRESSURE_NORMAL));
|
| - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
|
| - TestMemoryPressureMonitor::
|
| - MemoryPressureLevelForMacMemoryPressure(
|
| - DISPATCH_MEMORYPRESSURE_WARN));
|
| - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
|
| - TestMemoryPressureMonitor::
|
| - MemoryPressureLevelForMacMemoryPressure(
|
| - DISPATCH_MEMORYPRESSURE_CRITICAL));
|
| - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| - TestMemoryPressureMonitor::
|
| - MemoryPressureLevelForMacMemoryPressure(0));
|
| - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| - TestMemoryPressureMonitor::
|
| - MemoryPressureLevelForMacMemoryPressure(3));
|
| - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| - TestMemoryPressureMonitor::
|
| - MemoryPressureLevelForMacMemoryPressure(5));
|
| - EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| - TestMemoryPressureMonitor::
|
| - MemoryPressureLevelForMacMemoryPressure(-1));
|
| + EXPECT_EQ(
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| + TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
|
| + DISPATCH_MEMORYPRESSURE_NORMAL));
|
| + EXPECT_EQ(
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
|
| + TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
|
| + DISPATCH_MEMORYPRESSURE_WARN));
|
| + EXPECT_EQ(
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
|
| + TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
|
| + DISPATCH_MEMORYPRESSURE_CRITICAL));
|
| + EXPECT_EQ(
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| + TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
|
| + 0));
|
| + EXPECT_EQ(
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| + TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
|
| + 3));
|
| + EXPECT_EQ(
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| + TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
|
| + 5));
|
| + EXPECT_EQ(
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
|
| + TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
|
| + -1));
|
| }
|
|
|
| TEST(MacMemoryPressureMonitorTest, CurrentMemoryPressure) {
|
| TestMemoryPressureMonitor monitor;
|
| +
|
| MemoryPressureListener::MemoryPressureLevel memory_pressure =
|
| monitor.GetCurrentPressureLevel();
|
| EXPECT_TRUE(memory_pressure ==
|
| @@ -59,5 +107,124 @@ TEST(MacMemoryPressureMonitorTest, CurrentMemoryPressure) {
|
| MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
|
| }
|
|
|
| +TEST(MacMemoryPressureMonitorTest, MemoryPressureConversion) {
|
| + TestMemoryPressureMonitor monitor;
|
| +
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
|
| + MemoryPressureListener::MemoryPressureLevel memory_pressure =
|
| + monitor.GetCurrentPressureLevel();
|
| + EXPECT_EQ(memory_pressure,
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
|
| +
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN;
|
| + memory_pressure = monitor.GetCurrentPressureLevel();
|
| + EXPECT_EQ(memory_pressure,
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
|
| +
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
|
| + memory_pressure = monitor.GetCurrentPressureLevel();
|
| + EXPECT_EQ(memory_pressure,
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
|
| +}
|
| +
|
| +TEST(MacMemoryPressureMonitorTest, MemoryPressureRunLoopChecking) {
|
| + TestMemoryPressureMonitor monitor;
|
| +
|
| + // To test grabbing the memory presure at the end of the run loop, we have to
|
| + // run the run loop, but to do that the run loop needs a run loop source. Add
|
| + // a timer as the source. We know that the exit observer is attached to
|
| + // the kMessageLoopExclusiveRunLoopMode mode, so use that mode.
|
| + ScopedCFTypeRef<CFRunLoopTimerRef> timer_ref(CFRunLoopTimerCreate(
|
| + NULL, CFAbsoluteTimeGetCurrent() + 10, 0, 0, 0, nullptr, nullptr));
|
| + CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer_ref,
|
| + kMessageLoopExclusiveRunLoopMode);
|
| +
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN;
|
| + monitor.ResetRunLoopUpdateTime();
|
| + CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true);
|
| + EXPECT_EQ(monitor.LastPressureLevel(),
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
|
| +
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
|
| + monitor.ResetRunLoopUpdateTime();
|
| + CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true);
|
| + EXPECT_EQ(monitor.LastPressureLevel(),
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
|
| +
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
|
| + monitor.ResetRunLoopUpdateTime();
|
| + CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true);
|
| + EXPECT_EQ(monitor.LastPressureLevel(),
|
| + MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
|
| +
|
| + CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer_ref,
|
| + kMessageLoopExclusiveRunLoopMode);
|
| +}
|
| +
|
| +TEST(MacMemoryPressureMonitorTest, RecordMemoryPressureStats) {
|
| + TestMemoryPressureMonitor monitor;
|
| + const char* kHistogram = "Memory.PressureLevel";
|
| + CFTimeInterval now = CFAbsoluteTimeGetCurrent();
|
| + const int seconds_per_tick =
|
| + TestMemoryPressureMonitor::GetSecondsPerUMATick();
|
| +
|
| + // Set the initial pressure level.
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
|
| + // Incur one UMA tick of time (and include one extra second of elapsed time).
|
| + monitor.SetLastStatisticReportTime(now - (seconds_per_tick + 1));
|
| + monitor.UpdatePressureLevel();
|
| + monitor.tester.ExpectTotalCount(kHistogram, 1);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 0, 1);
|
| + // The report time above included an extra second so there should be 1
|
| + // sub-tick second left over.
|
| + EXPECT_EQ(1, monitor.SubTickSeconds());
|
| +
|
| + // Simulate sitting in normal pressure for 1 second less than 6 UMA tick
|
| + // seconds and then elevating to warning. With the left over sub-tick second
|
| + // from above, the total elapsed ticks should be an even 6 UMA ticks.
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN;
|
| + monitor.SetLastStatisticReportTime(now - (seconds_per_tick * 6 - 1));
|
| + monitor.UpdatePressureLevel();
|
| + monitor.tester.ExpectTotalCount(kHistogram, 7);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 1, 0);
|
| + EXPECT_EQ(0, monitor.SubTickSeconds());
|
| +
|
| + // Simulate sitting in warning pressure for 20 UMA ticks and 2 seconds, and
|
| + // then elevating to critical.
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
|
| + monitor.SetLastStatisticReportTime(now - (20 * seconds_per_tick + 2));
|
| + monitor.UpdatePressureLevel();
|
| + monitor.tester.ExpectTotalCount(kHistogram, 27);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 1, 20);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 2, 0);
|
| + EXPECT_EQ(2, monitor.SubTickSeconds());
|
| +
|
| + // A quick update while critical - the stats should not budge because less
|
| + // than 1 tick of time has elapsed.
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
|
| + monitor.SetLastStatisticReportTime(now - 1);
|
| + monitor.UpdatePressureLevel();
|
| + monitor.tester.ExpectTotalCount(kHistogram, 27);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 1, 20);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 2, 0);
|
| + EXPECT_EQ(3, monitor.SubTickSeconds());
|
| +
|
| + // A quick change back to normal. Less than 1 tick of time has elapsed, but
|
| + // in this case the pressure level changed, so the critical bucket should
|
| + // get another sample (otherwise we could miss quick level changes).
|
| + monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
|
| + monitor.SetLastStatisticReportTime(now - 1);
|
| + monitor.UpdatePressureLevel();
|
| + monitor.tester.ExpectTotalCount(kHistogram, 28);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 1, 20);
|
| + monitor.tester.ExpectBucketCount(kHistogram, 2, 1);
|
| + // When less than 1 tick of time has elapsed but the pressure level changed,
|
| + // the subtick remainder gets zeroed out.
|
| + EXPECT_EQ(0, monitor.SubTickSeconds());
|
| +}
|
| } // namespace mac
|
| } // namespace base
|
|
|