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