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

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

Issue 17106004: Add discardable memory emulation for non-android/mac platforms (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressing review. Created 7 years, 2 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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/memory/discardable_memory_provider.h"
6
7 #include "base/memory/discardable_memory.h"
8 #include "base/run_loop.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 using base::internal::DiscardableMemoryProvider;
12
13 namespace base {
14
15 class DiscardableMemoryProviderTest : public testing::Test {
16 public:
17 DiscardableMemoryProviderTest()
18 : message_loop_(MessageLoop::TYPE_IO),
19 provider_(new DiscardableMemoryProvider) {
20 // We set a provider here for two reasons:
21 // 1. It ensures that one test cannot affect the next, and
22 // 2. Since the provider listens for pressure notifications on the thread
23 // it was created on, if we create it on the test thread, we can run
24 // the test thread's message loop until idle when we want to process
25 // on of these notifications.
26 DiscardableMemoryProvider::SetInstanceForTest(provider_.get());
27 }
28
29 virtual ~DiscardableMemoryProviderTest() {
30 DiscardableMemoryProvider::SetInstanceForTest(NULL);
31 }
32
33 protected:
34 void Register(DiscardableMemory* discardable) {
35 DiscardableMemoryProvider::GetInstance()->Register(discardable);
36 }
37
38 const DiscardableMemoryProvider::AllocationMap& allocations() const {
39 return DiscardableMemoryProvider::GetInstance()->allocations_;
40 }
41
42 size_t bytes_allocated() const {
43 return DiscardableMemoryProvider::GetInstance()->bytes_allocated_;
44 }
45
46 void* Memory(const DiscardableMemory& discardable) const {
47 return discardable.memory_;
48 }
49
50 void SetDiscardableMemoryLimit(size_t bytes) {
51 DiscardableMemoryProvider::GetInstance()->
52 SetDiscardableMemoryLimit(bytes);
53 }
54
55 void SetBytesToReclaimUnderModeratePressure(size_t bytes) {
56 DiscardableMemoryProvider::GetInstance()->
57 SetBytesToReclaimUnderModeratePressure(bytes);
58 }
59
60 private:
61 MessageLoop message_loop_;
62 scoped_ptr<DiscardableMemoryProvider> provider_;
63 };
64
65 TEST_F(DiscardableMemoryProviderTest, Register) {
66 DiscardableMemory discardable;
67 Register(&discardable);
68 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
69 ASSERT_EQ(0u, bytes_allocated());
70 }
71
72 TEST_F(DiscardableMemoryProviderTest, InitializeAndLock) {
73 DiscardableMemory discardable;
74 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
75 size_t size = 1024;
76 ASSERT_TRUE(discardable.InitializeAndLock(size));
77 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
78 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable));
willchan no longer on Chromium 2013/10/01 19:05:05 You should use EXPECT_*() unless the following sta
reveman 2013/10/09 22:40:24 Done.
79 ASSERT_EQ(1024u, bytes_allocated());
80 ASSERT_TRUE(discardable.is_locked());
81 }
82
83 TEST_F(DiscardableMemoryProviderTest, InitializeAndLockZeroSize) {
84 DiscardableMemory discardable;
85 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
86 size_t size = 0;
87 ASSERT_FALSE(discardable.InitializeAndLock(size));
88 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
89 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
90 ASSERT_EQ(0u, bytes_allocated());
91 ASSERT_FALSE(discardable.is_locked());
92 }
93
94 static void AttemptToLockBeforeInitialization(DiscardableMemory* discardable) {
95 ASSERT_EQ(DISCARDABLE_MEMORY_FAILED, discardable->Lock());
96 }
97
98 TEST_F(DiscardableMemoryProviderTest, LockBeforeInitialization) {
99 DiscardableMemory discardable;
100 EXPECT_DEATH(AttemptToLockBeforeInitialization(&discardable),
101 ".*Check failed.*");
102 }
103
104 TEST_F(DiscardableMemoryProviderTest, LockAfterUnlock) {
105 DiscardableMemory discardable;
106 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
107 size_t size = 1024;
108 ASSERT_TRUE(discardable.InitializeAndLock(size));
109 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
110 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable));
111 ASSERT_EQ(1024u, bytes_allocated());
112 ASSERT_TRUE(discardable.is_locked());
113
114 // Now to unlock so we can lock later.
115 discardable.Unlock();
116 ASSERT_FALSE(discardable.is_locked());
117
118 ASSERT_EQ(DISCARDABLE_MEMORY_SUCCESS, discardable.Lock());
119 ASSERT_TRUE(discardable.is_locked());
120 }
121
122 TEST_F(DiscardableMemoryProviderTest, LockAfterPurge) {
123 DiscardableMemory discardable;
124 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
125 size_t size = 1024;
126 ASSERT_TRUE(discardable.InitializeAndLock(size));
127 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
128 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable));
129 ASSERT_EQ(1024u, bytes_allocated());
130 ASSERT_TRUE(discardable.is_locked());
131
132 // Now to unlock so we can lock later.
133 discardable.Unlock();
134 ASSERT_FALSE(discardable.is_locked());
135
136 // Force the system to purge.
137 MemoryPressureListener::NotifyMemoryPressure(
willchan no longer on Chromium 2013/10/01 19:05:05 You should add a test with a DiscardableMemory on
reveman 2013/10/09 22:40:24 I added a basic test that uses a DiscardableMemory
138 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
139
140 // Required because ObserverListThreadSafe notifies via PostTask.
141 RunLoop().RunUntilIdle();
142
143 ASSERT_EQ(DISCARDABLE_MEMORY_PURGED, discardable.Lock());
144 ASSERT_TRUE(discardable.is_locked());
145 }
146
147 TEST_F(DiscardableMemoryProviderTest, LockAfterPurgeAndCannotReallocate) {
148 DiscardableMemory discardable;
149 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
150 size_t size = 1024;
151 ASSERT_TRUE(discardable.InitializeAndLock(size));
152 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
153 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable));
154 ASSERT_EQ(1024u, bytes_allocated());
155 ASSERT_TRUE(discardable.is_locked());
156
157 // Now to unlock so we can lock later.
158 discardable.Unlock();
159 ASSERT_FALSE(discardable.is_locked());
160
161 // Force the system to purge.
162 MemoryPressureListener::NotifyMemoryPressure(
163 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
164
165 // Required because ObserverListThreadSafe notifies via PostTask.
166 RunLoop().RunUntilIdle();
167
168 // Set max allowed allocation to 1 byte. This will make reallocation fail.
169 SetDiscardableMemoryLimit(1);
170
171 ASSERT_EQ(DISCARDABLE_MEMORY_FAILED, discardable.Lock());
172 ASSERT_FALSE(discardable.is_locked());
173 }
174
175 #define DiscardableMemoryProviderPermutionTest(name, d0, d1, d2, pressure) \
176 TEST_F(DiscardableMemoryProviderTest, name##_##d0##_##d1##_##d2) { \
177 DiscardableMemory discardables[3]; \
178 for (int i = 0; i < 3; ++i) { \
179 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[i])); \
180 ASSERT_TRUE(discardables[i].InitializeAndLock(1024)); \
181 discardables[i].Unlock(); \
182 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[i])); \
183 } \
184 int ordering[] = { d0, d1, d2 }; \
185 for (int i = 0; i < 3; ++i) { \
186 int current_index = ordering[i]; \
187 ASSERT_NE(DISCARDABLE_MEMORY_FAILED, discardables[current_index].Lock()); \
188 if (i > 0) \
189 discardables[current_index].Unlock(); \
190 } \
191 SetBytesToReclaimUnderModeratePressure(1024); \
192 if (pressure) { \
193 MemoryPressureListener::NotifyMemoryPressure( \
194 MemoryPressureListener::MEMORY_PRESSURE_MODERATE); \
195 RunLoop().RunUntilIdle(); \
196 } else { \
197 SetDiscardableMemoryLimit(2048); \
198 } \
199 for (int i = 0; i < 3; ++i) { \
200 if (i == 1) \
201 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[ordering[i]])); \
202 else \
203 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[ordering[i]])); \
204 } \
205 }
206
207 #define DiscardableMemoryProviderPermutions(name, pressure) \
208 DiscardableMemoryProviderPermutionTest(name, 0, 1, 2, pressure); \
209 DiscardableMemoryProviderPermutionTest(name, 0, 2, 1, pressure); \
210 DiscardableMemoryProviderPermutionTest(name, 1, 0, 2, pressure); \
211 DiscardableMemoryProviderPermutionTest(name, 1, 2, 0, pressure); \
212 DiscardableMemoryProviderPermutionTest(name, 2, 0, 1, pressure); \
213 DiscardableMemoryProviderPermutionTest(name, 2, 1, 0, pressure);
214
215 DiscardableMemoryProviderPermutions(LRUDiscardedModeratePressure, true);
216 DiscardableMemoryProviderPermutions(LRUDiscardedExceedLimit, false);
217
218 TEST_F(DiscardableMemoryProviderTest, CriticalPressureFreesAllUnlocked) {
219 DiscardableMemory discardables[3];
220 for (int i = 0; i < 3; ++i) {
221 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[i]));
222 ASSERT_TRUE(discardables[i].InitializeAndLock(1024));
223 discardables[i].Unlock();
224 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[i]));
225 }
226
227 for (int i = 0; i < 3; ++i) {
228 ASSERT_NE(DISCARDABLE_MEMORY_FAILED, discardables[i].Lock());
229 if (i > 0)
230 discardables[i].Unlock();
231 }
232
233 MemoryPressureListener::NotifyMemoryPressure(
234 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
235 RunLoop().RunUntilIdle();
236
237 for (int i = 0; i < 3; ++i) {
238 if (discardables[i].is_locked())
239 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[i]));
240 else
241 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[i]));
242 }
243 }
244
245 TEST_F(DiscardableMemoryProviderTest, NormalDestruction) {
246 {
247 DiscardableMemory discardable;
248 size_t size = 1024;
249 ASSERT_TRUE(discardable.InitializeAndLock(size));
250 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
251 ASSERT_EQ(1024u, bytes_allocated());
252 }
253 ASSERT_TRUE(allocations().empty());
254 ASSERT_EQ(0u, bytes_allocated());
255 }
256
257 TEST_F(DiscardableMemoryProviderTest, DestructionWhileLocked) {
258 {
259 DiscardableMemory discardable;
260 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
261 size_t size = 1024;
262 ASSERT_TRUE(discardable.InitializeAndLock(size));
263 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
264 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable));
265 ASSERT_EQ(1024u, bytes_allocated());
266 ASSERT_TRUE(discardable.is_locked());
267 }
268 // Should have ignored the "locked" status and freed the discardable memory.
269 ASSERT_TRUE(allocations().empty());
270 ASSERT_EQ(0u, bytes_allocated());
271 }
272
273 TEST_F(DiscardableMemoryProviderTest, MemoryBeforeLock) {
274 DiscardableMemory discardable;
275 // We *must* die if we are asked to vend a pointer to unlocked memory.
276 EXPECT_DEATH(discardable.Memory(), ".*Check failed.*");
277 }
278
279 TEST_F(DiscardableMemoryProviderTest, MemoryAfterUnlock) {
280 DiscardableMemory discardable;
281 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable));
282 size_t size = 1024;
283 ASSERT_TRUE(discardable.InitializeAndLock(size));
284 ASSERT_NE(allocations().end(), allocations().Peek(&discardable));
285 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable));
286 ASSERT_EQ(1024u, bytes_allocated());
287 ASSERT_TRUE(discardable.is_locked());
288 discardable.Unlock();
289 ASSERT_FALSE(discardable.is_locked());
290 // We *must* die if we are asked to vend a pointer to unlocked memory.
291 EXPECT_DEATH(discardable.Memory(), ".*Check failed.*");
292 }
293
294 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698