8236847: CDS archive with 4K alignment unusable on machines with 64k pages

Reviewed-by: iklam, stuefe, erikj, ihse
This commit is contained in:
Yumin Qi 2021-03-11 16:49:24 +00:00
parent 273f8bdf5f
commit 3820ab9e82
16 changed files with 206 additions and 59 deletions

View File

@ -248,6 +248,7 @@ JDKOPT_ENABLE_DISABLE_GENERATE_CLASSLIST
JDKOPT_EXCLUDE_TRANSLATIONS
JDKOPT_ENABLE_DISABLE_MANPAGES
JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE
JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT
###############################################################################
#

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2011, 2021, 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
@ -585,6 +585,30 @@ AC_DEFUN([JDKOPT_ENABLE_DISABLE_CDS_ARCHIVE],
AC_SUBST(BUILD_CDS_ARCHIVE)
])
################################################################################
#
# Enable the alternative CDS core region alignment
#
AC_DEFUN([JDKOPT_ENABLE_DISABLE_COMPATIBLE_CDS_ALIGNMENT],
[
UTIL_ARG_ENABLE(NAME: compatible-cds-alignment, DEFAULT: false,
RESULT: ENABLE_COMPATIBLE_CDS_ALIGNMENT,
DESC: [enable use alternative compatible cds core region alignment],
DEFAULT_DESC: [disabled],
CHECKING_MSG: [if compatible cds region alignment enabled],
CHECK_AVAILABLE: [
AC_MSG_CHECKING([if CDS archive is available])
if test "x$BUILD_CDS_ARCHIVE" = "xfalse"; then
AVAILABLE=false
AC_MSG_RESULT([no (CDS is disabled)])
else
AVAILABLE=true
AC_MSG_RESULT([yes])
fi
])
AC_SUBST(ENABLE_COMPATIBLE_CDS_ALIGNMENT)
])
################################################################################
#
# Disallow any output from containing absolute paths from the build system.

View File

@ -349,6 +349,8 @@ BUILD_MANPAGES := @BUILD_MANPAGES@
BUILD_CDS_ARCHIVE := @BUILD_CDS_ARCHIVE@
ENABLE_COMPATIBLE_CDS_ALIGNMENT := @ENABLE_COMPATIBLE_CDS_ALIGNMENT@
ALLOW_ABSOLUTE_PATHS_IN_OUTPUT := @ALLOW_ABSOLUTE_PATHS_IN_OUTPUT@
# The boot jdk to use. This is overridden in bootcycle-spec.gmk. Make sure to keep

View File

