--- /dev/null 2020-09-04 12:37:41.765504620 +0200 +++ new/test/hotspot/gtest/metaspace/metaspaceGtestRangeHelpers.hpp 2020-09-04 13:58:14.757517479 +0200 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020 SAP SE. 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. + * + */ + +#ifndef GTEST_METASPACE_METASPACEGTESTRANGEHELPERS_HPP +#define GTEST_METASPACE_METASPACEGTESTRANGEHELPERS_HPP + +// We use ranges-of-things in these tests a lot so some helpers help +// keeping the code small. + +#include "memory/allocation.hpp" +#include "memory/metaspace/msChunklevel.hpp" +#include "runtime/os.hpp" // For os::random +#include "utilities/align.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +using metaspace::chunklevel_t; +using namespace metaspace::chunklevel; + +// A range of numerical values. +template +class Range : public StackObj { + + // start and size of range + T _start; + Td _size; + + static Td random_uncapped_offset() { + if (sizeof(Td) > 4) { + return (Td)((uint64_t)os::random() * os::random()); + } else { + return (Td)os::random(); + } + } + +protected: + + static void swap_if_needed(T& lo, T& hi) { + if (lo > hi) { + T v = lo; + lo = hi; + hi = v; + } + } + +public: + + // Lowest value in range + T lowest() const { return _start; } + + // Highest value in range (including) + T highest() const { return _start + (_size - 1); } + + T start() const { return _start; } + T end() const { return _start + _size; } + + // Number of values in range + Td size() const { return _size; } + + bool is_empty() const { return size() == 0; } + + bool contains(T v) const { + return v >= _start && v < end(); + } + + bool contains(Range r) const { + return contains(r.lowest()) && contains(r.highest()); + } + + // Create a range from [start, end) + Range(T start, T end) : _start(start), _size(end - start) { + assert(end >= start, "start and end reversed"); + } + + // a range with a given size, starting at 0 + Range(Td size) : _start(0), _size(size) {} + + // Return a random offset + Td random_offset() const { + assert(!is_empty(), "Range too small"); + Td v = random_uncapped_offset() % size(); + return v; + } + + // Return a random value within the range + T random_value() const { + assert(!is_empty(), "Range too small"); + T v = _start + random_offset(); + assert(contains(v), "Sanity"); + return v; + } + + // Return the head of this range up to but excluding + Range head(Td split_point) const { + assert(_size >= split_point, "Sanity"); + return Range(_start, _start + split_point); + } + + // Return the tail of this range, starting at + Range tail(Td split_point) const { + assert(_size > split_point, "Sanity"); + return Range(_start + split_point, end()); + } + + // Return a non-empty random sub range. + Range random_subrange() const { + assert(size() > 1, "Range too small"); + Td sz = MAX2((Td)1, random_offset()); + return random_sized_subrange(sz); + } + + // Return a subrange of given size at a random start position + Range random_sized_subrange(Td subrange_size) const { + assert(subrange_size > 0 && subrange_size < _size, "invalid size"); + T start = head(_size - subrange_size).random_value(); + return Range(start, start + subrange_size); + } + + //// aligned ranges //// + + bool range_is_aligned(Td alignment) const { + return is_aligned(_size, alignment) && is_aligned(_start, alignment); + } + + // Return a non-empty aligned random sub range. + Range random_aligned_subrange(Td alignment) const { + assert(alignment > 0, "Sanity"); + assert(range_is_aligned(alignment), "Outer range needs to be aligned"); // to keep matters simple + assert(_size >= alignment, "Outer range too small."); + Td sz = MAX2((Td)1, random_offset()); + sz = align_up(sz, alignment); + return random_aligned_sized_subrange(sz, alignment); + } + + // Return a subrange of given size at a random aligned start position + Range random_aligned_sized_subrange(Td subrange_size, Td alignment) const { + assert(alignment > 0, "Sanity"); + assert(range_is_aligned(alignment), "Outer range needs to be aligned"); // to keep matters simple + assert(subrange_size > 0 && subrange_size <= _size && + is_aligned(subrange_size, alignment), "invalid subrange size"); + if (_size == subrange_size) { + return *this; + } + T start = head(_size - subrange_size).random_value(); + start = align_down(start, alignment); + return Range(start, start + subrange_size); + } + +}; + +typedef Range IntRange; +typedef Range SizeRange; +typedef Range ChunkLevelRange; + +struct ChunkLevelRanges : public AllStatic { + static ChunkLevelRange small_chunks() { return ChunkLevelRange(CHUNK_LEVEL_32K, CHUNK_LEVEL_1K + 1); } + static ChunkLevelRange medium_chunks() { return ChunkLevelRange(CHUNK_LEVEL_512K, CHUNK_LEVEL_32K + 1); } + static ChunkLevelRange large_chunks() { return ChunkLevelRange(CHUNK_LEVEL_4M, CHUNK_LEVEL_512K + 1); } + static ChunkLevelRange all_chunks() { return ChunkLevelRange(CHUNK_LEVEL_4M, CHUNK_LEVEL_1K + 1); } +}; + +#endif // GTEST_METASPACE_METASPACEGTESTRANGEHELPERS_HPP