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
;
33 int next_discardable_shared_memory_id
= 0;
35 scoped_ptr
<base::DiscardableSharedMemory
> memory(
36 new base::DiscardableSharedMemory
);
37 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
39 // Create new span for memory.
40 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
41 heap
.Grow(memory
.Pass(), memory_size
, next_discardable_shared_memory_id
++,
42 base::Bind(NullTask
)));
44 // Size should match |memory_size|.
45 EXPECT_EQ(memory_size
, heap
.GetSize());
47 // Size of free lists should still be 0.
48 EXPECT_EQ(0u, heap
.GetSizeOfFreeLists());
50 // Free list should still be empty as |new_span| is currently in use.
51 EXPECT_FALSE(heap
.SearchFreeLists(1, 0));
53 // Done using |new_span|. Merge it into the free lists.
54 heap
.MergeIntoFreeLists(new_span
.Pass());
56 // Size of free lists should now match |memory_size|.
57 EXPECT_EQ(memory_size
, heap
.GetSizeOfFreeLists());
59 // Free lists should not contain a span that is larger than kBlocks.
60 EXPECT_FALSE(heap
.SearchFreeLists(kBlocks
+ 1, 0));
62 // Free lists should contain a span that satisfies the request for kBlocks.
63 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
64 heap
.SearchFreeLists(kBlocks
, 0);
67 // Free lists should be empty again.
68 EXPECT_FALSE(heap
.SearchFreeLists(1, 0));
70 // Merge it into the free lists again.
71 heap
.MergeIntoFreeLists(span
.Pass());
74 TEST(DiscardableSharedMemoryHeapTest
, SplitAndMerge
) {
75 size_t block_size
= base::GetPageSize();
76 DiscardableSharedMemoryHeap
heap(block_size
);
78 const size_t kBlocks
= 6;
79 size_t memory_size
= block_size
* kBlocks
;
80 int next_discardable_shared_memory_id
= 0;
82 scoped_ptr
<base::DiscardableSharedMemory
> memory(
83 new base::DiscardableSharedMemory
);
84 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
85 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
86 heap
.Grow(memory
.Pass(), memory_size
, next_discardable_shared_memory_id
++,
87 base::Bind(NullTask
)));
89 // Split span into two.
90 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> leftover
=
91 heap
.Split(new_span
.get(), 3);
92 ASSERT_TRUE(leftover
);
94 // Merge |leftover| into free lists.
95 heap
.MergeIntoFreeLists(leftover
.Pass());
97 // Some of the memory is still in use.
98 EXPECT_FALSE(heap
.SearchFreeLists(kBlocks
, 0));
100 // Merge |span| into free lists.
101 heap
.MergeIntoFreeLists(new_span
.Pass());
103 // Remove a 2 page span from free lists.
104 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span1
=
105 heap
.SearchFreeLists(2, kBlocks
);
108 // Remove another 2 page span from free lists.
109 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span2
=
110 heap
.SearchFreeLists(2, kBlocks
);
113 // Merge |span1| back into free lists.
114 heap
.MergeIntoFreeLists(span1
.Pass());
116 // Some of the memory is still in use.
117 EXPECT_FALSE(heap
.SearchFreeLists(kBlocks
, 0));
119 // Merge |span2| back into free lists.
120 heap
.MergeIntoFreeLists(span2
.Pass());
122 // All memory has been returned to the free lists.
123 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> large_span
=
124 heap
.SearchFreeLists(kBlocks
, 0);
125 ASSERT_TRUE(large_span
);
127 // Merge it into the free lists again.
128 heap
.MergeIntoFreeLists(large_span
.Pass());
131 TEST(DiscardableSharedMemoryHeapTest
, MergeSingleBlockSpan
) {
132 size_t block_size
= base::GetPageSize();
133 DiscardableSharedMemoryHeap
heap(block_size
);
135 const size_t kBlocks
= 6;
136 size_t memory_size
= block_size
* kBlocks
;
137 int next_discardable_shared_memory_id
= 0;
139 scoped_ptr
<base::DiscardableSharedMemory
> memory(
140 new base::DiscardableSharedMemory
);
141 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
142 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
143 heap
.Grow(memory
.Pass(), memory_size
, next_discardable_shared_memory_id
++,
144 base::Bind(NullTask
)));
146 // Split span into two.
147 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> leftover
=
148 heap
.Split(new_span
.get(), 5);
149 ASSERT_TRUE(leftover
);
151 // Merge |new_span| into free lists.
152 heap
.MergeIntoFreeLists(new_span
.Pass());
154 // Merge |leftover| into free lists.
155 heap
.MergeIntoFreeLists(leftover
.Pass());
158 TEST(DiscardableSharedMemoryHeapTest
, Grow
) {
159 size_t block_size
= base::GetPageSize();
160 DiscardableSharedMemoryHeap
heap(block_size
);
161 int next_discardable_shared_memory_id
= 0;
163 scoped_ptr
<base::DiscardableSharedMemory
> memory1(
164 new base::DiscardableSharedMemory
);
165 ASSERT_TRUE(memory1
->CreateAndMap(block_size
));
166 heap
.MergeIntoFreeLists(heap
.Grow(memory1
.Pass(), block_size
,
167 next_discardable_shared_memory_id
++,
168 base::Bind(NullTask
)).Pass());
170 // Remove a span from free lists.
171 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span1
=
172 heap
.SearchFreeLists(1, 0);
175 // No more memory available.
176 EXPECT_FALSE(heap
.SearchFreeLists(1, 0));
178 // Grow free lists using new memory.
179 scoped_ptr
<base::DiscardableSharedMemory
> memory2(
180 new base::DiscardableSharedMemory
);
181 ASSERT_TRUE(memory2
->CreateAndMap(block_size
));
182 heap
.MergeIntoFreeLists(heap
.Grow(memory2
.Pass(), block_size
,
183 next_discardable_shared_memory_id
++,
184 base::Bind(NullTask
)).Pass());
186 // Memory should now be available.
187 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span2
=
188 heap
.SearchFreeLists(1, 0);
191 // Merge spans into the free lists again.
192 heap
.MergeIntoFreeLists(span1
.Pass());
193 heap
.MergeIntoFreeLists(span2
.Pass());
196 TEST(DiscardableSharedMemoryHeapTest
, ReleaseFreeMemory
) {
197 size_t block_size
= base::GetPageSize();
198 DiscardableSharedMemoryHeap
heap(block_size
);
199 int next_discardable_shared_memory_id
= 0;
201 scoped_ptr
<base::DiscardableSharedMemory
> memory(
202 new base::DiscardableSharedMemory
);
203 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
204 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
205 heap
.Grow(memory
.Pass(), block_size
, next_discardable_shared_memory_id
++,
206 base::Bind(NullTask
));
208 // Free lists should be empty.
209 EXPECT_EQ(0u, heap
.GetSizeOfFreeLists());
211 heap
.ReleaseFreeMemory();
213 // Size should still match |block_size|.
214 EXPECT_EQ(block_size
, heap
.GetSize());
216 heap
.MergeIntoFreeLists(span
.Pass());
217 heap
.ReleaseFreeMemory();
219 // Memory should have been released.
220 EXPECT_EQ(0u, heap
.GetSize());
221 EXPECT_EQ(0u, heap
.GetSizeOfFreeLists());
224 TEST(DiscardableSharedMemoryHeapTest
, ReleasePurgedMemory
) {
225 size_t block_size
= base::GetPageSize();
226 DiscardableSharedMemoryHeap
heap(block_size
);
227 int next_discardable_shared_memory_id
= 0;
229 scoped_ptr
<base::DiscardableSharedMemory
> memory(
230 new base::DiscardableSharedMemory
);
231 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
232 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
233 heap
.Grow(memory
.Pass(), block_size
, next_discardable_shared_memory_id
++,
234 base::Bind(NullTask
));
236 // Unlock memory so it can be purged.
237 span
->shared_memory()->Unlock(0, 0);
239 // Purge and release shared memory.
240 bool rv
= span
->shared_memory()->Purge(base::Time::Now());
242 heap
.ReleasePurgedMemory();
244 // Shared memory backing for |span| should be gone.
245 EXPECT_FALSE(span
->shared_memory());
248 EXPECT_EQ(0u, heap
.GetSize());
251 TEST(DiscardableSharedMemoryHeapTest
, Slack
) {
252 size_t block_size
= base::GetPageSize();
253 DiscardableSharedMemoryHeap
heap(block_size
);
255 const size_t kBlocks
= 6;
256 size_t memory_size
= block_size
* kBlocks
;
257 int next_discardable_shared_memory_id
= 0;
259 scoped_ptr
<base::DiscardableSharedMemory
> memory(
260 new base::DiscardableSharedMemory
);
261 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
262 heap
.MergeIntoFreeLists(heap
.Grow(memory
.Pass(), memory_size
,
263 next_discardable_shared_memory_id
++,
264 base::Bind(NullTask
)).Pass());
266 // No free span that is less or equal to 3 + 1.
267 EXPECT_FALSE(heap
.SearchFreeLists(3, 1));
269 // No free span that is less or equal to 3 + 2.
270 EXPECT_FALSE(heap
.SearchFreeLists(3, 2));
272 // No free span that is less or equal to 1 + 4.
273 EXPECT_FALSE(heap
.SearchFreeLists(1, 4));
275 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
276 heap
.SearchFreeLists(1, 5);
279 heap
.MergeIntoFreeLists(span
.Pass());
282 void OnDeleted(bool* deleted
) {
286 TEST(DiscardableSharedMemoryHeapTest
, DeletedCallback
) {
287 size_t block_size
= base::GetPageSize();
288 DiscardableSharedMemoryHeap
heap(block_size
);
289 int next_discardable_shared_memory_id
= 0;
291 scoped_ptr
<base::DiscardableSharedMemory
> memory(
292 new base::DiscardableSharedMemory
);
293 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
294 bool deleted
= false;
295 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
296 heap
.Grow(memory
.Pass(), block_size
, next_discardable_shared_memory_id
++,
297 base::Bind(OnDeleted
, base::Unretained(&deleted
)));
299 heap
.MergeIntoFreeLists(span
.Pass());
300 heap
.ReleaseFreeMemory();
302 EXPECT_TRUE(deleted
);
305 TEST(DiscardableSharedMemoryHeapTest
, CreateMemoryAllocatorDumpTest
) {
306 size_t block_size
= base::GetPageSize();
307 DiscardableSharedMemoryHeap
heap(block_size
);
308 int next_discardable_shared_memory_id
= 0;
310 scoped_ptr
<base::DiscardableSharedMemory
> memory(
311 new base::DiscardableSharedMemory
);
312 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
313 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
314 heap
.Grow(memory
.Pass(), block_size
, next_discardable_shared_memory_id
++,
315 base::Bind(NullTask
));
317 // Check if allocator dump is created when span exists.
318 scoped_ptr
<base::trace_event::ProcessMemoryDump
> pmd(
319 new base::trace_event::ProcessMemoryDump(nullptr));
320 EXPECT_TRUE(heap
.CreateMemoryAllocatorDump(span
.get(), "discardable/test1",
323 // Unlock, Purge and release shared memory.
324 span
->shared_memory()->Unlock(0, 0);
325 bool rv
= span
->shared_memory()->Purge(base::Time::Now());
327 heap
.ReleasePurgedMemory();
329 // Check that allocator dump is created after memory is purged.
330 EXPECT_TRUE(heap
.CreateMemoryAllocatorDump(span
.get(), "discardable/test2",
335 } // namespace content