@ -441,6 +441,7 @@ var getJibProfilesProfiles = function (input, common, data) {
dependencies: ["devkit", "gtest", "pandoc"],
configure_args: concat(common.configure_args_64bit, "--with-zlib=system",
"--with-macosx-version-max=10.12.00",
"--enable-compatible-cds-alignment",
// Use system SetFile instead of the one in the devkit as the
// devkit one may not work on Catalina.
"SETFILE=/usr/bin/SetFile"),
@ -477,6 +478,7 @@ var getJibProfilesProfiles = function (input, common, data) {
dependencies: ["devkit", "gtest", "build_devkit", "pandoc"],
configure_args: [
"--openjdk-target=aarch64-linux-gnu",
"--enable-compatible-cds-alignment",
],
},

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2013, 2021, 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
@ -99,3 +99,7 @@ endif
ifneq ($(HOTSPOT_OVERRIDE_LIBPATH), )
JVM_CFLAGS += -DOVERRIDE_LIBPATH='"$(HOTSPOT_OVERRIDE_LIBPATH)"'
endif
ifeq ($(ENABLE_COMPATIBLE_CDS_ALIGNMENT), true)
JVM_CFLAGS += -DCOMPATIBLE_CDS_ALIGNMENT
endif

View File

@ -25,6 +25,12 @@
#ifndef OS_CPU_BSD_X86_OS_BSD_X86_HPP
#define OS_CPU_BSD_X86_OS_BSD_X86_HPP
// Core region alignment is 16K to be able to run binaries built on MacOS x64
// on MacOS aarch64.
#if defined(__APPLE__) && defined(COMPATIBLE_CDS_ALIGNMENT)
#define CDS_CORE_REGION_ALIGNMENT (16*K)
#endif
static void setup_fpu();
static bool supports_sse();
static juint cpu_microcode_revision();

View File

@ -26,6 +26,10 @@
#ifndef OS_CPU_LINUX_AARCH64_OS_LINUX_AARCH64_HPP
#define OS_CPU_LINUX_AARCH64_OS_LINUX_AARCH64_HPP
#if defined(COMPATIBLE_CDS_ALIGNMENT)
#define CDS_CORE_REGION_ALIGNMENT (64*K)
#endif
static void setup_fpu();
static bool is_allocatable(size_t bytes);

View File

@ -327,19 +327,19 @@ size_t ArchiveBuilder::estimate_archive_size() {
total += _estimated_hashtable_bytes;
// allow fragmentation at the end of each dump region
total += _total_dump_regions * reserve_alignment();
total += _total_dump_regions * MetaspaceShared::core_region_alignment();
log_info(cds)("_estimated_hashtable_bytes = " SIZE_FORMAT " + " SIZE_FORMAT " = " SIZE_FORMAT,
symbol_table_est, dictionary_est, _estimated_hashtable_bytes);
log_info(cds)("_estimated_metaspaceobj_bytes = " SIZE_FORMAT, _estimated_metaspaceobj_bytes);
log_info(cds)("total estimate bytes = " SIZE_FORMAT, total);
return align_up(total, reserve_alignment());
return align_up(total, MetaspaceShared::core_region_alignment());
}
address ArchiveBuilder::reserve_buffer() {
size_t buffer_size = estimate_archive_size();
ReservedSpace rs(buffer_size);
ReservedSpace rs(buffer_size, MetaspaceShared::core_region_alignment(), false);
if (!rs.is_reserved()) {
log_error(cds)("Failed to reserve " SIZE_FORMAT " bytes of output buffer.", buffer_size);
vm_direct_exit(0);
@ -377,7 +377,7 @@ address ArchiveBuilder::reserve_buffer() {
// At run time, we will mmap the dynamic archive at my_archive_requested_bottom
_requested_static_archive_top = _requested_static_archive_bottom + static_archive_size;
my_archive_requested_bottom = align_up(_requested_static_archive_top, MetaspaceShared::reserved_space_alignment());
my_archive_requested_bottom = align_up(_requested_static_archive_top, MetaspaceShared::core_region_alignment());
_requested_dynamic_archive_bottom = my_archive_requested_bottom;
}

View File

@ -223,9 +223,8 @@ private:
static ArchiveBuilder* _current;
public:
// Use this when you allocate space with MetaspaceShare::read_only_space_alloc()
// outside of ArchiveBuilder::dump_{rw,ro}_region. These are usually for misc tables
// that are allocated in the RO space.
// Use this when you allocate space outside of ArchiveBuilder::dump_{rw,ro}_region.
// These are usually for misc tables that are allocated in the RO space.
class OtherROAllocMark {
char* _oldtop;
public:
@ -265,10 +264,6 @@ protected:
size_t estimate_archive_size();
static size_t reserve_alignment() {
return os::vm_allocation_granularity();
}
void start_dump_space(DumpRegion* next);
void verify_estimate_size(size_t estimate, const char* which);

View File

@ -246,7 +246,7 @@ void DumpRegion::init(ReservedSpace* rs, VirtualSpace* vs) {
void DumpRegion::pack(DumpRegion* next) {
assert(!is_packed(), "sanity");
_end = (char*)align_up(_top, MetaspaceShared::reserved_space_alignment());
_end = (char*)align_up(_top, MetaspaceShared::core_region_alignment());
_is_packed = true;
if (next != NULL) {
next->_rs = _rs;

View File

@ -47,12 +47,6 @@
class DynamicArchiveBuilder : public ArchiveBuilder {
public:
static size_t reserve_alignment() {
return os::vm_allocation_granularity();
}
public:
void mark_pointer(address* ptr_loc) {
ArchivePtrMarker::mark_pointer(ptr_loc);
@ -179,7 +173,7 @@ void DynamicArchiveBuilder::init_header() {
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
_header->set_base_region_crc(i, base_info->space_crc(i));
}
_header->populate(base_info, os::vm_allocation_granularity());
_header->populate(base_info, base_info->core_region_alignment());
}
void DynamicArchiveBuilder::release_header() {

View File

@ -198,18 +198,18 @@ FileMapInfo::~FileMapInfo() {
}
}
void FileMapInfo::populate_header(size_t alignment) {
header()->populate(this, alignment);
void FileMapInfo::populate_header(size_t core_region_alignment) {
header()->populate(this, core_region_alignment);
}
void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
void FileMapHeader::populate(FileMapInfo* mapinfo, size_t core_region_alignment) {
if (DynamicDumpSharedSpaces) {
_magic = CDS_DYNAMIC_ARCHIVE_MAGIC;
} else {
_magic = CDS_ARCHIVE_MAGIC;
}
_version = CURRENT_CDS_ARCHIVE_VERSION;
_alignment = alignment;
_core_region_alignment = core_region_alignment;
_obj_alignment = ObjectAlignmentInBytes;
_compact_strings = CompactStrings;
if (HeapShared::is_heap_object_archiving_allowed()) {
@ -267,7 +267,7 @@ void FileMapHeader::print(outputStream* st) {
st->print_cr("============ end regions ======== ");
st->print_cr("- header_size: " SIZE_FORMAT, _header_size);
st->print_cr("- alignment: " SIZE_FORMAT, _alignment);
st->print_cr("- core_region_alignment: " SIZE_FORMAT, _core_region_alignment);
st->print_cr("- obj_alignment: %d", _obj_alignment);
st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base));
st->print_cr("- narrow_oop_base: " INTPTR_FORMAT, p2i(_narrow_oop_base));
@ -1225,7 +1225,7 @@ void FileMapInfo::open_for_write(const char* path) {
header_bytes += strlen(Arguments::GetSharedArchivePath()) + 1;
}
header_bytes = align_up(header_bytes, os::vm_allocation_granularity());
header_bytes = align_up(header_bytes, MetaspaceShared::core_region_alignment());
_file_offset = header_bytes;
seek_to_position(_file_offset);
}
@ -1251,7 +1251,7 @@ void FileMapInfo::write_header() {
}
size_t FileMapRegion::used_aligned() const {
return align_up(used(), os::vm_allocation_granularity());
return align_up(used(), MetaspaceShared::core_region_alignment());
}
void FileMapRegion::init(int region_index, size_t mapping_offset, size_t size, bool read_only,
@ -1456,7 +1456,7 @@ void FileMapInfo::write_bytes(const void* buffer, size_t nbytes) {
bool FileMapInfo::is_file_position_aligned() const {
return _file_offset == align_up(_file_offset,
os::vm_allocation_granularity());
MetaspaceShared::core_region_alignment());
}
// Align file position to an allocation unit boundary.
@ -1464,7 +1464,7 @@ bool FileMapInfo::is_file_position_aligned() const {
void FileMapInfo::align_file_position() {
assert(_file_open, "must be");
size_t new_file_offset = align_up(_file_offset,
os::vm_allocation_granularity());
MetaspaceShared::core_region_alignment());
if (new_file_offset != _file_offset) {
_file_offset = new_file_offset;
// Seek one byte back from the target and write a byte to insure
@ -1507,8 +1507,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() {
// the space is already readwrite so we are done
return true;
}
size_t used = si->used();
size_t size = align_up(used, os::vm_allocation_granularity());
size_t size = si->used_aligned();
if (!open_for_read()) {
return false;
}
@ -2088,8 +2087,7 @@ void FileMapInfo::unmap_region(int i) {
assert(!HeapShared::is_heap_region(i), "sanity");
FileMapRegion* si = space_at(i);
char* mapped_base = si->mapped_base();
size_t used = si->used();
size_t size = align_up(used, os::vm_allocation_granularity());
size_t size = si->used_aligned();
if (mapped_base != NULL) {
if (size > 0 && si->mapped_from_file()) {

View File

@ -154,7 +154,7 @@ public:
size_t mapping_offset() const { return _mapping_offset; }
size_t mapping_end_offset() const { return _mapping_offset + used_aligned(); }
size_t used() const { return _used; }
size_t used_aligned() const; // aligned up to os::vm_allocation_granularity()
size_t used_aligned() const; // aligned up to MetaspaceShared::core_region_alignment()
char* mapped_base() const { assert_is_not_heap_region(); return _mapped_base; }
char* mapped_end() const { return mapped_base() + used_aligned(); }
bool read_only() const { return _read_only != 0; }
@ -187,7 +187,7 @@ class FileMapHeader: private CDSFileMapHeaderBase {
// The following fields record the states of the VM during dump time.
// They are compared with the runtime states to see if the archive
// can be used.
size_t _alignment; // how shared archive should be aligned
size_t _core_region_alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
address _narrow_oop_base; // compressed oop encoding base
int _narrow_oop_shift; // compressed oop encoding shift
@ -251,7 +251,7 @@ public:
// Accessors -- fields declared in FileMapHeader
size_t header_size() const { return _header_size; }
size_t alignment() const { return _alignment; }
size_t core_region_alignment() const { return _core_region_alignment; }
int obj_alignment() const { return _obj_alignment; }
address narrow_oop_base() const { return _narrow_oop_base; }
int narrow_oop_shift() const { return _narrow_oop_shift; }
@ -312,7 +312,7 @@ public:
return FileMapRegion::cast(&_space[i]);
}
void populate(FileMapInfo* info, size_t alignment);
void populate(FileMapInfo* info, size_t core_region_alignment);
static bool is_valid_region(int region) {
return (0 <= region && region < NUM_CDS_REGIONS);
@ -378,17 +378,17 @@ public:
int compute_header_crc() const { return header()->compute_crc(); }
void set_header_crc(int crc) { header()->set_crc(crc); }
int space_crc(int i) const { return space_at(i)->crc(); }
void populate_header(size_t alignment);
void populate_header(size_t core_region_alignment);
bool validate_header();
void invalidate();
int crc() const { return header()->crc(); }
int version() const { return header()->version(); }
size_t alignment() const { return header()->alignment(); }
address narrow_oop_base() const { return header()->narrow_oop_base(); }
int narrow_oop_shift() const { return header()->narrow_oop_shift(); }
uintx max_heap_size() const { return header()->max_heap_size(); }
address narrow_klass_base() const { return header()->narrow_klass_base(); }
int narrow_klass_shift() const { return header()->narrow_klass_shift(); }
size_t core_region_alignment() const { return header()->core_region_alignment(); }
CompressedOops::Mode narrow_oop_mode() const { return header()->narrow_oop_mode(); }
jshort app_module_paths_start_index() const { return header()->app_module_paths_start_index(); }

View File

@ -120,7 +120,21 @@ char* MetaspaceShared::symbol_space_alloc(size_t num_bytes) {
return _symbol_region.allocate(num_bytes);
}
size_t MetaspaceShared::reserved_space_alignment() { return os::vm_allocation_granularity(); }
// os::vm_allocation_granularity() is usually 4K for most OSes. However, on Linux/aarch64,
// it can be either 4K or 64K and on Macosx-arm it is 16K. To generate archives that are
// compatible for both settings, an alternative cds core region alignment can be enabled
// at building time:
// --enable-compactible-cds-alignment
// Upon successful configuration, the compactible alignment then can be defined as in:
// os_linux_aarch64.hpp
// which is the highest page size configured on the platform.
size_t MetaspaceShared::core_region_alignment() {
#if defined(CDS_CORE_REGION_ALIGNMENT)
return CDS_CORE_REGION_ALIGNMENT;
#else
return (size_t)os::vm_allocation_granularity();
#endif // CDS_CORE_REGION_ALIGNMENT
}
static bool shared_base_valid(char* shared_base) {
#ifdef _LP64
@ -133,7 +147,7 @@ static bool shared_base_valid(char* shared_base) {
static bool shared_base_too_high(char* specified_base, char* aligned_base, size_t cds_max) {
if (specified_base != NULL && aligned_base < specified_base) {
// SharedBaseAddress is very high (e.g., 0xffffffffffffff00) so
// align_up(SharedBaseAddress, MetaspaceShared::reserved_space_alignment()) has wrapped around.
// align_up(SharedBaseAddress, MetaspaceShared::core_region_alignment()) has wrapped around.
return true;
}
if (max_uintx - uintx(aligned_base) < uintx(cds_max)) {
@ -146,7 +160,7 @@ static bool shared_base_too_high(char* specified_base, char* aligned_base, size_
static char* compute_shared_base(size_t cds_max) {
char* specified_base = (char*)SharedBaseAddress;
char* aligned_base = align_up(specified_base, MetaspaceShared::reserved_space_alignment());
char* aligned_base = align_up(specified_base, MetaspaceShared::core_region_alignment());
const char* err = NULL;
if (shared_base_too_high(specified_base, aligned_base, cds_max)) {
@ -162,7 +176,7 @@ static char* compute_shared_base(size_t cds_max) {
p2i((void*)Arguments::default_SharedBaseAddress()));
specified_base = (char*)Arguments::default_SharedBaseAddress();
aligned_base = align_up(specified_base, MetaspaceShared::reserved_space_alignment());
aligned_base = align_up(specified_base, MetaspaceShared::core_region_alignment());
// Make sure the default value of SharedBaseAddress specified in globals.hpp is sane.
assert(!shared_base_too_high(specified_base, aligned_base, cds_max), "Sanity");
@ -172,11 +186,11 @@ static char* compute_shared_base(size_t cds_max) {
void MetaspaceShared::initialize_for_static_dump() {
assert(DumpSharedSpaces, "should be called for dump time only");
log_info(cds)("Core region alignment: " SIZE_FORMAT, core_region_alignment());
// The max allowed size for CDS archive. We use this to limit SharedBaseAddress
// to avoid address space wrap around.
size_t cds_max;
const size_t reserve_alignment = MetaspaceShared::reserved_space_alignment();
const size_t reserve_alignment = core_region_alignment();
#ifdef _LP64
const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1);
@ -491,7 +505,7 @@ void VM_PopulateDumpSharedSpace::doit() {
// Write the archive file
FileMapInfo* mapinfo = new FileMapInfo(true);
mapinfo->populate_header(os::vm_allocation_granularity());
mapinfo->populate_header(MetaspaceShared::core_region_alignment());
mapinfo->set_serialized_data(serialized_data);
mapinfo->set_cloned_vtables(cloned_vtables);
mapinfo->open_for_write();
@ -854,6 +868,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
FileMapInfo* dynamic_mapinfo = NULL;
if (static_mapinfo != NULL) {
log_info(cds)("Core region alignment: " SIZE_FORMAT, static_mapinfo->core_region_alignment());
dynamic_mapinfo = open_dynamic_archive();
// First try to map at the requested address
@ -974,7 +989,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
assert(class_space_rs.base() >= archive_space_rs.end(),
"class space should follow the cds archive space");
assert(is_aligned(archive_space_rs.base(),
MetaspaceShared::reserved_space_alignment()),
core_region_alignment()),
"Archive space misaligned");
assert(is_aligned(class_space_rs.base(),
Metaspace::reserve_alignment()),
@ -982,9 +997,9 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File
}
#endif // ASSERT
log_debug(cds)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (" SIZE_FORMAT ") bytes",
log_info(cds)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (" SIZE_FORMAT ") bytes",
p2i(archive_space_rs.base()), p2i(archive_space_rs.end()), archive_space_rs.size());
log_debug(cds)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (" SIZE_FORMAT ") bytes",
log_info(cds)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (" SIZE_FORMAT ") bytes",
p2i(class_space_rs.base()), p2i(class_space_rs.end()), class_space_rs.size());
if (MetaspaceShared::use_windows_memory_mapping()) {
@ -1146,7 +1161,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
ReservedSpace& class_space_rs) {
address const base_address = (address) (use_archive_base_addr ? static_mapinfo->requested_base_address() : NULL);
const size_t archive_space_alignment = MetaspaceShared::reserved_space_alignment();
const size_t archive_space_alignment = core_region_alignment();
// Size and requested location of the archive_space_rs (for both static and dynamic archives)
assert(static_mapinfo->mapping_base_offset() == 0, "Must be");
@ -1204,8 +1219,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
const size_t gap_size = ccs_begin_offset - archive_space_size;
const size_t total_range_size =
align_up(archive_space_size + gap_size + class_space_size,
os::vm_allocation_granularity());
align_up(archive_space_size + gap_size + class_space_size, core_region_alignment());
assert(total_range_size > ccs_begin_offset, "must be");
if (use_windows_memory_mapping() && use_archive_base_addr) {
@ -1248,7 +1262,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
// Now split up the space into ccs and cds archive. For simplicity, just leave
// the gap reserved at the end of the archive space. Do not do real splitting.
archive_space_rs = total_space_rs.first_part(ccs_begin_offset,
(size_t)os::vm_allocation_granularity());
(size_t)archive_space_alignment);
class_space_rs = total_space_rs.last_part(ccs_begin_offset);
MemTracker::record_virtual_memory_split_reserved(total_space_rs.base(), total_space_rs.size(),
ccs_begin_offset);
@ -1299,10 +1313,9 @@ MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped
}
mapinfo->set_is_mapped(false);
if (mapinfo->alignment() != (size_t)os::vm_allocation_granularity()) {
log_info(cds)("Unable to map CDS archive -- os::vm_allocation_granularity() expected: " SIZE_FORMAT
" actual: %d", mapinfo->alignment(), os::vm_allocation_granularity());
if (mapinfo->core_region_alignment() != (size_t)core_region_alignment()) {
log_info(cds)("Unable to map CDS archive -- core_region_alignment() expected: " SIZE_FORMAT
" actual: " SIZE_FORMAT, mapinfo->core_region_alignment(), core_region_alignment());
return MAP_ARCHIVE_OTHER_FAILURE;
}

View File

@ -133,7 +133,9 @@ class MetaspaceShared : AllStatic {
static bool linking_required(InstanceKlass* ik) NOT_CDS_RETURN_(false);
#if INCLUDE_CDS
static size_t reserved_space_alignment();
// Alignment for the 3 core CDS regions (MC/RW/RO) only.
// (Heap region alignments are decided by GC).
static size_t core_region_alignment();
static void rewrite_nofast_bytecodes_and_calculate_fingerprints(Thread* thread, InstanceKlass* ik);
#endif

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2021, 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.
*/
/**
* @test
* @requires vm.cds
* @requires vm.gc != "Z"
* @summary Testing handling of CDS region alignment
* @comment ZGC may exit the VM if -XX:+UseLargePages is specified but
* unavailable. Since this test is independent of the actual GC type, let's
* disable it if ZGC is used.
* @bug 8236847
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes
* @build Hello
* @run driver ClassFileInstaller -jar hello.jar Hello
* @run driver SharedRegionAlignmentTest
*/
import jdk.test.lib.process.OutputAnalyzer;
public class SharedRegionAlignmentTest {
static String appJar = ClassFileInstaller.getJarPath("hello.jar");
static String mainClass = "Hello";
static String logArg = "-Xlog:cds";
static void testCombo() throws Exception {
// Test the following combinations:
// Dump (3 combinations): largePageArgs
// Run (3 combinations): largePageArgs
String UseLargePages = "-XX:+UseLargePages";
String [][] largePageArgs = {
{}, // default
{UseLargePages}
};
final String logFor64K = "core_region_alignment = 65535";
int dumpCase = 0;
for (String[] dumpLP: largePageArgs) {
dumpCase ++;
System.out.println("============================================================");
System.out.println("dump case (" + dumpCase + "): " + formatLargePageArgs(dumpLP));
System.out.println("============================================================");
OutputAnalyzer out = TestCommon.dump(appJar,
TestCommon.list(mainClass),
TestCommon.concat(dumpLP, logArg));
out.shouldContain("Dumping shared data to file");
boolean is_aligned_64k = out.getStdout().contains(logFor64K);
int runCase = 0;
for (String[] runLP: largePageArgs) {
runCase++;
System.out.println("--------------------------------------------------");
System.out.println("run case (" + dumpCase + "." + runCase + "):" + formatLargePageArgs(runLP));
System.out.println("--------------------------------------------------");
TestCommon.run(TestCommon.concat(runLP, "-cp", appJar, logArg, mainClass))
.assertNormalExit(output -> {
if (is_aligned_64k) {
output.shouldContain(logFor64K);
}
output.shouldContain("Hello World");
});
}
}
}
static String formatLargePageArgs(String args[]) {
StringBuilder sb = new StringBuilder();
for (String a : args) {
sb.append(" ");
sb.append(a);
}
return sb.toString();
}
public static void main(String... args) throws Exception {
testCombo();
}
}