blob: 4025805a3a3134c95297ffb7f39b73f3a8827524 [file] [log] [blame]
Carl Shapiro69759ea2011-07-21 18:13:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Carl Shapiro69759ea2011-07-21 18:13:35 -07002
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07003#include "space.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -07004
Brian Carlstrom9b7f2c22011-09-27 14:35:04 -07005#include "common_test.h"
Ian Rogers3bb17a62012-01-27 23:56:44 -08006#include "dlmalloc.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07007#include "globals.h"
Elliott Hughes90a33692011-08-30 13:27:07 -07008#include "UniquePtr.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -07009
Ian Rogers3bb17a62012-01-27 23:56:44 -080010#include <stdint.h>
11
Carl Shapiro69759ea2011-07-21 18:13:35 -070012namespace art {
13
Ian Rogers3bb17a62012-01-27 23:56:44 -080014class SpaceTest : public CommonTest {
15 public:
16 void SizeFootPrintGrowthLimitAndTrimBody(AllocSpace* space, intptr_t object_size,
17 int round, size_t growth_limit);
18 void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size);
19};
Brian Carlstrom9b7f2c22011-09-27 14:35:04 -070020
21TEST_F(SpaceTest, Init) {
Carl Shapiro69759ea2011-07-21 18:13:35 -070022 {
jeffhaoc1160702011-10-27 15:48:45 -070023 // Init < max == growth
Ian Rogers30fab402012-01-23 15:43:46 -080024 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 32 * MB, 32 * MB, NULL));
Elliott Hughes90a33692011-08-30 13:27:07 -070025 EXPECT_TRUE(space.get() != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070026 }
27 {
jeffhaoc1160702011-10-27 15:48:45 -070028 // Init == max == growth
Ian Rogers30fab402012-01-23 15:43:46 -080029 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 16 * MB, 16 * MB, NULL));
Elliott Hughes90a33692011-08-30 13:27:07 -070030 EXPECT_TRUE(space.get() != NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070031 }
32 {
jeffhaoc1160702011-10-27 15:48:45 -070033 // Init > max == growth
Ian Rogers30fab402012-01-23 15:43:46 -080034 UniquePtr<Space> space(Space::CreateAllocSpace("test", 32 * MB, 16 * MB, 16 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070035 EXPECT_TRUE(space.get() == NULL);
36 }
37 {
38 // Growth == init < max
Ian Rogers30fab402012-01-23 15:43:46 -080039 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 16 * MB, 32 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070040 EXPECT_TRUE(space.get() != NULL);
41 }
42 {
43 // Growth < init < max
Ian Rogers30fab402012-01-23 15:43:46 -080044 UniquePtr<Space> space(Space::CreateAllocSpace("test", 16 * MB, 8 * MB, 32 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070045 EXPECT_TRUE(space.get() == NULL);
46 }
47 {
48 // Init < growth < max
Ian Rogers30fab402012-01-23 15:43:46 -080049 UniquePtr<Space> space(Space::CreateAllocSpace("test", 8 * MB, 16 * MB, 32 * MB, NULL));
jeffhaoc1160702011-10-27 15:48:45 -070050 EXPECT_TRUE(space.get() != NULL);
51 }
52 {
53 // Init < max < growth
Ian Rogers30fab402012-01-23 15:43:46 -080054 UniquePtr<Space> space(Space::CreateAllocSpace("test", 8 * MB, 32 * MB, 16 * MB, NULL));
Elliott Hughes90a33692011-08-30 13:27:07 -070055 EXPECT_TRUE(space.get() == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070056 }
57}
58
Brian Carlstrom9b7f2c22011-09-27 14:35:04 -070059TEST_F(SpaceTest, AllocAndFree) {
Ian Rogers30fab402012-01-23 15:43:46 -080060 AllocSpace* space(Space::CreateAllocSpace("test", 4 * MB, 16 * MB, 16 * MB, NULL));
61 ASSERT_TRUE(space != NULL);
62
Ian Rogers3bb17a62012-01-27 23:56:44 -080063 // Make space findable to the heap, will also delete space when runtime is cleaned up
Ian Rogers30fab402012-01-23 15:43:46 -080064 Heap::AddSpace(space);
Carl Shapiro69759ea2011-07-21 18:13:35 -070065
Ian Rogers3bb17a62012-01-27 23:56:44 -080066 // Succeeds, fits without adjusting the footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -080067 Object* ptr1 = space->AllocWithoutGrowth(1 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -070068 EXPECT_TRUE(ptr1 != NULL);
69
Ian Rogers3bb17a62012-01-27 23:56:44 -080070 // Fails, requires a higher footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -080071 Object* ptr2 = space->AllocWithoutGrowth(8 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -070072 EXPECT_TRUE(ptr2 == NULL);
73
74 // Succeeds, adjusts the footprint.
Ian Rogers30fab402012-01-23 15:43:46 -080075 Object* ptr3 = space->AllocWithGrowth(8 * MB);
Carl Shapiro69759ea2011-07-21 18:13:35 -070076 EXPECT_TRUE(ptr3 != NULL);
77
Ian Rogers3bb17a62012-01-27 23:56:44 -080078 // Fails, requires a higher footprint limit.
Ian Rogers30fab402012-01-23 15:43:46 -080079 Object* ptr4 = space->AllocWithoutGrowth(8 * MB);
Ian Rogers3bb17a62012-01-27 23:56:44 -080080 EXPECT_TRUE(ptr4 == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070081
82 // Also fails, requires a higher allowed footprint.
Ian Rogers30fab402012-01-23 15:43:46 -080083 Object* ptr5 = space->AllocWithGrowth(8 * MB);
Ian Rogers3bb17a62012-01-27 23:56:44 -080084 EXPECT_TRUE(ptr5 == NULL);
Carl Shapiro69759ea2011-07-21 18:13:35 -070085
86 // Release some memory.
Ian Rogers30fab402012-01-23 15:43:46 -080087 size_t free3 = space->AllocationSize(ptr3);
88 space->Free(ptr3);
Carl Shapiro69759ea2011-07-21 18:13:35 -070089 EXPECT_LE(8U * MB, free3);
90
91 // Succeeds, now that memory has been freed.
92 void* ptr6 = space->AllocWithGrowth(9 * MB);
93 EXPECT_TRUE(ptr6 != NULL);
94
95 // Final clean up.
Ian Rogers30fab402012-01-23 15:43:46 -080096 size_t free1 = space->AllocationSize(ptr1);
97 space->Free(ptr1);
Carl Shapiro69759ea2011-07-21 18:13:35 -070098 EXPECT_LE(1U * MB, free1);
99}
100
Ian Rogers3bb17a62012-01-27 23:56:44 -0800101TEST_F(SpaceTest, AllocAndFreeList) {
102 AllocSpace* space(Space::CreateAllocSpace("test", 4 * MB, 16 * MB, 16 * MB, NULL));
103 ASSERT_TRUE(space != NULL);
104
105 // Make space findable to the heap, will also delete space when runtime is cleaned up
106 Heap::AddSpace(space);
107
108 // Succeeds, fits without adjusting the max allowed footprint.
109 Object* lots_of_objects[1024];
110 for(size_t i = 0; i < arraysize(lots_of_objects); i++) {
111 lots_of_objects[i] = space->AllocWithoutGrowth(16);
112 EXPECT_TRUE(lots_of_objects[i] != NULL);
113 }
114
115 // Release memory and check pointers are NULL
116 space->FreeList(arraysize(lots_of_objects), lots_of_objects);
117 for(size_t i = 0; i < arraysize(lots_of_objects); i++) {
118 EXPECT_TRUE(lots_of_objects[i] == NULL);
119 }
120
121 // Succeeds, fits by adjusting the max allowed footprint.
122 for(size_t i = 0; i < arraysize(lots_of_objects); i++) {
123 lots_of_objects[i] = space->AllocWithGrowth(1024);
124 EXPECT_TRUE(lots_of_objects[i] != NULL);
125 }
126
127 // Release memory and check pointers are NULL
128 space->FreeList(arraysize(lots_of_objects), lots_of_objects);
129 for(size_t i = 0; i < arraysize(lots_of_objects); i++) {
130 EXPECT_TRUE(lots_of_objects[i] == NULL);
131 }
132}
133
134static size_t test_rand() {
135 // TODO: replace this with something random yet deterministic
136 return rand();
137}
138
139void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(AllocSpace* space, intptr_t object_size,
140 int round, size_t growth_limit) {
141 if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) ||
142 ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) {
143 // No allocation can succeed
144 return;
145 }
146 // Mspace for raw dlmalloc operations
147 void* mspace = space->GetMspace();
148
149 // mspace's footprint equals amount of resources requested from system
150 size_t footprint = mspace_footprint(mspace);
151
152 // mspace must at least have its book keeping allocated
153 EXPECT_GT(footprint, 0u);
154
155 // mspace but it shouldn't exceed the initial size
156 EXPECT_LE(footprint, growth_limit);
157
158 // space's size shouldn't exceed the initial size
159 EXPECT_LE(space->Size(), growth_limit);
160
161 // this invariant should always hold or else the mspace has grown to be larger than what the
162 // space believes its size is (which will break invariants)
163 EXPECT_GE(space->Size(), footprint);
164
165 // Fill the space with lots of small objects up to the growth limit
166 size_t max_objects = (growth_limit / (object_size > 0 ? object_size : 8)) + 1;
167 UniquePtr<Object*> lots_of_objects(new Object*[max_objects]);
168 size_t last_object = 0; // last object for which allocation succeeded
169 size_t amount_allocated = 0; // amount of space allocated
170 for(size_t i = 0; i < max_objects; i++) {
171 size_t alloc_fails = 0; // number of failed allocations
172 size_t max_fails = 30; // number of times we fail allocation before giving up
173 for (; alloc_fails < max_fails; alloc_fails++) {
174 size_t alloc_size;
175 if (object_size > 0) {
176 alloc_size = object_size;
177 } else {
178 alloc_size = test_rand() % static_cast<size_t>(-object_size);
179 if (alloc_size < 8) {
180 alloc_size = 8;
181 }
182 }
183 Object* object;
184 if (round <= 1) {
185 object = space->AllocWithoutGrowth(alloc_size);
186 } else {
187 object = space->AllocWithGrowth(alloc_size);
188 }
189 footprint = mspace_footprint(mspace);
190 EXPECT_GE(space->Size(), footprint); // invariant
191 if(object != NULL) { // allocation succeeded
192 lots_of_objects.get()[i] = object;
193 size_t allocation_size = space->AllocationSize(object);
194 if (object_size > 0) {
195 EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
196 } else {
197 EXPECT_GE(allocation_size, 8u);
198 }
199 amount_allocated += allocation_size;
200 break;
201 }
202 }
203 if (alloc_fails == max_fails) {
204 last_object = i;
205 break;
206 }
207 }
208 CHECK_NE(last_object, 0u); // we should have filled the space
209 EXPECT_GT(amount_allocated, 0u);
210
211 // We shouldn't have gone past the growth_limit
212 EXPECT_LE(amount_allocated, growth_limit);
213 EXPECT_LE(footprint, growth_limit);
214 EXPECT_LE(space->Size(), growth_limit);
215
216 // footprint and size should agree with amount allocated
217 EXPECT_GE(footprint, amount_allocated);
218 EXPECT_GE(space->Size(), amount_allocated);
219
220 // Release storage in a semi-adhoc manner
221 size_t free_increment = 96;
222 while(true) {
223 // Give the space a haircut
224 space->Trim();
225
226 // Bounds sanity
227 footprint = mspace_footprint(mspace);
228 EXPECT_LE(amount_allocated, growth_limit);
229 EXPECT_GE(footprint, amount_allocated);
230 EXPECT_LE(footprint, growth_limit);
231 EXPECT_GE(space->Size(), amount_allocated);
232 EXPECT_LE(space->Size(), growth_limit);
233
234 if (free_increment == 0) {
235 break;
236 }
237
238 // Free some objects
239 for(size_t i = 0; i < last_object; i += free_increment) {
240 Object* object = lots_of_objects.get()[i];
241 if (object == NULL) {
242 continue;
243 }
244 size_t allocation_size = space->AllocationSize(object);
245 if (object_size > 0) {
246 EXPECT_GE(allocation_size, static_cast<size_t>(object_size));
247 } else {
248 EXPECT_GE(allocation_size, 8u);
249 }
250 space->Free(object);
251 lots_of_objects.get()[i] = NULL;
252 amount_allocated -= allocation_size;
253 footprint = mspace_footprint(mspace);
254 EXPECT_GE(space->Size(), footprint); // invariant
255 }
256
257 free_increment >>= 1;
258 }
259
260 // All memory was released, try a large allocation to check freed memory is being coalesced
261 Object* large_object;
262 size_t three_quarters_space = (growth_limit / 2) + (growth_limit / 4);
263 if (round <= 1) {
264 large_object = space->AllocWithoutGrowth(three_quarters_space);
265 } else {
266 large_object = space->AllocWithGrowth(three_quarters_space);
267 }
268 EXPECT_TRUE(large_object != NULL);
269
270 // Sanity check footprint
271 footprint = mspace_footprint(mspace);
272 EXPECT_LE(footprint, growth_limit);
273 EXPECT_GE(space->Size(), footprint);
274 EXPECT_LE(space->Size(), growth_limit);
275
276 // Clean up
277 space->Free(large_object);
278
279 // Sanity check footprint
280 footprint = mspace_footprint(mspace);
281 EXPECT_LE(footprint, growth_limit);
282 EXPECT_GE(space->Size(), footprint);
283 EXPECT_LE(space->Size(), growth_limit);
284}
285
286void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) {
287 size_t initial_size = 4 * MB;
288 size_t growth_limit = 8 * MB;
289 size_t capacity = 16 * MB;
290 AllocSpace* space(Space::CreateAllocSpace("test", initial_size, growth_limit, capacity, NULL));
291 ASSERT_TRUE(space != NULL);
292
293 // Basic sanity
294 EXPECT_EQ(space->Capacity(), growth_limit);
295 EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity);
296
297 // Make space findable to the heap, will also delete space when runtime is cleaned up
298 Heap::AddSpace(space);
299
300 // In this round we don't allocate with growth and therefore can't grow past the initial size.
301 // This effectively makes the growth_limit the initial_size, so assert this.
302 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 1, initial_size);
303 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 2, growth_limit);
304 // Remove growth limit
305 space->ClearGrowthLimit();
306 EXPECT_EQ(space->Capacity(), capacity);
307 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 3, capacity);
308}
309
310#define TEST_SizeFootPrintGrowthLimitAndTrim(name, size) \
311 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \
312 SizeFootPrintGrowthLimitAndTrimDriver(size); \
313 } \
314 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \
315 SizeFootPrintGrowthLimitAndTrimDriver(-size); \
316 }
317
318// Each size test is its own test so that we get a fresh heap each time
319TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_8B) {
320 SizeFootPrintGrowthLimitAndTrimDriver(8);
321}
322TEST_SizeFootPrintGrowthLimitAndTrim(16B, 16)
323TEST_SizeFootPrintGrowthLimitAndTrim(24B, 24)
324TEST_SizeFootPrintGrowthLimitAndTrim(32B, 32)
325TEST_SizeFootPrintGrowthLimitAndTrim(64B, 64)
326TEST_SizeFootPrintGrowthLimitAndTrim(128B, 128)
327TEST_SizeFootPrintGrowthLimitAndTrim(1KB, 1 * KB)
328TEST_SizeFootPrintGrowthLimitAndTrim(4KB, 4 * KB)
329TEST_SizeFootPrintGrowthLimitAndTrim(1MB, 1 * MB)
330TEST_SizeFootPrintGrowthLimitAndTrim(4MB, 4 * MB)
331TEST_SizeFootPrintGrowthLimitAndTrim(8MB, 8 * MB)
332
Carl Shapiro69759ea2011-07-21 18:13:35 -0700333} // namespace art