Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / base / memory / discardable_memory_manager_unittest.cc
blob674499fe0ea0bd98bf6618fbc47dbe4137b6019c
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.
5 #include "base/memory/discardable_memory_manager.h"
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"
12 namespace base {
13 namespace {
15 class TestAllocationImpl : public internal::DiscardableMemoryManagerAllocation {
16 public:
17 TestAllocationImpl() : is_allocated_(false), is_locked_(false) {}
18 virtual ~TestAllocationImpl() { DCHECK(!is_locked_); }
20 // Overridden from internal::DiscardableMemoryManagerAllocation:
21 virtual 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;
28 virtual void ReleaseLock() OVERRIDE {
29 DCHECK(is_locked_);
30 is_locked_ = false;
32 virtual void Purge() OVERRIDE {
33 DCHECK(is_allocated_);
34 is_allocated_ = false;
37 bool is_locked() const { return is_locked_; }
39 private:
40 bool is_allocated_;
41 bool is_locked_;
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;
49 class TestDiscardableMemoryManagerImpl
50 : public internal::DiscardableMemoryManager {
51 public:
52 TestDiscardableMemoryManagerImpl()
53 : DiscardableMemoryManager(kDefaultMemoryLimit,
54 kDefaultSoftMemoryLimit,
55 TimeDelta::Max()) {}
57 void SetNow(TimeTicks now) { now_ = now; }
59 private:
60 // Overriden from internal::DiscardableMemoryManager:
61 virtual TimeTicks Now() const OVERRIDE { return now_; }
63 TimeTicks now_;
66 class DiscardableMemoryManagerTestBase {
67 public:
68 DiscardableMemoryManagerTestBase() {}
70 protected:
71 enum LockStatus {
72 LOCK_STATUS_FAILED,
73 LOCK_STATUS_PURGED,
74 LOCK_STATUS_SUCCESS
77 size_t BytesAllocated() const { return manager_.GetBytesAllocatedForTest(); }
79 void SetMemoryLimit(size_t bytes) { manager_.SetMemoryLimit(bytes); }
81 void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); }
83 void SetHardMemoryLimitExpirationTime(TimeDelta time) {
84 manager_.SetHardMemoryLimitExpirationTime(time);
87 void Register(TestAllocationImpl* allocation, size_t bytes) {
88 manager_.Register(allocation, bytes);
91 void Unregister(TestAllocationImpl* allocation) {
92 manager_.Unregister(allocation);
95 bool IsRegistered(TestAllocationImpl* allocation) const {
96 return manager_.IsRegisteredForTest(allocation);
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;
106 void Unlock(TestAllocationImpl* allocation) {
107 manager_.ReleaseLock(allocation);
110 LockStatus RegisterAndLock(TestAllocationImpl* allocation, size_t bytes) {
111 manager_.Register(allocation, bytes);
112 return Lock(allocation);
115 bool CanBePurged(TestAllocationImpl* allocation) const {
116 return manager_.CanBePurgedForTest(allocation);
119 void SetNow(TimeTicks now) { manager_.SetNow(now); }
121 void PurgeAll() { return manager_.PurgeAll(); }
123 bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); }
125 void ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
126 manager_.ReduceMemoryUsageUntilWithinLimit(bytes);
129 private:
130 TestDiscardableMemoryManagerImpl manager_;
133 class DiscardableMemoryManagerTest : public DiscardableMemoryManagerTestBase,
134 public testing::Test {
135 public:
136 DiscardableMemoryManagerTest() {}
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);
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);
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));
169 // Now unlock so we can lock later.
170 Unlock(&allocation);
171 EXPECT_TRUE(CanBePurged(&allocation));
173 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(&allocation));
174 EXPECT_FALSE(CanBePurged(&allocation));
175 Unlock(&allocation);
176 Unregister(&allocation);
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));
186 // Now unlock so we can lock later.
187 Unlock(&allocation);
188 EXPECT_TRUE(CanBePurged(&allocation));
190 // Force the system to purge.
191 PurgeAll();
193 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
194 EXPECT_FALSE(CanBePurged(&allocation));
196 Unlock(&allocation);
197 Unregister(&allocation);
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));
207 // Now unlock so we can lock later.
208 Unlock(&allocation);
209 EXPECT_TRUE(CanBePurged(&allocation));
211 // Set max allowed allocation to 1 byte. This will cause the memory to be
212 // purged.
213 SetMemoryLimit(1);
215 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
216 EXPECT_FALSE(CanBePurged(&allocation));
218 Unlock(&allocation);
219 Unregister(&allocation);
222 TEST_F(DiscardableMemoryManagerTest, Overflow) {
223 size_t size = 1024;
225 TestAllocationImpl allocation;
226 RegisterAndLock(&allocation, size);
227 EXPECT_EQ(1024u, BytesAllocated());
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());
235 Unlock(&allocation);
236 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&massive_allocation));
237 Unlock(&massive_allocation);
238 Unregister(&massive_allocation);
239 Unregister(&allocation);
241 EXPECT_EQ(0u, BytesAllocated());
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;
252 const unsigned* ordering() const { return ordering_; }
254 private:
255 unsigned ordering_[3];
258 class DiscardableMemoryManagerPermutationTest
259 : public DiscardableMemoryManagerTestBase,
260 public testing::TestWithParam<PermutationTestData> {
261 public:
262 DiscardableMemoryManagerPermutationTest() {}
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]);
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]);
280 TestAllocationImpl* allocation(unsigned position) {
281 return &allocation_[GetParam().ordering()[position]];
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]);
292 private:
293 TestAllocationImpl allocation_[3];
296 // Verify that memory was discarded in the correct order after reducing usage to
297 // limit.
298 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscarded) {
299 RegisterAndUseAllocations();
301 SetMemoryLimit(2048);
303 ReduceMemoryUsageUntilWithinLimit(1024);
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());
310 UnlockAndUnregisterAllocations();
313 // Verify that memory was discarded in the correct order after changing
314 // memory limit.
315 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) {
316 RegisterAndUseAllocations();
318 SetMemoryLimit(2048);
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());
325 UnlockAndUnregisterAllocations();
328 // Verify that no more memory than necessary was discarded after changing
329 // memory limit.
330 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) {
331 SetMemoryLimit(4096);
333 RegisterAndUseAllocations();
335 SetMemoryLimit(2048);
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());
342 UnlockAndUnregisterAllocations();
345 TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) {
346 RegisterAndUseAllocations();
348 PurgeAll();
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)));
357 UnlockAndUnregisterAllocations();
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)));
369 TEST_F(DiscardableMemoryManagerTest, NormalDestruction) {
371 size_t size = 1024;
372 TestAllocationImpl allocation;
373 Register(&allocation, size);
374 Unregister(&allocation);
376 EXPECT_EQ(0u, BytesAllocated());
379 TEST_F(DiscardableMemoryManagerTest, DestructionAfterLocked) {
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);
389 EXPECT_EQ(0u, BytesAllocated());
392 TEST_F(DiscardableMemoryManagerTest, DestructionAfterPurged) {
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);
404 EXPECT_EQ(0u, BytesAllocated());
407 TEST_F(DiscardableMemoryManagerTest, ReduceMemoryUsage) {
408 SetMemoryLimit(3072);
409 SetSoftMemoryLimit(1024);
410 SetHardMemoryLimitExpirationTime(TimeDelta::FromInternalValue(1));
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());
419 // Above soft limit but nothing that can be purged.
420 EXPECT_FALSE(ReduceMemoryUsage());
422 SetNow(TimeTicks::FromInternalValue(0));
423 Unlock(&allocation[0]);
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());
429 SetNow(TimeTicks::FromInternalValue(1));
430 Unlock(&allocation[1]);
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());
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());
445 Unlock(&allocation[2]);
447 Unregister(&allocation[0]);
448 Unregister(&allocation[1]);
449 Unregister(&allocation[2]);
452 class ThreadedDiscardableMemoryManagerTest
453 : public DiscardableMemoryManagerTest {
454 public:
455 ThreadedDiscardableMemoryManagerTest()
456 : memory_usage_thread_("memory_usage_thread"),
457 thread_sync_(true, false) {}
459 virtual void SetUp() OVERRIDE { memory_usage_thread_.Start(); }
461 virtual void TearDown() OVERRIDE { memory_usage_thread_.Stop(); }
463 void UseMemoryHelper() {
464 size_t size = 1024;
465 TestAllocationImpl allocation;
466 RegisterAndLock(&allocation, size);
467 Unlock(&allocation);
468 Unregister(&allocation);
471 void SignalHelper() { thread_sync_.Signal(); }
473 Thread memory_usage_thread_;
474 WaitableEvent thread_sync_;
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();
489 } // namespace
490 } // namespace base