blob: 7ac049357fd3696b8e478ee7d4445e4bf40d14dc [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
Brian Carlstrom9b7f2c22011-09-27 14:35:04 -070073TEST_F(SpaceTest, AllocAndFree) {
Ian Rogers30fab402012-01-23 15:43:46 -080074 AllocSpace* space(Space::CreateAllocSpace("test", 4 * MB, 16 * MB, 16 * MB, NULL));
75 ASSERT_TRUE(space != NULL);
76
Ian Rogers3bb17a62012-01-27 23:56:44 -080077 // Make space findable to the heap, will also delete space when runtime is cleaned up
Elliott Hughesb3bd5f02012-03-08 21:05:27 -080078 Runtime::Current()->GetHeap()->AddSpace(space);
Carl Shapiro69759ea2011-07-21 18:13:35 -070079
Ian Rogers3bb17a62012-01-27 23:56:44 -080080 // Succeeds, fits without adjusting the footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -080081 Object* ptr1 = space->AllocWithoutGrowth(1 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -070082 EXPECT_TRUE(ptr1 != NULL);
83
Ian Rogers3bb17a62012-01-27 23:56:44 -080084 // Fails, requires a higher footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -080085 Object* ptr2 = space->AllocWithoutGrowth(8 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -070086 EXPECT_TRUE(ptr2 == NULL);
87
88 // Succeeds, adjusts the footprint.
Ian Rogers30fab402012-01-23 15:43:46 -080089 Object* ptr3 = space->AllocWithGrowth(8 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -070090 EXPECT_TRUE(ptr3 != NULL);
91
Ian Rogers3bb17a62012-01-27 23:56:44 -080092 // Fails, requires a higher footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -080093 Object* ptr4 = space->AllocWithoutGrowth(8 * MB);
Ian Rogers3bb17a62012-01-27 23:56:44 -080094 EXPECT_TRUE(ptr4 == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070095
96 // Also fails, requires a higher allowed footprint.
Ian Rogers30fab402012-01-23 15:43:46 -080097 Object* ptr5 = space->AllocWithGrowth(8 * MB);
Ian Rogers3bb17a62012-01-27 23:56:44 -080098 EXPECT_TRUE(ptr5 == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070099
100 // Release some memory.
Ian Rogers30fab402012-01-23 15:43:46 -0800101 size_t free3 = space->AllocationSize(ptr3);
102 space->Free(ptr3);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700103 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.
Ian Rogers30fab402012-01-23 15:43:46 -0800110 size_t free1 = space->AllocationSize(ptr1);
111 space->Free(ptr1);
Carl Shapiro69759ea2011-07-21 18:13:35 -0700112 EXPECT_LE(1U * MB, free1);
113}
114
Ian Rogers3bb17a62012-01-27 23:56:44 -0800115TEST_F(SpaceTest, AllocAndFreeList) {
116 AllocSpace* space(Space::CreateAllocSpace("test", 4 * MB, 16 * MB, 16 * MB, NULL));
117 ASSERT_TRUE(space != NULL);
118
119 // Make space findable to the heap, will also delete space when runtime is cleaned up
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800120 Runtime::Current()->GetHeap()->AddSpace(space);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800121
122 // Succeeds, fits without adjusting the max allowed footprint.
123 Object* lots_of_objects[1024];
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700124 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800125 lots_of_objects[i] = space->AllocWithoutGrowth(16);
126 EXPECT_TRUE(lots_of_objects[i] != NULL);
127 }
128
129 // Release memory and check pointers are NULL
130 space->FreeList(arraysize(lots_of_objects), lots_of_objects);
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700131 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800132 EXPECT_TRUE(lots_of_objects[i] == NULL);
133 }
134
135 // Succeeds, fits by adjusting the max allowed footprint.
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700136 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800137 lots_of_objects[i] = space->AllocWithGrowth(1024);
138 EXPECT_TRUE(lots_of_objects[i] != NULL);
139 }
140
141 // Release memory and check pointers are NULL
142 space->FreeList(arraysize(lots_of_objects), lots_of_objects);
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700143 for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800144 EXPECT_TRUE(lots_of_objects[i] == NULL);
145 }
146}
147
148static size_t test_rand() {
149 // TODO: replace this with something random yet deterministic
150 return rand();
151}
152
153void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(AllocSpace* space, intptr_t object_size,
154 int round, size_t growth_limit) {
155 if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) ||
156 ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) {
157 // No allocation can succeed
158 return;
159 }
160 // Mspace for raw dlmalloc operations
161 void* mspace = space->GetMspace();
162
163 // mspace's footprint equals amount of resources requested from system
164 size_t footprint = mspace_footprint(mspace);
165
166 // mspace must at least have its book keeping allocated
167 EXPECT_GT(footprint, 0u);
168
169 // mspace but it shouldn't exceed the initial size
170 EXPECT_LE(footprint, growth_limit);
171
172 // space's size shouldn't exceed the initial size
173 EXPECT_LE(space->Size(), growth_limit);
174
175 // this invariant should always hold or else the mspace has grown to be larger than what the
176 // space believes its size is (which will break invariants)
177 EXPECT_GE(space->Size(), footprint);
178
179 // Fill the space with lots of small objects up to the growth limit
180 size_t max_objects = (growth_limit / (object_size > 0 ? object_size : 8)) + 1;
Elliott Hughesf34f1742012-03-16 18:56:00 -0700181 UniquePtr<Object*[]> lots_of_objects(new Object*[max_objects]);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800182 size_t last_object = 0; // last object for which allocation succeeded
183 size_t amount_allocated = 0; // amount of space allocated
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700184 for (size_t i = 0; i < max_objects; i++) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800185 size_t alloc_fails = 0; // number of failed allocations
186 size_t max_fails = 30; // number of times we fail allocation before giving up
187 for (; alloc_fails < max_fails; alloc_fails++) {
188 size_t alloc_size;
189 if (object_size > 0) {
190 alloc_size = object_size;
191 } else {
192 alloc_size = test_rand() % static_cast<size_t>(-object_size);
193 if (alloc_size < 8) {
194 alloc_size = 8;
195 }
196 }
197 Object* object;
198 if (round <= 1) {
199 object = space->AllocWithoutGrowth(alloc_size);
200 } else {
201 object = space->AllocWithGrowth(alloc_size);
202 }
203 footprint = mspace_footprint(mspace);
204 EXPECT_GE(space->Size(), footprint); // invariant
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700205 if (object != NULL) { // allocation succeeded
Ian Rogers3bb17a62012-01-27 23:56:44 -0800206 lots_of_objects.get()[i] = object;
207 size_t allocation_size = space->AllocationSize(object);
208 if (object_size > 0) {
209 EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
210 } else {
211 EXPECT_GE(allocation_size, 8u);
212 }
213 amount_allocated += allocation_size;
214 break;
215 }
216 }
217 if (alloc_fails == max_fails) {
218 last_object = i;
219 break;
220 }
221 }
222 CHECK_NE(last_object, 0u); // we should have filled the space
223 EXPECT_GT(amount_allocated, 0u);
224
225 // We shouldn't have gone past the growth_limit
226 EXPECT_LE(amount_allocated, growth_limit);
227 EXPECT_LE(footprint, growth_limit);
228 EXPECT_LE(space->Size(), growth_limit);
229
230 // footprint and size should agree with amount allocated
231 EXPECT_GE(footprint, amount_allocated);
232 EXPECT_GE(space->Size(), amount_allocated);
233
234 // Release storage in a semi-adhoc manner
235 size_t free_increment = 96;
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700236 while (true) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800237 // Give the space a haircut
238 space->Trim();
239
240 // Bounds sanity
241 footprint = mspace_footprint(mspace);
242 EXPECT_LE(amount_allocated, growth_limit);
243 EXPECT_GE(footprint, amount_allocated);
244 EXPECT_LE(footprint, growth_limit);
245 EXPECT_GE(space->Size(), amount_allocated);
246 EXPECT_LE(space->Size(), growth_limit);
247
248 if (free_increment == 0) {
249 break;
250 }
251
252 // Free some objects
Elliott Hughesb25c3f62012-03-26 16:35:06 -0700253 for (size_t i = 0; i < last_object; i += free_increment) {
Ian Rogers3bb17a62012-01-27 23:56:44 -0800254 Object* object = lots_of_objects.get()[i];
255 if (object == NULL) {
256 continue;
257 }
258 size_t allocation_size = space->AllocationSize(object);
259 if (object_size > 0) {
260 EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
261 } else {
262 EXPECT_GE(allocation_size, 8u);
263 }
264 space->Free(object);
265 lots_of_objects.get()[i] = NULL;
266 amount_allocated -= allocation_size;
267 footprint = mspace_footprint(mspace);
268 EXPECT_GE(space->Size(), footprint); // invariant
269 }
270
271 free_increment >>= 1;
272 }
273
274 // All memory was released, try a large allocation to check freed memory is being coalesced
275 Object* large_object;
276 size_t three_quarters_space = (growth_limit / 2) + (growth_limit / 4);
277 if (round <= 1) {
278 large_object = space->AllocWithoutGrowth(three_quarters_space);
279 } else {
280 large_object = space->AllocWithGrowth(three_quarters_space);
281 }
282 EXPECT_TRUE(large_object != NULL);
283
284 // Sanity check footprint
285 footprint = mspace_footprint(mspace);
286 EXPECT_LE(footprint, growth_limit);
287 EXPECT_GE(space->Size(), footprint);
288 EXPECT_LE(space->Size(), growth_limit);
289
290 // Clean up
291 space->Free(large_object);
292
293 // Sanity check footprint
294 footprint = mspace_footprint(mspace);
295 EXPECT_LE(footprint, growth_limit);
296 EXPECT_GE(space->Size(), footprint);
297 EXPECT_LE(space->Size(), growth_limit);
298}
299
300void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) {
301 size_t initial_size = 4 * MB;
302 size_t growth_limit = 8 * MB;
303 size_t capacity = 16 * MB;
304 AllocSpace* space(Space::CreateAllocSpace("test", initial_size, growth_limit, capacity, NULL));
305 ASSERT_TRUE(space != NULL);
306
307 // Basic sanity
308 EXPECT_EQ(space->Capacity(), growth_limit);
309 EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity);
310
311 // Make space findable to the heap, will also delete space when runtime is cleaned up
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800312 Runtime::Current()->GetHeap()->AddSpace(space);
Ian Rogers3bb17a62012-01-27 23:56:44 -0800313
314 // In this round we don't allocate with growth and therefore can't grow past the initial size.
315 // This effectively makes the growth_limit the initial_size, so assert this.
316 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 1, initial_size);
317 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 2, growth_limit);
318 // Remove growth limit
319 space->ClearGrowthLimit();
320 EXPECT_EQ(space->Capacity(), capacity);
321 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 3, capacity);
322}
323
324#define TEST_SizeFootPrintGrowthLimitAndTrim(name, size) \
325 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \
326 SizeFootPrintGrowthLimitAndTrimDriver(size); \
327 } \
328 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \
329 SizeFootPrintGrowthLimitAndTrimDriver(-size); \
330 }
331
332// Each size test is its own test so that we get a fresh heap each time
333TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_8B) {
334 SizeFootPrintGrowthLimitAndTrimDriver(8);
335}
336TEST_SizeFootPrintGrowthLimitAndTrim(16B, 16)
337TEST_SizeFootPrintGrowthLimitAndTrim(24B, 24)
338TEST_SizeFootPrintGrowthLimitAndTrim(32B, 32)
339TEST_SizeFootPrintGrowthLimitAndTrim(64B, 64)
340TEST_SizeFootPrintGrowthLimitAndTrim(128B, 128)
341TEST_SizeFootPrintGrowthLimitAndTrim(1KB, 1 * KB)
342TEST_SizeFootPrintGrowthLimitAndTrim(4KB, 4 * KB)
343TEST_SizeFootPrintGrowthLimitAndTrim(1MB, 1 * MB)
344TEST_SizeFootPrintGrowthLimitAndTrim(4MB, 4 * MB)
345TEST_SizeFootPrintGrowthLimitAndTrim(8MB, 8 * MB)
346
Carl Shapiro69759ea2011-07-21 18:13:35 -0700347} // namespace art