1 /* 2 * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018, 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 28 //#define LOG_PLEASE 29 30 #include "metaspaceTestsCommon.hpp" 31 32 #define CHECK_CONTENT(fb, num_blocks_expected, word_size_expected) \ 33 { \ 34 if (word_size_expected > 0) { \ 35 EXPECT_FALSE(fb.is_empty()); \ 36 } else { \ 37 EXPECT_TRUE(fb.is_empty()); \ 38 } \ 39 EXPECT_EQ(fb.total_size(), (size_t)word_size_expected); \ 40 EXPECT_EQ(fb.count(), (int)num_blocks_expected); \ 41 } 42 43 class FreeBlocksTest { 44 45 FeederBuffer _fb; 46 FreeBlocks _freeblocks; 47 48 // random generator for block feeding 49 RandSizeGenerator _rgen_feeding; 50 51 // random generator for allocations (and, hence, deallocations) 52 RandSizeGenerator _rgen_allocations; 53 54 SizeCounter _allocated_words; 55 56 struct allocation_t { 57 allocation_t* next; 58 size_t word_size; 59 MetaWord* p; 60 }; 61 62 // Array of the same size as the pool max capacity; holds the allocated elements. 63 allocation_t* _allocations; 64 65 int _num_allocs; 66 int _num_deallocs; 67 int _num_feeds; 68 69 bool feed_some() { 70 size_t word_size = _rgen_feeding.get(); 71 MetaWord* p = _fb.get(word_size); 72 if (p != NULL) { 73 _freeblocks.add_block(p, word_size); 74 return true; 75 } 76 return false; 77 } 78 79 void deallocate_top() { 80 81 allocation_t* a = _allocations; 82 if (a != NULL) { 83 _allocations = a->next; 84 check_marked_range(a->p, a->word_size); 85 _freeblocks.add_block(a->p, a->word_size); 86 delete a; 87 DEBUG_ONLY(_freeblocks.verify();) 88 } 89 } 90 91 bool allocate() { 92 93 size_t word_size = MAX2(_rgen_allocations.get(), _freeblocks.minimal_word_size); 94 MetaWord* p = _freeblocks.get_block(word_size); 95 if (p != NULL) { 96 _allocated_words.increment_by(word_size); 97 allocation_t* a = new allocation_t; 98 a->p = p; a->word_size = word_size; 99 a->next = _allocations; 100 _allocations = a; 101 DEBUG_ONLY(_freeblocks.verify();) 102 mark_range(p, word_size); 103 return true; 104 } 105 return false; 106 } 107 108 void test_all_marked_ranges() { 109 for (allocation_t* a = _allocations; a != NULL; a = a->next) { 110 check_marked_range(a->p, a->word_size); 111 } 112 } 113 114 void test_loop() { 115 // We loop and in each iteration execute one of three operations: 116 // - allocation from lom 117 // - deallocation to lom of a previously allocated block 118 // - feeding a new larger block into the lom (mimicks chunk retiring) 119 // When we have fed all large blocks into the lom (feedbuffer empty), we 120 // switch to draining the lom completely (only allocs) 121 bool forcefeed = false; 122 bool draining = false; 123 bool stop = false; 124 int iter = 100000; // safety stop 125 while (!stop && iter > 0) { 126 iter --; 127 int surprise = (int)os::random() % 10; 128 if (!draining && (surprise >= 7 || forcefeed)) { 129 forcefeed = false; 130 if (feed_some()) { 131 _num_feeds ++; 132 } else { 133 // We fed all input memory into the LOM. Now lets proceed until the lom is drained. 134 draining = true; 135 } 136 } else if (!draining && surprise < 1) { 137 deallocate_top(); 138 _num_deallocs ++; 139 } else { 140 if (allocate()) { 141 _num_allocs ++; 142 } else { 143 if (draining) { 144 stop = _freeblocks.total_size() < 512; 145 } else { 146 forcefeed = true; 147 } 148 } 149 } 150 if ((iter % 1000) == 0) { 151 DEBUG_ONLY(_freeblocks.verify();) 152 test_all_marked_ranges(); 153 LOG("a %d (" SIZE_FORMAT "), d %d, f %d", _num_allocs, _allocated_words.get(), _num_deallocs, _num_feeds); 154 #ifdef LOG_PLEASE 155 _freeblocks.print(tty, true); 156 tty->cr(); 157 #endif 158 } 159 } 160 161 // Drain 162 163 164 } 165 166 167 168 public: 169 170 FreeBlocksTest(size_t avg_alloc_size) : 171 _fb(512 * K), _freeblocks(), 172 _rgen_feeding(128, 4096), 173 _rgen_allocations(avg_alloc_size / 4, avg_alloc_size * 2, 0.01f, avg_alloc_size / 3, avg_alloc_size * 30), 174 _allocations(NULL), 175 _num_allocs(0), _num_deallocs(0), _num_feeds(0) 176 { 177 CHECK_CONTENT(_freeblocks, 0, 0); 178 // some initial feeding 179 _freeblocks.add_block(_fb.get(1024), 1024); 180 CHECK_CONTENT(_freeblocks, 1, 1024); 181 } 182 183 184 static void test_small_allocations() { 185 FreeBlocksTest test(10); 186 test.test_loop(); 187 } 188 189 static void test_medium_allocations() { 190 FreeBlocksTest test(30); 191 test.test_loop(); 192 } 193 194 static void test_large_allocations() { 195 FreeBlocksTest test(150); 196 test.test_loop(); 197 } 198 199 200 }; 201 202 203 TEST_VM(metaspace, freeblocks_basics) { 204 205 FreeBlocks lom; 206 MetaWord tmp[1024]; 207 CHECK_CONTENT(lom, 0, 0); 208 209 lom.add_block(tmp, 1024); 210 DEBUG_ONLY(lom.verify();) 211 ASSERT_FALSE(lom.is_empty()); 212 CHECK_CONTENT(lom, 1, 1024); 213 214 MetaWord* p = lom.get_block(1024); 215 EXPECT_EQ(p, tmp); 216 DEBUG_ONLY(lom.verify();) 217 CHECK_CONTENT(lom, 0, 0); 218 219 } 220 221 TEST_VM(metaspace, freeblocks_small) { 222 FreeBlocksTest::test_small_allocations(); 223 } 224 225 TEST_VM(metaspace, freeblocks_medium) { 226 FreeBlocksTest::test_medium_allocations(); 227 } 228 229 TEST_VM(metaspace, freeblocks_large) { 230 FreeBlocksTest::test_large_allocations(); 231 } 232