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

Side by Side Diff: base/memory/memory_pressure_monitor_mac_unittest.cc

Issue 1587273002: [Mac] Collect real-time memory pressure stats, in an energy-efficient way (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix nits. Created 3 years, 10 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/memory/memory_pressure_monitor_mac.h" 5 #include "base/memory/memory_pressure_monitor_mac.h"
6 6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/mac/scoped_cftyperef.h"
7 #include "base/macros.h" 10 #include "base/macros.h"
11 #include "base/test/histogram_tester.h"
8 #include "testing/gtest/include/gtest/gtest.h" 12 #include "testing/gtest/include/gtest/gtest.h"
9 13
10 namespace base { 14 namespace base {
11 namespace mac { 15 namespace mac {
12 16
13 class TestMemoryPressureMonitor : public MemoryPressureMonitor { 17 class TestMemoryPressureMonitor : public MemoryPressureMonitor {
14 public: 18 public:
15 using MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure; 19 using MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel;
20
21 // A HistogramTester for verifying correct UMA stat generation.
22 base::HistogramTester tester;
16 23
17 TestMemoryPressureMonitor() { } 24 TestMemoryPressureMonitor() { }
18 25
26 // Clears the next run loop update time so that the next pass of the run
27 // loop checks the memory pressure level immediately. Normally there's a
28 // 5 second delay between pressure readings.
29 void ResetRunLoopUpdateTime() { next_run_loop_update_time_ = 0; }
30
31 // Access to the last-recorded memory pressure level.
32 MemoryPressureListener::MemoryPressureLevel LastPressureLevel() {
33 return last_pressure_level_;
34 }
35
36 // Sets the last UMA stat report time. Time spent in memory pressure is
37 // recorded in 5-second "ticks" from the last time statistics were recorded.
38 void SetLastStatisticReportTime(CFTimeInterval time) {
39 last_statistic_report_time_ = time;
40 }
41
42 // Sets the raw macOS memory pressure level read by the memory pressure
43 // monitor.
44 int macos_pressure_level_for_testing_;
45
46 // Exposes the UpdatePressureLevel() method for testing.
47 void UpdatePressureLevel() { MemoryPressureMonitor::UpdatePressureLevel(); }
48
49 // Returns the number of seconds left over from the last UMA tick
50 // calculation.
51 int SubTickSeconds() { return subtick_seconds_; }
52
53 // Returns the number of seconds per UMA tick.
54 static int GetSecondsPerUMATick() {
55 return MemoryPressureMonitor::GetSecondsPerUMATick();
56 }
57
19 private: 58 private:
20 DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor); 59 DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
60
61 int GetMacMemoryPressureLevel() override {
62 return macos_pressure_level_for_testing_;
63 }
21 }; 64 };
22 65
23 TEST(MacMemoryPressureMonitorTest, MemoryPressureFromMacMemoryPressure) { 66 TEST(MacMemoryPressureMonitorTest, MemoryPressureFromMacMemoryPressure) {
24 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, 67 EXPECT_EQ(
25 TestMemoryPressureMonitor:: 68 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
26 MemoryPressureLevelForMacMemoryPressure( 69 TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
27 DISPATCH_MEMORYPRESSURE_NORMAL)); 70 DISPATCH_MEMORYPRESSURE_NORMAL));
28 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE, 71 EXPECT_EQ(
29 TestMemoryPressureMonitor:: 72 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
30 MemoryPressureLevelForMacMemoryPressure( 73 TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
31 DISPATCH_MEMORYPRESSURE_WARN)); 74 DISPATCH_MEMORYPRESSURE_WARN));
32 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL, 75 EXPECT_EQ(
33 TestMemoryPressureMonitor:: 76 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
34 MemoryPressureLevelForMacMemoryPressure( 77 TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
35 DISPATCH_MEMORYPRESSURE_CRITICAL)); 78 DISPATCH_MEMORYPRESSURE_CRITICAL));
36 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, 79 EXPECT_EQ(
37 TestMemoryPressureMonitor:: 80 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
38 MemoryPressureLevelForMacMemoryPressure(0)); 81 TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
39 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, 82 0));
40 TestMemoryPressureMonitor:: 83 EXPECT_EQ(
41 MemoryPressureLevelForMacMemoryPressure(3)); 84 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
42 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, 85 TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
43 TestMemoryPressureMonitor:: 86 3));
44 MemoryPressureLevelForMacMemoryPressure(5)); 87 EXPECT_EQ(
45 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE, 88 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
46 TestMemoryPressureMonitor:: 89 TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
47 MemoryPressureLevelForMacMemoryPressure(-1)); 90 5));
91 EXPECT_EQ(
92 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
93 TestMemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressureLevel(
94 -1));
48 } 95 }
49 96
50 TEST(MacMemoryPressureMonitorTest, CurrentMemoryPressure) { 97 TEST(MacMemoryPressureMonitorTest, CurrentMemoryPressure) {
51 TestMemoryPressureMonitor monitor; 98 TestMemoryPressureMonitor monitor;
99
52 MemoryPressureListener::MemoryPressureLevel memory_pressure = 100 MemoryPressureListener::MemoryPressureLevel memory_pressure =
53 monitor.GetCurrentPressureLevel(); 101 monitor.GetCurrentPressureLevel();
54 EXPECT_TRUE(memory_pressure == 102 EXPECT_TRUE(memory_pressure ==
55 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE || 103 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE ||
56 memory_pressure == 104 memory_pressure ==
57 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE || 105 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE ||
58 memory_pressure == 106 memory_pressure ==
59 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL); 107 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
60 } 108 }
61 109
110 TEST(MacMemoryPressureMonitorTest, MemoryPressureConversion) {
111 TestMemoryPressureMonitor monitor;
112
113 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
114 MemoryPressureListener::MemoryPressureLevel memory_pressure =
115 monitor.GetCurrentPressureLevel();
116 EXPECT_EQ(memory_pressure,
117 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
118
119 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN;
120 memory_pressure = monitor.GetCurrentPressureLevel();
121 EXPECT_EQ(memory_pressure,
122 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
123
124 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
125 memory_pressure = monitor.GetCurrentPressureLevel();
126 EXPECT_EQ(memory_pressure,
127 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
128 }
129
130 TEST(MacMemoryPressureMonitorTest, MemoryPressureRunLoopChecking) {
131 TestMemoryPressureMonitor monitor;
132
133 // To test grabbing the memory presure at the end of the run loop, we have to
134 // run the run loop, but to do that the run loop needs a run loop source. Add
135 // a timer as the source. We know that the exit observer is attached to
136 // the kMessageLoopExclusiveRunLoopMode mode, so use that mode.
137 ScopedCFTypeRef<CFRunLoopTimerRef> timer_ref(CFRunLoopTimerCreate(
138 NULL, CFAbsoluteTimeGetCurrent() + 10, 0, 0, 0, nullptr, nullptr));
139 CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer_ref,
140 kMessageLoopExclusiveRunLoopMode);
141
142 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN;
143 monitor.ResetRunLoopUpdateTime();
144 CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true);
145 EXPECT_EQ(monitor.LastPressureLevel(),
146 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
147
148 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
149 monitor.ResetRunLoopUpdateTime();
150 CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true);
151 EXPECT_EQ(monitor.LastPressureLevel(),
152 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
153
154 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
155 monitor.ResetRunLoopUpdateTime();
156 CFRunLoopRunInMode(kMessageLoopExclusiveRunLoopMode, 0, true);
157 EXPECT_EQ(monitor.LastPressureLevel(),
158 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE);
159
160 CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), timer_ref,
161 kMessageLoopExclusiveRunLoopMode);
162 }
163
164 TEST(MacMemoryPressureMonitorTest, RecordMemoryPressureStats) {
165 TestMemoryPressureMonitor monitor;
166 const char* kHistogram = "Memory.PressureLevel";
167 CFTimeInterval now = CFAbsoluteTimeGetCurrent();
168 const int seconds_per_tick =
169 TestMemoryPressureMonitor::GetSecondsPerUMATick();
170
171 // Set the initial pressure level.
172 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
173 // Incur one UMA tick of time (and include one extra second of elapsed time).
174 monitor.SetLastStatisticReportTime(now - (seconds_per_tick + 1));
175 monitor.UpdatePressureLevel();
176 monitor.tester.ExpectTotalCount(kHistogram, 1);
177 monitor.tester.ExpectBucketCount(kHistogram, 0, 1);
178 // The report time above included an extra second so there should be 1
179 // sub-tick second left over.
180 EXPECT_EQ(1, monitor.SubTickSeconds());
181
182 // Simulate sitting in normal pressure for 1 second less than 6 UMA tick
183 // seconds and then elevating to warning. With the left over sub-tick second
184 // from above, the total elapsed ticks should be an even 6 UMA ticks.
185 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_WARN;
186 monitor.SetLastStatisticReportTime(now - (seconds_per_tick * 6 - 1));
187 monitor.UpdatePressureLevel();
188 monitor.tester.ExpectTotalCount(kHistogram, 7);
189 monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
190 monitor.tester.ExpectBucketCount(kHistogram, 1, 0);
191 EXPECT_EQ(0, monitor.SubTickSeconds());
192
193 // Simulate sitting in warning pressure for 20 UMA ticks and 2 seconds, and
194 // then elevating to critical.
195 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
196 monitor.SetLastStatisticReportTime(now - (20 * seconds_per_tick + 2));
197 monitor.UpdatePressureLevel();
198 monitor.tester.ExpectTotalCount(kHistogram, 27);
199 monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
200 monitor.tester.ExpectBucketCount(kHistogram, 1, 20);
201 monitor.tester.ExpectBucketCount(kHistogram, 2, 0);
202 EXPECT_EQ(2, monitor.SubTickSeconds());
lgrey 2017/02/22 21:33:40 I wonder if we should always be rounding up for co
shrike 2017/02/22 23:56:25 I think if we do, and if we get a lot of subtick_s
lgrey 2017/02/23 15:49:29 Nah, no problem. I guess the inaccuracy is baked i
203
204 // A quick update while critical - the stats should not budge because less
205 // than 1 tick of time has elapsed.
206 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_CRITICAL;
207 monitor.SetLastStatisticReportTime(now - 1);
208 monitor.UpdatePressureLevel();
209 monitor.tester.ExpectTotalCount(kHistogram, 27);
210 monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
211 monitor.tester.ExpectBucketCount(kHistogram, 1, 20);
212 monitor.tester.ExpectBucketCount(kHistogram, 2, 0);
213 EXPECT_EQ(3, monitor.SubTickSeconds());
214
215 // A quick change back to normal. Less than 1 tick of time has elapsed, but
216 // in this case the pressure level changed, so the critical bucket should
217 // get another sample (otherwise we could miss quick level changes).
218 monitor.macos_pressure_level_for_testing_ = DISPATCH_MEMORYPRESSURE_NORMAL;
219 monitor.SetLastStatisticReportTime(now - 1);
220 monitor.UpdatePressureLevel();
221 monitor.tester.ExpectTotalCount(kHistogram, 28);
222 monitor.tester.ExpectBucketCount(kHistogram, 0, 7);
223 monitor.tester.ExpectBucketCount(kHistogram, 1, 20);
224 monitor.tester.ExpectBucketCount(kHistogram, 2, 1);
225 // When less than 1 tick of time has elapsed but the pressure level changed,
226 // the subtick remainder gets zeroed out.
227 EXPECT_EQ(0, monitor.SubTickSeconds());
228 }
62 } // namespace mac 229 } // namespace mac
63 } // namespace base 230 } // namespace base
OLDNEW
« base/memory/memory_pressure_monitor_mac.cc ('K') | « base/memory/memory_pressure_monitor_mac.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698