mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 10:34:38 +02:00
8256155: Allow multiple large page sizes to be used on Linux
Co-authored-by: Marcus G K Williams <mgkwill@openjdk.org> Co-authored-by: Stefan Johansson <sjohanss@openjdk.org> Co-authored-by: Thomas Stuefe <stuefe@openjdk.org> Reviewed-by: stuefe, sjohanss
This commit is contained in:
parent
ec8a8097c3
commit
94cfeb9c4f
3 changed files with 121 additions and 63 deletions
|
@ -2346,6 +2346,9 @@ void os::print_memory_info(outputStream* st) {
|
||||||
st->print("(" UINT64_FORMAT "k free)",
|
st->print("(" UINT64_FORMAT "k free)",
|
||||||
((jlong)si.freeswap * si.mem_unit) >> 10);
|
((jlong)si.freeswap * si.mem_unit) >> 10);
|
||||||
st->cr();
|
st->cr();
|
||||||
|
st->print("Page Sizes: ");
|
||||||
|
_page_sizes.print_on(st);
|
||||||
|
st->cr();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print the first "model name" line and the first "flags" line
|
// Print the first "model name" line and the first "flags" line
|
||||||
|
@ -3504,6 +3507,25 @@ bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
|
||||||
// Mapping succeeded, sanity check passed.
|
// Mapping succeeded, sanity check passed.
|
||||||
munmap(p, page_size);
|
munmap(p, page_size);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
log_info(pagesize)("Large page size (" SIZE_FORMAT "%s) failed sanity check, "
|
||||||
|
"checking if smaller large page sizes are usable",
|
||||||
|
byte_size_in_exact_unit(page_size),
|
||||||
|
exact_unit_for_byte_size(page_size));
|
||||||
|
for (size_t page_size_ = _page_sizes.next_smaller(page_size);
|
||||||
|
page_size_ != (size_t)os::vm_page_size();
|
||||||
|
page_size_ = _page_sizes.next_smaller(page_size_)) {
|
||||||
|
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | hugetlbfs_page_size_flag(page_size_);
|
||||||
|
p = mmap(NULL, page_size_, PROT_READ|PROT_WRITE, flags, -1, 0);
|
||||||
|
if (p != MAP_FAILED) {
|
||||||
|
// Mapping succeeded, sanity check passed.
|
||||||
|
munmap(p, page_size_);
|
||||||
|
log_info(pagesize)("Large page size (" SIZE_FORMAT "%s) passed sanity check",
|
||||||
|
byte_size_in_exact_unit(page_size_),
|
||||||
|
exact_unit_for_byte_size(page_size_));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (warn) {
|
if (warn) {
|
||||||
|
@ -3578,35 +3600,20 @@ static void set_coredump_filter(CoredumpFilterBit bit) {
|
||||||
|
|
||||||
static size_t _large_page_size = 0;
|
static size_t _large_page_size = 0;
|
||||||
|
|
||||||
size_t os::Linux::find_default_large_page_size() {
|
static size_t scan_default_large_page_size() {
|
||||||
if (_default_large_page_size != 0) {
|
size_t default_large_page_size = 0;
|
||||||
return _default_large_page_size;
|
|
||||||
}
|
|
||||||
size_t large_page_size = 0;
|
|
||||||
|
|
||||||
// large_page_size on Linux is used to round up heap size. x86 uses either
|
// large_page_size on Linux is used to round up heap size. x86 uses either
|
||||||
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
|
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
|
||||||
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
|
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
|
||||||
// page as large as 256M.
|
// page as large as 1G.
|
||||||
//
|
//
|
||||||
// Here we try to figure out page size by parsing /proc/meminfo and looking
|
// Here we try to figure out page size by parsing /proc/meminfo and looking
|
||||||
// for a line with the following format:
|
// for a line with the following format:
|
||||||
// Hugepagesize: 2048 kB
|
// Hugepagesize: 2048 kB
|
||||||
//
|
//
|
||||||
// If we can't determine the value (e.g. /proc is not mounted, or the text
|
// If we can't determine the value (e.g. /proc is not mounted, or the text
|
||||||
// format has been changed), we'll use the largest page size supported by
|
// format has been changed), we'll set largest page size to 0
|
||||||
// the processor.
|
|
||||||
|
|
||||||
#ifndef ZERO
|
|
||||||
large_page_size =
|
|
||||||
AARCH64_ONLY(2 * M)
|
|
||||||
AMD64_ONLY(2 * M)
|
|
||||||
ARM32_ONLY(2 * M)
|
|
||||||
IA32_ONLY(4 * M)
|
|
||||||
IA64_ONLY(256 * M)
|
|
||||||
PPC_ONLY(4 * M)
|
|
||||||
S390_ONLY(1 * M);
|
|
||||||
#endif // ZERO
|
|
||||||
|
|
||||||
FILE *fp = fopen("/proc/meminfo", "r");
|
FILE *fp = fopen("/proc/meminfo", "r");
|
||||||
if (fp) {
|
if (fp) {
|
||||||
|
@ -3615,7 +3622,7 @@ size_t os::Linux::find_default_large_page_size() {
|
||||||
char buf[16];
|
char buf[16];
|
||||||
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
|
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
|
||||||
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
|
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
|
||||||
large_page_size = x * K;
|
default_large_page_size = x * K;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -3628,21 +3635,17 @@ size_t os::Linux::find_default_large_page_size() {
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
return large_page_size;
|
|
||||||
|
return default_large_page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t os::Linux::find_large_page_size(size_t large_page_size) {
|
static os::PageSizes scan_multiple_page_support() {
|
||||||
if (_default_large_page_size == 0) {
|
// Scan /sys/kernel/mm/hugepages
|
||||||
_default_large_page_size = Linux::find_default_large_page_size();
|
|
||||||
}
|
|
||||||
// We need to scan /sys/kernel/mm/hugepages
|
|
||||||
// to discover the available page sizes
|
// to discover the available page sizes
|
||||||
const char* sys_hugepages = "/sys/kernel/mm/hugepages";
|
const char* sys_hugepages = "/sys/kernel/mm/hugepages";
|
||||||
|
os::PageSizes page_sizes;
|
||||||
|
|
||||||
DIR *dir = opendir(sys_hugepages);
|
DIR *dir = opendir(sys_hugepages);
|
||||||
if (dir == NULL) {
|
|
||||||
return _default_large_page_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
size_t page_size;
|
size_t page_size;
|
||||||
|
@ -3650,43 +3653,32 @@ size_t os::Linux::find_large_page_size(size_t large_page_size) {
|
||||||
if (entry->d_type == DT_DIR &&
|
if (entry->d_type == DT_DIR &&
|
||||||
sscanf(entry->d_name, "hugepages-%zukB", &page_size) == 1) {
|
sscanf(entry->d_name, "hugepages-%zukB", &page_size) == 1) {
|
||||||
// The kernel is using kB, hotspot uses bytes
|
// The kernel is using kB, hotspot uses bytes
|
||||||
if (large_page_size == page_size * K) {
|
// Add each found Large Page Size to page_sizes
|
||||||
closedir(dir);
|
page_sizes.add(page_size * K);
|
||||||
return large_page_size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
return _default_large_page_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t os::Linux::setup_large_page_size() {
|
LogTarget(Debug, pagesize) lt;
|
||||||
_default_large_page_size = Linux::find_default_large_page_size();
|
if (lt.is_enabled()) {
|
||||||
|
LogStream ls(lt);
|
||||||
if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != _default_large_page_size ) {
|
ls.print("Large Page sizes: ");
|
||||||
_large_page_size = find_large_page_size(LargePageSizeInBytes);
|
page_sizes.print_on(&ls);
|
||||||
if (_large_page_size == _default_large_page_size) {
|
|
||||||
warning("Setting LargePageSizeInBytes=" SIZE_FORMAT " has no effect on this OS. Using the default large page size "
|
|
||||||
SIZE_FORMAT "%s.",
|
|
||||||
LargePageSizeInBytes,
|
|
||||||
byte_size_in_proper_unit(_large_page_size), proper_unit_for_byte_size(_large_page_size));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_large_page_size = _default_large_page_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t default_page_size = (size_t)Linux::page_size();
|
return page_sizes;
|
||||||
if (_large_page_size > default_page_size) {
|
|
||||||
_page_sizes.add(_large_page_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _large_page_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t os::Linux::default_large_page_size() {
|
size_t os::Linux::default_large_page_size() {
|
||||||
return _default_large_page_size;
|
return _default_large_page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void warn_no_large_pages_configured() {
|
||||||
|
if (!FLAG_IS_DEFAULT(UseLargePages)) {
|
||||||
|
log_warning(pagesize)("UseLargePages disabled, no large pages configured and available on the system.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool os::Linux::setup_large_page_type(size_t page_size) {
|
bool os::Linux::setup_large_page_type(size_t page_size) {
|
||||||
if (FLAG_IS_DEFAULT(UseHugeTLBFS) &&
|
if (FLAG_IS_DEFAULT(UseHugeTLBFS) &&
|
||||||
FLAG_IS_DEFAULT(UseSHM) &&
|
FLAG_IS_DEFAULT(UseSHM) &&
|
||||||
|
@ -3729,13 +3721,13 @@ bool os::Linux::setup_large_page_type(size_t page_size) {
|
||||||
UseSHM = false;
|
UseSHM = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FLAG_IS_DEFAULT(UseLargePages)) {
|
warn_no_large_pages_configured();
|
||||||
log_warning(pagesize)("UseLargePages disabled, no large pages configured and available on the system.");
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void os::large_page_init() {
|
void os::large_page_init() {
|
||||||
|
// 1) Handle the case where we do not want to use huge pages and hence
|
||||||
|
// there is no need to scan the OS for related info
|
||||||
if (!UseLargePages &&
|
if (!UseLargePages &&
|
||||||
!UseTransparentHugePages &&
|
!UseTransparentHugePages &&
|
||||||
!UseHugeTLBFS &&
|
!UseHugeTLBFS &&
|
||||||
|
@ -3753,8 +3745,73 @@ void os::large_page_init() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t large_page_size = Linux::setup_large_page_size();
|
// 2) Scan OS info
|
||||||
UseLargePages = Linux::setup_large_page_type(large_page_size);
|
size_t default_large_page_size = scan_default_large_page_size();
|
||||||
|
os::Linux::_default_large_page_size = default_large_page_size;
|
||||||
|
if (default_large_page_size == 0) {
|
||||||
|
// No large pages configured, return.
|
||||||
|
warn_no_large_pages_configured();
|
||||||
|
UseLargePages = false;
|
||||||
|
UseTransparentHugePages = false;
|
||||||
|
UseHugeTLBFS = false;
|
||||||
|
UseSHM = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
os::PageSizes all_large_pages = scan_multiple_page_support();
|
||||||
|
|
||||||
|
// 3) Consistency check and post-processing
|
||||||
|
|
||||||
|
// It is unclear if /sys/kernel/mm/hugepages/ and /proc/meminfo could disagree. Manually
|
||||||
|
// re-add the default page size to the list of page sizes to be sure.
|
||||||
|
all_large_pages.add(default_large_page_size);
|
||||||
|
|
||||||
|
// Check LargePageSizeInBytes matches an available page size and if so set _large_page_size
|
||||||
|
// using LargePageSizeInBytes as the maximum allowed large page size. If LargePageSizeInBytes
|
||||||
|
// doesn't match an available page size set _large_page_size to default_large_page_size
|
||||||
|
// and use it as the maximum.
|
||||||
|
if (FLAG_IS_DEFAULT(LargePageSizeInBytes) ||
|
||||||
|
LargePageSizeInBytes == 0 ||
|
||||||
|
LargePageSizeInBytes == default_large_page_size) {
|
||||||
|
_large_page_size = default_large_page_size;
|
||||||
|
log_info(pagesize)("Using the default large page size: " SIZE_FORMAT "%s",
|
||||||
|
byte_size_in_exact_unit(_large_page_size),
|
||||||
|
exact_unit_for_byte_size(_large_page_size));
|
||||||
|
} else {
|
||||||
|
if (all_large_pages.contains(LargePageSizeInBytes)) {
|
||||||
|
_large_page_size = LargePageSizeInBytes;
|
||||||
|
log_info(pagesize)("Overriding default large page size (" SIZE_FORMAT "%s) "
|
||||||
|
"using LargePageSizeInBytes: " SIZE_FORMAT "%s",
|
||||||
|
byte_size_in_exact_unit(default_large_page_size),
|
||||||
|
exact_unit_for_byte_size(default_large_page_size),
|
||||||
|
byte_size_in_exact_unit(_large_page_size),
|
||||||
|
exact_unit_for_byte_size(_large_page_size));
|
||||||
|
} else {
|
||||||
|
_large_page_size = default_large_page_size;
|
||||||
|
log_info(pagesize)("LargePageSizeInBytes is not a valid large page size (" SIZE_FORMAT "%s) "
|
||||||
|
"using the default large page size: " SIZE_FORMAT "%s",
|
||||||
|
byte_size_in_exact_unit(LargePageSizeInBytes),
|
||||||
|
exact_unit_for_byte_size(LargePageSizeInBytes),
|
||||||
|
byte_size_in_exact_unit(_large_page_size),
|
||||||
|
exact_unit_for_byte_size(_large_page_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate _page_sizes with large page sizes less than or equal to
|
||||||
|
// _large_page_size.
|
||||||
|
for (size_t page_size = _large_page_size; page_size != 0;
|
||||||
|
page_size = all_large_pages.next_smaller(page_size)) {
|
||||||
|
_page_sizes.add(page_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogTarget(Info, pagesize) lt;
|
||||||
|
if (lt.is_enabled()) {
|
||||||
|
LogStream ls(lt);
|
||||||
|
ls.print("Usable page sizes: ");
|
||||||
|
_page_sizes.print_on(&ls);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now determine the type of large pages to use:
|
||||||
|
UseLargePages = os::Linux::setup_large_page_type(_large_page_size);
|
||||||
|
|
||||||
set_coredump_filter(LARGEPAGES_BIT);
|
set_coredump_filter(LARGEPAGES_BIT);
|
||||||
}
|
}
|
||||||
|
@ -3965,6 +4022,7 @@ char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes,
|
||||||
assert(is_aligned(req_addr, page_size), "Must be");
|
assert(is_aligned(req_addr, page_size), "Must be");
|
||||||
assert(is_aligned(alignment, os::vm_allocation_granularity()), "Must be");
|
assert(is_aligned(alignment, os::vm_allocation_granularity()), "Must be");
|
||||||
assert(_page_sizes.contains(page_size), "Must be a valid page size");
|
assert(_page_sizes.contains(page_size), "Must be a valid page size");
|
||||||
|
assert(page_size > (size_t)os::vm_page_size(), "Must be a large page size");
|
||||||
assert(bytes >= page_size, "Shouldn't allocate large pages for small sizes");
|
assert(bytes >= page_size, "Shouldn't allocate large pages for small sizes");
|
||||||
|
|
||||||
// We only end up here when at least 1 large page can be used.
|
// We only end up here when at least 1 large page can be used.
|
||||||
|
|
|
@ -78,9 +78,8 @@ class Linux {
|
||||||
static GrowableArray<int>* nindex_to_node() { return _nindex_to_node; }
|
static GrowableArray<int>* nindex_to_node() { return _nindex_to_node; }
|
||||||
|
|
||||||
static size_t default_large_page_size();
|
static size_t default_large_page_size();
|
||||||
static size_t find_default_large_page_size();
|
static size_t scan_default_large_page_size();
|
||||||
static size_t find_large_page_size(size_t page_size);
|
static os::PageSizes scan_multiple_page_support();
|
||||||
static size_t setup_large_page_size();
|
|
||||||
|
|
||||||
static bool setup_large_page_type(size_t page_size);
|
static bool setup_large_page_type(size_t page_size);
|
||||||
static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size);
|
static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size);
|
||||||
|
|
|
@ -239,7 +239,8 @@ const intx ObjectAlignmentInBytes = 8;
|
||||||
"Use intrinsics for java.util.Base64") \
|
"Use intrinsics for java.util.Base64") \
|
||||||
\
|
\
|
||||||
product(size_t, LargePageSizeInBytes, 0, \
|
product(size_t, LargePageSizeInBytes, 0, \
|
||||||
"Large page size (0 to let VM choose the page size)") \
|
"Maximum large page size used (0 will use the default large " \
|
||||||
|
"page size for the environment as the maximum)") \
|
||||||
range(0, max_uintx) \
|
range(0, max_uintx) \
|
||||||
\
|
\
|
||||||
product(size_t, LargePageHeapSizeThreshold, 128*M, \
|
product(size_t, LargePageHeapSizeThreshold, 128*M, \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue