< prev index next >

test/hotspot/gtest/metaspace/test_metaspacearena.cpp

Print this page

 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 
 67   void initialize(const ArenaGrowthPolicy* growth_policy, const char* name = "gtest-MetaspaceArena") {

 68     _growth_policy = growth_policy;
 69     _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTest_lock");
 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
 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
 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 
 99   ~MetaspaceArenaTestHelper() {
100     delete_arena_with_tests();
101     delete _lock;
102   }
103 
104   const CommitLimiter& limiter() const { return _context.commit_limiter(); }
105   MetaspaceArena* arena() const { return _arena; }
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 
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;

264 
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.
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 
294 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_standard_c) {
295   test_chunk_enlargment_simple(Metaspace::StandardMetaspaceType, true);
296 }
297 
298 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_standard_nc) {
299   test_chunk_enlargment_simple(Metaspace::StandardMetaspaceType, false);
300 }
301 
302 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_micro_c) {
303   test_chunk_enlargment_simple(Metaspace::ReflectionMetaspaceType, true);
304 }

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.
361 TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_max_chunk_size) {

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()) {

 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/metaspaceAlignment.hpp"
 31 #include "memory/metaspace/metaspaceArena.hpp"
 32 #include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp"
 33 #include "memory/metaspace/metaspaceSettings.hpp"
 34 #include "memory/metaspace/metaspaceStatistics.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 class MetaspaceArenaTestHelper {
 55 
 56   MetaspaceGtestContext& _context;
 57 
 58   Mutex* _lock;
 59   const ArenaGrowthPolicy* _growth_policy;
 60   SizeAtomicCounter _used_words_counter;
 61   int _alignment_words;
 62   MetaspaceArena* _arena;
 63 
 64   void initialize(const ArenaGrowthPolicy* growth_policy, int alignment_words,
 65                   const char* name = "gtest-MetaspaceArena") {
 66     _growth_policy = growth_policy;
 67     _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTest_lock");
 68     // Lock during space creation, since this is what happens in the VM too
 69     //  (see ClassLoaderData::metaspace_non_null(), which we mimick here).
 70     {
 71       MutexLocker ml(_lock,  Mutex::_no_safepoint_check_flag);
 72       _arena = new MetaspaceArena(&_context.cm(), _growth_policy, alignment_words, _lock, &_used_words_counter, name);
 73     }
 74     DEBUG_ONLY(_arena->verify());
 75 
 76   }
 77 
 78 public:
 79 
 80   // Create a helper; growth policy for arena is determined by the given spacetype|class tupel
 81   MetaspaceArenaTestHelper(MetaspaceGtestContext& helper,
 82                             Metaspace::MetaspaceType space_type, bool is_class,
 83                             const char* name = "gtest-MetaspaceArena") :
 84     _context(helper)
 85   {
 86     initialize(ArenaGrowthPolicy::policy_for_space_type(space_type, is_class), metaspace::MetaspaceMinAlignmentWords, name);
 87   }
 88 
 89   // Create a helper; growth policy is directly specified
 90   MetaspaceArenaTestHelper(MetaspaceGtestContext& helper, const ArenaGrowthPolicy* growth_policy,
 91                            const char* name = "gtest-MetaspaceArena") :
 92     _context(helper)
 93   {
 94     initialize(growth_policy, metaspace::MetaspaceMinAlignmentWords, name);
 95   }
 96 
 97   ~MetaspaceArenaTestHelper() {
 98     delete_arena_with_tests();
 99     delete _lock;
100   }
101 
102   const CommitLimiter& limiter() const { return _context.commit_limiter(); }
103   MetaspaceArena* arena() const { return _arena; }
104   SizeAtomicCounter& used_words_counter() { return _used_words_counter; }
105 
106   // Note: all test functions return void due to gtests limitation that we cannot use ASSERT
107   // in non-void returning tests.
108 
109   void delete_arena_with_tests() {
110     if (_arena != NULL) {
111       size_t used_words_before = _used_words_counter.get();
112       size_t committed_words_before = limiter().committed_words();
113       DEBUG_ONLY(_arena->verify());
114       delete _arena;

262 
263 TEST_VM(metaspace, MetaspaceArena_basics_standard_limit) {
264   test_basics(256 * K, false);
265 }
266 
267 // Test chunk enlargement:
268 //  A single MetaspaceArena, left undisturbed with place to grow. Slowly fill arena up.
269 //  We should see at least some occurrences of chunk-in-place enlargement.
270 static void test_chunk_enlargment_simple(Metaspace::MetaspaceType spacetype, bool is_class) {
271 
272   MetaspaceGtestContext context;
273   MetaspaceArenaTestHelper helper(context, (Metaspace::MetaspaceType)spacetype, is_class);
274 
275   uint64_t n1 = metaspace::InternalStats::num_chunks_enlarged();
276 
277   size_t allocated = 0;
278   while (allocated <= MAX_CHUNK_WORD_SIZE &&
279          metaspace::InternalStats::num_chunks_enlarged() == n1) {
280     size_t s = IntRange(32, 128).random_value();
281     helper.allocate_from_arena_with_tests_expect_success(s);
282     allocated += metaspace::get_raw_word_size_for_requested_word_size(s, metaspace::MetaspaceMinAlignmentWords);
283   }
284 
285   EXPECT_GT(metaspace::InternalStats::num_chunks_enlarged(), n1);
286 
287 }
288 
289 // Do this test for some of the standard types; don't do it for the boot loader type
290 //  since that one starts out with max chunk size so we would not see any enlargement.
291 
292 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_standard_c) {
293   test_chunk_enlargment_simple(Metaspace::StandardMetaspaceType, true);
294 }
295 
296 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_standard_nc) {
297   test_chunk_enlargment_simple(Metaspace::StandardMetaspaceType, false);
298 }
299 
300 TEST_VM(metaspace, MetaspaceArena_test_enlarge_in_place_micro_c) {
301   test_chunk_enlargment_simple(Metaspace::ReflectionMetaspaceType, true);
302 }

319   // Note: internally, chunk in-place enlargement is disallowed if growing the chunk
320   //  would cause the arena to claim more memory than its growth policy allows. This
321   //  is done to prevent the arena to grow too fast.
322   //
323   // In order to test in-place growth here without that restriction I give it an
324   //  artificial growth policy which starts out with a tiny chunk size, then balloons
325   //  right up to max chunk size. This will cause the initial chunk to be tiny, and
326   //  then the arena is able to grow it without violating growth policy.
327   chunklevel_t growth[] = { HIGHEST_CHUNK_LEVEL, ROOT_CHUNK_LEVEL };
328   ArenaGrowthPolicy growth_policy(growth, 2);
329 
330   MetaspaceGtestContext context;
331   MetaspaceArenaTestHelper helper(context, &growth_policy);
332 
333   uint64_t n1 = metaspace::InternalStats::num_chunks_enlarged();
334 
335   size_t allocated = 0;
336   while (allocated <= MAX_CHUNK_WORD_SIZE) {
337     size_t s = IntRange(32, 128).random_value();
338     helper.allocate_from_arena_with_tests_expect_success(s);
339     allocated += metaspace::get_raw_word_size_for_requested_word_size(s, metaspace::MetaspaceMinAlignmentWords);
340     if (allocated <= MAX_CHUNK_WORD_SIZE) {
341       // Chunk should have been enlarged in place
342       ASSERT_EQ(1, helper.get_number_of_chunks());
343     } else {
344       // Next chunk should have started
345       ASSERT_EQ(2, helper.get_number_of_chunks());
346     }
347   }
348 
349   int times_chunk_were_enlarged = metaspace::InternalStats::num_chunks_enlarged() - n1;
350   LOG("chunk was enlarged %d times.", times_chunk_were_enlarged);
351 
352   ASSERT_GT0(times_chunk_were_enlarged);
353 
354 }
355 
356 // Regression test: Given a single MetaspaceArena, left undisturbed with place to grow,
357 //  test that in place enlargement correctly fails if growing the chunk would bring us
358 //  beyond the max. size of a chunk.
359 TEST_VM(metaspace, MetaspaceArena_test_failing_to_enlarge_in_place_max_chunk_size) {

576   DEBUG_ONLY(const uintx num_chunk_enlarged = metaspace::InternalStats::num_chunks_enlarged();)
577 
578   size_t words_allocated = 0;
579   int num_allocated = 0;
580   const size_t safety = MAX_CHUNK_WORD_SIZE * 1.2;
581   size_t highest_capacity_jump = capacity;
582   int num_capacity_jumps = 0;
583 
584   while (words_allocated < safety && num_capacity_jumps < 15) {
585 
586     // if we want to test growth with in-place chunk enlargement, leave MetaspaceArena
587     // undisturbed; it will have all the place to grow. Otherwise allocate from a little
588     // side arena to increase fragmentation.
589     // (Note that this does not completely prevent in-place chunk enlargement but makes it
590     //  rather improbable)
591     if (!test_in_place_enlargement) {
592       smhelper_harrasser.allocate_from_arena_with_tests_expect_success(alloc_words * 2);
593     }
594 
595     smhelper.allocate_from_arena_with_tests_expect_success(alloc_words);
596     words_allocated += metaspace::get_raw_word_size_for_requested_word_size(alloc_words, metaspace::MetaspaceMinAlignmentWords);
597     num_allocated++;
598 
599     size_t used2 = 0, committed2 = 0, capacity2 = 0;
600 
601     smhelper.arena()->usage_numbers(&used2, &committed2, &capacity2);
602 
603     // used should not grow larger than what we allocated, plus possible overhead.
604     ASSERT_GE(used2, used);
605     ASSERT_LE(used2, used + alloc_words * 2);
606     ASSERT_LE(used2, words_allocated + 100);
607     used = used2;
608 
609     // A jump in committed words should not be larger than commit granule size.
610     // It can be smaller, since the current chunk of the MetaspaceArena may be
611     // smaller than a commit granule.
612     // (Note: unless root chunks are born fully committed)
613     ASSERT_GE(committed2, used2);
614     ASSERT_GE(committed2, committed);
615     const size_t committed_jump = committed2 - committed;
616     if (committed_jump > 0 && !Settings::new_chunks_are_fully_committed()) {
< prev index next >