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