Use expanded heuristics for GPU rasterization on future OS versions
[chromium-blink-merge.git] / base / memory / discardable_memory_manager_unittest.cc
blobef5739a6526a5e03495d82c3b136c44f2b162e99
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/run_loop.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/threading/thread.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 namespace base {
14 namespace {
16 class TestAllocationImpl : public internal::DiscardableMemoryManagerAllocation {
17 public:
18 TestAllocationImpl() : is_allocated_(false), is_locked_(false) {}
19 virtual ~TestAllocationImpl() { DCHECK(!is_locked_); }
21 // Overridden from internal::DiscardableMemoryManagerAllocation:
22 virtual bool AllocateAndAcquireLock() OVERRIDE {
23 bool was_allocated = is_allocated_;
24 is_allocated_ = true;
25 DCHECK(!is_locked_);
26 is_locked_ = true;
27 return was_allocated;
29 virtual void ReleaseLock() OVERRIDE {
30 DCHECK(is_locked_);
31 is_locked_ = false;
33 virtual void Purge() OVERRIDE {
34 DCHECK(is_allocated_);
35 is_allocated_ = false;
38 bool is_locked() const { return is_locked_; }
40 private:
41 bool is_allocated_;
42 bool is_locked_;
45 // Tests can assume that the default limit is at least 1024. Tests that rely on
46 // something else needs to explicit set the limit.
47 const size_t kDefaultMemoryLimit = 1024;
48 const size_t kDefaultSoftMemoryLimit = kDefaultMemoryLimit;
49 const size_t kDefaultBytesToKeepUnderModeratePressure = kDefaultMemoryLimit;
51 class TestDiscardableMemoryManagerImpl
52 : public internal::DiscardableMemoryManager {
53 public:
54 TestDiscardableMemoryManagerImpl()
55 : DiscardableMemoryManager(kDefaultMemoryLimit,
56 kDefaultSoftMemoryLimit,
57 kDefaultBytesToKeepUnderModeratePressure,
58 TimeDelta::Max()) {}
60 void SetNow(TimeTicks now) { now_ = now; }
62 private:
63 // Overriden from internal::DiscardableMemoryManager:
64 virtual TimeTicks Now() const OVERRIDE { return now_; }
66 TimeTicks now_;
69 class DiscardableMemoryManagerTestBase {
70 public:
71 DiscardableMemoryManagerTestBase() {
72 manager_.RegisterMemoryPressureListener();
75 protected:
76 enum LockStatus {
77 LOCK_STATUS_FAILED,
78 LOCK_STATUS_PURGED,
79 LOCK_STATUS_SUCCESS
82 size_t BytesAllocated() const { return manager_.GetBytesAllocatedForTest(); }
84 void SetMemoryLimit(size_t bytes) { manager_.SetMemoryLimit(bytes); }
86 void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); }
88 void SetBytesToKeepUnderModeratePressure(size_t bytes) {
89 manager_.SetBytesToKeepUnderModeratePressure(bytes);
92 void SetHardMemoryLimitExpirationTime(TimeDelta time) {
93 manager_.SetHardMemoryLimitExpirationTime(time);
96 void Register(TestAllocationImpl* allocation, size_t bytes) {
97 manager_.Register(allocation, bytes);
100 void Unregister(TestAllocationImpl* allocation) {
101 manager_.Unregister(allocation);
104 bool IsRegistered(TestAllocationImpl* allocation) const {
105 return manager_.IsRegisteredForTest(allocation);
108 LockStatus Lock(TestAllocationImpl* allocation) {
109 bool purged;
110 if (!manager_.AcquireLock(allocation, &purged))
111 return LOCK_STATUS_FAILED;
112 return purged ? LOCK_STATUS_PURGED : LOCK_STATUS_SUCCESS;
115 void Unlock(TestAllocationImpl* allocation) {
116 manager_.ReleaseLock(allocation);
119 LockStatus RegisterAndLock(TestAllocationImpl* allocation, size_t bytes) {
120 manager_.Register(allocation, bytes);
121 return Lock(allocation);
124 bool CanBePurged(TestAllocationImpl* allocation) const {
125 return manager_.CanBePurgedForTest(allocation);
128 void SetNow(TimeTicks now) { manager_.SetNow(now); }
130 bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); }
132 private:
133 MessageLoopForIO message_loop_;
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 MemoryPressureListener::NotifyMemoryPressure(
196 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
198 // Required because ObserverListThreadSafe notifies via PostTask.
199 RunLoop().RunUntilIdle();
201 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
202 EXPECT_FALSE(CanBePurged(&allocation));
204 Unlock(&allocation);
205 Unregister(&allocation);
208 TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) {
209 size_t size = 1024;
210 TestAllocationImpl allocation;
211 RegisterAndLock(&allocation, size);
212 EXPECT_EQ(1024u, BytesAllocated());
213 EXPECT_FALSE(CanBePurged(&allocation));
215 // Now unlock so we can lock later.
216 Unlock(&allocation);
217 EXPECT_TRUE(CanBePurged(&allocation));
219 // Set max allowed allocation to 1 byte. This will cause the memory to be
220 // purged.
221 SetMemoryLimit(1);
223 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation));
224 EXPECT_FALSE(CanBePurged(&allocation));
226 Unlock(&allocation);
227 Unregister(&allocation);
230 TEST_F(DiscardableMemoryManagerTest, Overflow) {
231 size_t size = 1024;
233 TestAllocationImpl allocation;
234 RegisterAndLock(&allocation, size);
235 EXPECT_EQ(1024u, BytesAllocated());
237 size_t massive_size = std::numeric_limits<size_t>::max();
238 TestAllocationImpl massive_allocation;
239 Register(&massive_allocation, massive_size);
240 EXPECT_EQ(LOCK_STATUS_FAILED, Lock(&massive_allocation));
241 EXPECT_EQ(1024u, BytesAllocated());
243 Unlock(&allocation);
244 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&massive_allocation));
245 Unlock(&massive_allocation);
246 Unregister(&massive_allocation);
247 Unregister(&allocation);
249 EXPECT_EQ(0u, BytesAllocated());
252 class PermutationTestData {
253 public:
254 PermutationTestData(unsigned d0, unsigned d1, unsigned d2) {
255 ordering_[0] = d0;
256 ordering_[1] = d1;
257 ordering_[2] = d2;
260 const unsigned* ordering() const { return ordering_; }
262 private:
263 unsigned ordering_[3];
266 class DiscardableMemoryManagerPermutationTest
267 : public DiscardableMemoryManagerTestBase,
268 public testing::TestWithParam<PermutationTestData> {
269 public:
270 DiscardableMemoryManagerPermutationTest() {}
272 protected:
273 // Use memory in order specified by ordering parameter.
274 void RegisterAndUseAllocations() {
275 for (int i = 0; i < 3; ++i) {
276 RegisterAndLock(&allocation_[i], 1024);
277 Unlock(&allocation_[i]);
279 for (int i = 0; i < 3; ++i) {
280 int index = GetParam().ordering()[i];
281 EXPECT_NE(LOCK_STATUS_FAILED, Lock(&allocation_[index]));
282 // Leave i == 0 locked.
283 if (i > 0)
284 Unlock(&allocation_[index]);
288 TestAllocationImpl* allocation(unsigned position) {
289 return &allocation_[GetParam().ordering()[position]];
292 void UnlockAndUnregisterAllocations() {
293 for (int i = 0; i < 3; ++i) {
294 if (allocation_[i].is_locked())
295 Unlock(&allocation_[i]);
296 Unregister(&allocation_[i]);
300 private:
301 TestAllocationImpl allocation_[3];
304 // Verify that memory was discarded in the correct order after applying
305 // memory pressure.
306 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedModeratePressure) {
307 RegisterAndUseAllocations();
309 SetBytesToKeepUnderModeratePressure(1024);
310 SetMemoryLimit(2048);
312 MemoryPressureListener::NotifyMemoryPressure(
313 MemoryPressureListener::MEMORY_PRESSURE_MODERATE);
314 RunLoop().RunUntilIdle();
316 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
317 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
318 // 0 should still be locked.
319 EXPECT_TRUE(allocation(0)->is_locked());
321 UnlockAndUnregisterAllocations();
324 // Verify that memory was discarded in the correct order after changing
325 // memory limit.
326 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) {
327 RegisterAndUseAllocations();
329 SetBytesToKeepUnderModeratePressure(1024);
330 SetMemoryLimit(2048);
332 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2)));
333 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
334 // 0 should still be locked.
335 EXPECT_TRUE(allocation(0)->is_locked());
337 UnlockAndUnregisterAllocations();
340 // Verify that no more memory than necessary was discarded after changing
341 // memory limit.
342 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) {
343 SetBytesToKeepUnderModeratePressure(2048);
344 SetMemoryLimit(4096);
346 RegisterAndUseAllocations();
348 SetMemoryLimit(2048);
350 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(allocation(2)));
351 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1)));
352 // 0 should still be locked.
353 EXPECT_TRUE(allocation(0)->is_locked());
355 UnlockAndUnregisterAllocations();
358 TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) {
359 RegisterAndUseAllocations();
361 MemoryPressureListener::NotifyMemoryPressure(
362 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL);
363 RunLoop().RunUntilIdle();
365 for (int i = 0; i < 3; ++i) {
366 if (i == 0)
367 EXPECT_TRUE(allocation(i)->is_locked());
368 else
369 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(i)));
372 UnlockAndUnregisterAllocations();
375 INSTANTIATE_TEST_CASE_P(DiscardableMemoryManagerPermutationTests,
376 DiscardableMemoryManagerPermutationTest,
377 ::testing::Values(PermutationTestData(0, 1, 2),
378 PermutationTestData(0, 2, 1),
379 PermutationTestData(1, 0, 2),
380 PermutationTestData(1, 2, 0),
381 PermutationTestData(2, 0, 1),
382 PermutationTestData(2, 1, 0)));
384 TEST_F(DiscardableMemoryManagerTest, NormalDestruction) {
386 size_t size = 1024;
387 TestAllocationImpl allocation;
388 Register(&allocation, size);
389 Unregister(&allocation);
391 EXPECT_EQ(0u, BytesAllocated());
394 TEST_F(DiscardableMemoryManagerTest, DestructionAfterLocked) {
396 size_t size = 1024;
397 TestAllocationImpl allocation;
398 RegisterAndLock(&allocation, size);
399 EXPECT_EQ(1024u, BytesAllocated());
400 EXPECT_FALSE(CanBePurged(&allocation));
401 Unlock(&allocation);
402 Unregister(&allocation);
404 EXPECT_EQ(0u, BytesAllocated());
407 TEST_F(DiscardableMemoryManagerTest, DestructionAfterPurged) {
409 size_t size = 1024;
410 TestAllocationImpl allocation;
411 RegisterAndLock(&allocation, size);
412 EXPECT_EQ(1024u, BytesAllocated());
413 Unlock(&allocation);
414 EXPECT_TRUE(CanBePurged(&allocation));
415 SetMemoryLimit(0);
416 EXPECT_EQ(0u, BytesAllocated());
417 Unregister(&allocation);
419 EXPECT_EQ(0u, BytesAllocated());
422 TEST_F(DiscardableMemoryManagerTest, ReduceMemoryUsage) {
423 SetMemoryLimit(3072);
424 SetSoftMemoryLimit(1024);
425 SetHardMemoryLimitExpirationTime(TimeDelta::FromInternalValue(1));
427 size_t size = 1024;
428 TestAllocationImpl allocation[3];
429 RegisterAndLock(&allocation[0], size);
430 RegisterAndLock(&allocation[1], size);
431 RegisterAndLock(&allocation[2], size);
432 EXPECT_EQ(3072u, BytesAllocated());
434 // Above soft limit but nothing that can be purged.
435 EXPECT_FALSE(ReduceMemoryUsage());
437 SetNow(TimeTicks::FromInternalValue(0));
438 Unlock(&allocation[0]);
440 // Above soft limit but still nothing that can be purged as all unlocked
441 // allocations are within the hard limit cutoff time.
442 EXPECT_FALSE(ReduceMemoryUsage());
444 SetNow(TimeTicks::FromInternalValue(1));
445 Unlock(&allocation[1]);
447 // One unlocked allocation is no longer within the hard limit cutoff time. It
448 // should be purged and ReduceMemoryUsage() should return false as we're not
449 // yet within the soft memory limit.
450 EXPECT_FALSE(ReduceMemoryUsage());
451 EXPECT_EQ(2048u, BytesAllocated());
453 // One more unlocked allocation is no longer within the hard limit cutoff
454 // time. It should be purged and ReduceMemoryUsage() should return true as
455 // we're now within the soft memory limit.
456 SetNow(TimeTicks::FromInternalValue(2));
457 EXPECT_TRUE(ReduceMemoryUsage());
458 EXPECT_EQ(1024u, BytesAllocated());
460 Unlock(&allocation[2]);
462 Unregister(&allocation[0]);
463 Unregister(&allocation[1]);
464 Unregister(&allocation[2]);
467 class ThreadedDiscardableMemoryManagerTest
468 : public DiscardableMemoryManagerTest {
469 public:
470 ThreadedDiscardableMemoryManagerTest()
471 : memory_usage_thread_("memory_usage_thread"),
472 thread_sync_(true, false) {}
474 virtual void SetUp() OVERRIDE { memory_usage_thread_.Start(); }
476 virtual void TearDown() OVERRIDE { memory_usage_thread_.Stop(); }
478 void UseMemoryHelper() {
479 size_t size = 1024;
480 TestAllocationImpl allocation;
481 RegisterAndLock(&allocation, size);
482 Unlock(&allocation);
483 Unregister(&allocation);
486 void SignalHelper() { thread_sync_.Signal(); }
488 Thread memory_usage_thread_;
489 WaitableEvent thread_sync_;
492 TEST_F(ThreadedDiscardableMemoryManagerTest, UseMemoryOnThread) {
493 memory_usage_thread_.message_loop()->PostTask(
494 FROM_HERE,
495 Bind(&ThreadedDiscardableMemoryManagerTest::UseMemoryHelper,
496 Unretained(this)));
497 memory_usage_thread_.message_loop()->PostTask(
498 FROM_HERE,
499 Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper,
500 Unretained(this)));
501 thread_sync_.Wait();
504 } // namespace
505 } // namespace base