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 */