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 Metaspace* 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 _spaces[i].space = new Metaspace(_spaces[i].lock, msType); 108 _spaces[i].allocated = 0; 109 ASSERT_TRUE(_spaces[i].space != NULL); 110 } 111 112 // Returns the index of a random space where index is [0..metaspaces) and which is 113 // empty, non-empty or full. 114 // Returns -1 if no matching space exists. 115 enum fillgrade { fg_empty, fg_non_empty, fg_full }; 116 int get_random_matching_space(int metaspaces, fillgrade fg) { 117 const int start_index = os::random() % metaspaces; 118 int i = start_index; 119 do { 120 if (fg == fg_empty && _spaces[i].is_empty()) { 121 return i; 122 } else if ((fg == fg_full && _spaces[i].is_full()) || 123 (fg == fg_non_empty && !_spaces[i].is_full() && !_spaces[i].is_empty())) { 124 return i; 125 } 126 i ++; 127 if (i == metaspaces) { 128 i = 0; 129 } 130 } while (i != start_index); 131 return -1; 132 } 133 134 int get_random_emtpy_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_empty); } 135 int get_random_non_emtpy_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_non_empty); } 136 int get_random_full_space(int metaspaces) { return get_random_matching_space(metaspaces, fg_full); } 137 138 void do_test(Metaspace::MetadataType mdType, int metaspaces, int phases, int allocs_per_phase, 139 float probability_for_large_allocations // 0.0-1.0 140 ) { 141 // Alternate between breathing in (allocating n blocks for a random Metaspace) and 142 // breathing out (deleting a random Metaspace). The intent is to stress the coalescation 143 // and splitting of free chunks. 144 int phases_done = 0; 145 bool allocating = true; 146 while (phases_done < phases) { 147 bool force_switch = false; 148 if (allocating) { 149 // Allocate space from metaspace, with a preference for completely empty spaces. This 150 // should provide a good mixture of metaspaces in the virtual space. 151 int index = get_random_emtpy_space(metaspaces); 152 if (index == -1) { 153 index = get_random_non_emtpy_space(metaspaces); 154 } 155 if (index == -1) { 156 // All spaces are full, switch to freeing. 157 force_switch = true; 158 } else { 159 // create space if it does not yet exist. 160 if (_spaces[index].space == NULL) { 161 create_space(index); 162 } 163 // Allocate a bunch of blocks from it. Mostly small stuff but mix in large allocations 164 // to force humongous chunk allocations. 165 int allocs_done = 0; 166 while (allocs_done < allocs_per_phase && !_spaces[index].is_full()) { 167 size_t size = 0; 168 int r = os::random() % 1000; 169 if ((float)r < probability_for_large_allocations * 1000.0) { 170 size = (os::random() % _chunk_geometry.medium_chunk_word_size) + _chunk_geometry.medium_chunk_word_size; 171 } else { 172 size = os::random() % 64; 173 } 174 MetaWord* const p = _spaces[index].space->allocate(size, mdType); 175 if (p == NULL) { 176 // We very probably did hit the metaspace "until-gc" limit. 177 #ifdef DEBUG_VERBOSE 178 tty->print_cr("OOM for " SIZE_FORMAT " words. ", size); 179 #endif 180 // Just switch to deallocation and resume tests. 181 force_switch = true; 182 break; 183 } else { 184 _spaces[index].allocated += size; 185 allocs_done ++; 186 } 187 } 188 } 189 } else { 190 // freeing: find a metaspace and delete it, with preference for completely filled spaces. 191 int index = get_random_full_space(metaspaces); 192 if (index == -1) { 193 index = get_random_non_emtpy_space(metaspaces); 194 } 195 if (index == -1) { 196 force_switch = true; 197 } else { 198 assert(_spaces[index].space != NULL && _spaces[index].allocated > 0, "Sanity"); 199 delete _spaces[index].space; 200 _spaces[index].space = NULL; 201 _spaces[index].allocated = 0; 202 } 203 } 204 205 if (force_switch) { 206 allocating = !allocating; 207 } else { 208 // periodically switch between allocating and freeing, but prefer allocation because 209 // we want to intermingle allocations of multiple metaspaces. 210 allocating = os::random() % 5 < 4; 211 } 212 phases_done ++; 213 #ifdef DEBUG_VERBOSE 214 int metaspaces_in_use = 0; 215 size_t total_allocated = 0; 216 for (int i = 0; i < metaspaces; i ++) { 217 if (_spaces[i].allocated > 0) { 218 total_allocated += _spaces[i].allocated; 219 metaspaces_in_use ++; 220 } 221 } 222 tty->print("%u:\tspaces: %d total words: " SIZE_FORMAT "\t\t\t", phases_done, metaspaces_in_use, total_allocated); 223 print_chunkmanager_statistics(tty, mdType); 224 #endif 225 } 226 #ifdef DEBUG_VERBOSE 227 tty->print_cr("Test finished. "); 228 MetaspaceAux::print_metaspace_map(tty, mdType); 229 print_chunkmanager_statistics(tty, mdType); 230 #endif 231 } 232 }; 233 234 235 236 TEST_F(MetaspaceAllocationTest, chunk_geometry) { 237 ASSERT_GT(_chunk_geometry.specialized_chunk_word_size, (size_t) 0); 238 ASSERT_GT(_chunk_geometry.small_chunk_word_size, _chunk_geometry.specialized_chunk_word_size); 239 ASSERT_EQ(_chunk_geometry.small_chunk_word_size % _chunk_geometry.specialized_chunk_word_size, (size_t)0); 240 ASSERT_GT(_chunk_geometry.medium_chunk_word_size, _chunk_geometry.small_chunk_word_size); 241 ASSERT_EQ(_chunk_geometry.medium_chunk_word_size % _chunk_geometry.small_chunk_word_size, (size_t)0); 242 } 243 244 245 TEST_VM_F(MetaspaceAllocationTest, single_space_nonclass) { 246 do_test(Metaspace::NonClassType, 1, 1000, 100, 0); 247 } 248 249 TEST_VM_F(MetaspaceAllocationTest, single_space_class) { 250 do_test(Metaspace::ClassType, 1, 1000, 100, 0); 251 } 252 253 TEST_VM_F(MetaspaceAllocationTest, multi_space_nonclass) { 254 do_test(Metaspace::NonClassType, NUM_PARALLEL_METASPACES, 100, 1000, 0.0); 255 } 256 257 TEST_VM_F(MetaspaceAllocationTest, multi_space_class) { 258 do_test(Metaspace::ClassType, NUM_PARALLEL_METASPACES, 100, 1000, 0.0); 259 } 260 261 TEST_VM_F(MetaspaceAllocationTest, multi_space_nonclass_2) { 262 // many metaspaces, with humongous chunks mixed in. 263 do_test(Metaspace::NonClassType, NUM_PARALLEL_METASPACES, 100, 1000, .006f); 264 } 265