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