1 /* 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 */ 16 17 #include "dlmalloc_space.h" 18 #include "large_object_space.h" 19 20 #include "common_test.h" 21 #include "globals.h" 22 #include "UniquePtr.h" 23 24 #include <stdint.h> 25 26 namespace art { 27 namespace gc { 28 namespace space { 29 30 class SpaceTest : public CommonTest { 31 public: 32 void SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size, 33 int round, size_t growth_limit); 34 void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size); 35 36 void AddContinuousSpace(ContinuousSpace* space) { 37 Runtime::Current()->GetHeap()->AddContinuousSpace(space); 38 } 39 }; 40 41 static size_t test_rand(size_t* seed) { 42 *seed = *seed * 1103515245 + 12345; 43 return *seed; 44 } 45 46 TEST_F(SpaceTest, Init) { 47 { 48 // Init < max == growth 49 UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 32 * MB, 32 * MB, NULL)); 50 EXPECT_TRUE(space.get() != NULL); 51 } 52 { 53 // Init == max == growth 54 UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 16 * MB, NULL)); 55 EXPECT_TRUE(space.get() != NULL); 56 } 57 { 58 // Init > max == growth 59 UniquePtr<Space> space(DlMallocSpace::Create("test", 32 * MB, 16 * MB, 16 * MB, NULL)); 60 EXPECT_TRUE(space.get() == NULL); 61 } 62 { 63 // Growth == init < max 64 UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 32 * MB, NULL)); 65 EXPECT_TRUE(space.get() != NULL); 66 } 67 { 68 // Growth < init < max 69 UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 8 * MB, 32 * MB, NULL)); 70 EXPECT_TRUE(space.get() == NULL); 71 } 72 { 73 // Init < growth < max 74 UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 16 * MB, 32 * MB, NULL)); 75 EXPECT_TRUE(space.get() != NULL); 76 } 77 { 78 // Init < max < growth 79 UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 32 * MB, 16 * MB, NULL)); 80 EXPECT_TRUE(space.get() == NULL); 81 } 82 } 83 84 // TODO: This test is not very good, we should improve it. 85 // The test should do more allocations before the creation of the ZygoteSpace, and then do 86 // allocations after the ZygoteSpace is created. The test should also do some GCs to ensure that 87 // the GC works with the ZygoteSpace. 88 TEST_F(SpaceTest, ZygoteSpace) { 89 size_t dummy = 0; 90 DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL)); 91 ASSERT_TRUE(space != NULL); 92 93 // Make space findable to the heap, will also delete space when runtime is cleaned up 94 AddContinuousSpace(space); 95 Thread* self = Thread::Current(); 96 97 // Succeeds, fits without adjusting the footprint limit. 98 mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy); 99 EXPECT_TRUE(ptr1 != NULL); 100 101 // Fails, requires a higher footprint limit. 102 mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy); 103 EXPECT_TRUE(ptr2 == NULL); 104 105 // Succeeds, adjusts the footprint. 106 size_t ptr3_bytes_allocated; 107 mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated); 108 EXPECT_TRUE(ptr3 != NULL); 109 EXPECT_LE(8U * MB, ptr3_bytes_allocated); 110 111 // Fails, requires a higher footprint limit. 112 mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy); 113 EXPECT_TRUE(ptr4 == NULL); 114 115 // Also fails, requires a higher allowed footprint. 116 mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy); 117 EXPECT_TRUE(ptr5 == NULL); 118 119 // Release some memory. 120 size_t free3 = space->AllocationSize(ptr3); 121 EXPECT_EQ(free3, ptr3_bytes_allocated); 122 EXPECT_EQ(free3, space->Free(self, ptr3)); 123 EXPECT_LE(8U * MB, free3); 124 125 // Succeeds, now that memory has been freed. 126 void* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy); 127 EXPECT_TRUE(ptr6 != NULL); 128 129 // Final clean up. 130 size_t free1 = space->AllocationSize(ptr1); 131 space->Free(self, ptr1); 132 EXPECT_LE(1U * MB, free1); 133 134 // Make sure that the zygote space isn't directly at the start of the space. 135 space->Alloc(self, 1U * MB, &dummy); 136 space = space->CreateZygoteSpace("alloc space"); 137 138 // Make space findable to the heap, will also delete space when runtime is cleaned up 139 AddContinuousSpace(space); 140 141 // Succeeds, fits without adjusting the footprint limit. 142 ptr1 = space->Alloc(self, 1 * MB, &dummy); 143 EXPECT_TRUE(ptr1 != NULL); 144 145 // Fails, requires a higher footprint limit. 146 ptr2 = space->Alloc(self, 8 * MB, &dummy); 147 EXPECT_TRUE(ptr2 == NULL); 148 149 // Succeeds, adjusts the footprint. 150 ptr3 = space->AllocWithGrowth(self, 2 * MB, &dummy); 151 EXPECT_TRUE(ptr3 != NULL); 152 space->Free(self, ptr3); 153 154 // Final clean up. 155 free1 = space->AllocationSize(ptr1); 156 space->Free(self, ptr1); 157 EXPECT_LE(1U * MB, free1); 158 } 159 160 TEST_F(SpaceTest, AllocAndFree) { 161 size_t dummy = 0; 162 DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL)); 163 ASSERT_TRUE(space != NULL); 164 Thread* self = Thread::Current(); 165 166 // Make space findable to the heap, will also delete space when runtime is cleaned up 167 AddContinuousSpace(space); 168 169 // Succeeds, fits without adjusting the footprint limit. 170 mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy); 171 EXPECT_TRUE(ptr1 != NULL); 172 173 // Fails, requires a higher footprint limit. 174 mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy); 175 EXPECT_TRUE(ptr2 == NULL); 176 177 // Succeeds, adjusts the footprint. 178 size_t ptr3_bytes_allocated; 179 mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated); 180 EXPECT_TRUE(ptr3 != NULL); 181 EXPECT_LE(8U * MB, ptr3_bytes_allocated); 182 183 // Fails, requires a higher footprint limit. 184 mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy); 185 EXPECT_TRUE(ptr4 == NULL); 186 187 // Also fails, requires a higher allowed footprint. 188 mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy); 189 EXPECT_TRUE(ptr5 == NULL); 190 191 // Release some memory. 192 size_t free3 = space->AllocationSize(ptr3); 193 EXPECT_EQ(free3, ptr3_bytes_allocated); 194 space->Free(self, ptr3); 195 EXPECT_LE(8U * MB, free3); 196 197 // Succeeds, now that memory has been freed. 198 void* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy); 199 EXPECT_TRUE(ptr6 != NULL); 200 201 // Final clean up. 202 size_t free1 = space->AllocationSize(ptr1); 203 space->Free(self, ptr1); 204 EXPECT_LE(1U * MB, free1); 205 } 206 207 TEST_F(SpaceTest, LargeObjectTest) { 208 size_t rand_seed = 0; 209 for (size_t i = 0; i < 2; ++i) { 210 LargeObjectSpace* los = NULL; 211 if (i == 0) { 212 los = space::LargeObjectMapSpace::Create("large object space"); 213 } else { 214 los = space::FreeListSpace::Create("large object space", NULL, 128 * MB); 215 } 216 217 static const size_t num_allocations = 64; 218 static const size_t max_allocation_size = 0x100000; 219 std::vector<std::pair<mirror::Object*, size_t> > requests; 220 221 for (size_t phase = 0; phase < 2; ++phase) { 222 while (requests.size() < num_allocations) { 223 size_t request_size = test_rand(&rand_seed) % max_allocation_size; 224 size_t allocation_size = 0; 225 mirror::Object* obj = los->Alloc(Thread::Current(), request_size, &allocation_size); 226 ASSERT_TRUE(obj != NULL); 227 ASSERT_EQ(allocation_size, los->AllocationSize(obj)); 228 ASSERT_GE(allocation_size, request_size); 229 // Fill in our magic value. 230 byte magic = (request_size & 0xFF) | 1; 231 memset(obj, magic, request_size); 232 requests.push_back(std::make_pair(obj, request_size)); 233 } 234 235 // "Randomly" shuffle the requests. 236 for (size_t k = 0; k < 10; ++k) { 237 for (size_t j = 0; j < requests.size(); ++j) { 238 std::swap(requests[j], requests[test_rand(&rand_seed) % requests.size()]); 239 } 240 } 241 242 // Free 1 / 2 the allocations the first phase, and all the second phase. 243 size_t limit = !phase ? requests.size() / 2 : 0; 244 while (requests.size() > limit) { 245 mirror::Object* obj = requests.back().first; 246 size_t request_size = requests.back().second; 247 requests.pop_back(); 248 byte magic = (request_size & 0xFF) | 1; 249 for (size_t k = 0; k < request_size; ++k) { 250 ASSERT_EQ(reinterpret_cast<const byte*>(obj)[k], magic); 251 } 252 ASSERT_GE(los->Free(Thread::Current(), obj), request_size); 253 } 254 } 255 256 size_t bytes_allocated = 0; 257 // Checks that the coalescing works. 258 mirror::Object* obj = los->Alloc(Thread::Current(), 100 * MB, &bytes_allocated); 259 EXPECT_TRUE(obj != NULL); 260 los->Free(Thread::Current(), obj); 261 262 EXPECT_EQ(0U, los->GetBytesAllocated()); 263 EXPECT_EQ(0U, los->GetObjectsAllocated()); 264 delete los; 265 } 266 } 267 268 TEST_F(SpaceTest, AllocAndFreeList) { 269 DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL)); 270 ASSERT_TRUE(space != NULL); 271 272 // Make space findable to the heap, will also delete space when runtime is cleaned up 273 AddContinuousSpace(space); 274 Thread* self = Thread::Current(); 275 276 // Succeeds, fits without adjusting the max allowed footprint. 277 mirror::Object* lots_of_objects[1024]; 278 for (size_t i = 0; i < arraysize(lots_of_objects); i++) { 279 size_t allocation_size = 0; 280 lots_of_objects[i] = space->Alloc(self, 16, &allocation_size); 281 EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i])); 282 EXPECT_TRUE(lots_of_objects[i] != NULL); 283 } 284 285 // Release memory and check pointers are NULL 286 space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); 287 for (size_t i = 0; i < arraysize(lots_of_objects); i++) { 288 EXPECT_TRUE(lots_of_objects[i] == NULL); 289 } 290 291 // Succeeds, fits by adjusting the max allowed footprint. 292 for (size_t i = 0; i < arraysize(lots_of_objects); i++) { 293 size_t allocation_size = 0; 294 lots_of_objects[i] = space->AllocWithGrowth(self, 1024, &allocation_size); 295 EXPECT_EQ(allocation_size, space->AllocationSize(lots_of_objects[i])); 296 EXPECT_TRUE(lots_of_objects[i] != NULL); 297 } 298 299 // Release memory and check pointers are NULL 300 space->FreeList(self, arraysize(lots_of_objects), lots_of_objects); 301 for (size_t i = 0; i < arraysize(lots_of_objects); i++) { 302 EXPECT_TRUE(lots_of_objects[i] == NULL); 303 } 304 } 305 306 void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size, 307 int round, size_t growth_limit) { 308 if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) || 309 ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) { 310 // No allocation can succeed 311 return; 312 } 313 // Mspace for raw dlmalloc operations 314 void* mspace = space->GetMspace(); 315 316 // mspace's footprint equals amount of resources requested from system 317 size_t footprint = mspace_footprint(mspace); 318 319 // mspace must at least have its book keeping allocated 320 EXPECT_GT(footprint, 0u); 321 322 // mspace but it shouldn't exceed the initial size 323 EXPECT_LE(footprint, growth_limit); 324 325 // space's size shouldn't exceed the initial size 326 EXPECT_LE(space->Size(), growth_limit); 327 328 // this invariant should always hold or else the mspace has grown to be larger than what the 329 // space believes its size is (which will break invariants) 330 EXPECT_GE(space->Size(), footprint); 331 332 // Fill the space with lots of small objects up to the growth limit 333 size_t max_objects = (growth_limit / (object_size > 0 ? object_size : 8)) + 1; 334 UniquePtr<mirror::Object*[]> lots_of_objects(new mirror::Object*[max_objects]); 335 size_t last_object = 0; // last object for which allocation succeeded 336 size_t amount_allocated = 0; // amount of space allocated 337 Thread* self = Thread::Current(); 338 size_t rand_seed = 123456789; 339 for (size_t i = 0; i < max_objects; i++) { 340 size_t alloc_fails = 0; // number of failed allocations 341 size_t max_fails = 30; // number of times we fail allocation before giving up 342 for (; alloc_fails < max_fails; alloc_fails++) { 343 size_t alloc_size; 344 if (object_size > 0) { 345 alloc_size = object_size; 346 } else { 347 alloc_size = test_rand(&rand_seed) % static_cast<size_t>(-object_size); 348 if (alloc_size < 8) { 349 alloc_size = 8; 350 } 351 } 352 mirror::Object* object; 353 size_t bytes_allocated = 0; 354 if (round <= 1) { 355 object = space->Alloc(self, alloc_size, &bytes_allocated); 356 } else { 357 object = space->AllocWithGrowth(self, alloc_size, &bytes_allocated); 358 } 359 footprint = mspace_footprint(mspace); 360 EXPECT_GE(space->Size(), footprint); // invariant 361 if (object != NULL) { // allocation succeeded 362 lots_of_objects.get()[i] = object; 363 size_t allocation_size = space->AllocationSize(object); 364 EXPECT_EQ(bytes_allocated, allocation_size); 365 if (object_size > 0) { 366 EXPECT_GE(allocation_size, static_cast<size_t>(object_size)); 367 } else { 368 EXPECT_GE(allocation_size, 8u); 369 } 370 amount_allocated += allocation_size; 371 break; 372 } 373 } 374 if (alloc_fails == max_fails) { 375 last_object = i; 376 break; 377 } 378 } 379 CHECK_NE(last_object, 0u); // we should have filled the space 380 EXPECT_GT(amount_allocated, 0u); 381 382 // We shouldn't have gone past the growth_limit 383 EXPECT_LE(amount_allocated, growth_limit); 384 EXPECT_LE(footprint, growth_limit); 385 EXPECT_LE(space->Size(), growth_limit); 386 387 // footprint and size should agree with amount allocated 388 EXPECT_GE(footprint, amount_allocated); 389 EXPECT_GE(space->Size(), amount_allocated); 390 391 // Release storage in a semi-adhoc manner 392 size_t free_increment = 96; 393 while (true) { 394 // Give the space a haircut 395 space->Trim(); 396 397 // Bounds sanity 398 footprint = mspace_footprint(mspace); 399 EXPECT_LE(amount_allocated, growth_limit); 400 EXPECT_GE(footprint, amount_allocated); 401 EXPECT_LE(footprint, growth_limit); 402 EXPECT_GE(space->Size(), amount_allocated); 403 EXPECT_LE(space->Size(), growth_limit); 404 405 if (free_increment == 0) { 406 break; 407 } 408 409 // Free some objects 410 for (size_t i = 0; i < last_object; i += free_increment) { 411 mirror::Object* object = lots_of_objects.get()[i]; 412 if (object == NULL) { 413 continue; 414 } 415 size_t allocation_size = space->AllocationSize(object); 416 if (object_size > 0) { 417 EXPECT_GE(allocation_size, static_cast<size_t>(object_size)); 418 } else { 419 EXPECT_GE(allocation_size, 8u); 420 } 421 space->Free(self, object); 422 lots_of_objects.get()[i] = NULL; 423 amount_allocated -= allocation_size; 424 footprint = mspace_footprint(mspace); 425 EXPECT_GE(space->Size(), footprint); // invariant 426 } 427 428 free_increment >>= 1; 429 } 430 431 // All memory was released, try a large allocation to check freed memory is being coalesced 432 mirror::Object* large_object; 433 size_t three_quarters_space = (growth_limit / 2) + (growth_limit / 4); 434 size_t bytes_allocated = 0; 435 if (round <= 1) { 436 large_object = space->Alloc(self, three_quarters_space, &bytes_allocated); 437 } else { 438 large_object = space->AllocWithGrowth(self, three_quarters_space, &bytes_allocated); 439 } 440 EXPECT_TRUE(large_object != NULL); 441 442 // Sanity check footprint 443 footprint = mspace_footprint(mspace); 444 EXPECT_LE(footprint, growth_limit); 445 EXPECT_GE(space->Size(), footprint); 446 EXPECT_LE(space->Size(), growth_limit); 447 448 // Clean up 449 space->Free(self, large_object); 450 451 // Sanity check footprint 452 footprint = mspace_footprint(mspace); 453 EXPECT_LE(footprint, growth_limit); 454 EXPECT_GE(space->Size(), footprint); 455 EXPECT_LE(space->Size(), growth_limit); 456 } 457 458 void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) { 459 size_t initial_size = 4 * MB; 460 size_t growth_limit = 8 * MB; 461 size_t capacity = 16 * MB; 462 DlMallocSpace* space(DlMallocSpace::Create("test", initial_size, growth_limit, capacity, NULL)); 463 ASSERT_TRUE(space != NULL); 464 465 // Basic sanity 466 EXPECT_EQ(space->Capacity(), growth_limit); 467 EXPECT_EQ(space->NonGrowthLimitCapacity(), capacity); 468 469 // Make space findable to the heap, will also delete space when runtime is cleaned up 470 AddContinuousSpace(space); 471 472 // In this round we don't allocate with growth and therefore can't grow past the initial size. 473 // This effectively makes the growth_limit the initial_size, so assert this. 474 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 1, initial_size); 475 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 2, growth_limit); 476 // Remove growth limit 477 space->ClearGrowthLimit(); 478 EXPECT_EQ(space->Capacity(), capacity); 479 SizeFootPrintGrowthLimitAndTrimBody(space, object_size, 3, capacity); 480 } 481 482 #define TEST_SizeFootPrintGrowthLimitAndTrim(name, size) \ 483 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \ 484 SizeFootPrintGrowthLimitAndTrimDriver(size); \ 485 } \ 486 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \ 487 SizeFootPrintGrowthLimitAndTrimDriver(-size); \ 488 } 489 490 // Each size test is its own test so that we get a fresh heap each time 491 TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_8B) { 492 SizeFootPrintGrowthLimitAndTrimDriver(8); 493 } 494 TEST_SizeFootPrintGrowthLimitAndTrim(16B, 16) 495 TEST_SizeFootPrintGrowthLimitAndTrim(24B, 24) 496 TEST_SizeFootPrintGrowthLimitAndTrim(32B, 32) 497 TEST_SizeFootPrintGrowthLimitAndTrim(64B, 64) 498 TEST_SizeFootPrintGrowthLimitAndTrim(128B, 128) 499 TEST_SizeFootPrintGrowthLimitAndTrim(1KB, 1 * KB) 500 TEST_SizeFootPrintGrowthLimitAndTrim(4KB, 4 * KB) 501 TEST_SizeFootPrintGrowthLimitAndTrim(1MB, 1 * MB) 502 TEST_SizeFootPrintGrowthLimitAndTrim(4MB, 4 * MB) 503 TEST_SizeFootPrintGrowthLimitAndTrim(8MB, 8 * MB) 504 505 } // namespace space 506 } // namespace gc 507 } // namespace art 508