1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018, SAP. 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 #include "precompiled.hpp" 26 #include "memory/allocation.inline.hpp" 27 #include "memory/metaspace.hpp" 28 #include "runtime/mutex.hpp" 29 #include "runtime/os.hpp" 30 #include "utilities/align.hpp" 31 #include "utilities/debug.hpp" 32 #include "utilities/globalDefinitions.hpp" 33 #include "utilities/ostream.hpp" 34 #include "unittest.hpp" 35 36 #define NUM_PARALLEL_METASPACES 50 37 #define MAX_PER_METASPACE_ALLOCATION_WORDSIZE (512 * K) 38 39 //#define DEBUG_VERBOSE true 40 41 #ifdef DEBUG_VERBOSE 42 43 struct chunkmanager_statistics_t { 44 int num_specialized_chunks; 45 int num_small_chunks; 46 int num_medium_chunks; 47 int num_humongous_chunks; 48 }; 49 50 extern void test_metaspace_retrieve_chunkmanager_statistics(Metaspace::MetadataType mdType, chunkmanager_statistics_t* out); 51 52 static void print_chunkmanager_statistics(outputStream* st, Metaspace::MetadataType mdType) { 53 chunkmanager_statistics_t stat; 54 test_metaspace_retrieve_chunkmanager_statistics(mdType, &stat); 55 st->print_cr("free chunks: %d / %d / %d / %d", stat.num_specialized_chunks, stat.num_small_chunks, 56 stat.num_medium_chunks, stat.num_humongous_chunks); 57 } 58 59 #endif 60 61 struct chunk_geometry_t { 62 size_t specialized_chunk_word_size; 63 size_t small_chunk_word_size; 64 size_t medium_chunk_word_size; 65 }; 66 67 extern void test_metaspace_retrieve_chunk_geometry(Metaspace::MetadataType mdType, chunk_geometry_t* out); 68 69 70 class MetaspaceAllocationTest : public ::testing::Test { 71 protected: 72 73 struct { 74 size_t allocated; 75 Mutex* lock; 76 ClassLoaderMetaspace* space; 77 bool is_empty() const { return allocated == 0; } 78 bool is_full() const { return allocated >= MAX_PER_METASPACE_ALLOCATION_WORDSIZE; } 79 } _spaces[NUM_PARALLEL_METASPACES]; 80 81 chunk_geometry_t _chunk_geometry; 82 83 virtual void SetUp() { 84 ::memset(_spaces, 0, sizeof(_spaces)); 85 test_metaspace_retrieve_chunk_geometry(Metaspace::NonClassType, &_chunk_geometry); 86 } 87 88 virtual void TearDown() { 89 for (int i = 0; i < NUM_PARALLEL_METASPACES; i ++) { 90 if (_spaces[i].space != NULL) { 91 delete _spaces[i].space; 92 delete _spaces[i].lock; 93 } 94 } 95 } 96 97 void create_space(int i) { 98 assert(i >= 0 && i < NUM_PARALLEL_METASPACES, "Sanity"); 99 assert(_spaces[i].space == NULL && _spaces[i].allocated == 0, "Sanity"); 100 if (_spaces[i].lock == NULL) { 101 _spaces[i].lock = new Mutex(Monitor::native, "gtest-MetaspaceAllocationTest-lock", false, Monitor::_safepoint_check_never); 102 ASSERT_TRUE(_spaces[i].lock != NULL); 103 } 104 // Let every ~10th space be an anonymous one to test different allocation patterns. 105 const Metaspace::MetaspaceType msType = (os::random() % 100 < 10) ? 106 Metaspace::AnonymousMetaspaceType : Metaspace::StandardMetaspaceType; 107 { 108 // Pull lock during space creation, since this is what happens in the VM too 109 // (see ClassLoaderData::metaspace_non_null(), which we mimick here). 110 MutexLockerEx ml(_spaces[i].lock, Mutex::_no_safepoint_check_flag); 111 _spaces[i].space = new ClassLoaderMetaspace(_spaces[i].lock, msType); 112 } 113 _spaces[i].allocated = 0; 114 ASSERT_TRUE(_spaces[i].space != NULL); 115 } 116 117 // Returns the index of a random space where index is [0..metaspaces) and which is 118 // empty, non-empty or full. 119 // Returns -1 if no matching space exists. 120 enum fillgrade { fg_empty, fg_non_empty, fg_full }; 121 int get_random_matching_space(int metaspaces, fillgrade fg) { 122 const int start_index = os::random() % metaspaces; 123 int i = start_index; 124 do { 125 if (fg == fg_empty && _spaces[i].is_empty()) { 126 return i; 127 } else if ((fg == fg_full && _spaces[i].is_full()) || 128 (fg == fg_non_empty && !_spaces[i].is_full() && !_spaces[i].is_empty())) { 129 return i; 130 } 131 i ++; 132 if (i == metaspaces) { 133 i = 0; 134 } 135 } while (i != start_index); 136 return -1; 137 } 138 139 int get_random_emtpy_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_empty); } 140 int get_random_non_emtpy_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_non_empty); } 141 int get_random_full_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_full); } 142 143 void do_test(Metaspace::MetadataType mdType, int metaspaces, int phases, int allocs_per_phase, 144 float probability_for_large_allocations // 0.0-1.0 145 ) { 146 // Alternate between breathing in (allocating n blocks for a random Metaspace) and 147 // breathing out (deleting a random Metaspace). The intent is to stress the coalescation 148 // and splitting of free chunks. 149 int phases_done = 0; 150 bool allocating = true; 151 while (phases_done < phases) { 152 bool force_switch = false; 153 if (allocating) { 154 // Allocate space from metaspace, with a preference for completely empty spaces. This 155 // should provide a good mixture of metaspaces in the virtual space. 156 int index = get_random_emtpy_space(metaspaces); 157 if (index == -1) { 158 index = get_random_non_emtpy_space(metaspaces); 159 } 160 if (index == -1) { 161 // All spaces are full, switch to freeing. 162 force_switch = true; 163 } else { 164 // create space if it does not yet exist. 165 if (_spaces[index].space == NULL) { 166 create_space(index); 167 } 168 // Allocate a bunch of blocks from it. Mostly small stuff but mix in large allocations 169 // to force humongous chunk allocations. 170 int allocs_done = 0; 171 while (allocs_done < allocs_per_phase && !_spaces[index].is_full()) { 172 size_t size = 0; 173 int r = os::random() % 1000; 174 if ((float)r < probability_for_large_allocations * 1000.0) { 175 size = (os::random() % _chunk_geometry.medium_chunk_word_size) + _chunk_geometry.medium_chunk_word_size; 176 } else { 177 size = os::random() % 64; 178 } 179 // Note: In contrast to space creation, no need to lock here. ClassLoaderMetaspace::allocate() will lock itself. 180 MetaWord* const p = _spaces[index].space->allocate(size, mdType); 181 if (p == NULL) { 182 // We very probably did hit the metaspace "until-gc" limit. 183 #ifdef DEBUG_VERBOSE 184 tty->print_cr("OOM for " SIZE_FORMAT " words. ", size); 185 #endif 186 // Just switch to deallocation and resume tests. 187 force_switch = true; 188 break; 189 } else { 190 _spaces[index].allocated += size; 191 allocs_done ++; 192 } 193 } 194 } 195 } else { 196 // freeing: find a metaspace and delete it, with preference for completely filled spaces. 197 int index = get_random_full_space(metaspaces); 198 if (index == -1) { 199 index = get_random_non_emtpy_space(metaspaces); 200 } 201 if (index == -1) { 202 force_switch = true; 203 } else { 204 assert(_spaces[index].space != NULL && _spaces[index].allocated > 0, "Sanity"); 205 // Note: do not lock here. In the "wild" (the VM), we do not so either (see ~ClassLoaderData()). 206 delete _spaces[index].space; 207 _spaces[index].space = NULL; 208 _spaces[index].allocated = 0; 209 } 210 } 211 212 if (force_switch) { 213 allocating = !allocating; 214 } else { 215 // periodically switch between allocating and freeing, but prefer allocation because 216 // we want to intermingle allocations of multiple metaspaces. 217 allocating = os::random() % 5 < 4; 218 } 219 phases_done ++; 220 #ifdef DEBUG_VERBOSE 221 int metaspaces_in_use = 0; 222 size_t total_allocated = 0; 223 for (int i = 0; i < metaspaces; i ++) { 224 if (_spaces[i].allocated > 0) { 225 total_allocated += _spaces[i].allocated; 226 metaspaces_in_use ++; 227 } 228 } 229 tty->print("%u:\tspaces: %d total words: " SIZE_FORMAT "\t\t\t", phases_done, metaspaces_in_use, total_allocated); 230 print_chunkmanager_statistics(tty, mdType); 231 #endif 232 } 233 #ifdef DEBUG_VERBOSE 234 tty->print_cr("Test finished. "); 235 MetaspaceUtils::print_metaspace_map(tty, mdType); 236 print_chunkmanager_statistics(tty, mdType); 237 #endif 238 } 239 }; 240 241 242 243 TEST_F(MetaspaceAllocationTest, chunk_geometry) { 244 ASSERT_GT(_chunk_geometry.specialized_chunk_word_size, (size_t) 0); 245 ASSERT_GT(_chunk_geometry.small_chunk_word_size, _chunk_geometry.specialized_chunk_word_size); 246 ASSERT_EQ(_chunk_geometry.small_chunk_word_size % _chunk_geometry.specialized_chunk_word_size, (size_t)0); 247 ASSERT_GT(_chunk_geometry.medium_chunk_word_size, _chunk_geometry.small_chunk_word_size); 248 ASSERT_EQ(_chunk_geometry.medium_chunk_word_size % _chunk_geometry.small_chunk_word_size, (size_t)0); 249 } 250 251 252 TEST_VM_F(MetaspaceAllocationTest, single_space_nonclass) { 253 do_test(Metaspace::NonClassType, 1, 1000, 100, 0); 254 } 255 256 TEST_VM_F(MetaspaceAllocationTest, single_space_class) { 257 do_test(Metaspace::ClassType, 1, 1000, 100, 0); 258 } 259 260 TEST_VM_F(MetaspaceAllocationTest, multi_space_nonclass) { 261 do_test(Metaspace::NonClassType, NUM_PARALLEL_METASPACES, 100, 1000, 0.0); 262 } 263 264 TEST_VM_F(MetaspaceAllocationTest, multi_space_class) { 265 do_test(Metaspace::ClassType, NUM_PARALLEL_METASPACES, 100, 1000, 0.0); 266 } 267 268 TEST_VM_F(MetaspaceAllocationTest, multi_space_nonclass_2) { 269 // many metaspaces, with humongous chunks mixed in. 270 do_test(Metaspace::NonClassType, NUM_PARALLEL_METASPACES, 100, 1000, .006f); 271 } 272