blob: f377a6142cf65f661bcd44d25f0334ff5a7ce393 [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Carl Shapiro69759ea2011-07-21 18:13:35 -070016
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070017#include "space.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070018
Brian Carlstrom9b7f2c22011-09-27 14:35:04 -070019#include "common_test.h"
Ian Rogers3bb17a62012-01-27 23:56:44 -080020#include "dlmalloc.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070021#include "globals.h"
Elliott Hughes90a33692011-08-30 13:27:07 -070022#include "UniquePtr.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070023
Ian Rogers3bb17a62012-01-27 23:56:44 -080024#include <stdint.h>
25
Carl Shapiro69759ea2011-07-21 18:13:35 -070026namespace art {
27
Ian Rogers3bb17a62012-01-27 23:56:44 -080028class SpaceTest : public CommonTest {
29 public:
30 void SizeFootPrintGrowthLimitAndTrimBody(AllocSpace* space, intptr_t object_size,
31 int round, size_t growth_limit);
32 void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size);
33};
Brian Carlstrom9b7f2c22011-09-27 14:35:04 -070034
35TEST_F(SpaceTest, Init) {
Carl Shapiro69759ea2011-07-21 18:13:35 -070036 {
jeffhaoc1160702011-10-27 15:48:45 -070037 // Init < max == growth
Ian Rogers30fab402012-01-23 15:43:46 -080038 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 32 * MB, 32 * MB, NULL));
Elliott Hughes90a33692011-08-30 13:27:07 -070039 EXPECT_TRUE(space.get() != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070040 }
41 {
jeffhaoc1160702011-10-27 15:48:45 -070042 // Init == max == growth
Ian Rogers30fab402012-01-23 15:43:46 -080043 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 16 * MB, 16 * MB, NULL));
Elliott Hughes90a33692011-08-30 13:27:07 -070044 EXPECT_TRUE(space.get() != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070045 }
46 {
jeffhaoc1160702011-10-27 15:48:45 -070047 // Init > max == growth
Ian Rogers30fab402012-01-23 15:43:46 -080048 UniquePtr<Space> space(Space::CreateAllocSpace("test", 32 * MB, 16 * MB, 16 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070049 EXPECT_TRUE(space.get() == NULL);
50 }
51 {
52 // Growth == init < max
Ian Rogers30fab402012-01-23 15:43:46 -080053 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 16 * MB, 32 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070054 EXPECT_TRUE(space.get() != NULL);
55 }
56 {
57 // Growth < init < max
Ian Rogers30fab402012-01-23 15:43:46 -080058 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 8 * MB, 32 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070059 EXPECT_TRUE(space.get() == NULL);
60 }
61 {
62 // Init < growth < max
Ian Rogers30fab402012-01-23 15:43:46 -080063 UniquePtr<Space> space(Space::CreateAllocSpace("test", 8 * MB, 16 * MB, 32 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070064 EXPECT_TRUE(space.get() != NULL);
65 }
66 {
67 // Init < max < growth
Ian Rogers30fab402012-01-23 15:43:46 -080068 UniquePtr<Space> space(Space::CreateAllocSpace("test", 8 * MB, 32 * MB, 16 * MB, NULL));
Elliott Hughes90a33692011-08-30 13:27:07 -070069 EXPECT_TRUE(space.get() == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070070 }
71}
72
Mathieu Chartiercc236d72012-07-20 10:29:05 -070073TEST_F(SpaceTest, ZygoteSpace) {
74 AllocSpace* space(Space::CreateAllocSpace("test", 4 * MB, 16 * MB, 16 * MB, NULL));
75 ASSERT_TRUE(space != NULL);
76
77 // Make space findable to the heap, will also delete space when runtime is cleaned up
78 Runtime::Current()->GetHeap()->AddSpace(space);
79
80 // Succeeds, fits without adjusting the footprint limit.
81 Object* ptr1 = space->AllocWithoutGrowth(1 * MB);
82 EXPECT_TRUE(ptr1 != NULL);
83
84 // Fails, requires a higher footprint limit.
85 Object* ptr2 = space->AllocWithoutGrowth(8 * MB);
86 EXPECT_TRUE(ptr2 == NULL);
87
88 // Succeeds, adjusts the footprint.
89 Object* ptr3 = space->AllocWithGrowth(8 * MB);
90 EXPECT_TRUE(ptr3 != NULL);
91
92 // Fails, requires a higher footprint limit.
93 Object* ptr4 = space->AllocWithoutGrowth(8 * MB);
94 EXPECT_TRUE(ptr4 == NULL);
95
96 // Also fails, requires a higher allowed footprint.
97 Object* ptr5 = space->AllocWithGrowth(8 * MB);
98 EXPECT_TRUE(ptr5 == NULL);
99
100 // Release some memory.
101 size_t free3 = space->AllocationSize(ptr3);
102 space->Free(ptr3);
103 EXPECT_LE(8U * MB, free3);
104
105 // Succeeds, now that memory has been freed.
106 void* ptr6 = space->AllocWithGrowth(9 * MB);
107 EXPECT_TRUE(ptr6 != NULL);
108
109 // Final clean up.
110 size_t free1 = space->AllocationSize(ptr1);
111 space->Free(ptr1);
112 EXPECT_LE(1U * MB, free1);
113
114 // Make sure that the zygote space isn't directly at the start of the space.
115 space->AllocWithoutGrowth(1U * MB);
116 space = space->CreateZygoteSpace();
117
118 // Make space findable to the heap, will also delete space when runtime is cleaned up
119 Runtime::Current()->GetHeap()->AddSpace(space);
120
121 // Succeeds, fits without adjusting the footprint limit.
122 ptr1 = space->AllocWithoutGrowth(1 * MB);
123 EXPECT_TRUE(ptr1 != NULL);
124
125 // Fails, requires a higher footprint limit.
126 ptr2 = space->AllocWithoutGrowth(8 * MB);
127 EXPECT_TRUE(ptr2 == NULL);
128
129 // Succeeds, adjusts the footprint.
130 ptr3 = space->AllocWithGrowth(2 * MB);
131 EXPECT_TRUE(ptr3 != NULL);
132 space->Free(ptr3);
133
134 // Final clean up.
135 free1 = space->AllocationSize(ptr1);
136 space->Free(ptr1);
137 EXPECT_LE(1U * MB, free1);
138}
139
Brian Carlstrom9b7f2c22011-09-27 14:35:04 -0700140TEST_F(SpaceTest, AllocAndFree) {
Ian Rogers30fab402012-01-23 15:43:46 -0800141 AllocSpace* space(Space::CreateAllocSpace("test", 4 * MB, 16 * MB, 16 * MB, NULL));
142 ASSERT_TRUE(space != NULL);
143
Ian Rogers3bb17a62012-01-27 23:56:44 -0800144 // Make space findable to the heap, will also delete space when runtime is cleaned up
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800145 Runtime::Current()->GetHeap()->AddSpace(space);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700146
Ian Rogers3bb17a62012-01-27 23:56:44 -0800147 // Succeeds, fits without adjusting the footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -0800148 Object* ptr1 = space->AllocWithoutGrowth(1 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700149 EXPECT_TRUE(ptr1 != NULL);
150
Ian Rogers3bb17a62012-01-27 23:56:44 -0800151 // Fails, requires a higher footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -0800152 Object* ptr2 = space->AllocWithoutGrowth(8 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700153 EXPECT_TRUE(ptr2 == NULL);
154
155 // Succeeds, adjusts the footprint.
Ian Rogers30fab402012-01-23 15:43:46 -0800156 Object* ptr3 = space->AllocWithGrowth(8 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700157 EXPECT_TRUE(ptr3 != NULL);
158
Ian Rogers3bb17a62012-01-27 23:56:44 -0800159 // Fails, requires a higher footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -0800160 Object* ptr4 = space->AllocWithoutGrowth(8 * MB);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800161 EXPECT_TRUE(ptr4 == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700162
163 // Also fails, requires a higher allowed footprint.
Ian Rogers30fab402012-01-23 15:43:46 -0800164 Object* ptr5 = space->AllocWithGrowth(8 * MB);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800165 EXPECT_TRUE(ptr5 == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700166
167 // Release some memory.
Ian Rogers30fab402012-01-23 15:43:46 -0800168 size_t free3 = space->AllocationSize(ptr3);
169 space->Free(ptr3);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700170 EXPECT_LE(8U * MB, free3);
171
172 // Succeeds, now that memory has been freed.
173 void* ptr6 = space->AllocWithGrowth(9 * MB);
174 EXPECT_TRUE(ptr6 != NULL);
175
176 // Final clean up.
Ian Rogers30fab402012-01-23 15:43:46 -0800177 size_t free1 = space->AllocationSize(ptr1);
178 space->Free(ptr1);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700179 EXPECT_LE(1U * MB, free1);
180}
181
Ian Rogers3bb17a62012-01-27 23:56:44 -0800182TEST_F(SpaceTest, AllocAndFreeList) {
183 AllocSpace* space(Space::CreateAllocSpace("test", 4 * MB, 16 * MB, 16 * MB, NULL));
184 ASSERT_TRUE(space != NULL);
185
186 // Make space findable to the heap, will also delete space when runtime is cleaned up
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800187 Runtime::Current()->GetHeap()->AddSpace(space);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800188
189 // Succeeds, fits without adjusting the max allowed footprint.
190 Object* lots_of_objects[1024];
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700191 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800192 lots_of_objects[i] = space->AllocWithoutGrowth(16);
193 EXPECT_TRUE(lots_of_objects[i] != NULL);
194 }
195
196 // Release memory and check pointers are NULL
197 space->FreeList(arraysize(lots_of_objects), lots_of_objects);
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700198 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800199 EXPECT_TRUE(lots_of_objects[i] == NULL);
200 }
201
202 // Succeeds, fits by adjusting the max allowed footprint.
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700203 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800204 lots_of_objects[i] = space->AllocWithGrowth(1024);
205 EXPECT_TRUE(lots_of_objects[i] != NULL);
206 }
207
208 // Release memory and check pointers are NULL
209 space->FreeList(arraysize(lots_of_objects), lots_of_objects);
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700210 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800211 EXPECT_TRUE(lots_of_objects[i] == NULL);
212 }
213}
214
215static size_t test_rand() {
216 // TODO: replace this with something random yet deterministic
217 return rand();
218}
219
220void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(AllocSpace* space, intptr_t object_size,
221 int round, size_t growth_limit) {
222 if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) ||
223 ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) {
224 // No allocation can succeed
225 return;
226 }
227 // Mspace for raw dlmalloc operations
228 void* mspace = space->GetMspace();
229
230 // mspace's footprint equals amount of resources requested from system
231 size_t footprint = mspace_footprint(mspace);
232
233 // mspace must at least have its book keeping allocated
234 EXPECT_GT(footprint, 0u);
235
236 // mspace but it shouldn't exceed the initial size
237 EXPECT_LE(footprint, growth_limit);
238
239 // space's size shouldn't exceed the initial size
240 EXPECT_LE(space->Size(), growth_limit);
241
242 // this invariant should always hold or else the mspace has grown to be larger than what the
243 // space believes its size is (which will break invariants)
244 EXPECT_GE(space->Size(), footprint);
245
246 // Fill the space with lots of small objects up to the growth limit
247 size_t max_objects = (growth_limit / (object_size > 0 ? object_size : 8)) + 1;
Elliott Hughesf34f1742012-03-16 18:56:00 -0700248 UniquePtr<Object*[]> lots_of_objects(new Object*[max_objects]);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800249 size_t last_object = 0; // last object for which allocation succeeded
250 size_t amount_allocated = 0; // amount of space allocated
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700251 for (size_t i = 0; i < max_objects; i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800252 size_t alloc_fails = 0; // number of failed allocations
253 size_t max_fails = 30; // number of times we fail allocation before giving up
254 for (; alloc_fails < max_fails; alloc_fails++) {
255 size_t alloc_size;
256 if (object_size > 0) {
257 alloc_size = object_size;
258 } else {
259 alloc_size = test_rand() % static_cast<size_t>(-object_size);
260 if (alloc_size < 8) {
261 alloc_size = 8;
262 }
263 }
264 Object* object;
265 if (round <= 1) {
266 object = space->AllocWithoutGrowth(alloc_size);
267 } else {
268 object = space->AllocWithGrowth(alloc_size);
269 }
270 footprint = mspace_footprint(mspace);
271 EXPECT_GE(space->Size(), footprint); // invariant
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700272 if (object != NULL) { // allocation succeeded
Ian Rogers3bb17a62012-01-27 23:56:44 -0800273 lots_of_objects.get()[i] = object;
274 size_t allocation_size = space->AllocationSize(object);
275 if (object_size > 0) {
276 EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
277 } else {
278 EXPECT_GE(allocation_size, 8u);
279 }
280 amount_allocated += allocation_size;
281 break;
282 }
283 }
284 if (alloc_fails == max_fails) {
285 last_object = i;
286 break;
287 }
288 }
289 CHECK_NE(last_object, 0u); // we should have filled the space
290 EXPECT_GT(amount_allocated, 0u);
291
292 // We shouldn't have gone past the growth_limit
293 EXPECT_LE(amount_allocated, growth_limit);
294 EXPECT_LE(footprint, growth_limit);
295 EXPECT_LE(space->Size(), growth_limit);
296
297 // footprint and size should agree with amount allocated
298 EXPECT_GE(footprint, amount_allocated);
299 EXPECT_GE(space->Size(), amount_allocated);
300
301 // Release storage in a semi-adhoc manner
302 size_t free_increment = 96;
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700303 while (true) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800304 // Give the space a haircut
305 space->Trim();
306
307 // Bounds sanity
308 footprint = mspace_footprint(mspace);
309 EXPECT_LE(amount_allocated, growth_limit);
310 EXPECT_GE(footprint, amount_allocated);
311 EXPECT_LE(footprint, growth_limit);
312 EXPECT_GE(space->Size(), amount_allocated);
313 EXPECT_LE(space->Size(), growth_limit);
314
315 if (free_increment == 0) {
316 break;
317 }
318
319 // Free some objects
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700320 for (size_t i = 0; i < last_object; i += free_increment) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800321 Object* object = lots_of_objects.get()[i];
322 if (object == NULL) {
323 continue;
324 }
325 size_t allocation_size = space->AllocationSize(object);
326 if (object_size > 0) {
327 EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
328 } else {
329 EXPECT_GE(allocation_size, 8u);
330 }
331 space->Free(object);
332 lots_of_objects.get()[i] = NULL;
333 amount_allocated -= allocation_size;
334 footprint = mspace_footprint(mspace);
335 EXPECT_GE(space->Size(), footprint); // invariant
336 }
337
338 free_increment >>= 1;
339 }
340
341 // All memory was released, try a large allocation to check freed memory is being coalesced
342 Object* large_object;
343 size_t three_quarters_space = (growth_limit / 2) + (growth_limit / 4);
344 if (round <= 1) {
345 large_object = space->AllocWithoutGrowth(three_quarters_space);
346 } else {
347 large_object = space->AllocWithGrowth(three_quarters_space);
348 }
349 EXPECT_TRUE(large_object != NULL);
350
351 // Sanity check footprint
352 footprint = mspace_footprint(mspace);
353 EXPECT_LE(footprint, growth_limit);
354 EXPECT_GE(space->Size(), footprint);
355 EXPECT_LE(space->Size(), growth_limit);
356
357 // Clean up
358 space->Free(large_object);
359
360 // Sanity check footprint
361 footprint = mspace_footprint(mspace);
362 EXPECT_LE(footprint, growth_limit);
363 EXPECT_GE(space->Size(), footprint);
364 EXPECT_LE(space->Size(), growth_limit);
365}
366
367void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) {
368 size_t initial_size = 4 * MB;
369 size_t growth_limit = 8 * MB;
370 size_t capacity = 16 * MB;
371 AllocSpace* space(Space::CreateAllocSpace("test", initial_size, growth_limit, capacity, NULL));
372 ASSERT_TRUE(space != NULL);
373
374 // Basic sanity
375 EXPECT_EQ(space->Capacity(), growth_limit);
376 EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity);
377
378 // Make space findable to the heap, will also delete space when runtime is cleaned up
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800379 Runtime::Current()->GetHeap()->AddSpace(space);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800380
381 // In this round we don't allocate with growth and therefore can't grow past the initial size.
382 // This effectively makes the growth_limit the initial_size, so assert this.
383 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 1, initial_size);
384 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 2, growth_limit);
385 // Remove growth limit
386 space->ClearGrowthLimit();
387 EXPECT_EQ(space->Capacity(), capacity);
388 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 3, capacity);
389}
390
391#define TEST_SizeFootPrintGrowthLimitAndTrim(name, size) \
392 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \
393 SizeFootPrintGrowthLimitAndTrimDriver(size); \
394 } \
395 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \
396 SizeFootPrintGrowthLimitAndTrimDriver(-size); \
397 }
398
399// Each size test is its own test so that we get a fresh heap each time
400TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_8B) {
401 SizeFootPrintGrowthLimitAndTrimDriver(8);
402}
403TEST_SizeFootPrintGrowthLimitAndTrim(16B, 16)
404TEST_SizeFootPrintGrowthLimitAndTrim(24B, 24)
405TEST_SizeFootPrintGrowthLimitAndTrim(32B, 32)
406TEST_SizeFootPrintGrowthLimitAndTrim(64B, 64)
407TEST_SizeFootPrintGrowthLimitAndTrim(128B, 128)
408TEST_SizeFootPrintGrowthLimitAndTrim(1KB, 1 * KB)
409TEST_SizeFootPrintGrowthLimitAndTrim(4KB, 4 * KB)
410TEST_SizeFootPrintGrowthLimitAndTrim(1MB, 1 * MB)
411TEST_SizeFootPrintGrowthLimitAndTrim(4MB, 4 * MB)
412TEST_SizeFootPrintGrowthLimitAndTrim(8MB, 8 * MB)
413
Carl Shapiro69759ea2011-07-21 18:13:35 -0700414} // namespace art