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"
7 #include "base/memory/discardable_shared_memory.h"
8 #include "base/process/process_metrics.h"
9 #include "testing/gtest/include/gtest/gtest.h"
14 class DiscardableSharedMemoryHeapTest
: public testing::Test
{};
16 TEST_F(DiscardableSharedMemoryHeapTest
, Basic
) {
17 size_t block_size
= base::GetPageSize();
18 DiscardableSharedMemoryHeap
heap(block_size
);
20 // Free list is initially empty.
21 EXPECT_FALSE(heap
.SearchFreeList(1));
23 const size_t kBlocks
= 10;
24 size_t memory_size
= block_size
* kBlocks
;
26 scoped_ptr
<base::DiscardableSharedMemory
> memory(
27 new base::DiscardableSharedMemory
);
28 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
30 // Create new span for memory.
31 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
32 heap
.Grow(memory
.Pass(), memory_size
));
34 // Free list should still be empty as |new_span| is currently in use.
35 EXPECT_FALSE(heap
.SearchFreeList(1));
37 // Done using |new_span|. Merge it into the free list.
38 heap
.MergeIntoFreeList(new_span
.Pass());
40 // Free list should not contain a span that is larger than kBlocks.
41 EXPECT_FALSE(heap
.SearchFreeList(kBlocks
+ 1));
43 // Free list should contain a span that satisfies the request for kBlocks.
44 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
45 heap
.SearchFreeList(kBlocks
);
48 // Free list should be empty again.
49 EXPECT_FALSE(heap
.SearchFreeList(1));
51 // Merge it into the free list again.
52 heap
.MergeIntoFreeList(span
.Pass());
55 TEST_F(DiscardableSharedMemoryHeapTest
, SplitAndMerge
) {
56 size_t block_size
= base::GetPageSize();
57 DiscardableSharedMemoryHeap
heap(block_size
);
59 const size_t kBlocks
= 6;
60 size_t memory_size
= block_size
* kBlocks
;
62 scoped_ptr
<base::DiscardableSharedMemory
> memory(
63 new base::DiscardableSharedMemory
);
64 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
65 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
66 heap
.Grow(memory
.Pass(), memory_size
));
68 // Split span into two.
69 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> leftover
=
70 heap
.Split(new_span
.get(), 3);
71 ASSERT_TRUE(leftover
);
73 // Merge |leftover| into free list.
74 heap
.MergeIntoFreeList(leftover
.Pass());
76 // Some of the memory is still in use.
77 EXPECT_FALSE(heap
.SearchFreeList(kBlocks
));
79 // Merge |span| into free list.
80 heap
.MergeIntoFreeList(new_span
.Pass());
82 // Remove a 2 page span from free list.
83 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span1
= heap
.SearchFreeList(2);
86 // Remove another 2 page span from free list.
87 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span2
= heap
.SearchFreeList(2);
90 // Merge |span1| back into free list.
91 heap
.MergeIntoFreeList(span1
.Pass());
93 // Some of the memory is still in use.
94 EXPECT_FALSE(heap
.SearchFreeList(kBlocks
));
96 // Merge |span2| back into free list.
97 heap
.MergeIntoFreeList(span2
.Pass());
99 // All memory has been returned to the free list.
100 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> large_span
=
101 heap
.SearchFreeList(kBlocks
);
102 ASSERT_TRUE(large_span
);
104 // Merge it into the free list again.
105 heap
.MergeIntoFreeList(large_span
.Pass());
108 TEST_F(DiscardableSharedMemoryHeapTest
, MergeSingleBlockSpan
) {
109 size_t block_size
= base::GetPageSize();
110 DiscardableSharedMemoryHeap
heap(block_size
);
112 const size_t kBlocks
= 6;
113 size_t memory_size
= block_size
* kBlocks
;
115 scoped_ptr
<base::DiscardableSharedMemory
> memory(
116 new base::DiscardableSharedMemory
);
117 ASSERT_TRUE(memory
->CreateAndMap(memory_size
));
118 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> new_span(
119 heap
.Grow(memory
.Pass(), memory_size
));
121 // Split span into two.
122 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> leftover
=
123 heap
.Split(new_span
.get(), 5);
124 ASSERT_TRUE(leftover
);
126 // Merge |new_span| into free list.
127 heap
.MergeIntoFreeList(new_span
.Pass());
129 // Merge |leftover| into free list.
130 heap
.MergeIntoFreeList(leftover
.Pass());
133 TEST_F(DiscardableSharedMemoryHeapTest
, Grow
) {
134 size_t block_size
= base::GetPageSize();
135 DiscardableSharedMemoryHeap
heap(block_size
);
137 scoped_ptr
<base::DiscardableSharedMemory
> memory1(
138 new base::DiscardableSharedMemory
);
139 ASSERT_TRUE(memory1
->CreateAndMap(block_size
));
140 heap
.MergeIntoFreeList(heap
.Grow(memory1
.Pass(), block_size
).Pass());
142 // Remove a span from free list.
143 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span1
= heap
.SearchFreeList(1);
146 // No more memory available.
147 EXPECT_FALSE(heap
.SearchFreeList(1));
149 // Grow free list using new memory.
150 scoped_ptr
<base::DiscardableSharedMemory
> memory2(
151 new base::DiscardableSharedMemory
);
152 ASSERT_TRUE(memory2
->CreateAndMap(block_size
));
153 heap
.MergeIntoFreeList(heap
.Grow(memory2
.Pass(), block_size
).Pass());
155 // Memory should now be available.
156 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span2
= heap
.SearchFreeList(1);
159 // Merge spans into the free list again.
160 heap
.MergeIntoFreeList(span1
.Pass());
161 heap
.MergeIntoFreeList(span2
.Pass());
164 TEST_F(DiscardableSharedMemoryHeapTest
, ReleaseFreeMemory
) {
165 size_t block_size
= base::GetPageSize();
166 DiscardableSharedMemoryHeap
heap(block_size
);
168 scoped_ptr
<base::DiscardableSharedMemory
> memory(
169 new base::DiscardableSharedMemory
);
170 ASSERT_TRUE(memory
->CreateAndMap(block_size
));
171 scoped_ptr
<DiscardableSharedMemoryHeap::Span
> span
=
172 heap
.Grow(memory
.Pass(), block_size
);
174 // Unlock memory so it can be purged.
175 span
->shared_memory()->Unlock(0, 0);
177 // Purge and release shared memory.
178 bool rv
= span
->shared_memory()->Purge(base::Time::Now());
180 heap
.ReleaseFreeMemory();
182 // Shared memory backing for |span| should be gone.
183 EXPECT_FALSE(span
->shared_memory());
187 } // namespace content