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