OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/memory/discardable_memory_manager.h" | 5 #include "base/memory/discardable_memory_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/run_loop.h" | |
9 #include "base/synchronization/waitable_event.h" | 8 #include "base/synchronization/waitable_event.h" |
10 #include "base/threading/thread.h" | 9 #include "base/threading/thread.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
12 | 11 |
13 namespace base { | 12 namespace base { |
14 namespace { | 13 namespace { |
15 | 14 |
16 class TestAllocationImpl : public internal::DiscardableMemoryManagerAllocation { | 15 class TestAllocationImpl : public internal::DiscardableMemoryManagerAllocation { |
17 public: | 16 public: |
18 TestAllocationImpl() : is_allocated_(false), is_locked_(false) {} | 17 TestAllocationImpl() : is_allocated_(false), is_locked_(false) {} |
(...skipping 20 matching lines...) Expand all Loading... |
39 | 38 |
40 private: | 39 private: |
41 bool is_allocated_; | 40 bool is_allocated_; |
42 bool is_locked_; | 41 bool is_locked_; |
43 }; | 42 }; |
44 | 43 |
45 // Tests can assume that the default limit is at least 1024. Tests that rely on | 44 // Tests can assume that the default limit is at least 1024. Tests that rely on |
46 // something else needs to explicit set the limit. | 45 // something else needs to explicit set the limit. |
47 const size_t kDefaultMemoryLimit = 1024; | 46 const size_t kDefaultMemoryLimit = 1024; |
48 const size_t kDefaultSoftMemoryLimit = kDefaultMemoryLimit; | 47 const size_t kDefaultSoftMemoryLimit = kDefaultMemoryLimit; |
49 const size_t kDefaultBytesToKeepUnderModeratePressure = kDefaultMemoryLimit; | |
50 | 48 |
51 class TestDiscardableMemoryManagerImpl | 49 class TestDiscardableMemoryManagerImpl |
52 : public internal::DiscardableMemoryManager { | 50 : public internal::DiscardableMemoryManager { |
53 public: | 51 public: |
54 TestDiscardableMemoryManagerImpl() | 52 TestDiscardableMemoryManagerImpl() |
55 : DiscardableMemoryManager(kDefaultMemoryLimit, | 53 : DiscardableMemoryManager(kDefaultMemoryLimit, |
56 kDefaultSoftMemoryLimit, | 54 kDefaultSoftMemoryLimit, |
57 kDefaultBytesToKeepUnderModeratePressure, | |
58 TimeDelta::Max()) {} | 55 TimeDelta::Max()) {} |
59 | 56 |
60 void SetNow(TimeTicks now) { now_ = now; } | 57 void SetNow(TimeTicks now) { now_ = now; } |
61 | 58 |
62 private: | 59 private: |
63 // Overriden from internal::DiscardableMemoryManager: | 60 // Overriden from internal::DiscardableMemoryManager: |
64 virtual TimeTicks Now() const OVERRIDE { return now_; } | 61 virtual TimeTicks Now() const OVERRIDE { return now_; } |
65 | 62 |
66 TimeTicks now_; | 63 TimeTicks now_; |
67 }; | 64 }; |
68 | 65 |
69 class DiscardableMemoryManagerTestBase { | 66 class DiscardableMemoryManagerTestBase { |
70 public: | 67 public: |
71 DiscardableMemoryManagerTestBase() { | 68 DiscardableMemoryManagerTestBase() {} |
72 manager_.RegisterMemoryPressureListener(); | |
73 } | |
74 | 69 |
75 protected: | 70 protected: |
76 enum LockStatus { | 71 enum LockStatus { |
77 LOCK_STATUS_FAILED, | 72 LOCK_STATUS_FAILED, |
78 LOCK_STATUS_PURGED, | 73 LOCK_STATUS_PURGED, |
79 LOCK_STATUS_SUCCESS | 74 LOCK_STATUS_SUCCESS |
80 }; | 75 }; |
81 | 76 |
82 size_t BytesAllocated() const { return manager_.GetBytesAllocatedForTest(); } | 77 size_t BytesAllocated() const { return manager_.GetBytesAllocatedForTest(); } |
83 | 78 |
84 void SetMemoryLimit(size_t bytes) { manager_.SetMemoryLimit(bytes); } | 79 void SetMemoryLimit(size_t bytes) { manager_.SetMemoryLimit(bytes); } |
85 | 80 |
86 void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); } | 81 void SetSoftMemoryLimit(size_t bytes) { manager_.SetSoftMemoryLimit(bytes); } |
87 | 82 |
88 void SetBytesToKeepUnderModeratePressure(size_t bytes) { | |
89 manager_.SetBytesToKeepUnderModeratePressure(bytes); | |
90 } | |
91 | |
92 void SetHardMemoryLimitExpirationTime(TimeDelta time) { | 83 void SetHardMemoryLimitExpirationTime(TimeDelta time) { |
93 manager_.SetHardMemoryLimitExpirationTime(time); | 84 manager_.SetHardMemoryLimitExpirationTime(time); |
94 } | 85 } |
95 | 86 |
96 void Register(TestAllocationImpl* allocation, size_t bytes) { | 87 void Register(TestAllocationImpl* allocation, size_t bytes) { |
97 manager_.Register(allocation, bytes); | 88 manager_.Register(allocation, bytes); |
98 } | 89 } |
99 | 90 |
100 void Unregister(TestAllocationImpl* allocation) { | 91 void Unregister(TestAllocationImpl* allocation) { |
101 manager_.Unregister(allocation); | 92 manager_.Unregister(allocation); |
(...skipping 18 matching lines...) Expand all Loading... |
120 manager_.Register(allocation, bytes); | 111 manager_.Register(allocation, bytes); |
121 return Lock(allocation); | 112 return Lock(allocation); |
122 } | 113 } |
123 | 114 |
124 bool CanBePurged(TestAllocationImpl* allocation) const { | 115 bool CanBePurged(TestAllocationImpl* allocation) const { |
125 return manager_.CanBePurgedForTest(allocation); | 116 return manager_.CanBePurgedForTest(allocation); |
126 } | 117 } |
127 | 118 |
128 void SetNow(TimeTicks now) { manager_.SetNow(now); } | 119 void SetNow(TimeTicks now) { manager_.SetNow(now); } |
129 | 120 |
| 121 void PurgeAll() { return manager_.PurgeAll(); } |
| 122 |
130 bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); } | 123 bool ReduceMemoryUsage() { return manager_.ReduceMemoryUsage(); } |
131 | 124 |
| 125 void ReduceMemoryUsageUntilWithinLimit(size_t bytes) { |
| 126 manager_.ReduceMemoryUsageUntilWithinLimit(bytes); |
| 127 } |
| 128 |
132 private: | 129 private: |
133 MessageLoopForIO message_loop_; | |
134 TestDiscardableMemoryManagerImpl manager_; | 130 TestDiscardableMemoryManagerImpl manager_; |
135 }; | 131 }; |
136 | 132 |
137 class DiscardableMemoryManagerTest : public DiscardableMemoryManagerTestBase, | 133 class DiscardableMemoryManagerTest : public DiscardableMemoryManagerTestBase, |
138 public testing::Test { | 134 public testing::Test { |
139 public: | 135 public: |
140 DiscardableMemoryManagerTest() {} | 136 DiscardableMemoryManagerTest() {} |
141 }; | 137 }; |
142 | 138 |
143 TEST_F(DiscardableMemoryManagerTest, CreateAndLock) { | 139 TEST_F(DiscardableMemoryManagerTest, CreateAndLock) { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 TestAllocationImpl allocation; | 181 TestAllocationImpl allocation; |
186 RegisterAndLock(&allocation, size); | 182 RegisterAndLock(&allocation, size); |
187 EXPECT_EQ(1024u, BytesAllocated()); | 183 EXPECT_EQ(1024u, BytesAllocated()); |
188 EXPECT_FALSE(CanBePurged(&allocation)); | 184 EXPECT_FALSE(CanBePurged(&allocation)); |
189 | 185 |
190 // Now unlock so we can lock later. | 186 // Now unlock so we can lock later. |
191 Unlock(&allocation); | 187 Unlock(&allocation); |
192 EXPECT_TRUE(CanBePurged(&allocation)); | 188 EXPECT_TRUE(CanBePurged(&allocation)); |
193 | 189 |
194 // Force the system to purge. | 190 // Force the system to purge. |
195 MemoryPressureListener::NotifyMemoryPressure( | 191 PurgeAll(); |
196 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL); | |
197 | |
198 // Required because ObserverListThreadSafe notifies via PostTask. | |
199 RunLoop().RunUntilIdle(); | |
200 | 192 |
201 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation)); | 193 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(&allocation)); |
202 EXPECT_FALSE(CanBePurged(&allocation)); | 194 EXPECT_FALSE(CanBePurged(&allocation)); |
203 | 195 |
204 Unlock(&allocation); | 196 Unlock(&allocation); |
205 Unregister(&allocation); | 197 Unregister(&allocation); |
206 } | 198 } |
207 | 199 |
208 TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) { | 200 TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) { |
209 size_t size = 1024; | 201 size_t size = 1024; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 if (allocation_[i].is_locked()) | 286 if (allocation_[i].is_locked()) |
295 Unlock(&allocation_[i]); | 287 Unlock(&allocation_[i]); |
296 Unregister(&allocation_[i]); | 288 Unregister(&allocation_[i]); |
297 } | 289 } |
298 } | 290 } |
299 | 291 |
300 private: | 292 private: |
301 TestAllocationImpl allocation_[3]; | 293 TestAllocationImpl allocation_[3]; |
302 }; | 294 }; |
303 | 295 |
304 // Verify that memory was discarded in the correct order after applying | 296 // Verify that memory was discarded in the correct order after reducing usage to |
305 // memory pressure. | 297 // limit. |
306 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedModeratePressure) { | 298 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscarded) { |
307 RegisterAndUseAllocations(); | 299 RegisterAndUseAllocations(); |
308 | 300 |
309 SetBytesToKeepUnderModeratePressure(1024); | |
310 SetMemoryLimit(2048); | 301 SetMemoryLimit(2048); |
311 | 302 |
312 MemoryPressureListener::NotifyMemoryPressure( | 303 ReduceMemoryUsageUntilWithinLimit(1024); |
313 MemoryPressureListener::MEMORY_PRESSURE_MODERATE); | |
314 RunLoop().RunUntilIdle(); | |
315 | 304 |
316 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2))); | 305 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2))); |
317 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1))); | 306 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1))); |
318 // 0 should still be locked. | 307 // 0 should still be locked. |
319 EXPECT_TRUE(allocation(0)->is_locked()); | 308 EXPECT_TRUE(allocation(0)->is_locked()); |
320 | 309 |
321 UnlockAndUnregisterAllocations(); | 310 UnlockAndUnregisterAllocations(); |
322 } | 311 } |
323 | 312 |
324 // Verify that memory was discarded in the correct order after changing | 313 // Verify that memory was discarded in the correct order after changing |
325 // memory limit. | 314 // memory limit. |
326 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) { | 315 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) { |
327 RegisterAndUseAllocations(); | 316 RegisterAndUseAllocations(); |
328 | 317 |
329 SetBytesToKeepUnderModeratePressure(1024); | |
330 SetMemoryLimit(2048); | 318 SetMemoryLimit(2048); |
331 | 319 |
332 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2))); | 320 EXPECT_NE(LOCK_STATUS_FAILED, Lock(allocation(2))); |
333 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1))); | 321 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1))); |
334 // 0 should still be locked. | 322 // 0 should still be locked. |
335 EXPECT_TRUE(allocation(0)->is_locked()); | 323 EXPECT_TRUE(allocation(0)->is_locked()); |
336 | 324 |
337 UnlockAndUnregisterAllocations(); | 325 UnlockAndUnregisterAllocations(); |
338 } | 326 } |
339 | 327 |
340 // Verify that no more memory than necessary was discarded after changing | 328 // Verify that no more memory than necessary was discarded after changing |
341 // memory limit. | 329 // memory limit. |
342 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) { | 330 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) { |
343 SetBytesToKeepUnderModeratePressure(2048); | |
344 SetMemoryLimit(4096); | 331 SetMemoryLimit(4096); |
345 | 332 |
346 RegisterAndUseAllocations(); | 333 RegisterAndUseAllocations(); |
347 | 334 |
348 SetMemoryLimit(2048); | 335 SetMemoryLimit(2048); |
349 | 336 |
350 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(allocation(2))); | 337 EXPECT_EQ(LOCK_STATUS_SUCCESS, Lock(allocation(2))); |
351 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1))); | 338 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(1))); |
352 // 0 should still be locked. | 339 // 0 should still be locked. |
353 EXPECT_TRUE(allocation(0)->is_locked()); | 340 EXPECT_TRUE(allocation(0)->is_locked()); |
354 | 341 |
355 UnlockAndUnregisterAllocations(); | 342 UnlockAndUnregisterAllocations(); |
356 } | 343 } |
357 | 344 |
358 TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) { | 345 TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) { |
359 RegisterAndUseAllocations(); | 346 RegisterAndUseAllocations(); |
360 | 347 |
361 MemoryPressureListener::NotifyMemoryPressure( | 348 PurgeAll(); |
362 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL); | |
363 RunLoop().RunUntilIdle(); | |
364 | 349 |
365 for (int i = 0; i < 3; ++i) { | 350 for (int i = 0; i < 3; ++i) { |
366 if (i == 0) | 351 if (i == 0) |
367 EXPECT_TRUE(allocation(i)->is_locked()); | 352 EXPECT_TRUE(allocation(i)->is_locked()); |
368 else | 353 else |
369 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(i))); | 354 EXPECT_EQ(LOCK_STATUS_PURGED, Lock(allocation(i))); |
370 } | 355 } |
371 | 356 |
372 UnlockAndUnregisterAllocations(); | 357 UnlockAndUnregisterAllocations(); |
373 } | 358 } |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
496 Unretained(this))); | 481 Unretained(this))); |
497 memory_usage_thread_.message_loop()->PostTask( | 482 memory_usage_thread_.message_loop()->PostTask( |
498 FROM_HERE, | 483 FROM_HERE, |
499 Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper, | 484 Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper, |
500 Unretained(this))); | 485 Unretained(this))); |
501 thread_sync_.Wait(); | 486 thread_sync_.Wait(); |
502 } | 487 } |
503 | 488 |
504 } // namespace | 489 } // namespace |
505 } // namespace base | 490 } // namespace base |
OLD | NEW |