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