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.
5 #include "content/common/discardable_shared_memory_heap.h"
8 #include "base/memory/discardable_shared_memory.h"
9 #include "base/process/process_metrics.h"
10 #include "testing/gtest/include/gtest/gtest.h"
18 TEST(DiscardableSharedMemoryHeapTest
, Basic
) {
19 size_t block_size
= base::GetPageSize();
20 DiscardableSharedMemoryHeap
heap(block_size
);
22 // Initial size should be 0.
23 EXPECT_EQ(0u, heap
.GetSize());
25 // Initial size of free lists should be 0.
26 EXPECT_EQ(0u, heap
.GetSizeOfFreeLists());
28 // Free lists are initially empty.
29 EXPECT_FALSE(heap
.SearchFreeLists(1, 0));
31 const size_t kBlocks
= 10;
32 size_t memory_size
= block_size
* kBlocks
;
34 scoped_ptr
<base::DiscardableSharedMemory
> memory(
35 new base::DiscardableSharedMemory
);
36 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
38 // Create new span for memory.
39 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
40 heap
.Grow(memory
.Pass(), memory_size
, base::Bind(NullTask
)));
42 // Size should match |memory_size|.
43 EXPECT_EQ(memory_size
, heap
.GetSize());
45 // Size of free lists should still be 0.
46 EXPECT_EQ(0u, heap
.GetSizeOfFreeLists());
48 // Free list should still be empty as |new_span| is currently in use.
49 EXPECT_FALSE(heap
.SearchFreeLists(1, 0));
51 // Done using |new_span|. Merge it into the free lists.
52 heap
.MergeIntoFreeLists(new_span
.Pass());
54 // Size of free lists should now match |memory_size|.
55 EXPECT_EQ(memory_size
, heap
.GetSizeOfFreeLists());
57 // Free lists should not contain a span that is larger than kBlocks.
58 EXPECT_FALSE(heap
.SearchFreeLists(kBlocks
+ 1, 0));
60 // Free lists should contain a span that satisfies the request for kBlocks.
61 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
62 heap
.SearchFreeLists(kBlocks
, 0);
65 // Free lists should be empty again.
66 EXPECT_FALSE(heap
.SearchFreeLists(1, 0));
68 // Merge it into the free lists again.
69 heap
.MergeIntoFreeLists(span
.Pass());
72 TEST(DiscardableSharedMemoryHeapTest
, SplitAndMerge
) {
73 size_t block_size
= base::GetPageSize();
74 DiscardableSharedMemoryHeap
heap(block_size
);
76 const size_t kBlocks
= 6;
77 size_t memory_size
= block_size
* kBlocks
;
79 scoped_ptr
<base::DiscardableSharedMemory
> memory(
80 new base::DiscardableSharedMemory
);
81 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
82 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
83 heap
.Grow(memory
.Pass(), memory_size
, base::Bind(NullTask
)));
85 // Split span into two.
86 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> leftover
=
87 heap
.Split(new_span
.get(), 3);
88 ASSERT_TRUE(leftover
);
90 // Merge |leftover| into free lists.
91 heap
.MergeIntoFreeLists(leftover
.Pass());
93 // Some of the memory is still in use.
94 EXPECT_FALSE(heap
.SearchFreeLists(kBlocks
, 0));
96 // Merge |span| into free lists.
97 heap
.MergeIntoFreeLists(new_span
.Pass());
99 // Remove a 2 page span from free lists.
100 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span1
=
101 heap
.SearchFreeLists(2, kBlocks
);
104 // Remove another 2 page span from free lists.
105 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span2
=
106 heap
.SearchFreeLists(2, kBlocks
);
109 // Merge |span1| back into free lists.
110 heap
.MergeIntoFreeLists(span1
.Pass());
112 // Some of the memory is still in use.
113 EXPECT_FALSE(heap
.SearchFreeLists(kBlocks
, 0));
115 // Merge |span2| back into free lists.
116 heap
.MergeIntoFreeLists(span2
.Pass());
118 // All memory has been returned to the free lists.
119 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> large_span
=
120 heap
.SearchFreeLists(kBlocks
, 0);
121 ASSERT_TRUE(large_span
);
123 // Merge it into the free lists again.
124 heap
.MergeIntoFreeLists(large_span
.Pass());
127 TEST(DiscardableSharedMemoryHeapTest
, MergeSingleBlockSpan
) {
128 size_t block_size
= base::GetPageSize();
129 DiscardableSharedMemoryHeap
heap(block_size
);
131 const size_t kBlocks
= 6;
132 size_t memory_size
= block_size
* kBlocks
;
134 scoped_ptr
<base::DiscardableSharedMemory
> memory(
135 new base::DiscardableSharedMemory
);
136 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
137 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
138 heap
.Grow(memory
.Pass(), memory_size
, base::Bind(NullTask
)));
140 // Split span into two.
141 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> leftover
=
142 heap
.Split(new_span
.get(), 5);
143 ASSERT_TRUE(leftover
);
145 // Merge |new_span| into free lists.
146 heap
.MergeIntoFreeLists(new_span
.Pass());
148 // Merge |leftover| into free lists.
149 heap
.MergeIntoFreeLists(leftover
.Pass());
152 TEST(DiscardableSharedMemoryHeapTest
, Grow
) {
153 size_t block_size
= base::GetPageSize();
154 DiscardableSharedMemoryHeap
heap(block_size
);
156 scoped_ptr
<base::DiscardableSharedMemory
> memory1(
157 new base::DiscardableSharedMemory
);
158 ASSERT_TRUE(memory1
->CreateAndMap(block_size
));
159 heap
.MergeIntoFreeLists(
160 heap
.Grow(memory1
.Pass(), block_size
, base::Bind(NullTask
)).Pass());
162 // Remove a span from free lists.
163 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span1
=
164 heap
.SearchFreeLists(1, 0);
167 // No more memory available.
168 EXPECT_FALSE(heap
.SearchFreeLists(1, 0));
170 // Grow free lists using new memory.
171 scoped_ptr
<base::DiscardableSharedMemory
> memory2(
172 new base::DiscardableSharedMemory
);
173 ASSERT_TRUE(memory2
->CreateAndMap(block_size
));
174 heap
.MergeIntoFreeLists(
175 heap
.Grow(memory2
.Pass(), block_size
, base::Bind(NullTask
)).Pass());
177 // Memory should now be available.
178 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span2
=
179 heap
.SearchFreeLists(1, 0);
182 // Merge spans into the free lists again.
183 heap
.MergeIntoFreeLists(span1
.Pass());
184 heap
.MergeIntoFreeLists(span2
.Pass());
187 TEST(DiscardableSharedMemoryHeapTest
, ReleaseFreeMemory
) {
188 size_t block_size
= base::GetPageSize();
189 DiscardableSharedMemoryHeap
heap(block_size
);
191 scoped_ptr
<base::DiscardableSharedMemory
> memory(
192 new base::DiscardableSharedMemory
);
193 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
194 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
195 heap
.Grow(memory
.Pass(), block_size
, base::Bind(NullTask
));
197 // Free lists should be empty.
198 EXPECT_EQ(0u, heap
.GetSizeOfFreeLists());
200 heap
.ReleaseFreeMemory();
202 // Size should still match |block_size|.
203 EXPECT_EQ(block_size
, heap
.GetSize());
205 heap
.MergeIntoFreeLists(span
.Pass());
206 heap
.ReleaseFreeMemory();
208 // Memory should have been released.
209 EXPECT_EQ(0u, heap
.GetSize());
210 EXPECT_EQ(0u, heap
.GetSizeOfFreeLists());
213 TEST(DiscardableSharedMemoryHeapTest
, ReleasePurgedMemory
) {
214 size_t block_size
= base::GetPageSize();
215 DiscardableSharedMemoryHeap
heap(block_size
);
217 scoped_ptr
<base::DiscardableSharedMemory
> memory(
218 new base::DiscardableSharedMemory
);
219 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
220 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
221 heap
.Grow(memory
.Pass(), block_size
, base::Bind(NullTask
));
223 // Unlock memory so it can be purged.
224 span
->shared_memory()->Unlock(0, 0);
226 // Purge and release shared memory.
227 bool rv
= span
->shared_memory()->Purge(base::Time::Now());
229 heap
.ReleasePurgedMemory();
231 // Shared memory backing for |span| should be gone.
232 EXPECT_FALSE(span
->shared_memory());
235 EXPECT_EQ(0u, heap
.GetSize());
238 TEST(DiscardableSharedMemoryHeapTest
, Slack
) {
239 size_t block_size
= base::GetPageSize();
240 DiscardableSharedMemoryHeap
heap(block_size
);
242 const size_t kBlocks
= 6;
243 size_t memory_size
= block_size
* kBlocks
;
245 scoped_ptr
<base::DiscardableSharedMemory
> memory(
246 new base::DiscardableSharedMemory
);
247 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
248 heap
.MergeIntoFreeLists(
249 heap
.Grow(memory
.Pass(), memory_size
, base::Bind(NullTask
)).Pass());
251 // No free span that is less or equal to 3 + 1.
252 EXPECT_FALSE(heap
.SearchFreeLists(3, 1));
254 // No free span that is less or equal to 3 + 2.
255 EXPECT_FALSE(heap
.SearchFreeLists(3, 2));
257 // No free span that is less or equal to 1 + 4.
258 EXPECT_FALSE(heap
.SearchFreeLists(1, 4));
260 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
261 heap
.SearchFreeLists(1, 5);
264 heap
.MergeIntoFreeLists(span
.Pass());
267 void OnDeleted(bool* deleted
) {
271 TEST(DiscardableSharedMemoryHeapTest
, DeletedCallback
) {
272 size_t block_size
= base::GetPageSize();
273 DiscardableSharedMemoryHeap
heap(block_size
);
275 scoped_ptr
<base::DiscardableSharedMemory
> memory(
276 new base::DiscardableSharedMemory
);
277 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
278 bool deleted
= false;
279 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
280 heap
.Grow(memory
.Pass(), block_size
,
281 base::Bind(OnDeleted
, base::Unretained(&deleted
)));
283 heap
.MergeIntoFreeLists(span
.Pass());
284 heap
.ReleaseFreeMemory();
286 EXPECT_TRUE(deleted
);
290 } // namespace content