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

Side by Side Diff: base/win/memory_pressure_monitor_win_unittest.cc

Issue 1122863005: Create base::win::MemoryPressureMonitor class. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 7 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "base/basictypes.h"
6 #include "base/memory/memory_pressure_listener.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/win/memory_pressure_monitor_win.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 namespace base {
12
13 namespace {
14
15 // True if the memory notifier got called.
grt (UTC plus 2) 2015/05/05 15:34:00 you could use Google Mock here rather than rolling
chrisha 2015/05/05 19:46:13 Yeah, I use gmock all over the place in Syzygy lan
grt (UTC plus 2) 2015/05/06 13:26:36 My personal belief is that gmock is okay to use wh
16 // Do not read/modify value directly.
17 bool on_memory_pressure_called = false;
18
19 // If the memory notifier got called, this is the memory pressure reported.
20 MemoryPressureListener::MemoryPressureLevel on_memory_pressure_level =
21 MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
22
23 // Processes OnMemoryPressure calls.
24 void OnMemoryPressure(MemoryPressureListener::MemoryPressureLevel level) {
25 on_memory_pressure_called = true;
26 on_memory_pressure_level = level;
27 }
28
29 // Resets the indicator for memory pressure.
30 void ResetOnMemoryPressureCalled() {
31 on_memory_pressure_called = false;
32 }
33
34 // Returns true when OnMemoryPressure was called (and resets it).
35 bool WasOnMemoryPressureCalled() {
36 bool b = on_memory_pressure_called;
37 ResetOnMemoryPressureCalled();
38 return b;
39 }
40
41 struct PressureSettings {
42 int phys;
43 int virt;
44 MemoryPressureListener::MemoryPressureLevel level;
45 };
46
47 } // namespace
48
49 // This is outside of the anonymous namespace so that it can be seen as a friend
50 // to the monitor class.
51 class TestMemoryPressureMonitor : public MemoryPressureMonitorWin {
52 public:
53 using MemoryPressureMonitorWin::CalculateCurrentPressureLevel;
54 using MemoryPressureMonitorWin::CheckMemoryPressure;
55
56 TestMemoryPressureMonitor() {
57 // Disable any timers which are going on and set a special memory reporting
58 // function.
59 StopObserving();
60 }
61
62 virtual ~TestMemoryPressureMonitor() {}
63
64 // Sets up the memory status to reflect the provided loads.
65 void SetMemoryLoad(int phys_load_pct, int virt_load_pct) {
66 static const DWORDLONG k4GB = 4ull * 1024 * 1024 * 1024;
67
68 mem_status_.dwMemoryLoad = static_cast<DWORD>(phys_load_pct);
69 mem_status_.ullTotalPhys = k4GB;
70 mem_status_.ullAvailPhys = (k4GB * (100 - phys_load_pct)) / 100;
71 mem_status_.ullTotalPageFile = k4GB;
72 mem_status_.ullAvailPageFile = k4GB;
73 mem_status_.ullTotalVirtual = k4GB;
74 mem_status_.ullAvailVirtual = (k4GB * (100 - virt_load_pct)) / 100;
75 }
76
77 // Sets up the memory status to reflect the provided absolute memory left.
78 // This uses quite small total memory quantities so that the absolute memory
79 // limits have a chance to kick in.
80 void SetMemoryFree(int phys_left_mb, int virt_left_mb) {
81 // Figure out an amount of memory that makes sense for the desired
82 // quantities of memory to be left.
83 DWORDLONG total = 64; // Minimum of 64MB.
84 while (total < phys_left_mb || total < virt_left_mb)
85 total *= 2;
86 total *= 1024 * 1024;
87
88 mem_status_.ullTotalPhys = total;
89 mem_status_.ullAvailPhys =
90 static_cast<DWORDLONG>(phys_left_mb) * 1024 * 1024;
91 mem_status_.ullTotalPageFile = total;
92 mem_status_.ullAvailPageFile = total;
93 mem_status_.ullTotalVirtual = total;
94 mem_status_.ullAvailVirtual =
95 static_cast<DWORDLONG>(virt_left_mb) * 1024 * 1024;
96 mem_status_.dwMemoryLoad = static_cast<DWORD>(
97 100 * (mem_status_.ullTotalPhys - mem_status_.ullAvailPhys) /
98 mem_status_.ullTotalPhys);
99 }
100
101 private:
102 virtual bool GetSystemMemoryStatus(_MEMORYSTATUSEX* mem_status) override {
103 // Simply copy the memory status set by the test fixture.
104 *mem_status = mem_status_;
105 return true;
106 }
107
108 _MEMORYSTATUSEX mem_status_;
109
110 DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
111 };
112
113 // Tests the fundamental direct calculation of memory pressure.
114 TEST(MemoryPressureMonitorWinTest, CalculateCurrentMemoryPressureLevel) {
115 base::MessageLoopForUI message_loop;
116 scoped_ptr<TestMemoryPressureMonitor> monitor(
grt (UTC plus 2) 2015/05/05 15:34:00 why not put the instance on the stack?
chrisha 2015/05/05 19:46:13 No real reason, other than cut and paste from Memo
117 new TestMemoryPressureMonitor);
118
119 // A bunch of memory load settings and the expected memory pressure.
120 const PressureSettings kLoadSettings[] = {
121 { 10, 10, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE },
122 { 40, 40, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE },
123 { 65, 10, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE },
124 { 10, 65, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE },
125 { 65, 65, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE },
126 { 98, 10, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
127 { 98, 65, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
128 { 10, 98, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
129 { 65, 98, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
130 { 98, 98, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
131 };
132
133 for (size_t i = 0; i < arraysize(kLoadSettings); ++i) {
grt (UTC plus 2) 2015/05/05 15:34:00 for (const PressureSettings& setting : kLoadSettin
chrisha 2015/05/05 19:46:13 Done.
134 monitor->SetMemoryLoad(kLoadSettings[i].phys, kLoadSettings[i].virt);
135 EXPECT_EQ(kLoadSettings[i].level,
136 monitor->CalculateCurrentPressureLevel());
137 }
138
139 // A bunch of free memory settings and the expected memory pressure.
140 const PressureSettings kFreeSettings[] = {
141 { 500, 500, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE },
142 { 250, 500, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE },
143 { 500, 250, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE },
144 { 250, 250, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE },
145 { 50, 500, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
146 { 50, 250, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
147 { 500, 50, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
148 { 250, 50, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
149 { 50, 50, MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL },
150 };
151
152 for (size_t i = 0; i < arraysize(kFreeSettings); ++i) {
153 monitor->SetMemoryFree(kFreeSettings[i].phys, kFreeSettings[i].virt);
154 EXPECT_EQ(kFreeSettings[i].level,
155 monitor->CalculateCurrentPressureLevel());
156 }
157 }
158
159 // This test tests the various transition states from memory pressure, looking
160 // for the correct behavior on event reposting as well as state updates.
161 TEST(MemoryPressureMonitorWinTest, CheckMemoryPressure) {
162 base::MessageLoopForUI message_loop;
grt (UTC plus 2) 2015/05/05 15:34:00 does this test use the timer? if so, it'll be a sl
chrisha 2015/05/05 19:46:13 No, the test bypasses the timer entirely by direct
163 scoped_ptr<TestMemoryPressureMonitor> monitor(
164 new TestMemoryPressureMonitor);
165 scoped_ptr<MemoryPressureListener> listener(
166 new MemoryPressureListener(base::Bind(&OnMemoryPressure)));
167
168 // Checking the memory pressure while 0% are used should not produce any
169 // events.
170 ResetOnMemoryPressureCalled();
171 monitor->SetMemoryLoad(0, 0);
172 monitor->CheckMemoryPressure();
173 message_loop.RunUntilIdle();
174 EXPECT_FALSE(WasOnMemoryPressureCalled());
175 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
176 monitor->GetCurrentPressureLevel());
177
178 // Setting the memory level to 80% should produce a moderate pressure level.
179 monitor->SetMemoryLoad(80, 80);
180 monitor->CheckMemoryPressure();
181 message_loop.RunUntilIdle();
182 EXPECT_TRUE(WasOnMemoryPressureCalled());
183 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
184 monitor->GetCurrentPressureLevel());
185 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
186 on_memory_pressure_level);
187
188 // We need to check that the event gets reposted after a while.
189 int i = 0;
190 for (; i < 100; i++) {
191 monitor->CheckMemoryPressure();
192 message_loop.RunUntilIdle();
193 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
194 monitor->GetCurrentPressureLevel());
195 if (WasOnMemoryPressureCalled()) {
196 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
197 on_memory_pressure_level);
198 break;
199 }
200 }
201 // Should be more then 5 and less then 100.
202 EXPECT_LE(5, i);
203 EXPECT_GE(99, i);
204
205 // Setting the memory usage to 99% should produce critical levels.
206 monitor->SetMemoryLoad(99, 99);
207 monitor->CheckMemoryPressure();
208 message_loop.RunUntilIdle();
209 EXPECT_TRUE(WasOnMemoryPressureCalled());
210 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
211 on_memory_pressure_level);
212 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
213 monitor->GetCurrentPressureLevel());
214
215 // Calling it again should immediately produce a second call.
216 monitor->CheckMemoryPressure();
217 message_loop.RunUntilIdle();
218 EXPECT_TRUE(WasOnMemoryPressureCalled());
219 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
220 on_memory_pressure_level);
221 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
222 monitor->GetCurrentPressureLevel());
223
224 // When lowering the pressure again we should get an event and the
225 // pressure should go back to moderate.
226 monitor->SetMemoryLoad(80, 80);
227 monitor->CheckMemoryPressure();
228 message_loop.RunUntilIdle();
229 EXPECT_TRUE(WasOnMemoryPressureCalled());
230 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
231 on_memory_pressure_level);
232 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
233 monitor->GetCurrentPressureLevel());
234
235 // We should need exactly the same amount of calls as before, before the next
236 // call comes in.
237 int j = 0;
238 for (; j < 100; j++) {
239 monitor->CheckMemoryPressure();
240 message_loop.RunUntilIdle();
241 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
242 monitor->GetCurrentPressureLevel());
243 if (WasOnMemoryPressureCalled()) {
244 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
245 on_memory_pressure_level);
246 break;
247 }
248 }
249 // We should have needed exactly the same amount of checks as before.
250 EXPECT_EQ(j, i);
251
252 // Going down to no pressure should not produce an event.
253 monitor->SetMemoryLoad(0, 0);
254 monitor->CheckMemoryPressure();
255 message_loop.RunUntilIdle();
256 EXPECT_FALSE(WasOnMemoryPressureCalled());
257 EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
258 monitor->GetCurrentPressureLevel());
259 }
260
261 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698