--- /dev/null 2019-07-25 13:07:35.456009699 +0200 +++ new/test/hotspot/gtest/metaspace/test_pool.cpp 2019-07-25 15:30:13.213571233 +0200 @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2019, SAP. All rights reserved. + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" + +#include "memory/allocation.hpp" +#include "memory/metaspace/abstractPool.hpp" +#include "runtime/os.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +#include "unittest.hpp" + +#include + +// Test AbstractPool class + +template +class AbstractPoolTest { +public: + + typedef metaspace::AbstractPool PoolType; + +private: + + PoolType _pool; + size_t _num_allocated; + + // Array of the same size as the pool max capacity; holds the allocated elements. + E** _elems; + + + // Helper function. Writes a canary into *E. + static void mark_element(E* e, uint8_t v) { *(uint8_t*)e = v; } + + // Helper function. Check expected canary in *E. + static void check_element_mark(const E* e, uint8_t v) { uint8_t v2 = *(const uint8_t*)e; ASSERT_TRUE(v == v2); } + + // Given an element, check its index resolution. + void check_element_to_index_translation(const E* e) { + I idx = _pool->index_for_elem(e); + ASSERT_TRUE(_pool->is_valid_index(idx)); + E* e2 = _pool->elem_at_index(idx); + ASSERT_TRUE(e2 = e); + } + + void attempt_free_at(size_t index) { + if (_elems[index] == NULL) { + return; + } + + check_element_mark(_elems[index]); + _pool.return_element(_elems[index]); + _elems[index] = NULL; + + ASSERT_GT(_num_allocated, 0); + _num_allocated --; + + ASSERT_EQ(_num_allocated, _pool.used()); + } + + void attempt_allocate_at(size_t index) { + + assert(index <= _pool.max_capacity(), "Sanity"); + + if (_elems[index] != NULL) { + return; + } + + E* e = _pool.allocate_element(); + if (e == NULL) { + ASSERT_TRUE(_pool.is_full()); + ASSERT_TRUE(_pool.used() == _pool.max_capacity()); + } else { + mark_element(e, index & 0xFF); + check_element_to_index_translation(e); + _num_allocated ++; + _elems[index] = e; + ASSERT_EQ(_num_allocated, _pool.used()); + } + + } + + void attempt_allocate_or_free_at(size_t index) { + if (_elems[index] == NULL) { + attempt_allocate_at(index); + } else { + attempt_free_at(index); + } + } + + // Fill pool until exhaustion. + void test_exhaustion() { + + for (size_t i = 0; i < _pool.max_capacity(); i ++) { + attempt_allocate_at(i); + } + + ASSERT_TRUE(_pool.used() == _pool.max_capacity()); + ASSERT_TRUE(_pool.is_full()); + + DEBUG_ONLY(_pool.verify(true);) + + } + + // Fill pool until exhaustion. + void test_draining() { + + for (size_t i = 0; i < _pool.max_capacity(); i ++) { + attempt_free_at(i); + } + + ASSERT_TRUE(_pool.used() == _pool.max_capacity()); + ASSERT_TRUE(_pool.is_empty()); + + DEBUG_ONLY(_pool.verify(true);) + } + + // Randomly allocate from the pool and free. Slight preference for allocation. + void test_random_alloc_free(int num_iterations) { + + for (int iter = 0; iter < num_iterations; iter ++) { + size_t index = (size_t)os::random() % _pool.max_capacity(); + attempt_allocate_or_free_at(index); + } + + DEBUG_ONLY(_pool.verify(true);) + + } + + static void test_once() { + + + const int max_for_index_type = (int) std::numeric_limits::max(); + + const size_t max = MAX2(os::random() % max_for_index_type, 2); + const size_t inc = MAX2(max / ((os::random() % 100) + 1), (size_t)1); + + AbstractPoolTest test(inc, max); + + test.test_random_alloc_free(100); + test.test_exhaustion(); + test.test_draining(); + test.test_random_alloc_free(100); + + } + + +public: + + AbstractPoolTest(size_t capacity_increase, + size_t max_capacity) + : _pool("just-a-test-pool", max_capacity, capacity_increase), + _num_allocated(0), _elems(NULL) + { + _elems = NEW_C_HEAP_ARRAY(E*, max_capacity, mtInternal); + memset(_elems, 0, max_capacity * sizeof(E)); + } + + ~AbstractPoolTest() { FREE_C_HEAP_ARRAY(E*, _elems); } + + static void run_tests() { + for (int i = 0; i < 1000; i ++) { + test_once(); + } + } + +}; + + + + + +TEST(metaspace, pool1) { + AbstractPoolTest::run_tests(); +} + +TEST(metaspace, pool2) { + AbstractPoolTest::run_tests(); +} + +TEST(metaspace, pool3) { + AbstractPoolTest::run_tests(); +} + +struct S1 { uint16_t i1; uint16_t i2; uint16_t i3; }; + +TEST(metaspace, pool4) { + AbstractPoolTest::run_tests(); +} + +TEST(metaspace, pool5) { + AbstractPoolTest::run_tests(); +} + +// crooked and unaligned :) + +struct S2 { char i [0x100]; }; + +TEST(metaspace, pool6) { + AbstractPoolTest::run_tests(); +} + +TEST(metaspace, pool7) { + AbstractPoolTest::run_tests(); +} + + +// crooked and unaligned :) +/* + * + FOr now, excluded: see STATIC_ASSERT in AssertPool. We should not be able to define an AbstractPool where + E has a smaller alignment requirement than I. + +struct S3 { char i [33]; }; + +TEST(metaspace, pool8) { + AbstractPoolTest::run_tests(); +} + +TEST(metaspace, pool9) { + AbstractPoolTest::run_tests(); +} + +*/ + +