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

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

Issue 1001833005: Update from https://crrev.com/320343 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Supress Created 5 years, 9 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
« no previous file with comments | « base/memory/discardable_memory_manager.cc ('k') | base/memory/discardable_memory_shmem.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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_manager.h"
6
7 #include "base/bind.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "base/threading/thread.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11
12 namespace base {
13 namespace {
14
15 class TestAllocationImpl : public internal::DiscardableMemoryManagerAllocation {
16 public:
17 TestAllocationImpl() : is_allocated_(false), is_locked_(false) {}
18 ~TestAllocationImpl() override { DCHECK(!is_locked_); }
19
20 // Overridden from internal::DiscardableMemoryManagerAllocation:
21 bool AllocateAndAcquireLock() override {
22 bool was_allocated = is_allocated_;
23 is_allocated_ = true;
24 DCHECK(!is_locked_);
25 is_locked_ = true;
26 return was_allocated;
27 }
28 void ReleaseLock() override {
29 DCHECK(is_locked_);
30 is_locked_ = false;
31 }
32 void Purge() override {
33 DCHECK(is_allocated_);
34 is_allocated_ = false;
35 }
36
37 bool is_locked() const { return is_locked_; }
38
39 private:
40 bool is_allocated_;
41 bool is_locked_;
42 };
43
44 // Tests can assume that the default limit is at least 1024. Tests that rely on
45 // something else needs to explicit set the limit.
46 const size_t kDefaultMemoryLimit = 1024;
47 const size_t kDefaultSoftMemoryLimit = kDefaultMemoryLimit;
48
49 class TestDiscardableMemoryManagerImpl
50 : public internal::DiscardableMemoryManager {
51 public:
52 TestDiscardableMemoryManagerImpl()
53 : DiscardableMemoryManager(kDefaultMemoryLimit,
54 kDefaultSoftMemoryLimit,
55 TimeDelta::Max()) {}
56
57 void SetNow(TimeTicks now) { now_ = now; }
58
59 private:
60 // Overriden from internal::DiscardableMemoryManager:
61 TimeTicks Now() const override { return now_; }
62
63 TimeTicks now_;
64 };
65
66 class DiscardableMemoryManagerTestBase {
67 public:
68 DiscardableMemoryManagerTestBase() {}
69
70 protected:
71 enum LockStatus {
72 LOCK_STATUS_FAILED,
73 LOCK_STATUS_PURGED,
74 LOCK_STATUS_SUCCESS
75 };
76
77 size_t BytesAllocated() const { return manager_.GetBytesAllocatedForTest(); }
78
79 void SetMemoryLimit(size_t bytes) { manager_.SetMemoryLimit(bytes); }
80
81 void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); }
82
83 void SetHardMemoryLimitExpirationTime(TimeDelta time) {
84 manager_.SetHardMemoryLimitExpirationTime(time);
85 }
86
87 void Register(TestAllocationImpl* allocation, size_t bytes) {
88 manager_.Register(allocation, bytes);
89 }
90
91 void Unregister(TestAllocationImpl* allocation) {
92 manager_.Unregister(allocation);
93 }
94
95 bool IsRegistered(TestAllocationImpl* allocation) const {
96 return manager_.IsRegisteredForTest(allocation);
97 }
98
99 LockStatus Lock(TestAllocationImpl* allocation) {
100 bool purged;
101 if (!manager_.AcquireLock(allocation, &purged))
102 return LOCK_STATUS_FAILED;
103 return purged ? LOCK_STATUS_PURGED : LOCK_STATUS_SUCCESS;
104 }
105
106 void Unlock(TestAllocationImpl* allocation) {
107 manager_.ReleaseLock(allocation);
108 }
109
110 LockStatus RegisterAndLock(TestAllocationImpl* allocation, size_t bytes) {
111 manager_.Register(allocation, bytes);
112 return Lock(allocation);
113 }
114
115 bool CanBePurged(TestAllocationImpl* allocation) const {
116 return manager_.CanBePurgedForTest(allocation);
117 }
118
119 void SetNow(TimeTicks now) { manager_.SetNow(now); }
120
121 void PurgeAll() { return manager_.PurgeAll(); }
122
123 bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); }
124
125 void ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
126 manager_.ReduceMemoryUsageUntilWithinLimit(bytes);
127 }
128
129 private:
130 TestDiscardableMemoryManagerImpl manager_;
131 };
132
133 class DiscardableMemoryManagerTest : public DiscardableMemoryManagerTestBase,
134 public testing::Test {
135 public:
136 DiscardableMemoryManagerTest() {}
137 };
138
139 TEST_F(DiscardableMemoryManagerTest, CreateAndLock) {
140 size_t size = 1024;
141 TestAllocationImpl allocation;
142 Register(&allocation, size);
143 EXPECT_TRUE(IsRegistered(&allocation));
144 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
145 EXPECT_TRUE(allocation.is_locked());
146 EXPECT_EQ(1024u, BytesAllocated());
147 EXPECT_FALSE(CanBePurged(&allocation));
148 Unlock(&allocation);
149 Unregister(&allocation);
150 }
151
152 TEST_F(DiscardableMemoryManagerTest, CreateZeroSize) {
153 size_t size = 0;
154 TestAllocationImpl allocation;
155 Register(&allocation, size);
156 EXPECT_TRUE(IsRegistered(&allocation));
157 EXPECT_EQ(LOCK_STATUS_FAILED, Lock(&allocation));
158 EXPECT_EQ(0u, BytesAllocated());
159 Unregister(&allocation);
160 }
161
162 TEST_F(DiscardableMemoryManagerTest, LockAfterUnlock) {
163 size_t size = 1024;
164 TestAllocationImpl allocation;
165 RegisterAndLock(&allocation, size);
166 EXPECT_EQ(1024u, BytesAllocated());
167 EXPECT_FALSE(CanBePurged(&allocation));
168
169 // Now unlock so we can lock later.
170 Unlock(&allocation);
171 EXPECT_TRUE(CanBePurged(&allocation));
172
173 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(&allocation));
174 EXPECT_FALSE(CanBePurged(&allocation));
175 Unlock(&allocation);
176 Unregister(&allocation);
177 }
178
179 TEST_F(DiscardableMemoryManagerTest, LockAfterPurge) {
180 size_t size = 1024;
181 TestAllocationImpl allocation;
182 RegisterAndLock(&allocation, size);
183 EXPECT_EQ(1024u, BytesAllocated());
184 EXPECT_FALSE(CanBePurged(&allocation));
185
186 // Now unlock so we can lock later.
187 Unlock(&allocation);
188 EXPECT_TRUE(CanBePurged(&allocation));
189
190 // Force the system to purge.
191 PurgeAll();
192
193 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
194 EXPECT_FALSE(CanBePurged(&allocation));
195
196 Unlock(&allocation);
197 Unregister(&allocation);
198 }
199
200 TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) {
201 size_t size = 1024;
202 TestAllocationImpl allocation;
203 RegisterAndLock(&allocation, size);
204 EXPECT_EQ(1024u, BytesAllocated());
205 EXPECT_FALSE(CanBePurged(&allocation));
206
207 // Now unlock so we can lock later.
208 Unlock(&allocation);
209 EXPECT_TRUE(CanBePurged(&allocation));
210
211 // Set max allowed allocation to 1 byte. This will cause the memory to be
212 // purged.
213 SetMemoryLimit(1);
214
215 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
216 EXPECT_FALSE(CanBePurged(&allocation));
217
218 Unlock(&allocation);
219 Unregister(&allocation);
220 }
221
222 TEST_F(DiscardableMemoryManagerTest, Overflow) {
223 size_t size = 1024;
224 {
225 TestAllocationImpl allocation;
226 RegisterAndLock(&allocation, size);
227 EXPECT_EQ(1024u, BytesAllocated());
228
229 size_t massive_size = std::numeric_limits<size_t>::max();
230 TestAllocationImpl massive_allocation;
231 Register(&massive_allocation, massive_size);
232 EXPECT_EQ(LOCK_STATUS_FAILED, Lock(&massive_allocation));
233 EXPECT_EQ(1024u, BytesAllocated());
234
235 Unlock(&allocation);
236 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&massive_allocation));
237 Unlock(&massive_allocation);
238 Unregister(&massive_allocation);
239 Unregister(&allocation);
240 }
241 EXPECT_EQ(0u, BytesAllocated());
242 }
243
244 class PermutationTestData {
245 public:
246 PermutationTestData(unsigned d0, unsigned d1, unsigned d2) {
247 ordering_[0] = d0;
248 ordering_[1] = d1;
249 ordering_[2] = d2;
250 }
251
252 const unsigned* ordering() const { return ordering_; }
253
254 private:
255 unsigned ordering_[3];
256 };
257
258 class DiscardableMemoryManagerPermutationTest
259 : public DiscardableMemoryManagerTestBase,
260 public testing::TestWithParam<PermutationTestData> {
261 public:
262 DiscardableMemoryManagerPermutationTest() {}
263
264 protected:
265 // Use memory in order specified by ordering parameter.
266 void RegisterAndUseAllocations() {
267 for (int i = 0; i < 3; ++i) {
268 RegisterAndLock(&allocation_[i], 1024);
269 Unlock(&allocation_[i]);
270 }
271 for (int i = 0; i < 3; ++i) {
272 int index = GetParam().ordering()[i];
273 EXPECT_NE(LOCK_STATUS_FAILED, Lock(&allocation_[index]));
274 // Leave i == 0 locked.
275 if (i > 0)
276 Unlock(&allocation_[index]);
277 }
278 }
279
280 TestAllocationImpl* allocation(unsigned position) {
281 return &allocation_[GetParam().ordering()[position]];
282 }
283
284 void UnlockAndUnregisterAllocations() {
285 for (int i = 0; i < 3; ++i) {
286 if (allocation_[i].is_locked())
287 Unlock(&allocation_[i]);
288 Unregister(&allocation_[i]);
289 }
290 }
291
292 private:
293 TestAllocationImpl allocation_[3];
294 };
295
296 // Verify that memory was discarded in the correct order after reducing usage to
297 // limit.
298 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscarded) {
299 RegisterAndUseAllocations();
300
301 SetMemoryLimit(2048);
302
303 ReduceMemoryUsageUntilWithinLimit(1024);
304
305 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
306 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
307 // 0 should still be locked.
308 EXPECT_TRUE(allocation(0)->is_locked());
309
310 UnlockAndUnregisterAllocations();
311 }
312
313 // Verify that memory was discarded in the correct order after changing
314 // memory limit.
315 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) {
316 RegisterAndUseAllocations();
317
318 SetMemoryLimit(2048);
319
320 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
321 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
322 // 0 should still be locked.
323 EXPECT_TRUE(allocation(0)->is_locked());
324
325 UnlockAndUnregisterAllocations();
326 }
327
328 // Verify that no more memory than necessary was discarded after changing
329 // memory limit.
330 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) {
331 SetMemoryLimit(4096);
332
333 RegisterAndUseAllocations();
334
335 SetMemoryLimit(2048);
336
337 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(allocation(2)));
338 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
339 // 0 should still be locked.
340 EXPECT_TRUE(allocation(0)->is_locked());
341
342 UnlockAndUnregisterAllocations();
343 }
344
345 TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) {
346 RegisterAndUseAllocations();
347
348 PurgeAll();
349
350 for (int i = 0; i < 3; ++i) {
351 if (i == 0)
352 EXPECT_TRUE(allocation(i)->is_locked());
353 else
354 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(i)));
355 }
356
357 UnlockAndUnregisterAllocations();
358 }
359
360 INSTANTIATE_TEST_CASE_P(DiscardableMemoryManagerPermutationTests,
361 DiscardableMemoryManagerPermutationTest,
362 ::testing::Values(PermutationTestData(0, 1, 2),
363 PermutationTestData(0, 2, 1),
364 PermutationTestData(1, 0, 2),
365 PermutationTestData(1, 2, 0),
366 PermutationTestData(2, 0, 1),
367 PermutationTestData(2, 1, 0)));
368
369 TEST_F(DiscardableMemoryManagerTest, NormalDestruction) {
370 {
371 size_t size = 1024;
372 TestAllocationImpl allocation;
373 Register(&allocation, size);
374 Unregister(&allocation);
375 }
376 EXPECT_EQ(0u, BytesAllocated());
377 }
378
379 TEST_F(DiscardableMemoryManagerTest, DestructionAfterLocked) {
380 {
381 size_t size = 1024;
382 TestAllocationImpl allocation;
383 RegisterAndLock(&allocation, size);
384 EXPECT_EQ(1024u, BytesAllocated());
385 EXPECT_FALSE(CanBePurged(&allocation));
386 Unlock(&allocation);
387 Unregister(&allocation);
388 }
389 EXPECT_EQ(0u, BytesAllocated());
390 }
391
392 TEST_F(DiscardableMemoryManagerTest, DestructionAfterPurged) {
393 {
394 size_t size = 1024;
395 TestAllocationImpl allocation;
396 RegisterAndLock(&allocation, size);
397 EXPECT_EQ(1024u, BytesAllocated());
398 Unlock(&allocation);
399 EXPECT_TRUE(CanBePurged(&allocation));
400 SetMemoryLimit(0);
401 EXPECT_EQ(0u, BytesAllocated());
402 Unregister(&allocation);
403 }
404 EXPECT_EQ(0u, BytesAllocated());
405 }
406
407 TEST_F(DiscardableMemoryManagerTest, ReduceMemoryUsage) {
408 SetMemoryLimit(3072);
409 SetSoftMemoryLimit(1024);
410 SetHardMemoryLimitExpirationTime(TimeDelta::FromInternalValue(1));
411
412 size_t size = 1024;
413 TestAllocationImpl allocation[3];
414 RegisterAndLock(&allocation[0], size);
415 RegisterAndLock(&allocation[1], size);
416 RegisterAndLock(&allocation[2], size);
417 EXPECT_EQ(3072u, BytesAllocated());
418
419 // Above soft limit but nothing that can be purged.
420 EXPECT_FALSE(ReduceMemoryUsage());
421
422 SetNow(TimeTicks::FromInternalValue(0));
423 Unlock(&allocation[0]);
424
425 // Above soft limit but still nothing that can be purged as all unlocked
426 // allocations are within the hard limit cutoff time.
427 EXPECT_FALSE(ReduceMemoryUsage());
428
429 SetNow(TimeTicks::FromInternalValue(1));
430 Unlock(&allocation[1]);
431
432 // One unlocked allocation is no longer within the hard limit cutoff time. It
433 // should be purged and ReduceMemoryUsage() should return false as we're not
434 // yet within the soft memory limit.
435 EXPECT_FALSE(ReduceMemoryUsage());
436 EXPECT_EQ(2048u, BytesAllocated());
437
438 // One more unlocked allocation is no longer within the hard limit cutoff
439 // time. It should be purged and ReduceMemoryUsage() should return true as
440 // we're now within the soft memory limit.
441 SetNow(TimeTicks::FromInternalValue(2));
442 EXPECT_TRUE(ReduceMemoryUsage());
443 EXPECT_EQ(1024u, BytesAllocated());
444
445 Unlock(&allocation[2]);
446
447 Unregister(&allocation[0]);
448 Unregister(&allocation[1]);
449 Unregister(&allocation[2]);
450 }
451
452 class ThreadedDiscardableMemoryManagerTest
453 : public DiscardableMemoryManagerTest {
454 public:
455 ThreadedDiscardableMemoryManagerTest()
456 : memory_usage_thread_("memory_usage_thread"),
457 thread_sync_(true, false) {}
458
459 void SetUp() override { memory_usage_thread_.Start(); }
460
461 void TearDown() override { memory_usage_thread_.Stop(); }
462
463 void UseMemoryHelper() {
464 size_t size = 1024;
465 TestAllocationImpl allocation;
466 RegisterAndLock(&allocation, size);
467 Unlock(&allocation);
468 Unregister(&allocation);
469 }
470
471 void SignalHelper() { thread_sync_.Signal(); }
472
473 Thread memory_usage_thread_;
474 WaitableEvent thread_sync_;
475 };
476
477 TEST_F(ThreadedDiscardableMemoryManagerTest, UseMemoryOnThread) {
478 memory_usage_thread_.message_loop()->PostTask(
479 FROM_HERE,
480 Bind(&ThreadedDiscardableMemoryManagerTest::UseMemoryHelper,
481 Unretained(this)));
482 memory_usage_thread_.message_loop()->PostTask(
483 FROM_HERE,
484 Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper,
485 Unretained(this)));
486 thread_sync_.Wait();
487 }
488
489 } // namespace
490 } // namespace base
OLDNEW
« no previous file with comments | « base/memory/discardable_memory_manager.cc ('k') | base/memory/discardable_memory_shmem.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698