| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/memory/discardable_memory.h" | |
| 9 #include "base/run_loop.h" | |
| 10 #include "base/synchronization/waitable_event.h" | 8 #include "base/synchronization/waitable_event.h" |
| 11 #include "base/threading/thread.h" | 9 #include "base/threading/thread.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 10 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 11 |
| 14 namespace base { | 12 namespace base { |
| 15 | 13 |
| 16 class DiscardableMemoryManagerTestBase { | 14 class DiscardableMemoryAllocationImpl |
| 15 : public internal::DiscardableMemoryAllocation { |
| 17 public: | 16 public: |
| 18 class TestDiscardableMemory : public DiscardableMemory { | 17 // Overridden from internal::DiscardableMemoryAllocation: |
| 19 public: | 18 virtual bool Lock() OVERRIDE { return true; } |
| 20 TestDiscardableMemory( | 19 virtual void Unlock() OVERRIDE {} |
| 21 internal::DiscardableMemoryManager* manager, size_t size) | 20 virtual void* Memory() OVERRIDE { |
| 22 : manager_(manager), | 21 return reinterpret_cast<void*>(0xdeadbeef); |
| 23 is_locked_(false) { | 22 } |
| 24 manager_->Register(this, size); | 23 }; |
| 25 } | |
| 26 | 24 |
| 27 virtual ~TestDiscardableMemory() { | 25 const size_t kDefaultDiscardableMemoryLimit = 8192u; |
| 28 if (is_locked_) | |
| 29 Unlock(); | |
| 30 manager_->Unregister(this); | |
| 31 } | |
| 32 | 26 |
| 33 // Overridden from DiscardableMemory: | 27 class DiscardableMemoryManagerTestBase |
| 34 virtual DiscardableMemoryLockStatus Lock() OVERRIDE { | 28 : public internal::DiscardableMemoryAllocation::Factory { |
| 35 DCHECK(!is_locked_); | 29 public: |
| 30 struct Allocation { |
| 31 Allocation(internal::DiscardableMemoryManager* manager, size_t bytes) |
| 32 : manager(manager), id(manager->Register(bytes)) {} |
| 33 ~Allocation() { manager->Unregister(id); } |
| 36 | 34 |
| 37 bool purged = false; | 35 internal::DiscardableMemoryManager* manager; |
| 38 memory_ = manager_->Acquire(this, &purged); | 36 internal::DiscardableMemoryManager::AllocationId id; |
| 39 if (!memory_) | |
| 40 return DISCARDABLE_MEMORY_LOCK_STATUS_FAILED; | |
| 41 | |
| 42 is_locked_ = true; | |
| 43 return purged ? DISCARDABLE_MEMORY_LOCK_STATUS_PURGED | |
| 44 : DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS; | |
| 45 } | |
| 46 virtual void Unlock() OVERRIDE { | |
| 47 DCHECK(is_locked_); | |
| 48 manager_->Release(this, memory_.Pass()); | |
| 49 is_locked_ = false; | |
| 50 } | |
| 51 virtual void* Memory() const OVERRIDE { | |
| 52 DCHECK(memory_); | |
| 53 return memory_.get(); | |
| 54 } | |
| 55 | |
| 56 private: | |
| 57 internal::DiscardableMemoryManager* manager_; | |
| 58 scoped_ptr<uint8, FreeDeleter> memory_; | |
| 59 bool is_locked_; | |
| 60 | |
| 61 DISALLOW_COPY_AND_ASSIGN(TestDiscardableMemory); | |
| 62 }; | 37 }; |
| 63 | 38 |
| 64 DiscardableMemoryManagerTestBase() | 39 DiscardableMemoryManagerTestBase() |
| 65 : manager_(new internal::DiscardableMemoryManager) { | 40 : manager_(new internal::DiscardableMemoryManager( |
| 66 manager_->RegisterMemoryPressureListener(); | 41 this, |
| 42 kDefaultDiscardableMemoryLimit)) {} |
| 43 |
| 44 // Overridden from internal::DiscardableMemoryAllocation::Factory: |
| 45 virtual scoped_ptr<internal::DiscardableMemoryAllocation> |
| 46 CreateLockedAllocation(size_t bytes) OVERRIDE { |
| 47 return make_scoped_ptr<internal::DiscardableMemoryAllocation>( |
| 48 new DiscardableMemoryAllocationImpl); |
| 67 } | 49 } |
| 68 | 50 |
| 69 protected: | 51 protected: |
| 70 bool IsRegistered(const DiscardableMemory* discardable) { | 52 bool IsRegistered(Allocation* allocation) { |
| 71 return manager_->IsRegisteredForTest(discardable); | 53 return manager_->IsRegisteredForTest(allocation->id); |
| 72 } | 54 } |
| 73 | 55 |
| 74 bool CanBePurged(const DiscardableMemory* discardable) { | 56 bool CanBePurged(Allocation* allocation) { |
| 75 return manager_->CanBePurgedForTest(discardable); | 57 return manager_->CanBePurgedForTest(allocation->id); |
| 76 } | 58 } |
| 77 | 59 |
| 78 size_t BytesAllocated() const { | 60 size_t BytesAllocated() const { |
| 79 return manager_->GetBytesAllocatedForTest(); | 61 return manager_->GetBytesAllocatedForTest(); |
| 80 } | 62 } |
| 81 | 63 |
| 82 void* Memory(const DiscardableMemory* discardable) const { | 64 bool Lock(Allocation* allocation) { |
| 83 return discardable->Memory(); | 65 bool purged; |
| 66 return !!manager_->Lock(allocation->id, &purged); |
| 84 } | 67 } |
| 85 | 68 |
| 69 bool Lock(Allocation* allocation, bool expected_to_be_purged) { |
| 70 bool purged; |
| 71 return !!manager_->Lock(allocation->id, &purged) && |
| 72 expected_to_be_purged == purged; |
| 73 } |
| 74 |
| 75 void Unlock(Allocation* allocation) { manager_->Unlock(allocation->id); } |
| 76 |
| 86 void SetDiscardableMemoryLimit(size_t bytes) { | 77 void SetDiscardableMemoryLimit(size_t bytes) { |
| 87 manager_->SetDiscardableMemoryLimit(bytes); | 78 manager_->SetDiscardableMemoryLimit(bytes); |
| 88 } | 79 } |
| 89 | 80 |
| 90 void SetBytesToKeepUnderModeratePressure(size_t bytes) { | 81 scoped_ptr<Allocation> Create(size_t bytes) { |
| 91 manager_->SetBytesToKeepUnderModeratePressure(bytes); | 82 return make_scoped_ptr(new Allocation(manager_.get(), bytes)); |
| 92 } | 83 } |
| 93 | 84 |
| 94 scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size) { | 85 scoped_ptr<Allocation> CreateLocked(size_t bytes) { |
| 95 scoped_ptr<TestDiscardableMemory> memory( | 86 scoped_ptr<Allocation> allocation(Create(bytes)); |
| 96 new TestDiscardableMemory(manager_.get(), size)); | 87 EXPECT_TRUE(IsRegistered(allocation.get())); |
| 97 if (memory->Lock() != DISCARDABLE_MEMORY_LOCK_STATUS_PURGED) | 88 EXPECT_TRUE(Lock(allocation.get(), true)); |
| 98 return scoped_ptr<DiscardableMemory>(); | 89 return allocation.Pass(); |
| 99 return memory.PassAs<DiscardableMemory>(); | 90 } |
| 91 |
| 92 void PurgeUntilUsageIsWithin(size_t limit) { |
| 93 manager_->PurgeUntilUsageIsWithin(limit); |
| 100 } | 94 } |
| 101 | 95 |
| 102 private: | 96 private: |
| 103 MessageLoopForIO message_loop_; | |
| 104 scoped_ptr<internal::DiscardableMemoryManager> manager_; | 97 scoped_ptr<internal::DiscardableMemoryManager> manager_; |
| 105 }; | 98 }; |
| 106 | 99 |
| 107 class DiscardableMemoryManagerTest | 100 class DiscardableMemoryManagerTest |
| 108 : public DiscardableMemoryManagerTestBase, | 101 : public DiscardableMemoryManagerTestBase, |
| 109 public testing::Test { | 102 public testing::Test { |
| 110 public: | 103 public: |
| 111 DiscardableMemoryManagerTest() {} | 104 DiscardableMemoryManagerTest() {} |
| 112 }; | 105 }; |
| 113 | 106 |
| 114 TEST_F(DiscardableMemoryManagerTest, CreateLockedMemory) { | 107 TEST_F(DiscardableMemoryManagerTest, CreateAndLock) { |
| 115 size_t size = 1024; | 108 size_t size = 1024u; |
| 116 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 109 const scoped_ptr<Allocation> allocation(Create(size)); |
| 117 EXPECT_TRUE(IsRegistered(discardable.get())); | 110 EXPECT_TRUE(IsRegistered(allocation.get())); |
| 118 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | 111 EXPECT_TRUE(Lock(allocation.get(), true)); |
| 119 EXPECT_EQ(1024u, BytesAllocated()); | 112 EXPECT_EQ(1024u, BytesAllocated()); |
| 120 EXPECT_FALSE(CanBePurged(discardable.get())); | 113 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 121 } | 114 } |
| 122 | 115 |
| 123 TEST_F(DiscardableMemoryManagerTest, CreateLockedMemoryZeroSize) { | 116 TEST_F(DiscardableMemoryManagerTest, CreateZeroSize) { |
| 124 size_t size = 0; | 117 size_t size = 0u; |
| 125 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 118 const scoped_ptr<Allocation> allocation(Create(size)); |
| 126 EXPECT_FALSE(discardable); | 119 EXPECT_TRUE(IsRegistered(allocation.get())); |
| 127 EXPECT_FALSE(IsRegistered(discardable.get())); | 120 EXPECT_FALSE(Lock(allocation.get(), true)); |
| 128 EXPECT_EQ(0u, BytesAllocated()); | 121 EXPECT_EQ(0u, BytesAllocated()); |
| 129 } | 122 } |
| 130 | 123 |
| 131 TEST_F(DiscardableMemoryManagerTest, LockAfterUnlock) { | 124 TEST_F(DiscardableMemoryManagerTest, LockAfterUnlock) { |
| 132 size_t size = 1024; | 125 size_t size = 1024u; |
| 133 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 126 const scoped_ptr<Allocation> allocation(CreateLocked(size)); |
| 134 EXPECT_TRUE(IsRegistered(discardable.get())); | |
| 135 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | |
| 136 EXPECT_EQ(1024u, BytesAllocated()); | 127 EXPECT_EQ(1024u, BytesAllocated()); |
| 137 EXPECT_FALSE(CanBePurged(discardable.get())); | 128 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 138 | 129 |
| 139 // Now unlock so we can lock later. | 130 // Now unlock so we can lock later. |
| 140 discardable->Unlock(); | 131 Unlock(allocation.get()); |
| 141 EXPECT_TRUE(CanBePurged(discardable.get())); | 132 EXPECT_TRUE(CanBePurged(allocation.get())); |
| 142 | 133 |
| 143 EXPECT_EQ(DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS, discardable->Lock()); | 134 EXPECT_TRUE(Lock(allocation.get(), false)); |
| 144 EXPECT_FALSE(CanBePurged(discardable.get())); | 135 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 145 } | 136 } |
| 146 | 137 |
| 147 TEST_F(DiscardableMemoryManagerTest, LockAfterPurge) { | 138 TEST_F(DiscardableMemoryManagerTest, LockAfterPurge) { |
| 148 size_t size = 1024; | 139 size_t size = 1024u; |
| 149 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 140 const scoped_ptr<Allocation> allocation(CreateLocked(size)); |
| 150 EXPECT_TRUE(IsRegistered(discardable.get())); | |
| 151 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | |
| 152 EXPECT_EQ(1024u, BytesAllocated()); | 141 EXPECT_EQ(1024u, BytesAllocated()); |
| 153 EXPECT_FALSE(CanBePurged(discardable.get())); | 142 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 154 | 143 |
| 155 // Now unlock so we can lock later. | 144 // Now unlock so we can lock later. |
| 156 discardable->Unlock(); | 145 Unlock(allocation.get()); |
| 157 EXPECT_TRUE(CanBePurged(discardable.get())); | 146 EXPECT_TRUE(CanBePurged(allocation.get())); |
| 158 | 147 |
| 159 // Force the system to purge. | 148 // Force the system to purge. |
| 160 MemoryPressureListener::NotifyMemoryPressure( | 149 PurgeUntilUsageIsWithin(0u); |
| 161 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL); | |
| 162 | 150 |
| 163 // Required because ObserverListThreadSafe notifies via PostTask. | 151 EXPECT_TRUE(Lock(allocation.get(), true)); |
| 164 RunLoop().RunUntilIdle(); | 152 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 165 | |
| 166 EXPECT_EQ(DISCARDABLE_MEMORY_LOCK_STATUS_PURGED, discardable->Lock()); | |
| 167 EXPECT_FALSE(CanBePurged(discardable.get())); | |
| 168 } | 153 } |
| 169 | 154 |
| 170 TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) { | 155 TEST_F(DiscardableMemoryManagerTest, LockAfterPurgeAndCannotReallocate) { |
| 171 size_t size = 1024; | 156 size_t size = 1024u; |
| 172 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 157 const scoped_ptr<Allocation> allocation(CreateLocked(size)); |
| 173 EXPECT_TRUE(IsRegistered(discardable.get())); | |
| 174 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | |
| 175 EXPECT_EQ(1024u, BytesAllocated()); | 158 EXPECT_EQ(1024u, BytesAllocated()); |
| 176 EXPECT_FALSE(CanBePurged(discardable.get())); | 159 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 177 | 160 |
| 178 // Now unlock so we can lock later. | 161 // Now unlock so we can lock later. |
| 179 discardable->Unlock(); | 162 Unlock(allocation.get()); |
| 180 EXPECT_TRUE(CanBePurged(discardable.get())); | 163 EXPECT_TRUE(CanBePurged(allocation.get())); |
| 181 | 164 |
| 182 // Set max allowed allocation to 1 byte. This will make cause the memory | 165 // Set max allowed allocation to 1 byte. This will cause the memory to be |
| 183 // to be purged. | 166 // purged. |
| 184 SetDiscardableMemoryLimit(1); | 167 SetDiscardableMemoryLimit(1); |
| 185 | 168 |
| 186 EXPECT_EQ(DISCARDABLE_MEMORY_LOCK_STATUS_PURGED, discardable->Lock()); | 169 EXPECT_TRUE(Lock(allocation.get(), true)); |
| 187 EXPECT_FALSE(CanBePurged(discardable.get())); | 170 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 188 } | 171 } |
| 189 | 172 |
| 190 TEST_F(DiscardableMemoryManagerTest, Overflow) { | 173 TEST_F(DiscardableMemoryManagerTest, Overflow) { |
| 191 { | 174 { |
| 192 size_t size = 1024; | 175 size_t size = 1024u; |
| 193 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 176 const scoped_ptr<Allocation> allocation(CreateLocked(size)); |
| 194 EXPECT_TRUE(IsRegistered(discardable.get())); | |
| 195 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | |
| 196 EXPECT_EQ(1024u, BytesAllocated()); | 177 EXPECT_EQ(1024u, BytesAllocated()); |
| 197 | 178 |
| 198 size_t massive_size = std::numeric_limits<size_t>::max(); | 179 size_t massive_size = std::numeric_limits<size_t>::max(); |
| 199 const scoped_ptr<DiscardableMemory> massive_discardable( | 180 const scoped_ptr<Allocation> massive_allocation(Create(massive_size)); |
| 200 CreateLockedMemory(massive_size)); | 181 EXPECT_FALSE(Lock(massive_allocation.get(), true)); |
| 201 EXPECT_FALSE(massive_discardable); | |
| 202 EXPECT_EQ(1024u, BytesAllocated()); | 182 EXPECT_EQ(1024u, BytesAllocated()); |
| 203 } | 183 } |
| 204 EXPECT_EQ(0u, BytesAllocated()); | 184 EXPECT_EQ(0u, BytesAllocated()); |
| 205 } | 185 } |
| 206 | 186 |
| 207 class PermutationTestData { | 187 class PermutationTestData { |
| 208 public: | 188 public: |
| 209 PermutationTestData(unsigned d0, unsigned d1, unsigned d2) { | 189 PermutationTestData(unsigned d0, unsigned d1, unsigned d2) { |
| 210 ordering_[0] = d0; | 190 ordering_[0] = d0; |
| 211 ordering_[1] = d1; | 191 ordering_[1] = d1; |
| 212 ordering_[2] = d2; | 192 ordering_[2] = d2; |
| 213 } | 193 } |
| 214 | 194 |
| 215 const unsigned* ordering() const { return ordering_; } | 195 const unsigned* ordering() const { return ordering_; } |
| 216 | 196 |
| 217 private: | 197 private: |
| 218 unsigned ordering_[3]; | 198 unsigned ordering_[3]; |
| 219 }; | 199 }; |
| 220 | 200 |
| 221 class DiscardableMemoryManagerPermutationTest | 201 class DiscardableMemoryManagerPermutationTest |
| 222 : public DiscardableMemoryManagerTestBase, | 202 : public DiscardableMemoryManagerTestBase, |
| 223 public testing::TestWithParam<PermutationTestData> { | 203 public testing::TestWithParam<PermutationTestData> { |
| 224 public: | 204 public: |
| 225 DiscardableMemoryManagerPermutationTest() {} | 205 DiscardableMemoryManagerPermutationTest() {} |
| 226 | 206 |
| 227 protected: | 207 protected: |
| 228 // Use discardable memory in order specified by ordering parameter. | 208 // Use discardable memory in order specified by ordering parameter. |
| 229 void CreateAndUseDiscardableMemory() { | 209 void CreateAndUseDiscardableMemory() { |
| 230 for (int i = 0; i < 3; ++i) { | 210 for (int i = 0; i < 3; ++i) { |
| 231 discardables_[i] = CreateLockedMemory(1024); | 211 allocations_[i] = CreateLocked(1024u); |
| 232 EXPECT_TRUE(discardables_[i]); | 212 Unlock(allocations_[i].get()); |
| 233 EXPECT_NE(static_cast<void*>(NULL), Memory(discardables_[i].get())); | |
| 234 discardables_[i]->Unlock(); | |
| 235 } | 213 } |
| 236 for (int i = 0; i < 3; ++i) { | 214 for (int i = 0; i < 3; ++i) { |
| 237 int index = GetParam().ordering()[i]; | 215 int index = GetParam().ordering()[i]; |
| 238 EXPECT_NE(DISCARDABLE_MEMORY_LOCK_STATUS_FAILED, | 216 EXPECT_TRUE(Lock(allocations_[index].get())); |
| 239 discardables_[index]->Lock()); | |
| 240 // Leave i == 0 locked. | 217 // Leave i == 0 locked. |
| 241 if (i > 0) | 218 if (i > 0) |
| 242 discardables_[index]->Unlock(); | 219 Unlock(allocations_[index].get()); |
| 243 } | 220 } |
| 244 } | 221 } |
| 245 | 222 |
| 246 DiscardableMemory* discardable(unsigned position) { | 223 Allocation* allocation(unsigned position) { |
| 247 return discardables_[GetParam().ordering()[position]].get(); | 224 return allocations_[GetParam().ordering()[position]].get(); |
| 248 } | 225 } |
| 249 | 226 |
| 250 private: | 227 private: |
| 251 scoped_ptr<DiscardableMemory> discardables_[3]; | 228 scoped_ptr<Allocation> allocations_[3]; |
| 252 }; | 229 }; |
| 253 | 230 |
| 254 // Verify that memory was discarded in the correct order after applying | 231 // Verify that memory was discarded in the correct order after applying |
| 255 // memory pressure. | 232 // memory pressure. |
| 256 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedModeratePressure) { | 233 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedModeratePressure) { |
| 257 CreateAndUseDiscardableMemory(); | 234 CreateAndUseDiscardableMemory(); |
| 258 | 235 |
| 259 SetBytesToKeepUnderModeratePressure(1024); | 236 SetDiscardableMemoryLimit(2048u); |
| 260 SetDiscardableMemoryLimit(2048); | 237 // Simulate moderate pressure by purging until usage is within 1024u bytes. |
| 238 PurgeUntilUsageIsWithin(1024u); |
| 261 | 239 |
| 262 MemoryPressureListener::NotifyMemoryPressure( | 240 EXPECT_TRUE(Lock(allocation(2))); |
| 263 MemoryPressureListener::MEMORY_PRESSURE_MODERATE); | 241 EXPECT_TRUE(Lock(allocation(1), true)); |
| 264 RunLoop().RunUntilIdle(); | |
| 265 | |
| 266 EXPECT_NE(DISCARDABLE_MEMORY_LOCK_STATUS_FAILED, discardable(2)->Lock()); | |
| 267 EXPECT_NE(DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS, discardable(1)->Lock()); | |
| 268 // 0 should still be locked. | 242 // 0 should still be locked. |
| 269 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable(0))); | 243 EXPECT_FALSE(CanBePurged(allocation(0))); |
| 270 } | 244 } |
| 271 | 245 |
| 272 // Verify that memory was discarded in the correct order after changing | 246 // Verify that memory was discarded in the correct order after changing |
| 273 // memory limit. | 247 // memory limit. |
| 274 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) { | 248 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedExceedLimit) { |
| 275 CreateAndUseDiscardableMemory(); | 249 CreateAndUseDiscardableMemory(); |
| 276 | 250 |
| 277 SetBytesToKeepUnderModeratePressure(1024); | 251 SetDiscardableMemoryLimit(2048u); |
| 278 SetDiscardableMemoryLimit(2048); | |
| 279 | 252 |
| 280 EXPECT_NE(DISCARDABLE_MEMORY_LOCK_STATUS_FAILED, discardable(2)->Lock()); | 253 EXPECT_TRUE(Lock(allocation(2))); |
| 281 EXPECT_NE(DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS, discardable(1)->Lock()); | 254 EXPECT_TRUE(Lock(allocation(1), true)); |
| 282 // 0 should still be locked. | 255 // 0 should still be locked. |
| 283 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable(0))); | 256 EXPECT_FALSE(CanBePurged(allocation(0))); |
| 284 } | 257 } |
| 285 | 258 |
| 286 // Verify that no more memory than necessary was discarded after changing | 259 // Verify that no more memory than necessary was discarded after changing |
| 287 // memory limit. | 260 // memory limit. |
| 288 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) { | 261 TEST_P(DiscardableMemoryManagerPermutationTest, LRUDiscardedAmount) { |
| 289 SetBytesToKeepUnderModeratePressure(2048); | |
| 290 SetDiscardableMemoryLimit(4096); | |
| 291 | |
| 292 CreateAndUseDiscardableMemory(); | 262 CreateAndUseDiscardableMemory(); |
| 293 | 263 |
| 294 SetDiscardableMemoryLimit(2048); | 264 SetDiscardableMemoryLimit(2048u); |
| 295 | 265 |
| 296 EXPECT_EQ(DISCARDABLE_MEMORY_LOCK_STATUS_SUCCESS, discardable(2)->Lock()); | 266 EXPECT_TRUE(Lock(allocation(2), false)); |
| 297 EXPECT_EQ(DISCARDABLE_MEMORY_LOCK_STATUS_PURGED, discardable(1)->Lock()); | 267 EXPECT_TRUE(Lock(allocation(1), true)); |
| 298 // 0 should still be locked. | 268 // 0 should still be locked. |
| 299 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable(0))); | 269 EXPECT_FALSE(CanBePurged(allocation(0))); |
| 300 } | 270 } |
| 301 | 271 |
| 302 TEST_P(DiscardableMemoryManagerPermutationTest, | 272 TEST_P(DiscardableMemoryManagerPermutationTest, PurgeFreesAllUnlocked) { |
| 303 CriticalPressureFreesAllUnlocked) { | |
| 304 CreateAndUseDiscardableMemory(); | 273 CreateAndUseDiscardableMemory(); |
| 305 | 274 |
| 306 MemoryPressureListener::NotifyMemoryPressure( | 275 PurgeUntilUsageIsWithin(0u); |
| 307 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL); | |
| 308 RunLoop().RunUntilIdle(); | |
| 309 | 276 |
| 310 for (int i = 0; i < 3; ++i) { | 277 for (int i = 0; i < 3; ++i) { |
| 311 if (i == 0) | 278 if (i == 0) |
| 312 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable(i))); | 279 EXPECT_FALSE(CanBePurged(allocation(i))); |
| 313 else | 280 else |
| 314 EXPECT_EQ(DISCARDABLE_MEMORY_LOCK_STATUS_PURGED, discardable(i)->Lock()); | 281 EXPECT_TRUE(Lock(allocation(i), true)); |
| 315 } | 282 } |
| 316 } | 283 } |
| 317 | 284 |
| 318 INSTANTIATE_TEST_CASE_P(DiscardableMemoryManagerPermutationTests, | 285 INSTANTIATE_TEST_CASE_P(DiscardableMemoryManagerPermutationTests, |
| 319 DiscardableMemoryManagerPermutationTest, | 286 DiscardableMemoryManagerPermutationTest, |
| 320 ::testing::Values(PermutationTestData(0, 1, 2), | 287 ::testing::Values(PermutationTestData(0, 1, 2), |
| 321 PermutationTestData(0, 2, 1), | 288 PermutationTestData(0, 2, 1), |
| 322 PermutationTestData(1, 0, 2), | 289 PermutationTestData(1, 0, 2), |
| 323 PermutationTestData(1, 2, 0), | 290 PermutationTestData(1, 2, 0), |
| 324 PermutationTestData(2, 0, 1), | 291 PermutationTestData(2, 0, 1), |
| 325 PermutationTestData(2, 1, 0))); | 292 PermutationTestData(2, 1, 0))); |
| 326 | 293 |
| 327 TEST_F(DiscardableMemoryManagerTest, NormalDestruction) { | 294 TEST_F(DiscardableMemoryManagerTest, NormalDestruction) { |
| 328 { | 295 { |
| 329 size_t size = 1024; | 296 size_t size = 1024u; |
| 330 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 297 const scoped_ptr<Allocation> allocation(CreateLocked(size)); |
| 331 EXPECT_TRUE(IsRegistered(discardable.get())); | |
| 332 EXPECT_EQ(1024u, BytesAllocated()); | 298 EXPECT_EQ(1024u, BytesAllocated()); |
| 299 Unlock(allocation.get()); |
| 333 } | 300 } |
| 334 EXPECT_EQ(0u, BytesAllocated()); | 301 EXPECT_EQ(0u, BytesAllocated()); |
| 335 } | 302 } |
| 336 | 303 |
| 337 TEST_F(DiscardableMemoryManagerTest, DestructionWhileLocked) { | 304 TEST_F(DiscardableMemoryManagerTest, DestructionWhileLocked) { |
| 338 { | 305 { |
| 339 size_t size = 1024; | 306 size_t size = 1024u; |
| 340 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 307 const scoped_ptr<Allocation> allocation(CreateLocked(size)); |
| 341 EXPECT_TRUE(IsRegistered(discardable.get())); | |
| 342 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | |
| 343 EXPECT_EQ(1024u, BytesAllocated()); | 308 EXPECT_EQ(1024u, BytesAllocated()); |
| 344 EXPECT_FALSE(CanBePurged(discardable.get())); | 309 EXPECT_FALSE(CanBePurged(allocation.get())); |
| 345 } | 310 } |
| 346 // Should have ignored the "locked" status and freed the discardable memory. | 311 // Should have ignored the "locked" status and freed the discardable memory. |
| 347 EXPECT_EQ(0u, BytesAllocated()); | 312 EXPECT_EQ(0u, BytesAllocated()); |
| 348 } | 313 } |
| 349 | 314 |
| 350 #if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS) | |
| 351 // Death tests are not supported with Android APKs. | |
| 352 TEST_F(DiscardableMemoryManagerTest, UnlockedMemoryAccessCrashesInDebugMode) { | |
| 353 size_t size = 1024; | |
| 354 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | |
| 355 EXPECT_TRUE(IsRegistered(discardable.get())); | |
| 356 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | |
| 357 EXPECT_EQ(1024u, BytesAllocated()); | |
| 358 EXPECT_FALSE(CanBePurged(discardable.get())); | |
| 359 discardable->Unlock(); | |
| 360 EXPECT_TRUE(CanBePurged(discardable.get())); | |
| 361 // We *must* die if we are asked to vend a pointer to unlocked memory. | |
| 362 EXPECT_DEATH(discardable->Memory(), ".*Check failed.*"); | |
| 363 } | |
| 364 #endif | |
| 365 | |
| 366 class ThreadedDiscardableMemoryManagerTest | 315 class ThreadedDiscardableMemoryManagerTest |
| 367 : public DiscardableMemoryManagerTest { | 316 : public DiscardableMemoryManagerTest { |
| 368 public: | 317 public: |
| 369 ThreadedDiscardableMemoryManagerTest() | 318 ThreadedDiscardableMemoryManagerTest() |
| 370 : memory_usage_thread_("memory_usage_thread"), | 319 : memory_usage_thread_("memory_usage_thread"), |
| 371 thread_sync_(true, false) { | 320 thread_sync_(true, false) { |
| 372 } | 321 } |
| 373 | 322 |
| 374 virtual void SetUp() OVERRIDE { | 323 virtual void SetUp() OVERRIDE { |
| 375 memory_usage_thread_.Start(); | 324 memory_usage_thread_.Start(); |
| 376 } | 325 } |
| 377 | 326 |
| 378 virtual void TearDown() OVERRIDE { | 327 virtual void TearDown() OVERRIDE { |
| 379 memory_usage_thread_.Stop(); | 328 memory_usage_thread_.Stop(); |
| 380 } | 329 } |
| 381 | 330 |
| 382 void UseMemoryHelper() { | 331 void UseMemoryHelper() { |
| 383 size_t size = 1024; | 332 size_t size = 1024u; |
| 384 const scoped_ptr<DiscardableMemory> discardable(CreateLockedMemory(size)); | 333 const scoped_ptr<Allocation> allocation(CreateLocked(size)); |
| 385 EXPECT_TRUE(IsRegistered(discardable.get())); | 334 Unlock(allocation.get()); |
| 386 EXPECT_NE(static_cast<void*>(NULL), Memory(discardable.get())); | |
| 387 discardable->Unlock(); | |
| 388 } | 335 } |
| 389 | 336 |
| 390 void SignalHelper() { | 337 void SignalHelper() { |
| 391 thread_sync_.Signal(); | 338 thread_sync_.Signal(); |
| 392 } | 339 } |
| 393 | 340 |
| 394 Thread memory_usage_thread_; | 341 Thread memory_usage_thread_; |
| 395 WaitableEvent thread_sync_; | 342 WaitableEvent thread_sync_; |
| 396 }; | 343 }; |
| 397 | 344 |
| 398 TEST_F(ThreadedDiscardableMemoryManagerTest, UseMemoryOnThread) { | 345 TEST_F(ThreadedDiscardableMemoryManagerTest, UseMemoryOnThread) { |
| 399 memory_usage_thread_.message_loop()->PostTask( | 346 memory_usage_thread_.message_loop()->PostTask( |
| 400 FROM_HERE, | 347 FROM_HERE, |
| 401 Bind(&ThreadedDiscardableMemoryManagerTest::UseMemoryHelper, | 348 Bind(&ThreadedDiscardableMemoryManagerTest::UseMemoryHelper, |
| 402 Unretained(this))); | 349 Unretained(this))); |
| 403 memory_usage_thread_.message_loop()->PostTask( | 350 memory_usage_thread_.message_loop()->PostTask( |
| 404 FROM_HERE, | 351 FROM_HERE, |
| 405 Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper, | 352 Bind(&ThreadedDiscardableMemoryManagerTest::SignalHelper, |
| 406 Unretained(this))); | 353 Unretained(this))); |
| 407 thread_sync_.Wait(); | 354 thread_sync_.Wait(); |
| 408 } | 355 } |
| 409 | 356 |
| 410 } // namespace base | 357 } // namespace base |
| OLD | NEW |