1 /* 2 * Copyright (c) 2019, SAP. All rights reserved. 3 * Copyright (c) 2019, Oracle and/or its affiliates. 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 #include "precompiled.hpp" 26 27 #include "memory/allocation.hpp" 28 #include "memory/metaspace/abstractPool.hpp" 29 #include "runtime/os.hpp" 30 #include "utilities/debug.hpp" 31 #include "utilities/globalDefinitions.hpp" 32 33 #include "unittest.hpp" 34 35 #include <stdio.h> 36 #include <limits> 37 38 #define LOG(FMT, ...) { printf(FMT, __VA_ARGS__); printf("\n"); } 39 40 // Test AbstractPool class 41 42 template <class E, class I> 43 class AbstractPoolTest { 44 public: 45 46 typedef metaspace::AbstractPool<E, I> PoolType; 47 48 private: 49 50 PoolType _pool; 51 size_t _num_allocated; 52 53 // Array of the same size as the pool max capacity; holds the allocated elements. 54 E** _elems; 55 56 57 // Helper function. Writes a canary into *E. 58 static void mark_element(E* e, uint8_t v) { *(uint8_t*)e = v; } 59 60 // Helper function. Check expected canary in *E. 61 static void check_element_mark(const E* e, uint8_t v) { uint8_t v2 = *(const uint8_t*)e; ASSERT_TRUE(v == v2); } 62 63 // Given an element, check its index resolution. 64 void check_element_to_index_translation(const E* e) { 65 I idx = _pool.index_for_elem(e); 66 ASSERT_TRUE(_pool.is_valid_index(idx)); 67 E* e2 = _pool.elem_at_index(idx); 68 ASSERT_TRUE(e2 == e); 69 } 70 71 void attempt_free_at(size_t index) { 72 73 LOG("attempt_free_at " SIZE_FORMAT ".", index); 74 75 if (_elems[index] == NULL) { 76 return; 77 } 78 79 check_element_mark(_elems[index], index & 0xFF); 80 _pool.return_element(_elems[index]); 81 _elems[index] = NULL; 82 83 ASSERT_GT(_num_allocated, (size_t)0); 84 _num_allocated --; 85 86 // Note: AbstractPool::used() returns number of used items incl. the 87 // zero item, wich is not handed out but reserved. 88 ASSERT_EQ(_num_allocated, (size_t)(_pool.used() - 1)); 89 } 90 91 void attempt_allocate_at(size_t index) { 92 93 LOG("attempt_allocate_at " SIZE_FORMAT ".", index); 94 95 assert(index <= _pool.max_capacity(), "Sanity"); 96 97 if (_elems[index] != NULL) { 98 return; 99 } 100 101 E* e = _pool.allocate_element(); 102 if (e == NULL) { 103 ASSERT_TRUE(_pool.is_full()); 104 ASSERT_TRUE(_pool.used() == _pool.max_capacity()); 105 } else { 106 mark_element(e, index & 0xFF); 107 check_element_to_index_translation(e); 108 _num_allocated ++; 109 _elems[index] = e; 110 111 check_element_mark(_elems[index], index & 0xFF); 112 113 // Note: AbstractPool::used() returns number of used items incl. the 114 // zero item, wich is not handed out but reserved. 115 ASSERT_EQ(_num_allocated, (size_t)(_pool.used() - 1)); 116 } 117 118 } 119 120 void attempt_allocate_or_free_at(size_t index) { 121 if (_elems[index] == NULL) { 122 attempt_allocate_at(index); 123 } else { 124 attempt_free_at(index); 125 } 126 } 127 128 // Fill pool until exhaustion. 129 void test_exhaustion() { 130 131 for (size_t i = 0; i < _pool.max_capacity(); i ++) { 132 attempt_allocate_at(i); 133 } 134 135 ASSERT_TRUE(_pool.used() == _pool.max_capacity()); 136 ASSERT_TRUE(_pool.is_full()); 137 138 DEBUG_ONLY(_pool.verify(true);) 139 140 } 141 142 // Fill pool until exhaustion. 143 void test_draining() { 144 145 for (size_t i = 0; i < _pool.max_capacity(); i ++) { 146 attempt_free_at(i); 147 } 148 149 ASSERT_TRUE(_pool.used() == _pool.max_capacity()); 150 ASSERT_TRUE(_pool.is_empty()); 151 152 DEBUG_ONLY(_pool.verify(true);) 153 } 154 155 // Randomly allocate from the pool and free. Slight preference for allocation. 156 void test_random_alloc_free(int num_iterations) { 157 158 for (int iter = 0; iter < num_iterations; iter ++) { 159 size_t index = (size_t)os::random() % _pool.max_capacity(); 160 attempt_allocate_or_free_at(index); 161 } 162 163 DEBUG_ONLY(_pool.verify(true);) 164 165 } 166 167 static void test_once() { 168 169 170 const int max_for_index_type = (int) std::numeric_limits<I>::max(); 171 172 const size_t max = MAX2(os::random() % max_for_index_type, 2); 173 const size_t inc = MAX2(max / ((os::random() % 100) + 1), (size_t)1); 174 175 AbstractPoolTest<E, I> test(inc, max); 176 177 test.test_random_alloc_free(100); 178 test.test_exhaustion(); 179 test.test_draining(); 180 test.test_random_alloc_free(100); 181 182 } 183 184 185 public: 186 187 AbstractPoolTest(size_t capacity_increase, 188 size_t max_capacity) 189 : _pool("just-a-test-pool", max_capacity, capacity_increase), 190 _num_allocated(0), _elems(NULL) 191 { 192 _elems = NEW_C_HEAP_ARRAY(E*, max_capacity, mtInternal); 193 memset(_elems, 0, max_capacity * sizeof(E)); 194 } 195 196 ~AbstractPoolTest() { FREE_C_HEAP_ARRAY(E*, _elems); } 197 198 static void run_tests() { 199 for (int i = 0; i < 1000; i ++) { 200 test_once(); 201 } 202 } 203 204 }; 205 206 207 208 209 210 TEST(metaspace, pool1) { 211 AbstractPoolTest<uint64_t, uint8_t>::run_tests(); 212 } 213 214 TEST(metaspace, pool2) { 215 AbstractPoolTest<uint64_t, uint16_t>::run_tests(); 216 } 217 218 TEST(metaspace, pool3) { 219 AbstractPoolTest<uint32_t, uint8_t>::run_tests(); 220 } 221 222 struct S1 { uint16_t i1; uint16_t i2; uint16_t i3; }; 223 224 TEST(metaspace, pool4) { 225 AbstractPoolTest<S1, uint8_t>::run_tests(); 226 } 227 228 TEST(metaspace, pool5) { 229 AbstractPoolTest<S1, uint16_t>::run_tests(); 230 } 231 232 // crooked and unaligned :) 233 234 struct S2 { char i [0x100]; }; 235 236 TEST(metaspace, pool6) { 237 AbstractPoolTest<S2, uint8_t>::run_tests(); 238 } 239 240 TEST(metaspace, pool7) { 241 AbstractPoolTest<S2, uint16_t>::run_tests(); 242 } 243 244 245 // crooked and unaligned :) 246 /* 247 * 248 FOr now, excluded: see STATIC_ASSERT in AssertPool. We should not be able to define an AbstractPool where 249 E has a smaller alignment requirement than I. 250 251 struct S3 { char i [33]; }; 252 253 TEST(metaspace, pool8) { 254 AbstractPoolTest<S3, uint8_t>::run_tests(); 255 } 256 257 TEST(metaspace, pool9) { 258 AbstractPoolTest<S3, uint16_t>::run_tests(); 259 } 260 261 */ 262 263