1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2020 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 #include "precompiled.hpp" 27 28 #include "memory/metaspace/msArena.hpp" 29 #include "memory/metaspace/msArenaGrowthPolicy.hpp" 30 #include "memory/metaspace/msCommitLimiter.hpp" 31 #include "memory/metaspace/msCounter.hpp" 32 #include "memory/metaspace/msInternalStats.hpp" 33 #include "memory/metaspace/msSettings.hpp" 34 #include "memory/metaspace/msStatistics.hpp" 35 #include "runtime/mutex.hpp" 36 #include "runtime/mutexLocker.hpp" 37 #include "utilities/debug.hpp" 38 #include "utilities/globalDefinitions.hpp" 39 40 //#define LOG_PLEASE 41 #include "metaspaceGtestCommon.hpp" 42 #include "metaspaceGtestContexts.hpp" 43 #include "metaspaceGtestRangeHelpers.hpp" 44 45 using metaspace::ArenaGrowthPolicy; 46 using metaspace::CommitLimiter; 47 using metaspace::InternalStats; 48 using metaspace::MemRangeCounter; 49 using metaspace::MetaspaceArena; 50 using metaspace::SizeAtomicCounter; 51 using metaspace::Settings; 52 using metaspace::ArenaStats; 53 54 // See metaspaceArena.cpp : needed for predicting commit sizes. 55 namespace metaspace { 56 extern size_t get_raw_word_size_for_requested_word_size(size_t net_word_size); 57 } 58 59 class MetaspaceArenaTestHelper { 60 61 MetaspaceGtestContext& _context; 62 63 Mutex* _lock; 64 const ArenaGrowthPolicy* _growth_policy; 65 SizeAtomicCounter _used_words_counter; 66 MetaspaceArena* _arena; 67 68 void initialize(const ArenaGrowthPolicy* growth_policy, const char* name = "gtest-MetaspaceArena") { 69 _growth_policy = growth_policy; 70 _lock = new Mutex(Monitor::native, "gtest-MetaspaceArenaTest-lock", false, Monitor::_safepoint_check_never); 71 // Lock during space creation, since this is what happens in the VM too 72 // (see ClassLoaderData::metaspace_non_null(), which we mimick here). 73 { 74 MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag); 75 _arena = new MetaspaceArena(&_context.cm(), _growth_policy, _lock, &_used_words_counter, name); 76 } 77 DEBUG_ONLY(_arena->verify()); 78 79 } 80 81 public: 82 83 // Create a helper; growth policy for arena is determined by the given spacetype|class tupel 84 MetaspaceArenaTestHelper(MetaspaceGtestContext& helper, 85 Metaspace::MetaspaceType space_type, bool is_class, 86 const char* name = "gtest-MetaspaceArena") 87 :_context(helper) 88 { 89 initialize(ArenaGrowthPolicy::policy_for_space_type(space_type, is_class), name); 90 } 91 92 // Create a helper; growth policy is directly specified 93 MetaspaceArenaTestHelper(MetaspaceGtestContext& helper, const ArenaGrowthPolicy* growth_policy, 94 const char* name = "gtest-MetaspaceArena") 95 :_context(helper) 96 { 97 initialize(growth_policy, name); 98 } 99 100 ~MetaspaceArenaTestHelper() { 101 delete_arena_with_tests(); 102 delete _lock; 103 } 104 105 const CommitLimiter& limiter() const { return _context.commit_limiter(); } 106 MetaspaceArena* arena() const { return _arena; } 107 SizeAtomicCounter& used_words_counter() { return _used_words_counter; } 108 109 // Note: all test functions return void due to gtests limitation that we cannot use ASSERT 110 // in non-void returning tests. 111 112 void delete_arena_with_tests() { 113 if (_arena != NULL) { 114 size_t used_words_before = _used_words_counter.get(); 115 size_t committed_words_before = limiter().committed_words(); 116 DEBUG_ONLY(_arena->verify()); 117 delete _arena; 118 _arena = NULL; 119 size_t used_words_after = _used_words_counter.get(); 120 size_t committed_words_after = limiter().committed_words(); 121 ASSERT_0(used_words_after); 122 if (Settings::uncommit_free_chunks()) { 123 ASSERT_LE(committed_words_after, committed_words_before); 124 } else { 125 ASSERT_EQ(committed_words_after, committed_words_before); 126 } 127 } 128 } 129 130 void usage_numbers_with_test(size_t* p_used, size_t* p_committed, size_t* p_capacity) const { 131 _arena->usage_numbers(p_used, p_committed, p_capacity); 132 if (p_used != NULL) { 133 if (p_committed != NULL) { 134 ASSERT_GE(*p_committed, *p_used); 135 } 136 // Since we own the used words counter, it should reflect our usage number 1:1 137 ASSERT_EQ(_used_words_counter.get(), *p_used); 138 } 139 if (p_committed != NULL && p_capacity != NULL) { 140 ASSERT_GE(*p_capacity, *p_committed); 141 } 142 } 143 144 // Allocate; caller expects success; return pointer in *p_return_value 145 void allocate_from_arena_with_tests_expect_success(MetaWord** p_return_value, size_t word_size) { 146 allocate_from_arena_with_tests(p_return_value, word_size); 147 ASSERT_NOT_NULL(*p_return_value); 148 } 149 150 // Allocate; caller expects success but is not interested in return value 151 void allocate_from_arena_with_tests_expect_success(size_t word_size) { 152 MetaWord* dummy = NULL; 153 allocate_from_arena_with_tests_expect_success(&dummy, word_size); 154 } 155 156 // Allocate; caller expects failure 157 void allocate_from_arena_with_tests_expect_failure(size_t word_size) { 158 MetaWord* dummy = NULL; 159 allocate_from_arena_with_tests(&dummy, word_size); 160 ASSERT_NULL(dummy); 161 } 162 163 // Allocate; it may or may not work; return value in *p_return_value 164 void allocate_from_arena_with_tests(MetaWord** p_return_value, size_t word_size) { 165 166 // Note: usage_numbers walks all chunks in use and counts. 167 size_t used = 0, committed = 0, capacity = 0; 168 usage_numbers_with_test(&used, &committed, &capacity); 169 170 size_t possible_expansion = limiter().possible_expansion_words(); 171 172 MetaWord* p = _arena->allocate(word_size); 173 174 SOMETIMES(DEBUG_ONLY(_arena->verify();)) 175 176 size_t used2 = 0, committed2 = 0, capacity2 = 0; 177 usage_numbers_with_test(&used2, &committed2, &capacity2); 178 179 if (p == NULL) { 180 // Allocation failed. 181 if (Settings::new_chunks_are_fully_committed()) { 182 ASSERT_LT(possible_expansion, MAX_CHUNK_WORD_SIZE); 183 } else { 184 ASSERT_LT(possible_expansion, word_size); 185 } 186 187 ASSERT_EQ(used, used2); 188 ASSERT_EQ(committed, committed2); 189 ASSERT_EQ(capacity, capacity2); 190 } else { 191 // Allocation succeeded. Should be correctly aligned. 192 ASSERT_TRUE(is_aligned(p, sizeof(MetaWord))); 193 // used: may go up or may not (since our request may have been satisfied from the freeblocklist 194 // whose content already counts as used). 195 // committed: may go up, may not 196 // capacity: ditto 197 ASSERT_GE(used2, used); 198 ASSERT_GE(committed2, committed); 199 ASSERT_GE(capacity2, capacity); 200 } 201 202 *p_return_value = p; 203 } 204 205 // Allocate; it may or may not work; but caller does not care for the result value 206 void allocate_from_arena_with_tests(size_t word_size) { 207 MetaWord* dummy = NULL; 208 allocate_from_arena_with_tests(&dummy, word_size); 209 } 210 211 void deallocate_with_tests(MetaWord* p, size_t word_size) { 212 size_t used = 0, committed = 0, capacity = 0; 213 usage_numbers_with_test(&used, &committed, &capacity); 214 215 _arena->deallocate(p, word_size); 216 217 SOMETIMES(DEBUG_ONLY(_arena->verify();)) 218 219 size_t used2 = 0, committed2 = 0, capacity2 = 0; 220 usage_numbers_with_test(&used2, &committed2, &capacity2); 221 222 // Nothing should have changed. Deallocated blocks are added to the free block list 223 // which still counts as used. 224 ASSERT_EQ(used2, used); 225 ASSERT_EQ(committed2, committed); 226 ASSERT_EQ(capacity2, capacity); 227 } 228 229 ArenaStats get_arena_statistics() const { 230 ArenaStats stats; 231 _arena->add_to_statistics(&stats); 232 return stats; 233 } 234 235 // Convenience method to return number of chunks in arena (including current chunk) 236 int get_number_of_chunks() const { 237 return get_arena_statistics().totals()._num; 238 } 239 240 }; 241 242 static void test_basics(size_t commit_limit, bool is_micro) { 243 MetaspaceGtestContext context(commit_limit); 244 MetaspaceArenaTestHelper helper(context, is_micro ? Metaspace::ReflectionMetaspaceType : Metaspace::StandardMetaspaceType, false); 245 246 helper.allocate_from_arena_with_tests(1); 247 helper.allocate_from_arena_with_tests(128); 248 helper.allocate_from_arena_with_tests(128 * K); 249 helper.allocate_from_arena_with_tests(1); 250 helper.allocate_from_arena_with_tests(128); 251 helper.allocate_from_arena_with_tests(128 * K); 252 } 253 254 TEST_VM(metaspace, MetaspaceArena_basics_micro_nolimit) { 255 test_basics(max_uintx, true); 256 } 257 258 TEST_VM(metaspace, MetaspaceArena_basics_micro_limit) { 259 test_basics(256 * K, true); 260 } 261 262 TEST_VM(metaspace, MetaspaceArena_basics_standard_nolimit) { 263 test_basics(max_uintx, false); 264 } 265 266 TEST_VM(metaspace, MetaspaceArena_basics_standard_limit) { 267 test_basics(256 * K, false); 268 } 269 270 // Test chunk enlargement: 271 // A single MetaspaceArena, left undisturbed with place to grow. Slowly fill arena up. 272 // We should see at least some occurrences of chunk-in-place enlargement. 273 static void test_chunk_enlargment_simple(Metaspace::MetaspaceType spacetype, bool is_class) { 274 275 MetaspaceGtestContext context; 276 MetaspaceArenaTestHelper helper(context, (Metaspace::MetaspaceType)spacetype, is_class); 277 278 uint64_t n1 = metaspace::InternalStats::num_chunks_enlarged(); 279 280 size_t allocated = 0; 281 while (allocated <= MAX_CHUNK_WORD_SIZE && 282 metaspace::InternalStats::num_chunks_enlarged() == n1) { 283 size_t s = IntRange(32, 128).random_value(); 284 helper.allocate_from_arena_with_tests_expect_success(s); 285 allocated += metaspace::get_raw_word_size_for_requested_word_size(s); 286 } 287 288 EXPECT_GT(metaspace::InternalStats::num_chunks_enlarged(), n1); 289 290 } 291 292 // Do this test for some of the standard types; don't do it for the boot loader type 293 // since that one starts out with max chunk size so we would not see any enlargement. 294 295 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_standard_c) { 296 test_chunk_enlargment_simple(Metaspace::StandardMetaspaceType, true); 297 } 298 299 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_standard_nc) { 300 test_chunk_enlargment_simple(Metaspace::StandardMetaspaceType, false); 301 } 302 303 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_micro_c) { 304 test_chunk_enlargment_simple(Metaspace::ReflectionMetaspaceType, true); 305 } 306 307 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_micro_nc) { 308 test_chunk_enlargment_simple(Metaspace::ReflectionMetaspaceType, false); 309 } 310 311 // Test chunk enlargement: 312 // A single MetaspaceArena, left undisturbed with place to grow. Slowly fill arena up. 313 // We should see occurrences of chunk-in-place enlargement. 314 // Here, we give it an ideal policy which should enable the initial chunk to grow unmolested 315 // until finish. 316 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_2) { 317 318 if (Settings::use_allocation_guard()) { 319 return; 320 } 321 322 // Note: internally, chunk in-place enlargement is disallowed if growing the chunk 323 // would cause the arena to claim more memory than its growth policy allows. This 324 // is done to prevent the arena to grow too fast. 325 // 326 // In order to test in-place growth here without that restriction I give it an 327 // artificial growth policy which starts out with a tiny chunk size, then balloons 328 // right up to max chunk size. This will cause the initial chunk to be tiny, and 329 // then the arena is able to grow it without violating growth policy. 330 chunklevel_t growth[] = { HIGHEST_CHUNK_LEVEL, ROOT_CHUNK_LEVEL }; 331 ArenaGrowthPolicy growth_policy(growth, 2); 332 333 MetaspaceGtestContext context; 334 MetaspaceArenaTestHelper helper(context, &growth_policy); 335 336 uint64_t n1 = metaspace::InternalStats::num_chunks_enlarged(); 337 338 size_t allocated = 0; 339 while (allocated <= MAX_CHUNK_WORD_SIZE) { 340 size_t s = IntRange(32, 128).random_value(); 341 helper.allocate_from_arena_with_tests_expect_success(s); 342 allocated += metaspace::get_raw_word_size_for_requested_word_size(s); 343 if (allocated <= MAX_CHUNK_WORD_SIZE) { 344 // Chunk should have been enlarged in place 345 ASSERT_EQ(1, helper.get_number_of_chunks()); 346 } else { 347 // Next chunk should have started 348 ASSERT_EQ(2, helper.get_number_of_chunks()); 349 } 350 } 351 352 int times_chunk_were_enlarged = metaspace::InternalStats::num_chunks_enlarged() - n1; 353 LOG("chunk was enlarged %d times.", times_chunk_were_enlarged); 354 355 ASSERT_GT0(times_chunk_were_enlarged); 356 357 } 358 359 // Regression test: Given a single MetaspaceArena, left undisturbed with place to grow, 360 // test that in place enlargement correctly fails if growing the chunk would bring us 361 // beyond the max. size of a chunk. 362 TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_max_chunk_size) { 363 364 if (Settings::use_allocation_guard()) { 365 return; 366 } 367 368 MetaspaceGtestContext context; 369 370 for (size_t first_allocation_size = 1; first_allocation_size <= MAX_CHUNK_WORD_SIZE / 2; first_allocation_size *= 2) { 371 372 MetaspaceArenaTestHelper helper(context, Metaspace::StandardMetaspaceType, false); 373 374 // we allocate first a small amount, then the full amount possible. 375 // The sum of first and second allocation should bring us above root chunk size. 376 // This should work, we should not see any problems, but no chunk enlargement should 377 // happen. 378 int n1 = metaspace::InternalStats::num_chunks_enlarged(); 379 380 helper.allocate_from_arena_with_tests_expect_success(first_allocation_size); 381 EXPECT_EQ(helper.get_number_of_chunks(), 1); 382 383 helper.allocate_from_arena_with_tests_expect_success(MAX_CHUNK_WORD_SIZE - first_allocation_size + 1); 384 EXPECT_EQ(helper.get_number_of_chunks(), 2); 385 386 int times_chunk_were_enlarged = metaspace::InternalStats::num_chunks_enlarged() - n1; 387 LOG("chunk was enlarged %d times.", times_chunk_were_enlarged); 388 389 EXPECT_0(times_chunk_were_enlarged); 390 391 } 392 } 393 394 // Regression test: Given a single MetaspaceArena, left undisturbed with place to grow, 395 // test that in place enlargement correctly fails if growing the chunk would cause more 396 // than doubling its size 397 TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_doubling_chunk_size) { 398 399 if (Settings::use_allocation_guard()) { 400 return; 401 } 402 403 MetaspaceGtestContext context; 404 MetaspaceArenaTestHelper helper(context, Metaspace::StandardMetaspaceType, false); 405 406 int n1 = metaspace::InternalStats::num_chunks_enlarged(); 407 408 helper.allocate_from_arena_with_tests_expect_success(1000); 409 EXPECT_EQ(helper.get_number_of_chunks(), 1); 410 411 helper.allocate_from_arena_with_tests_expect_success(4000); 412 EXPECT_EQ(helper.get_number_of_chunks(), 2); 413 414 int times_chunk_were_enlarged = metaspace::InternalStats::num_chunks_enlarged() - n1; 415 LOG("chunk was enlarged %d times.", times_chunk_were_enlarged); 416 417 EXPECT_0(times_chunk_were_enlarged); 418 419 } 420 421 // Test the MetaspaceArenas' free block list: 422 // Allocate, deallocate, then allocate the same block again. The second allocate should 423 // reuse the deallocated block. 424 TEST_VM(metaspace, MetaspaceArena_deallocate) { 425 if (Settings::use_allocation_guard()) { 426 return; 427 } 428 for (size_t s = 2; s <= MAX_CHUNK_WORD_SIZE; s *= 2) { 429 MetaspaceGtestContext context; 430 MetaspaceArenaTestHelper helper(context, Metaspace::StandardMetaspaceType, false); 431 432 MetaWord* p1 = NULL; 433 helper.allocate_from_arena_with_tests_expect_success(&p1, s); 434 435 size_t used1 = 0, capacity1 = 0; 436 helper.usage_numbers_with_test(&used1, NULL, &capacity1); 437 ASSERT_EQ(used1, s); 438 439 helper.deallocate_with_tests(p1, s); 440 441 size_t used2 = 0, capacity2 = 0; 442 helper.usage_numbers_with_test(&used2, NULL, &capacity2); 443 ASSERT_EQ(used1, used2); 444 ASSERT_EQ(capacity2, capacity2); 445 446 MetaWord* p2 = NULL; 447 helper.allocate_from_arena_with_tests_expect_success(&p2, s); 448 449 size_t used3 = 0, capacity3 = 0; 450 helper.usage_numbers_with_test(&used3, NULL, &capacity3); 451 ASSERT_EQ(used3, used2); 452 ASSERT_EQ(capacity3, capacity2); 453 454 // Actually, we should get the very same allocation back 455 ASSERT_EQ(p1, p2); 456 } 457 } 458 459 static void test_recover_from_commit_limit_hit() { 460 461 if (Settings::new_chunks_are_fully_committed()) { 462 return; // This would throw off the commit counting in this test. 463 } 464 465 // Test: 466 // - Multiple MetaspaceArena allocate (operating under the same commit limiter). 467 // - One, while attempting to commit parts of its current chunk on demand, 468 // triggers the limit and cannot commit its chunk further. 469 // - We release the other MetaspaceArena - its content is put back to the 470 // freelists. 471 // - We re-attempt allocation from the first manager. It should now succeed. 472 // 473 // This means if the first MetaspaceArena may have to let go of its current chunk and 474 // retire it and take a fresh chunk from the freelist. 475 476 const size_t commit_limit = Settings::commit_granule_words() * 10; 477 MetaspaceGtestContext context(commit_limit); 478 479 // The first MetaspaceArena mimicks a micro loader. This will fill the free 480 // chunk list with very small chunks. We allocate from them in an interleaved 481 // way to cause fragmentation. 482 MetaspaceArenaTestHelper helper1(context, Metaspace::ReflectionMetaspaceType, false); 483 MetaspaceArenaTestHelper helper2(context, Metaspace::ReflectionMetaspaceType, false); 484 485 // This MetaspaceArena should hit the limit. We use BootMetaspaceType here since 486 // it gets a large initial chunk which is committed 487 // on demand and we are likely to hit a commit limit while trying to expand it. 488 MetaspaceArenaTestHelper helper3(context, Metaspace::BootMetaspaceType, false); 489 490 // Allocate space until we have below two but above one granule left 491 size_t allocated_from_1_and_2 = 0; 492 while (context.commit_limiter().possible_expansion_words() >= Settings::commit_granule_words() * 2 && 493 allocated_from_1_and_2 < commit_limit) { 494 helper1.allocate_from_arena_with_tests_expect_success(1); 495 helper2.allocate_from_arena_with_tests_expect_success(1); 496 allocated_from_1_and_2 += 2; 497 } 498 499 // Now, allocating from helper3, creep up on the limit 500 size_t allocated_from_3 = 0; 501 MetaWord* p = NULL; 502 while ( (helper3.allocate_from_arena_with_tests(&p, 1), p != NULL) && 503 ++allocated_from_3 < Settings::commit_granule_words() * 2); 504 505 EXPECT_LE(allocated_from_3, Settings::commit_granule_words() * 2); 506 507 // We expect the freelist to be empty of committed space... 508 EXPECT_0(context.cm().total_committed_word_size()); 509 510 //msthelper.cm().print_on(tty); 511 512 // Release the first MetaspaceArena. 513 helper1.delete_arena_with_tests(); 514 515 //msthelper.cm().print_on(tty); 516 517 // Should have populated the freelist with committed space 518 // We expect the freelist to be empty of committed space... 519 EXPECT_GT(context.cm().total_committed_word_size(), (size_t)0); 520 521 // Repeat allocation from helper3, should now work. 522 helper3.allocate_from_arena_with_tests_expect_success(1); 523 524 } 525 526 TEST_VM(metaspace, MetaspaceArena_recover_from_limit_hit) { 527 test_recover_from_commit_limit_hit(); 528 } 529 530 static void test_controlled_growth(Metaspace::MetaspaceType type, bool is_class, 531 size_t expected_starting_capacity, 532 bool test_in_place_enlargement) 533 { 534 535 if (Settings::use_allocation_guard()) { 536 return; 537 } 538 539 // From a MetaspaceArena in a clean room allocate tiny amounts; 540 // watch it grow. Used/committed/capacity should not grow in 541 // large jumps. Also, different types of MetaspaceArena should 542 // have different initial capacities. 543 544 MetaspaceGtestContext context; 545 MetaspaceArenaTestHelper smhelper(context, type, is_class, "Grower"); 546 547 MetaspaceArenaTestHelper smhelper_harrasser(context, Metaspace::ReflectionMetaspaceType, true, "Harasser"); 548 549 size_t used = 0, committed = 0, capacity = 0; 550 const size_t alloc_words = 16; 551 552 smhelper.arena()->usage_numbers(&used, &committed, &capacity); 553 ASSERT_0(used); 554 ASSERT_0(committed); 555 ASSERT_0(capacity); 556 557 ///// First allocation // 558 559 smhelper.allocate_from_arena_with_tests_expect_success(alloc_words); 560 561 smhelper.arena()->usage_numbers(&used, &committed, &capacity); 562 563 ASSERT_EQ(used, alloc_words); 564 ASSERT_GE(committed, used); 565 ASSERT_GE(capacity, committed); 566 567 ASSERT_EQ(capacity, expected_starting_capacity); 568 569 if (!(Settings::new_chunks_are_fully_committed() && type == Metaspace::BootMetaspaceType)) { 570 // Initial commit charge for the whole context should be one granule 571 ASSERT_EQ(context.committed_words(), Settings::commit_granule_words()); 572 // Initial commit number for the arena should be less since - apart from boot loader - no 573 // space type has large initial chunks. 574 ASSERT_LE(committed, Settings::commit_granule_words()); 575 } 576 577 ///// subsequent allocations // 578 579 DEBUG_ONLY(const uintx num_chunk_enlarged = metaspace::InternalStats::num_chunks_enlarged();) 580 581 size_t words_allocated = 0; 582 int num_allocated = 0; 583 const size_t safety = MAX_CHUNK_WORD_SIZE * 1.2; 584 size_t highest_capacity_jump = capacity; 585 int num_capacity_jumps = 0; 586 587 while (words_allocated < safety && num_capacity_jumps < 15) { 588 589 // if we want to test growth with in-place chunk enlargement, leave MetaspaceArena 590 // undisturbed; it will have all the place to grow. Otherwise allocate from a little 591 // side arena to increase fragmentation. 592 // (Note that this does not completely prevent in-place chunk enlargement but makes it 593 // rather improbable) 594 if (!test_in_place_enlargement) { 595 smhelper_harrasser.allocate_from_arena_with_tests_expect_success(alloc_words * 2); 596 } 597 598 smhelper.allocate_from_arena_with_tests_expect_success(alloc_words); 599 words_allocated += metaspace::get_raw_word_size_for_requested_word_size(alloc_words); 600 num_allocated++; 601 602 size_t used2 = 0, committed2 = 0, capacity2 = 0; 603 604 smhelper.arena()->usage_numbers(&used2, &committed2, &capacity2); 605 606 // used should not grow larger than what we allocated, plus possible overhead. 607 ASSERT_GE(used2, used); 608 ASSERT_LE(used2, used + alloc_words * 2); 609 ASSERT_LE(used2, words_allocated + 100); 610 used = used2; 611 612 // A jump in committed words should not be larger than commit granule size. 613 // It can be smaller, since the current chunk of the MetaspaceArena may be 614 // smaller than a commit granule. 615 // (Note: unless root chunks are born fully committed) 616 ASSERT_GE(committed2, used2); 617 ASSERT_GE(committed2, committed); 618 const size_t committed_jump = committed2 - committed; 619 if (committed_jump > 0 && !Settings::new_chunks_are_fully_committed()) { 620 ASSERT_LE(committed_jump, Settings::commit_granule_words()); 621 } 622 committed = committed2; 623 624 // Capacity jumps: Test that arenas capacity does not grow too fast. 625 ASSERT_GE(capacity2, committed2); 626 ASSERT_GE(capacity2, capacity); 627 const size_t capacity_jump = capacity2 - capacity; 628 if (capacity_jump > 0) { 629 LOG(">" SIZE_FORMAT "->" SIZE_FORMAT "(+" SIZE_FORMAT ")", capacity, capacity2, capacity_jump) 630 if (capacity_jump > highest_capacity_jump) { 631 /* Disabled for now since this is rather shaky. The way it is tested makes it too dependent 632 * on allocation history. Need to rethink this. 633 ASSERT_LE(capacity_jump, highest_capacity_jump * 2); 634 ASSERT_GE(capacity_jump, MIN_CHUNK_WORD_SIZE); 635 ASSERT_LE(capacity_jump, MAX_CHUNK_WORD_SIZE); 636 */ 637 highest_capacity_jump = capacity_jump; 638 } 639 num_capacity_jumps++; 640 } 641 642 capacity = capacity2; 643 644 } 645 646 // After all this work, we should see an increase in number of chunk-in-place-enlargements 647 // (this especially is vulnerable to regression: the decisions of when to do in-place-enlargements are somewhat 648 // complicated, see MetaspaceArena::attempt_enlarge_current_chunk()) 649 #ifdef ASSERT 650 if (test_in_place_enlargement) { 651 const uintx num_chunk_enlarged_2 = metaspace::InternalStats::num_chunks_enlarged(); 652 ASSERT_GT(num_chunk_enlarged_2, num_chunk_enlarged); 653 } 654 #endif 655 } 656 657 // these numbers have to be in sync with arena policy numbers (see memory/metaspace/arenaGrowthPolicy.cpp) 658 TEST_VM(metaspace, MetaspaceArena_growth_refl_c_inplace) { 659 test_controlled_growth(Metaspace::ReflectionMetaspaceType, true, 660 word_size_for_level(CHUNK_LEVEL_1K), true); 661 } 662 663 TEST_VM(metaspace, MetaspaceArena_growth_refl_c_not_inplace) { 664 test_controlled_growth(Metaspace::ReflectionMetaspaceType, true, 665 word_size_for_level(CHUNK_LEVEL_1K), false); 666 } 667 668 TEST_VM(metaspace, MetaspaceArena_growth_anon_c_inplace) { 669 test_controlled_growth(Metaspace::ClassMirrorHolderMetaspaceType, true, 670 word_size_for_level(CHUNK_LEVEL_1K), true); 671 } 672 673 TEST_VM(metaspace, MetaspaceArena_growth_anon_c_not_inplace) { 674 test_controlled_growth(Metaspace::ClassMirrorHolderMetaspaceType, true, 675 word_size_for_level(CHUNK_LEVEL_1K), false); 676 } 677 678 TEST_VM(metaspace, MetaspaceArena_growth_standard_c_inplace) { 679 test_controlled_growth(Metaspace::StandardMetaspaceType, true, 680 word_size_for_level(CHUNK_LEVEL_2K), true); 681 } 682 683 TEST_VM(metaspace, MetaspaceArena_growth_standard_c_not_inplace) { 684 test_controlled_growth(Metaspace::StandardMetaspaceType, true, 685 word_size_for_level(CHUNK_LEVEL_2K), false); 686 } 687 688 /* Disabled growth tests for BootMetaspaceType: there, the growth steps are too rare, 689 * and too large, to make any reliable guess as toward chunks get enlarged in place. 690 TEST_VM(metaspace, MetaspaceArena_growth_boot_c_inplace) { 691 test_controlled_growth(Metaspace::BootMetaspaceType, true, 692 word_size_for_level(CHUNK_LEVEL_1M), true); 693 } 694 695 TEST_VM(metaspace, MetaspaceArena_growth_boot_c_not_inplace) { 696 test_controlled_growth(Metaspace::BootMetaspaceType, true, 697 word_size_for_level(CHUNK_LEVEL_1M), false); 698 } 699 */ 700 701 TEST_VM(metaspace, MetaspaceArena_growth_refl_nc_inplace) { 702 test_controlled_growth(Metaspace::ReflectionMetaspaceType, false, 703 word_size_for_level(CHUNK_LEVEL_2K), true); 704 } 705 706 TEST_VM(metaspace, MetaspaceArena_growth_refl_nc_not_inplace) { 707 test_controlled_growth(Metaspace::ReflectionMetaspaceType, false, 708 word_size_for_level(CHUNK_LEVEL_2K), false); 709 } 710 711 TEST_VM(metaspace, MetaspaceArena_growth_anon_nc_inplace) { 712 test_controlled_growth(Metaspace::ClassMirrorHolderMetaspaceType, false, 713 word_size_for_level(CHUNK_LEVEL_1K), true); 714 } 715 716 TEST_VM(metaspace, MetaspaceArena_growth_anon_nc_not_inplace) { 717 test_controlled_growth(Metaspace::ClassMirrorHolderMetaspaceType, false, 718 word_size_for_level(CHUNK_LEVEL_1K), false); 719 } 720 721 TEST_VM(metaspace, MetaspaceArena_growth_standard_nc_inplace) { 722 test_controlled_growth(Metaspace::StandardMetaspaceType, false, 723 word_size_for_level(CHUNK_LEVEL_4K), true); 724 } 725 726 TEST_VM(metaspace, MetaspaceArena_growth_standard_nc_not_inplace) { 727 test_controlled_growth(Metaspace::StandardMetaspaceType, false, 728 word_size_for_level(CHUNK_LEVEL_4K), false); 729 } 730 731 /* Disabled growth tests for BootMetaspaceType: there, the growth steps are too rare, 732 * and too large, to make any reliable guess as toward chunks get enlarged in place. 733 TEST_VM(metaspace, MetaspaceArena_growth_boot_nc_inplace) { 734 test_controlled_growth(Metaspace::BootMetaspaceType, false, 735 word_size_for_level(CHUNK_LEVEL_4M), true); 736 } 737 738 TEST_VM(metaspace, MetaspaceArena_growth_boot_nc_not_inplace) { 739 test_controlled_growth(Metaspace::BootMetaspaceType, false, 740 word_size_for_level(CHUNK_LEVEL_4M), false); 741 } 742 */