8231552: ZGC: Refine address space reservation
Reviewed-by: eosterlund, stefank
This commit is contained in:
parent
b4d37ba6b9
commit
a8c4e6786d
@ -142,8 +142,7 @@ uintptr_t ZPlatformAddressBase() {
|
||||
size_t ZPlatformAddressOffsetBits() {
|
||||
const size_t min_address_offset_bits = 42; // 4TB
|
||||
const size_t max_address_offset_bits = 44; // 16TB
|
||||
const size_t virtual_to_physical_ratio = 7; // 7:1
|
||||
const size_t address_offset = ZUtils::round_up_power_of_2(MaxHeapSize * virtual_to_physical_ratio);
|
||||
const size_t address_offset = ZUtils::round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
|
||||
const size_t address_offset_bits = log2_intptr(address_offset);
|
||||
return MIN2(MAX2(address_offset_bits, min_address_offset_bits), max_address_offset_bits);
|
||||
}
|
||||
|
@ -24,23 +24,13 @@
|
||||
#ifndef CPU_AARCH64_GC_Z_ZGLOBALS_AARCH64_HPP
|
||||
#define CPU_AARCH64_GC_Z_ZGLOBALS_AARCH64_HPP
|
||||
|
||||
//
|
||||
// Page Allocation Tiers
|
||||
// ---------------------
|
||||
//
|
||||
// Page Type Page Size Object Size Limit Object Alignment
|
||||
// ------------------------------------------------------------------
|
||||
// Small 2M <= 265K <MinObjAlignmentInBytes>
|
||||
// Medium 32M <= 4M 4K
|
||||
// Large X*M > 4M 2M
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
const size_t ZPlatformGranuleSizeShift = 21; // 2MB
|
||||
const size_t ZPlatformHeapViews = 3;
|
||||
const size_t ZPlatformNMethodDisarmedOffset = 4;
|
||||
const size_t ZPlatformCacheLineSize = 64;
|
||||
|
||||
uintptr_t ZPlatformAddressBase();
|
||||
size_t ZPlatformAddressOffsetBits();
|
||||
size_t ZPlatformAddressMetadataShift();
|
||||
uintptr_t ZPlatformAddressBase();
|
||||
size_t ZPlatformAddressOffsetBits();
|
||||
size_t ZPlatformAddressMetadataShift();
|
||||
|
||||
#endif // CPU_AARCH64_GC_Z_ZGLOBALS_AARCH64_HPP
|
||||
|
@ -142,8 +142,7 @@ uintptr_t ZPlatformAddressBase() {
|
||||
size_t ZPlatformAddressOffsetBits() {
|
||||
const size_t min_address_offset_bits = 42; // 4TB
|
||||
const size_t max_address_offset_bits = 44; // 16TB
|
||||
const size_t virtual_to_physical_ratio = 7; // 7:1
|
||||
const size_t address_offset = ZUtils::round_up_power_of_2(MaxHeapSize * virtual_to_physical_ratio);
|
||||
const size_t address_offset = ZUtils::round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio);
|
||||
const size_t address_offset_bits = log2_intptr(address_offset);
|
||||
return MIN2(MAX2(address_offset_bits, min_address_offset_bits), max_address_offset_bits);
|
||||
}
|
||||
|
@ -24,23 +24,13 @@
|
||||
#ifndef CPU_X86_GC_Z_ZGLOBALS_X86_HPP
|
||||
#define CPU_X86_GC_Z_ZGLOBALS_X86_HPP
|
||||
|
||||
//
|
||||
// Page Allocation Tiers
|
||||
// ---------------------
|
||||
//
|
||||
// Page Type Page Size Object Size Limit Object Alignment
|
||||
// ------------------------------------------------------------------
|
||||
// Small 2M <= 265K <MinObjAlignmentInBytes>
|
||||
// Medium 32M <= 4M 4K
|
||||
// Large X*M > 4M 2M
|
||||
// ------------------------------------------------------------------
|
||||
//
|
||||
const size_t ZPlatformGranuleSizeShift = 21; // 2MB
|
||||
const size_t ZPlatformHeapViews = 3;
|
||||
const size_t ZPlatformNMethodDisarmedOffset = 4;
|
||||
const size_t ZPlatformCacheLineSize = 64;
|
||||
|
||||
uintptr_t ZPlatformAddressBase();
|
||||
size_t ZPlatformAddressOffsetBits();
|
||||
size_t ZPlatformAddressMetadataShift();
|
||||
uintptr_t ZPlatformAddressBase();
|
||||
size_t ZPlatformAddressOffsetBits();
|
||||
size_t ZPlatformAddressMetadataShift();
|
||||
|
||||
#endif // CPU_X86_GC_Z_ZGLOBALS_X86_HPP
|
||||
|
@ -51,7 +51,7 @@ static bool map(uintptr_t start, size_t size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZVirtualMemoryManager::reserve_platform(uintptr_t start, size_t size) {
|
||||
bool ZVirtualMemoryManager::reserve_contiguous_platform(uintptr_t start, size_t size) {
|
||||
// Reserve address views
|
||||
const uintptr_t marked0 = ZAddress::marked0(start);
|
||||
const uintptr_t marked1 = ZAddress::marked1(start);
|
||||
|
51
src/hotspot/share/gc/z/zAddressSpaceLimit.cpp
Normal file
51
src/hotspot/share/gc/z/zAddressSpaceLimit.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 "gc/z/zAddressSpaceLimit.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
static size_t address_space_limit() {
|
||||
julong limit = 0;
|
||||
|
||||
if (os::has_allocatable_memory_limit(&limit)) {
|
||||
return (size_t)limit;
|
||||
}
|
||||
|
||||
// No limit
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
size_t ZAddressSpaceLimit::mark_stack() {
|
||||
// Allow mark stacks to occupy 10% of the address space
|
||||
const size_t limit = address_space_limit() / 10;
|
||||
return align_up(limit, ZMarkStackSpaceExpandSize);
|
||||
}
|
||||
|
||||
size_t ZAddressSpaceLimit::heap_view() {
|
||||
// Allow all heap views to occupy 50% of the address space
|
||||
const size_t limit = address_space_limit() / 2 / ZHeapViews;
|
||||
return align_up(limit, ZGranuleSize);
|
||||
}
|
35
src/hotspot/share/gc/z/zAddressSpaceLimit.hpp
Normal file
35
src/hotspot/share/gc/z/zAddressSpaceLimit.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_Z_ZADDRESSSPACELIMIT_HPP
|
||||
#define SHARE_GC_Z_ZADDRESSSPACELIMIT_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class ZAddressSpaceLimit : public AllStatic {
|
||||
public:
|
||||
static size_t mark_stack();
|
||||
static size_t heap_view();
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_Z_ZADDRESSSPACELIMIT_HPP
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zAddressSpaceLimit.hpp"
|
||||
#include "gc/z/zArguments.hpp"
|
||||
#include "gc/z/zCollectedHeap.hpp"
|
||||
#include "gc/z/zWorkers.hpp"
|
||||
@ -37,6 +38,15 @@ void ZArguments::initialize_alignments() {
|
||||
void ZArguments::initialize() {
|
||||
GCArguments::initialize();
|
||||
|
||||
// Check mark stack size
|
||||
const size_t mark_stack_space_limit = ZAddressSpaceLimit::mark_stack();
|
||||
if (ZMarkStackSpaceLimit > mark_stack_space_limit) {
|
||||
if (!FLAG_IS_DEFAULT(ZMarkStackSpaceLimit)) {
|
||||
vm_exit_during_initialization("ZMarkStackSpaceLimit too large for limited address space");
|
||||
}
|
||||
FLAG_SET_DEFAULT(ZMarkStackSpaceLimit, mark_stack_space_limit);
|
||||
}
|
||||
|
||||
// Enable NUMA by default
|
||||
if (FLAG_IS_DEFAULT(UseNUMA)) {
|
||||
FLAG_SET_DEFAULT(UseNUMA, true);
|
||||
|
@ -44,6 +44,23 @@ extern uint32_t ZGlobalSeqNum;
|
||||
const size_t ZGranuleSizeShift = ZPlatformGranuleSizeShift;
|
||||
const size_t ZGranuleSize = (size_t)1 << ZGranuleSizeShift;
|
||||
|
||||
// Number of heap views
|
||||
const size_t ZHeapViews = ZPlatformHeapViews;
|
||||
|
||||
// Virtual memory to physical memory ratio
|
||||
const size_t ZVirtualToPhysicalRatio = 16; // 16:1
|
||||
|
||||
//
|
||||
// Page Tiers (assuming ZGranuleSize=2M)
|
||||
// -------------------------------------
|
||||
//
|
||||
// Page Size Object Size Object Alignment
|
||||
// --------------------------------------------------
|
||||
// Small 2M <= 265K MinObjAlignmentInBytes
|
||||
// Medium 32M <= 4M 4K
|
||||
// Large N x 2M > 4M 2M
|
||||
//
|
||||
|
||||
// Page types
|
||||
const uint8_t ZPageTypeSmall = 0;
|
||||
const uint8_t ZPageTypeMedium = 1;
|
||||
|
@ -22,10 +22,13 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zAddressSpaceLimit.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zVirtualMemory.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) :
|
||||
_manager(),
|
||||
@ -38,11 +41,9 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) :
|
||||
return;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Address Space: " SIZE_FORMAT "T", ZAddressOffsetMax / K / G);
|
||||
|
||||
// Reserve address space
|
||||
if (reserve(0, ZAddressOffsetMax) < max_capacity) {
|
||||
log_error(gc)("Failed to reserve address space for Java heap");
|
||||
if (!reserve(max_capacity)) {
|
||||
log_error(gc)("Failed to reserve enough address space for Java heap");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -50,21 +51,92 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) :
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
size_t ZVirtualMemoryManager::reserve(uintptr_t start, size_t size) {
|
||||
if (size < ZGranuleSize) {
|
||||
size_t ZVirtualMemoryManager::reserve_discontiguous(uintptr_t start, size_t size, size_t min_range) {
|
||||
if (size < min_range) {
|
||||
// Too small
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!reserve_platform(start, size)) {
|
||||
const size_t half = size / 2;
|
||||
return reserve(start, half) + reserve(start + half, half);
|
||||
assert(is_aligned(size, ZGranuleSize), "Misaligned");
|
||||
|
||||
if (reserve_contiguous_platform(start, size)) {
|
||||
// Make the address range free
|
||||
_manager.free(start, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
// Make the address range free
|
||||
_manager.free(start, size);
|
||||
const size_t half = size / 2;
|
||||
if (half < min_range) {
|
||||
// Too small
|
||||
return 0;
|
||||
}
|
||||
|
||||
return size;
|
||||
// Divide and conquer
|
||||
const size_t first_part = align_down(half, ZGranuleSize);
|
||||
const size_t second_part = size - first_part;
|
||||
return reserve_discontiguous(start, first_part, min_range) +
|
||||
reserve_discontiguous(start + first_part, second_part, min_range);
|
||||
}
|
||||
|
||||
size_t ZVirtualMemoryManager::reserve_discontiguous(size_t size) {
|
||||
// Don't try to reserve address ranges smaller than 1% of the requested size.
|
||||
// This avoids an explosion of reservation attempts in case large parts of the
|
||||
// address space is already occupied.
|
||||
const size_t min_range = align_up(size / 100, ZGranuleSize);
|
||||
size_t start = 0;
|
||||
size_t reserved = 0;
|
||||
|
||||
// Reserve size somewhere between [0, ZAddressOffsetMax)
|
||||
while (reserved < size && start < ZAddressOffsetMax) {
|
||||
const size_t remaining = MIN2(size - reserved, ZAddressOffsetMax - start);
|
||||
reserved += reserve_discontiguous(start, remaining, min_range);
|
||||
start += remaining;
|
||||
}
|
||||
|
||||
return reserved;
|
||||
}
|
||||
|
||||
bool ZVirtualMemoryManager::reserve_contiguous(size_t size) {
|
||||
// Allow at most 8192 attempts spread evenly across [0, ZAddressOffsetMax)
|
||||
const size_t end = ZAddressOffsetMax - size;
|
||||
const size_t increment = align_up(end / 8192, ZGranuleSize);
|
||||
|
||||
for (size_t start = 0; start <= end; start += increment) {
|
||||
if (reserve_contiguous_platform(start, size)) {
|
||||
// Make the address range free
|
||||
_manager.free(start, size);
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Failed
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZVirtualMemoryManager::reserve(size_t max_capacity) {
|
||||
const size_t limit = MIN2(ZAddressOffsetMax, ZAddressSpaceLimit::heap_view());
|
||||
const size_t size = MIN2(max_capacity * ZVirtualToPhysicalRatio, limit);
|
||||
|
||||
size_t reserved = size;
|
||||
bool contiguous = true;
|
||||
|
||||
// Prefer a contiguous address space
|
||||
if (!reserve_contiguous(size)) {
|
||||
// Fall back to a discontiguous address space
|
||||
reserved = reserve_discontiguous(size);
|
||||
contiguous = false;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Address Space Type: %s/%s/%s",
|
||||
(contiguous ? "Contiguous" : "Discontiguous"),
|
||||
(limit == ZAddressOffsetMax ? "Unrestricted" : "Restricted"),
|
||||
(reserved == size ? "Complete" : "Degraded"));
|
||||
log_info(gc, init)("Address Space Size: " SIZE_FORMAT "M x " SIZE_FORMAT " = " SIZE_FORMAT "M",
|
||||
reserved / M, ZHeapViews, (reserved * ZHeapViews) / M);
|
||||
|
||||
return reserved >= max_capacity;
|
||||
}
|
||||
|
||||
void ZVirtualMemoryManager::nmt_reserve(uintptr_t start, size_t size) {
|
||||
|
@ -50,8 +50,12 @@ private:
|
||||
ZMemoryManager _manager;
|
||||
bool _initialized;
|
||||
|
||||
bool reserve_platform(uintptr_t start, size_t size);
|
||||
size_t reserve(uintptr_t start, size_t size);
|
||||
bool reserve_contiguous_platform(uintptr_t start, size_t size);
|
||||
bool reserve_contiguous(size_t size);
|
||||
size_t reserve_discontiguous(uintptr_t start, size_t size, size_t min_range);
|
||||
size_t reserve_discontiguous(size_t size);
|
||||
bool reserve(size_t max_capacity);
|
||||
|
||||
void nmt_reserve(uintptr_t start, size_t size);
|
||||
|
||||
public:
|
||||
|
@ -42,8 +42,6 @@
|
||||
* @library /vmTestbase
|
||||
* /test/lib
|
||||
* @requires os.family != "aix"
|
||||
* @comment Test is incompatible with ZGC, due to ZGC's address space requirements.
|
||||
* @requires vm.gc != "Z"
|
||||
* @run driver jdk.test.lib.FileInstaller . .
|
||||
* @build nsk.jvmti.Allocate.alloc001
|
||||
* @run shell alloc001.sh
|
||||
|
Loading…
Reference in New Issue
Block a user