/* * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 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_METASPACE_RANGEHELPERS_HPP #define GTEST_METASPACE_METASPACE_RANGEHELPERS_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/chunkLevel.hpp" #include "runtime/os.hpp" #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_METASPACE_RANGEHELPERS_HPP