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