OLD | NEW |
| (Empty) |
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 "content/common/discardable_shared_memory_heap.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <utility> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/memory/discardable_shared_memory.h" | |
12 #include "base/process/process_metrics.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 namespace content { | |
16 namespace { | |
17 | |
18 void NullTask() { | |
19 } | |
20 | |
21 TEST(DiscardableSharedMemoryHeapTest, Basic) { | |
22 size_t block_size = base::GetPageSize(); | |
23 DiscardableSharedMemoryHeap heap(block_size); | |
24 | |
25 // Initial size should be 0. | |
26 EXPECT_EQ(0u, heap.GetSize()); | |
27 | |
28 // Initial size of free lists should be 0. | |
29 EXPECT_EQ(0u, heap.GetSizeOfFreeLists()); | |
30 | |
31 // Free lists are initially empty. | |
32 EXPECT_FALSE(heap.SearchFreeLists(1, 0)); | |
33 | |
34 const size_t kBlocks = 10; | |
35 size_t memory_size = block_size * kBlocks; | |
36 int next_discardable_shared_memory_id = 0; | |
37 | |
38 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
39 new base::DiscardableSharedMemory); | |
40 ASSERT_TRUE(memory->CreateAndMap(memory_size)); | |
41 | |
42 // Create new span for memory. | |
43 std::unique_ptr<DiscardableSharedMemoryHeap::Span> new_span( | |
44 heap.Grow(std::move(memory), memory_size, | |
45 next_discardable_shared_memory_id++, base::Bind(NullTask))); | |
46 | |
47 // Size should match |memory_size|. | |
48 EXPECT_EQ(memory_size, heap.GetSize()); | |
49 | |
50 // Size of free lists should still be 0. | |
51 EXPECT_EQ(0u, heap.GetSizeOfFreeLists()); | |
52 | |
53 // Free list should still be empty as |new_span| is currently in use. | |
54 EXPECT_FALSE(heap.SearchFreeLists(1, 0)); | |
55 | |
56 // Done using |new_span|. Merge it into the free lists. | |
57 heap.MergeIntoFreeLists(std::move(new_span)); | |
58 | |
59 // Size of free lists should now match |memory_size|. | |
60 EXPECT_EQ(memory_size, heap.GetSizeOfFreeLists()); | |
61 | |
62 // Free lists should not contain a span that is larger than kBlocks. | |
63 EXPECT_FALSE(heap.SearchFreeLists(kBlocks + 1, 0)); | |
64 | |
65 // Free lists should contain a span that satisfies the request for kBlocks. | |
66 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span = | |
67 heap.SearchFreeLists(kBlocks, 0); | |
68 ASSERT_TRUE(span); | |
69 | |
70 // Free lists should be empty again. | |
71 EXPECT_FALSE(heap.SearchFreeLists(1, 0)); | |
72 | |
73 // Merge it into the free lists again. | |
74 heap.MergeIntoFreeLists(std::move(span)); | |
75 } | |
76 | |
77 TEST(DiscardableSharedMemoryHeapTest, SplitAndMerge) { | |
78 size_t block_size = base::GetPageSize(); | |
79 DiscardableSharedMemoryHeap heap(block_size); | |
80 | |
81 const size_t kBlocks = 6; | |
82 size_t memory_size = block_size * kBlocks; | |
83 int next_discardable_shared_memory_id = 0; | |
84 | |
85 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
86 new base::DiscardableSharedMemory); | |
87 ASSERT_TRUE(memory->CreateAndMap(memory_size)); | |
88 std::unique_ptr<DiscardableSharedMemoryHeap::Span> new_span( | |
89 heap.Grow(std::move(memory), memory_size, | |
90 next_discardable_shared_memory_id++, base::Bind(NullTask))); | |
91 | |
92 // Split span into two. | |
93 std::unique_ptr<DiscardableSharedMemoryHeap::Span> leftover = | |
94 heap.Split(new_span.get(), 3); | |
95 ASSERT_TRUE(leftover); | |
96 | |
97 // Merge |leftover| into free lists. | |
98 heap.MergeIntoFreeLists(std::move(leftover)); | |
99 | |
100 // Some of the memory is still in use. | |
101 EXPECT_FALSE(heap.SearchFreeLists(kBlocks, 0)); | |
102 | |
103 // Merge |span| into free lists. | |
104 heap.MergeIntoFreeLists(std::move(new_span)); | |
105 | |
106 // Remove a 2 page span from free lists. | |
107 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span1 = | |
108 heap.SearchFreeLists(2, kBlocks); | |
109 ASSERT_TRUE(span1); | |
110 | |
111 // Remove another 2 page span from free lists. | |
112 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span2 = | |
113 heap.SearchFreeLists(2, kBlocks); | |
114 ASSERT_TRUE(span2); | |
115 | |
116 // Merge |span1| back into free lists. | |
117 heap.MergeIntoFreeLists(std::move(span1)); | |
118 | |
119 // Some of the memory is still in use. | |
120 EXPECT_FALSE(heap.SearchFreeLists(kBlocks, 0)); | |
121 | |
122 // Merge |span2| back into free lists. | |
123 heap.MergeIntoFreeLists(std::move(span2)); | |
124 | |
125 // All memory has been returned to the free lists. | |
126 std::unique_ptr<DiscardableSharedMemoryHeap::Span> large_span = | |
127 heap.SearchFreeLists(kBlocks, 0); | |
128 ASSERT_TRUE(large_span); | |
129 | |
130 // Merge it into the free lists again. | |
131 heap.MergeIntoFreeLists(std::move(large_span)); | |
132 } | |
133 | |
134 TEST(DiscardableSharedMemoryHeapTest, MergeSingleBlockSpan) { | |
135 size_t block_size = base::GetPageSize(); | |
136 DiscardableSharedMemoryHeap heap(block_size); | |
137 | |
138 const size_t kBlocks = 6; | |
139 size_t memory_size = block_size * kBlocks; | |
140 int next_discardable_shared_memory_id = 0; | |
141 | |
142 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
143 new base::DiscardableSharedMemory); | |
144 ASSERT_TRUE(memory->CreateAndMap(memory_size)); | |
145 std::unique_ptr<DiscardableSharedMemoryHeap::Span> new_span( | |
146 heap.Grow(std::move(memory), memory_size, | |
147 next_discardable_shared_memory_id++, base::Bind(NullTask))); | |
148 | |
149 // Split span into two. | |
150 std::unique_ptr<DiscardableSharedMemoryHeap::Span> leftover = | |
151 heap.Split(new_span.get(), 5); | |
152 ASSERT_TRUE(leftover); | |
153 | |
154 // Merge |new_span| into free lists. | |
155 heap.MergeIntoFreeLists(std::move(new_span)); | |
156 | |
157 // Merge |leftover| into free lists. | |
158 heap.MergeIntoFreeLists(std::move(leftover)); | |
159 } | |
160 | |
161 TEST(DiscardableSharedMemoryHeapTest, Grow) { | |
162 size_t block_size = base::GetPageSize(); | |
163 DiscardableSharedMemoryHeap heap(block_size); | |
164 int next_discardable_shared_memory_id = 0; | |
165 | |
166 std::unique_ptr<base::DiscardableSharedMemory> memory1( | |
167 new base::DiscardableSharedMemory); | |
168 ASSERT_TRUE(memory1->CreateAndMap(block_size)); | |
169 heap.MergeIntoFreeLists(heap.Grow(std::move(memory1), block_size, | |
170 next_discardable_shared_memory_id++, | |
171 base::Bind(NullTask))); | |
172 | |
173 // Remove a span from free lists. | |
174 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span1 = | |
175 heap.SearchFreeLists(1, 0); | |
176 EXPECT_TRUE(span1); | |
177 | |
178 // No more memory available. | |
179 EXPECT_FALSE(heap.SearchFreeLists(1, 0)); | |
180 | |
181 // Grow free lists using new memory. | |
182 std::unique_ptr<base::DiscardableSharedMemory> memory2( | |
183 new base::DiscardableSharedMemory); | |
184 ASSERT_TRUE(memory2->CreateAndMap(block_size)); | |
185 heap.MergeIntoFreeLists(heap.Grow(std::move(memory2), block_size, | |
186 next_discardable_shared_memory_id++, | |
187 base::Bind(NullTask))); | |
188 | |
189 // Memory should now be available. | |
190 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span2 = | |
191 heap.SearchFreeLists(1, 0); | |
192 EXPECT_TRUE(span2); | |
193 | |
194 // Merge spans into the free lists again. | |
195 heap.MergeIntoFreeLists(std::move(span1)); | |
196 heap.MergeIntoFreeLists(std::move(span2)); | |
197 } | |
198 | |
199 TEST(DiscardableSharedMemoryHeapTest, ReleaseFreeMemory) { | |
200 size_t block_size = base::GetPageSize(); | |
201 DiscardableSharedMemoryHeap heap(block_size); | |
202 int next_discardable_shared_memory_id = 0; | |
203 | |
204 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
205 new base::DiscardableSharedMemory); | |
206 ASSERT_TRUE(memory->CreateAndMap(block_size)); | |
207 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span = | |
208 heap.Grow(std::move(memory), block_size, | |
209 next_discardable_shared_memory_id++, base::Bind(NullTask)); | |
210 | |
211 // Free lists should be empty. | |
212 EXPECT_EQ(0u, heap.GetSizeOfFreeLists()); | |
213 | |
214 heap.ReleaseFreeMemory(); | |
215 | |
216 // Size should still match |block_size|. | |
217 EXPECT_EQ(block_size, heap.GetSize()); | |
218 | |
219 heap.MergeIntoFreeLists(std::move(span)); | |
220 heap.ReleaseFreeMemory(); | |
221 | |
222 // Memory should have been released. | |
223 EXPECT_EQ(0u, heap.GetSize()); | |
224 EXPECT_EQ(0u, heap.GetSizeOfFreeLists()); | |
225 } | |
226 | |
227 TEST(DiscardableSharedMemoryHeapTest, ReleasePurgedMemory) { | |
228 size_t block_size = base::GetPageSize(); | |
229 DiscardableSharedMemoryHeap heap(block_size); | |
230 int next_discardable_shared_memory_id = 0; | |
231 | |
232 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
233 new base::DiscardableSharedMemory); | |
234 ASSERT_TRUE(memory->CreateAndMap(block_size)); | |
235 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span = | |
236 heap.Grow(std::move(memory), block_size, | |
237 next_discardable_shared_memory_id++, base::Bind(NullTask)); | |
238 | |
239 // Unlock memory so it can be purged. | |
240 span->shared_memory()->Unlock(0, 0); | |
241 | |
242 // Purge and release shared memory. | |
243 bool rv = span->shared_memory()->Purge(base::Time::Now()); | |
244 EXPECT_TRUE(rv); | |
245 heap.ReleasePurgedMemory(); | |
246 | |
247 // Shared memory backing for |span| should be gone. | |
248 EXPECT_FALSE(span->shared_memory()); | |
249 | |
250 // Size should be 0. | |
251 EXPECT_EQ(0u, heap.GetSize()); | |
252 } | |
253 | |
254 TEST(DiscardableSharedMemoryHeapTest, Slack) { | |
255 size_t block_size = base::GetPageSize(); | |
256 DiscardableSharedMemoryHeap heap(block_size); | |
257 | |
258 const size_t kBlocks = 6; | |
259 size_t memory_size = block_size * kBlocks; | |
260 int next_discardable_shared_memory_id = 0; | |
261 | |
262 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
263 new base::DiscardableSharedMemory); | |
264 ASSERT_TRUE(memory->CreateAndMap(memory_size)); | |
265 heap.MergeIntoFreeLists(heap.Grow(std::move(memory), memory_size, | |
266 next_discardable_shared_memory_id++, | |
267 base::Bind(NullTask))); | |
268 | |
269 // No free span that is less or equal to 3 + 1. | |
270 EXPECT_FALSE(heap.SearchFreeLists(3, 1)); | |
271 | |
272 // No free span that is less or equal to 3 + 2. | |
273 EXPECT_FALSE(heap.SearchFreeLists(3, 2)); | |
274 | |
275 // No free span that is less or equal to 1 + 4. | |
276 EXPECT_FALSE(heap.SearchFreeLists(1, 4)); | |
277 | |
278 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span = | |
279 heap.SearchFreeLists(1, 5); | |
280 EXPECT_TRUE(span); | |
281 | |
282 heap.MergeIntoFreeLists(std::move(span)); | |
283 } | |
284 | |
285 void OnDeleted(bool* deleted) { | |
286 *deleted = true; | |
287 } | |
288 | |
289 TEST(DiscardableSharedMemoryHeapTest, DeletedCallback) { | |
290 size_t block_size = base::GetPageSize(); | |
291 DiscardableSharedMemoryHeap heap(block_size); | |
292 int next_discardable_shared_memory_id = 0; | |
293 | |
294 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
295 new base::DiscardableSharedMemory); | |
296 ASSERT_TRUE(memory->CreateAndMap(block_size)); | |
297 bool deleted = false; | |
298 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span = heap.Grow( | |
299 std::move(memory), block_size, next_discardable_shared_memory_id++, | |
300 base::Bind(OnDeleted, base::Unretained(&deleted))); | |
301 | |
302 heap.MergeIntoFreeLists(std::move(span)); | |
303 heap.ReleaseFreeMemory(); | |
304 | |
305 EXPECT_TRUE(deleted); | |
306 } | |
307 | |
308 TEST(DiscardableSharedMemoryHeapTest, CreateMemoryAllocatorDumpTest) { | |
309 size_t block_size = base::GetPageSize(); | |
310 DiscardableSharedMemoryHeap heap(block_size); | |
311 int next_discardable_shared_memory_id = 0; | |
312 | |
313 std::unique_ptr<base::DiscardableSharedMemory> memory( | |
314 new base::DiscardableSharedMemory); | |
315 ASSERT_TRUE(memory->CreateAndMap(block_size)); | |
316 std::unique_ptr<DiscardableSharedMemoryHeap::Span> span = | |
317 heap.Grow(std::move(memory), block_size, | |
318 next_discardable_shared_memory_id++, base::Bind(NullTask)); | |
319 | |
320 // Check if allocator dump is created when span exists. | |
321 std::unique_ptr<base::trace_event::ProcessMemoryDump> pmd( | |
322 new base::trace_event::ProcessMemoryDump( | |
323 nullptr, {base::trace_event::MemoryDumpLevelOfDetail::DETAILED})); | |
324 EXPECT_TRUE(heap.CreateMemoryAllocatorDump(span.get(), "discardable/test1", | |
325 pmd.get())); | |
326 | |
327 // Unlock, Purge and release shared memory. | |
328 span->shared_memory()->Unlock(0, 0); | |
329 bool rv = span->shared_memory()->Purge(base::Time::Now()); | |
330 EXPECT_TRUE(rv); | |
331 heap.ReleasePurgedMemory(); | |
332 | |
333 // Check that allocator dump is created after memory is purged. | |
334 EXPECT_TRUE(heap.CreateMemoryAllocatorDump(span.get(), "discardable/test2", | |
335 pmd.get())); | |
336 } | |
337 | |
338 } // namespace | |
339 } // namespace content | |
OLD | NEW |