OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "base/memory/discardable_memory_provider.h" |
| 6 |
| 7 #include "base/memory/discardable_memory.h" |
| 8 #include "base/run_loop.h" |
| 9 #include "testing/gtest/include/gtest/gtest.h" |
| 10 |
| 11 namespace base { |
| 12 |
| 13 class DiscardableMemoryProviderTest : public testing::Test { |
| 14 public: |
| 15 DiscardableMemoryProviderTest() |
| 16 : message_loop_(MessageLoop::TYPE_IO), |
| 17 provider_(new DiscardableMemoryProvider) { |
| 18 // We set a provider here for two reasons: |
| 19 // 1. It ensures that one test cannot affect the next, and |
| 20 // 2. Since the provider listens for pressure notifications on the thread |
| 21 // it was created on, if we create it on the test thread, we can run |
| 22 // the test thread's message loop until idle when we want to process |
| 23 // on of these notifications. |
| 24 DiscardableMemoryProvider::SetInstanceForTest(provider_.get()); |
| 25 } |
| 26 |
| 27 virtual ~DiscardableMemoryProviderTest() { |
| 28 DiscardableMemoryProvider::SetInstanceForTest(NULL); |
| 29 } |
| 30 |
| 31 protected: |
| 32 void Register(DiscardableMemory* discardable) { |
| 33 DiscardableMemoryProvider::GetInstance()->Register(discardable); |
| 34 } |
| 35 |
| 36 const DiscardableMemoryProvider::AllocationMap& allocations() const { |
| 37 return DiscardableMemoryProvider::GetInstance()->allocations_; |
| 38 } |
| 39 |
| 40 size_t bytes_allocated() const { |
| 41 return DiscardableMemoryProvider::GetInstance()->bytes_allocated_; |
| 42 } |
| 43 |
| 44 void* Memory(const DiscardableMemory& discardable) const { |
| 45 return discardable.memory_; |
| 46 } |
| 47 |
| 48 void SetDiscardableMemoryLimit(size_t bytes) { |
| 49 DiscardableMemoryProvider::GetInstance()-> |
| 50 SetDiscardableMemoryLimit(bytes); |
| 51 } |
| 52 |
| 53 void SetBytesToReclaimUnderModeratePressure(size_t bytes) { |
| 54 DiscardableMemoryProvider::GetInstance()-> |
| 55 SetBytesToReclaimUnderModeratePressure(bytes); |
| 56 } |
| 57 |
| 58 private: |
| 59 MessageLoop message_loop_; |
| 60 scoped_ptr<DiscardableMemoryProvider> provider_; |
| 61 }; |
| 62 |
| 63 TEST_F(DiscardableMemoryProviderTest, Register) { |
| 64 DiscardableMemory discardable; |
| 65 Register(&discardable); |
| 66 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 67 ASSERT_EQ(0u, bytes_allocated()); |
| 68 } |
| 69 |
| 70 TEST_F(DiscardableMemoryProviderTest, InitializeAndLock) { |
| 71 DiscardableMemory discardable; |
| 72 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 73 size_t size = 1024; |
| 74 ASSERT_TRUE(discardable.InitializeAndLock(size)); |
| 75 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 76 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable)); |
| 77 ASSERT_EQ(1024u, bytes_allocated()); |
| 78 ASSERT_TRUE(discardable.is_locked()); |
| 79 } |
| 80 |
| 81 TEST_F(DiscardableMemoryProviderTest, InitializeAndLockZeroSize) { |
| 82 DiscardableMemory discardable; |
| 83 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 84 size_t size = 0; |
| 85 ASSERT_FALSE(discardable.InitializeAndLock(size)); |
| 86 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 87 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 88 ASSERT_EQ(0u, bytes_allocated()); |
| 89 ASSERT_FALSE(discardable.is_locked()); |
| 90 } |
| 91 |
| 92 TEST_F(DiscardableMemoryProviderTest, LockBeforeInitialization) { |
| 93 DiscardableMemory discardable; |
| 94 ASSERT_EQ(DISCARDABLE_MEMORY_FAILED, discardable.Lock()); |
| 95 } |
| 96 |
| 97 TEST_F(DiscardableMemoryProviderTest, LockAfterUnlock) { |
| 98 DiscardableMemory discardable; |
| 99 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 100 size_t size = 1024; |
| 101 ASSERT_TRUE(discardable.InitializeAndLock(size)); |
| 102 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 103 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable)); |
| 104 ASSERT_EQ(1024u, bytes_allocated()); |
| 105 ASSERT_TRUE(discardable.is_locked()); |
| 106 |
| 107 // Now to unlock so we can lock later. |
| 108 discardable.Unlock(); |
| 109 ASSERT_FALSE(discardable.is_locked()); |
| 110 |
| 111 ASSERT_EQ(DISCARDABLE_MEMORY_SUCCESS, discardable.Lock()); |
| 112 ASSERT_TRUE(discardable.is_locked()); |
| 113 } |
| 114 |
| 115 TEST_F(DiscardableMemoryProviderTest, LockAfterPurge) { |
| 116 DiscardableMemory discardable; |
| 117 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 118 size_t size = 1024; |
| 119 ASSERT_TRUE(discardable.InitializeAndLock(size)); |
| 120 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 121 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable)); |
| 122 ASSERT_EQ(1024u, bytes_allocated()); |
| 123 ASSERT_TRUE(discardable.is_locked()); |
| 124 |
| 125 // Now to unlock so we can lock later. |
| 126 discardable.Unlock(); |
| 127 ASSERT_FALSE(discardable.is_locked()); |
| 128 |
| 129 // Force the system to purge. |
| 130 MemoryPressureListener::NotifyMemoryPressure( |
| 131 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL); |
| 132 |
| 133 // Required because ObserverListThreadSafe notifies via PostTask. |
| 134 RunLoop().RunUntilIdle(); |
| 135 |
| 136 ASSERT_EQ(DISCARDABLE_MEMORY_PURGED, discardable.Lock()); |
| 137 ASSERT_TRUE(discardable.is_locked()); |
| 138 } |
| 139 |
| 140 TEST_F(DiscardableMemoryProviderTest, LockAfterPurgeAndCannotReallocate) { |
| 141 DiscardableMemory discardable; |
| 142 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 143 size_t size = 1024; |
| 144 ASSERT_TRUE(discardable.InitializeAndLock(size)); |
| 145 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 146 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable)); |
| 147 ASSERT_EQ(1024u, bytes_allocated()); |
| 148 ASSERT_TRUE(discardable.is_locked()); |
| 149 |
| 150 // Now to unlock so we can lock later. |
| 151 discardable.Unlock(); |
| 152 ASSERT_FALSE(discardable.is_locked()); |
| 153 |
| 154 // Force the system to purge. |
| 155 MemoryPressureListener::NotifyMemoryPressure( |
| 156 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL); |
| 157 |
| 158 // Required because ObserverListThreadSafe notifies via PostTask. |
| 159 RunLoop().RunUntilIdle(); |
| 160 |
| 161 // Set max allowed allocation to 1 byte. This will make reallocation fail. |
| 162 SetDiscardableMemoryLimit(1); |
| 163 |
| 164 ASSERT_EQ(DISCARDABLE_MEMORY_FAILED, discardable.Lock()); |
| 165 ASSERT_FALSE(discardable.is_locked()); |
| 166 } |
| 167 |
| 168 #define DiscardableMemoryProviderPermutionTest(name, d0, d1, d2, pressure) \ |
| 169 TEST_F(DiscardableMemoryProviderTest, name##_##d0##_##d1##_##d2) { \ |
| 170 DiscardableMemory discardables[3]; \ |
| 171 for (int i = 0; i < 3; ++i) { \ |
| 172 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[i])); \ |
| 173 ASSERT_TRUE(discardables[i].InitializeAndLock(1024)); \ |
| 174 discardables[i].Unlock(); \ |
| 175 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[i])); \ |
| 176 } \ |
| 177 int ordering[] = { d0, d1, d2 }; \ |
| 178 for (int i = 0; i < 3; ++i) { \ |
| 179 int current_index = ordering[i]; \ |
| 180 ASSERT_NE(DISCARDABLE_MEMORY_FAILED, discardables[current_index].Lock()); \ |
| 181 if (i > 0) \ |
| 182 discardables[current_index].Unlock(); \ |
| 183 } \ |
| 184 SetBytesToReclaimUnderModeratePressure(1024); \ |
| 185 if (pressure) { \ |
| 186 MemoryPressureListener::NotifyMemoryPressure( \ |
| 187 MemoryPressureListener::MEMORY_PRESSURE_MODERATE); \ |
| 188 RunLoop().RunUntilIdle(); \ |
| 189 } else { \ |
| 190 SetDiscardableMemoryLimit(2048); \ |
| 191 } \ |
| 192 for (int i = 0; i < 3; ++i) { \ |
| 193 if (i == 1) \ |
| 194 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[ordering[i]])); \ |
| 195 else \ |
| 196 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[ordering[i]])); \ |
| 197 } \ |
| 198 } |
| 199 |
| 200 #define DiscardableMemoryProviderPermutions(name, pressure) \ |
| 201 DiscardableMemoryProviderPermutionTest(name, 0, 1, 2, pressure); \ |
| 202 DiscardableMemoryProviderPermutionTest(name, 0, 2, 1, pressure); \ |
| 203 DiscardableMemoryProviderPermutionTest(name, 1, 0, 2, pressure); \ |
| 204 DiscardableMemoryProviderPermutionTest(name, 1, 2, 0, pressure); \ |
| 205 DiscardableMemoryProviderPermutionTest(name, 2, 0, 1, pressure); \ |
| 206 DiscardableMemoryProviderPermutionTest(name, 2, 1, 0, pressure); |
| 207 |
| 208 DiscardableMemoryProviderPermutions(LRUDiscardedModeratePressure, true); |
| 209 DiscardableMemoryProviderPermutions(LRUDiscardedExceedLimit, false); |
| 210 |
| 211 TEST_F(DiscardableMemoryProviderTest, CriticalPressureFreesAllUnlocked) { |
| 212 DiscardableMemory discardables[3]; |
| 213 for (int i = 0; i < 3; ++i) { |
| 214 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[i])); |
| 215 ASSERT_TRUE(discardables[i].InitializeAndLock(1024)); |
| 216 discardables[i].Unlock(); |
| 217 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[i])); |
| 218 } |
| 219 |
| 220 for (int i = 0; i < 3; ++i) { |
| 221 ASSERT_NE(DISCARDABLE_MEMORY_FAILED, discardables[i].Lock()); |
| 222 if (i > 0) |
| 223 discardables[i].Unlock(); |
| 224 } |
| 225 |
| 226 MemoryPressureListener::NotifyMemoryPressure( |
| 227 MemoryPressureListener::MEMORY_PRESSURE_CRITICAL); |
| 228 RunLoop().RunUntilIdle(); |
| 229 |
| 230 for (int i = 0; i < 3; ++i) { |
| 231 if (discardables[i].is_locked()) |
| 232 ASSERT_NE(static_cast<void*>(NULL), Memory(discardables[i])); |
| 233 else |
| 234 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardables[i])); |
| 235 } |
| 236 } |
| 237 |
| 238 TEST_F(DiscardableMemoryProviderTest, NormalDestruction) { |
| 239 { |
| 240 DiscardableMemory discardable; |
| 241 size_t size = 1024; |
| 242 ASSERT_TRUE(discardable.InitializeAndLock(size)); |
| 243 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 244 ASSERT_EQ(1024u, bytes_allocated()); |
| 245 } |
| 246 ASSERT_TRUE(allocations().empty()); |
| 247 ASSERT_EQ(0u, bytes_allocated()); |
| 248 } |
| 249 |
| 250 TEST_F(DiscardableMemoryProviderTest, DestructionWhileLocked) { |
| 251 { |
| 252 DiscardableMemory discardable; |
| 253 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 254 size_t size = 1024; |
| 255 ASSERT_TRUE(discardable.InitializeAndLock(size)); |
| 256 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 257 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable)); |
| 258 ASSERT_EQ(1024u, bytes_allocated()); |
| 259 ASSERT_TRUE(discardable.is_locked()); |
| 260 } |
| 261 // Should have ignored the "locked" status and freed the discardable memory. |
| 262 ASSERT_TRUE(allocations().empty()); |
| 263 ASSERT_EQ(0u, bytes_allocated()); |
| 264 } |
| 265 |
| 266 TEST_F(DiscardableMemoryProviderTest, MemoryBeforeLock) { |
| 267 DiscardableMemory discardable; |
| 268 // We *must* die if we are asked to vend a pointer to unlocked memory. |
| 269 EXPECT_DEATH(discardable.Memory(), ".*Check failed.*"); |
| 270 } |
| 271 |
| 272 TEST_F(DiscardableMemoryProviderTest, MemoryAfterUnlock) { |
| 273 DiscardableMemory discardable; |
| 274 ASSERT_EQ(static_cast<void*>(NULL), Memory(discardable)); |
| 275 size_t size = 1024; |
| 276 ASSERT_TRUE(discardable.InitializeAndLock(size)); |
| 277 ASSERT_NE(allocations().end(), allocations().Peek(&discardable)); |
| 278 ASSERT_NE(static_cast<void*>(NULL), Memory(discardable)); |
| 279 ASSERT_EQ(1024u, bytes_allocated()); |
| 280 ASSERT_TRUE(discardable.is_locked()); |
| 281 discardable.Unlock(); |
| 282 ASSERT_FALSE(discardable.is_locked()); |
| 283 // We *must* die if we are asked to vend a pointer to unlocked memory. |
| 284 EXPECT_DEATH(discardable.Memory(), ".*Check failed.*"); |
| 285 } |
| 286 |
| 287 } // namespace base |
OLD | NEW |