Infer appropriate GNU_STACK alignment for a shared library.
[chromium-blink-merge.git] / base / memory / discardable_memory_manager_unittest.cc
blob9f06e3738c3f6b1ad7c53b8c81311e5e525d2788
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 ~TestAllocationImpl() override { DCHECK(!is_locked_); }
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;
28 void ReleaseLock() override {
29 DCHECK(is_locked_);
30 is_locked_ = false;
32 void Purge() override {
33 DCHECK(is_allocated_);
34 is_allocated_ = false;
36 bool IsMemoryResident() const override {
37 DCHECK(is_allocated_);
38 return true;
41 bool is_locked() const { return is_locked_; }
43 private:
44 bool is_allocated_;
45 bool is_locked_;
48 // Tests can assume that the default limit is at least 1024. Tests that rely on
49 // something else needs to explicit set the limit.
50 const size_t kDefaultMemoryLimit = 1024;
51 const size_t kDefaultSoftMemoryLimit = kDefaultMemoryLimit;
53 class TestDiscardableMemoryManagerImpl
54 : public internal::DiscardableMemoryManager {
55 public:
56 TestDiscardableMemoryManagerImpl()
57 : DiscardableMemoryManager(kDefaultMemoryLimit,
58 kDefaultSoftMemoryLimit,
59 TimeDelta::Max()) {}
61 void SetNow(TimeTicks now) { now_ = now; }
63 private:
64 // Overriden from internal::DiscardableMemoryManager:
65 TimeTicks Now() const override { return now_; }
67 TimeTicks now_;
70 class DiscardableMemoryManagerTestBase {
71 public:
72 DiscardableMemoryManagerTestBase() {}
74 protected:
75 enum LockStatus {
76 LOCK_STATUS_FAILED,
77 LOCK_STATUS_PURGED,
78 LOCK_STATUS_SUCCESS
81 size_t BytesAllocated() const { return manager_.GetBytesAllocatedForTest(); }
83 void SetMemoryLimit(size_t bytes) { manager_.SetMemoryLimit(bytes); }
85 void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); }
87 void SetHardMemoryLimitExpirationTime(TimeDelta time) {
88 manager_.SetHardMemoryLimitExpirationTime(time);
91 void Register(TestAllocationImpl* allocation, size_t bytes) {
92 manager_.Register(allocation, bytes);
95 void Unregister(TestAllocationImpl* allocation) {
96 manager_.Unregister(allocation);
99 bool IsRegistered(TestAllocationImpl* allocation) const {
100 return manager_.IsRegisteredForTest(allocation);
103 LockStatus Lock(TestAllocationImpl* allocation) {
104 bool purged;
105 if (!manager_.AcquireLock(allocation, &purged))
106 return LOCK_STATUS_FAILED;
107 return purged ? LOCK_STATUS_PURGED : LOCK_STATUS_SUCCESS;
110 void Unlock(TestAllocationImpl* allocation) {
111 manager_.ReleaseLock(allocation);
114 LockStatus RegisterAndLock(TestAllocationImpl* allocation, size_t bytes) {
115 manager_.Register(allocation, bytes);
116 return Lock(allocation);
119 bool CanBePurged(TestAllocationImpl* allocation) const {
120 return manager_.CanBePurgedForTest(allocation);
123 void SetNow(TimeTicks now) { manager_.SetNow(now); }
125 void PurgeAll() { return manager_.PurgeAll(); }
127 bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); }
129 void ReduceMemoryUsageUntilWithinLimit(size_t bytes) {
130 manager_.ReduceMemoryUsageUntilWithinLimit(bytes);
133 private:
134 TestDiscardableMemoryManagerImpl manager_;
137 class DiscardableMemoryManagerTest : public DiscardableMemoryManagerTestBase,
138 public testing::Test {
139 public:
140 DiscardableMemoryManagerTest() {}
143 TEST_F(DiscardableMemoryManagerTest, CreateAndLock) {
144 size_t size = 1024;
145 TestAllocationImpl allocation;
146 Register(&allocation, size);
147 EXPECT_TRUE(IsRegistered(&allocation));
148 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
149 EXPECT_TRUE(allocation.is_locked());
150 EXPECT_EQ(1024u, BytesAllocated());
151 EXPECT_FALSE(CanBePurged(&allocation));
152 Unlock(&allocation);
153 Unregister(&allocation);
156 TEST_F(DiscardableMemoryManagerTest, CreateZeroSize) {
157 size_t size = 0;
158 TestAllocationImpl allocation;
159 Register(&allocation, size);
160 EXPECT_TRUE(IsRegistered(&allocation));
161 EXPECT_EQ(LOCK_STATUS_FAILED, Lock(&allocation));
162 EXPECT_EQ(0u, BytesAllocated());
163 Unregister(&allocation);
166 TEST_F(DiscardableMemoryManagerTest, LockAfterUnlock) {
167 size_t size = 1024;
168 TestAllocationImpl allocation;
169 RegisterAndLock(&allocation, size);
170 EXPECT_EQ(1024u, BytesAllocated());
171 EXPECT_FALSE(CanBePurged(&allocation));
173 // Now unlock so we can lock later.
174 Unlock(&allocation);
175 EXPECT_TRUE(CanBePurged(&allocation));
177 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(&allocation));
178 EXPECT_FALSE(CanBePurged(&allocation));
179 Unlock(&allocation);
180 Unregister(&allocation);
183 TEST_F(DiscardableMemoryManagerTest, LockAfterPurge) {
184 size_t size = 1024;
185 TestAllocationImpl allocation;
186 RegisterAndLock(&allocation, size);
187 EXPECT_EQ(1024u, BytesAllocated());
188 EXPECT_FALSE(CanBePurged(&allocation));
190 // Now unlock so we can lock later.
191 Unlock(&allocation);
192 EXPECT_TRUE(CanBePurged(&allocation));
194 // Force the system to purge.
195 PurgeAll();
197 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
198 EXPECT_FALSE(CanBePurged(&allocation));
200 Unlock(&allocation);
201 Unregister(&allocation);
204 TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) {
205 size_t size = 1024;
206 TestAllocationImpl allocation;
207 RegisterAndLock(&allocation, size);
208 EXPECT_EQ(1024u, BytesAllocated());
209 EXPECT_FALSE(CanBePurged(&allocation));
211 // Now unlock so we can lock later.
212 Unlock(&allocation);
213 EXPECT_TRUE(CanBePurged(&allocation));
215 // Set max allowed allocation to 1 byte. This will cause the memory to be
216 // purged.
217 SetMemoryLimit(1);
219 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
220 EXPECT_FALSE(CanBePurged(&allocation));
222 Unlock(&allocation);
223 Unregister(&allocation);
226 TEST_F(DiscardableMemoryManagerTest, Overflow) {
227 size_t size = 1024;
229 TestAllocationImpl allocation;
230 RegisterAndLock(&allocation, size);
231 EXPECT_EQ(1024u, BytesAllocated());
233 size_t massive_size = std::numeric_limits<size_t>::max();
234 TestAllocationImpl massive_allocation;
235 Register(&massive_allocation, massive_size);
236 EXPECT_EQ(LOCK_STATUS_FAILED, Lock(&massive_allocation));
237 EXPECT_EQ(1024u, BytesAllocated());
239 Unlock(&allocation);
240 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&massive_allocation));
241 Unlock(&massive_allocation);
242 Unregister(&massive_allocation);
243 Unregister(&allocation);
245 EXPECT_EQ(0u, BytesAllocated());
248 class PermutationTestData {
249 public:
250 PermutationTestData(unsigned d0, unsigned d1, unsigned d2) {
251 ordering_[0] = d0;
252 ordering_[1] = d1;
253 ordering_[2] = d2;
256 const unsigned* ordering() const { return ordering_; }
258 private:
259 unsigned ordering_[3];
262 class DiscardableMemoryManagerPermutationTest
263 : public DiscardableMemoryManagerTestBase,
264 public testing::TestWithParam<PermutationTestData> {
265 public:
266 DiscardableMemoryManagerPermutationTest() {}
268 protected:
269 // Use memory in order specified by ordering parameter.
270 void RegisterAndUseAllocations() {
271 for (int i = 0; i < 3; ++i) {
272 RegisterAndLock(&allocation_[i], 1024);
273 Unlock(&allocation_[i]);
275 for (int i = 0; i < 3; ++i) {
276 int index = GetParam().ordering()[i];
277 EXPECT_NE(LOCK_STATUS_FAILED, Lock(&allocation_[index]));
278 // Leave i == 0 locked.
279 if (i > 0)
280 Unlock(&allocation_[index]);
284 TestAllocationImpl* allocation(unsigned position) {
285 return &allocation_[GetParam().ordering()[position]];
288 void UnlockAndUnregisterAllocations() {
289 for (int i = 0; i < 3; ++i) {
290 if (allocation_[i].is_locked())
291 Unlock(&allocation_[i]);
292 Unregister(&allocation_[i]);
296 private:
297 TestAllocationImpl allocation_[3];
300 // Verify that memory was discarded in the correct order after reducing usage to
301 // limit.
302 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscarded) {
303 RegisterAndUseAllocations();
305 SetMemoryLimit(2048);
307 ReduceMemoryUsageUntilWithinLimit(1024);
309 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
310 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
311 // 0 should still be locked.
312 EXPECT_TRUE(allocation(0)->is_locked());
314 UnlockAndUnregisterAllocations();
317 // Verify that memory was discarded in the correct order after changing
318 // memory limit.
319 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) {
320 RegisterAndUseAllocations();
322 SetMemoryLimit(2048);
324 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
325 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
326 // 0 should still be locked.
327 EXPECT_TRUE(allocation(0)->is_locked());
329 UnlockAndUnregisterAllocations();
332 // Verify that no more memory than necessary was discarded after changing
333 // memory limit.
334 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) {
335 SetMemoryLimit(4096);
337 RegisterAndUseAllocations();
339 SetMemoryLimit(2048);
341 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(allocation(2)));
342 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
343 // 0 should still be locked.
344 EXPECT_TRUE(allocation(0)->is_locked());
346 UnlockAndUnregisterAllocations();
349 TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) {
350 RegisterAndUseAllocations();
352 PurgeAll();
354 for (int i = 0; i < 3; ++i) {
355 if (i == 0)
356 EXPECT_TRUE(allocation(i)->is_locked());
357 else
358 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(i)));
361 UnlockAndUnregisterAllocations();
364 INSTANTIATE_TEST_CASE_P(DiscardableMemoryManagerPermutationTests,
365 DiscardableMemoryManagerPermutationTest,
366 ::testing::Values(PermutationTestData(0, 1, 2),
367 PermutationTestData(0, 2, 1),
368 PermutationTestData(1, 0, 2),
369 PermutationTestData(1, 2, 0),
370 PermutationTestData(2, 0, 1),
371 PermutationTestData(2, 1, 0)));
373 TEST_F(DiscardableMemoryManagerTest, NormalDestruction) {
375 size_t size = 1024;
376 TestAllocationImpl allocation;
377 Register(&allocation, size);
378 Unregister(&allocation);
380 EXPECT_EQ(0u, BytesAllocated());
383 TEST_F(DiscardableMemoryManagerTest, DestructionAfterLocked) {
385 size_t size = 1024;
386 TestAllocationImpl allocation;
387 RegisterAndLock(&allocation, size);
388 EXPECT_EQ(1024u, BytesAllocated());
389 EXPECT_FALSE(CanBePurged(&allocation));
390 Unlock(&allocation);
391 Unregister(&allocation);
393 EXPECT_EQ(0u, BytesAllocated());
396 TEST_F(DiscardableMemoryManagerTest, DestructionAfterPurged) {
398 size_t size = 1024;
399 TestAllocationImpl allocation;
400 RegisterAndLock(&allocation, size);
401 EXPECT_EQ(1024u, BytesAllocated());
402 Unlock(&allocation);
403 EXPECT_TRUE(CanBePurged(&allocation));
404 SetMemoryLimit(0);
405 EXPECT_EQ(0u, BytesAllocated());
406 Unregister(&allocation);
408 EXPECT_EQ(0u, BytesAllocated());
411 TEST_F(DiscardableMemoryManagerTest, ReduceMemoryUsage) {
412 SetMemoryLimit(3072);
413 SetSoftMemoryLimit(1024);
414 SetHardMemoryLimitExpirationTime(TimeDelta::FromInternalValue(1));
416 size_t size = 1024;
417 TestAllocationImpl allocation[3];
418 RegisterAndLock(&allocation[0], size);
419 RegisterAndLock(&allocation[1], size);
420 RegisterAndLock(&allocation[2], size);
421 EXPECT_EQ(3072u, BytesAllocated());
423 // Above soft limit but nothing that can be purged.
424 EXPECT_FALSE(ReduceMemoryUsage());
426 SetNow(TimeTicks::FromInternalValue(0));
427 Unlock(&allocation[0]);
429 // Above soft limit but still nothing that can be purged as all unlocked
430 // allocations are within the hard limit cutoff time.
431 EXPECT_FALSE(ReduceMemoryUsage());
433 SetNow(TimeTicks::FromInternalValue(1));
434 Unlock(&allocation[1]);
436 // One unlocked allocation is no longer within the hard limit cutoff time. It
437 // should be purged and ReduceMemoryUsage() should return false as we're not
438 // yet within the soft memory limit.
439 EXPECT_FALSE(ReduceMemoryUsage());
440 EXPECT_EQ(2048u, BytesAllocated());
442 // One more unlocked allocation is no longer within the hard limit cutoff
443 // time. It should be purged and ReduceMemoryUsage() should return true as
444 // we're now within the soft memory limit.
445 SetNow(TimeTicks::FromInternalValue(2));
446 EXPECT_TRUE(ReduceMemoryUsage());
447 EXPECT_EQ(1024u, BytesAllocated());
449 Unlock(&allocation[2]);
451 Unregister(&allocation[0]);
452 Unregister(&allocation[1]);
453 Unregister(&allocation[2]);
456 class ThreadedDiscardableMemoryManagerTest
457 : public DiscardableMemoryManagerTest {
458 public:
459 ThreadedDiscardableMemoryManagerTest()
460 : memory_usage_thread_("memory_usage_thread"),
461 thread_sync_(true, false) {}
463 void SetUp() override { memory_usage_thread_.Start(); }
465 void TearDown() override { memory_usage_thread_.Stop(); }
467 void UseMemoryHelper() {
468 size_t size = 1024;
469 TestAllocationImpl allocation;
470 RegisterAndLock(&allocation, size);
471 Unlock(&allocation);
472 Unregister(&allocation);
475 void SignalHelper() { thread_sync_.Signal(); }
477 Thread memory_usage_thread_;
478 WaitableEvent thread_sync_;
481 TEST_F(ThreadedDiscardableMemoryManagerTest, UseMemoryOnThread) {
482 memory_usage_thread_.message_loop()->PostTask(
483 FROM_HERE,
484 Bind(&ThreadedDiscardableMemoryManagerTest::UseMemoryHelper,
485 Unretained(this)));
486 memory_usage_thread_.message_loop()->PostTask(
487 FROM_HERE,
488 Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper,
489 Unretained(this)));
490 thread_sync_.Wait();
493 } // namespace
494 } // namespace base