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