Skip to content

Commit 94cfeb9

Browse files
Marcus G K Williamskstefanjtstuefe
committed
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
1 parent ec8a809 commit 94cfeb9

File tree

3 files changed

+121
-63
lines changed

3 files changed

+121
-63
lines changed

src/hotspot/os/linux/os_linux.cpp

Lines changed: 117 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,6 +2346,9 @@ void os::print_memory_info(outputStream* st) {
23462346
st->print("(" UINT64_FORMAT "k free)",
23472347
((jlong)si.freeswap * si.mem_unit) >> 10);
23482348
st->cr();
2349+
st->print("Page Sizes: ");
2350+
_page_sizes.print_on(st);
2351+
st->cr();
23492352
}
23502353

23512354
// 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) {
35043507
// Mapping succeeded, sanity check passed.
35053508
munmap(p, page_size);
35063509
return true;
3510+
} else {
3511+
log_info(pagesize)("Large page size (" SIZE_FORMAT "%s) failed sanity check, "
3512+
"checking if smaller large page sizes are usable",
3513+
byte_size_in_exact_unit(page_size),
3514+
exact_unit_for_byte_size(page_size));
3515+
for (size_t page_size_ = _page_sizes.next_smaller(page_size);
3516+
page_size_ != (size_t)os::vm_page_size();
3517+
page_size_ = _page_sizes.next_smaller(page_size_)) {
3518+
flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB | hugetlbfs_page_size_flag(page_size_);
3519+
p = mmap(NULL, page_size_, PROT_READ|PROT_WRITE, flags, -1, 0);
3520+
if (p != MAP_FAILED) {
3521+
// Mapping succeeded, sanity check passed.
3522+
munmap(p, page_size_);
3523+
log_info(pagesize)("Large page size (" SIZE_FORMAT "%s) passed sanity check",
3524+
byte_size_in_exact_unit(page_size_),
3525+
exact_unit_for_byte_size(page_size_));
3526+
return true;
3527+
}
3528+
}
35073529
}
35083530

35093531
if (warn) {
@@ -3578,35 +3600,20 @@ static void set_coredump_filter(CoredumpFilterBit bit) {
35783600

35793601
static size_t _large_page_size = 0;
35803602

3581-
size_t os::Linux::find_default_large_page_size() {
3582-
if (_default_large_page_size != 0) {
3583-
return _default_large_page_size;
3584-
}
3585-
size_t large_page_size = 0;
3603+
static size_t scan_default_large_page_size() {
3604+
size_t default_large_page_size = 0;
35863605

35873606
// large_page_size on Linux is used to round up heap size. x86 uses either
35883607
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
35893608
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
3590-
// page as large as 256M.
3609+
// page as large as 1G.
35913610
//
35923611
// Here we try to figure out page size by parsing /proc/meminfo and looking
35933612
// for a line with the following format:
35943613
// Hugepagesize: 2048 kB
35953614
//
35963615
// If we can't determine the value (e.g. /proc is not mounted, or the text
3597-
// format has been changed), we'll use the largest page size supported by
3598-
// the processor.
3599-
3600-
#ifndef ZERO
3601-
large_page_size =
3602-
AARCH64_ONLY(2 * M)
3603-
AMD64_ONLY(2 * M)
3604-
ARM32_ONLY(2 * M)
3605-
IA32_ONLY(4 * M)
3606-
IA64_ONLY(256 * M)
3607-
PPC_ONLY(4 * M)
3608-
S390_ONLY(1 * M);
3609-
#endif // ZERO
3616+
// format has been changed), we'll set largest page size to 0
36103617

36113618
FILE *fp = fopen("/proc/meminfo", "r");
36123619
if (fp) {
@@ -3615,7 +3622,7 @@ size_t os::Linux::find_default_large_page_size() {
36153622
char buf[16];
36163623
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
36173624
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
3618-
large_page_size = x * K;
3625+
default_large_page_size = x * K;
36193626
break;
36203627
}
36213628
} else {
@@ -3628,65 +3635,50 @@ size_t os::Linux::find_default_large_page_size() {
36283635
}
36293636
fclose(fp);
36303637
}
3631-
return large_page_size;
3638+
3639+
return default_large_page_size;
36323640
}
36333641

3634-
size_t os::Linux::find_large_page_size(size_t large_page_size) {
3635-
if (_default_large_page_size == 0) {
3636-
_default_large_page_size = Linux::find_default_large_page_size();
3637-
}
3638-
// We need to scan /sys/kernel/mm/hugepages
3642+
static os::PageSizes scan_multiple_page_support() {
3643+
// Scan /sys/kernel/mm/hugepages
36393644
// to discover the available page sizes
36403645
const char* sys_hugepages = "/sys/kernel/mm/hugepages";
3646+
os::PageSizes page_sizes;
36413647

36423648
DIR *dir = opendir(sys_hugepages);
3643-
if (dir == NULL) {
3644-
return _default_large_page_size;
3645-
}
36463649

36473650
struct dirent *entry;
36483651
size_t page_size;
36493652
while ((entry = readdir(dir)) != NULL) {
36503653
if (entry->d_type == DT_DIR &&
36513654
sscanf(entry->d_name, "hugepages-%zukB", &page_size) == 1) {
36523655
// The kernel is using kB, hotspot uses bytes
3653-
if (large_page_size == page_size * K) {
3654-
closedir(dir);
3655-
return large_page_size;
3656-
}
3656+
// Add each found Large Page Size to page_sizes
3657+
page_sizes.add(page_size * K);
36573658
}
36583659
}
36593660
closedir(dir);
3660-
return _default_large_page_size;
3661-
}
3662-
3663-
size_t os::Linux::setup_large_page_size() {
3664-
_default_large_page_size = Linux::find_default_large_page_size();
3665-
3666-
if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != _default_large_page_size ) {
3667-
_large_page_size = find_large_page_size(LargePageSizeInBytes);
3668-
if (_large_page_size == _default_large_page_size) {
3669-
warning("Setting LargePageSizeInBytes=" SIZE_FORMAT " has no effect on this OS. Using the default large page size "
3670-
SIZE_FORMAT "%s.",
3671-
LargePageSizeInBytes,
3672-
byte_size_in_proper_unit(_large_page_size), proper_unit_for_byte_size(_large_page_size));
3673-
}
3674-
} else {
3675-
_large_page_size = _default_large_page_size;
3676-
}
36773661

3678-
const size_t default_page_size = (size_t)Linux::page_size();
3679-
if (_large_page_size > default_page_size) {
3680-
_page_sizes.add(_large_page_size);
3662+
LogTarget(Debug, pagesize) lt;
3663+
if (lt.is_enabled()) {
3664+
LogStream ls(lt);
3665+
ls.print("Large Page sizes: ");
3666+
page_sizes.print_on(&ls);
36813667
}
36823668

3683-
return _large_page_size;
3669+
return page_sizes;
36843670
}
36853671

36863672
size_t os::Linux::default_large_page_size() {
36873673
return _default_large_page_size;
36883674
}
36893675

3676+
void warn_no_large_pages_configured() {
3677+
if (!FLAG_IS_DEFAULT(UseLargePages)) {
3678+
log_warning(pagesize)("UseLargePages disabled, no large pages configured and available on the system.");
3679+
}
3680+
}
3681+
36903682
bool os::Linux::setup_large_page_type(size_t page_size) {
36913683
if (FLAG_IS_DEFAULT(UseHugeTLBFS) &&
36923684
FLAG_IS_DEFAULT(UseSHM) &&
@@ -3729,13 +3721,13 @@ bool os::Linux::setup_large_page_type(size_t page_size) {
37293721
UseSHM = false;
37303722
}
37313723

3732-
if (!FLAG_IS_DEFAULT(UseLargePages)) {
3733-
log_warning(pagesize)("UseLargePages disabled, no large pages configured and available on the system.");
3734-
}
3724+
warn_no_large_pages_configured();
37353725
return false;
37363726
}
37373727

37383728
void os::large_page_init() {
3729+
// 1) Handle the case where we do not want to use huge pages and hence
3730+
// there is no need to scan the OS for related info
37393731
if (!UseLargePages &&
37403732
!UseTransparentHugePages &&
37413733
!UseHugeTLBFS &&
@@ -3753,8 +3745,73 @@ void os::large_page_init() {
37533745
return;
37543746
}
37553747

3756-
size_t large_page_size = Linux::setup_large_page_size();
3757-
UseLargePages = Linux::setup_large_page_type(large_page_size);
3748+
// 2) Scan OS info
3749+
size_t default_large_page_size = scan_default_large_page_size();
3750+
os::Linux::_default_large_page_size = default_large_page_size;
3751+
if (default_large_page_size == 0) {
3752+
// No large pages configured, return.
3753+
warn_no_large_pages_configured();
3754+
UseLargePages = false;
3755+
UseTransparentHugePages = false;
3756+
UseHugeTLBFS = false;
3757+
UseSHM = false;
3758+
return;
3759+
}
3760+
os::PageSizes all_large_pages = scan_multiple_page_support();
3761+
3762+
// 3) Consistency check and post-processing
3763+
3764+
// It is unclear if /sys/kernel/mm/hugepages/ and /proc/meminfo could disagree. Manually
3765+
// re-add the default page size to the list of page sizes to be sure.
3766+
all_large_pages.add(default_large_page_size);
3767+
3768+
// Check LargePageSizeInBytes matches an available page size and if so set _large_page_size
3769+
// using LargePageSizeInBytes as the maximum allowed large page size. If LargePageSizeInBytes
3770+
// doesn't match an available page size set _large_page_size to default_large_page_size
3771+
// and use it as the maximum.
3772+
if (FLAG_IS_DEFAULT(LargePageSizeInBytes) ||
3773+
LargePageSizeInBytes == 0 ||
3774+
LargePageSizeInBytes == default_large_page_size) {
3775+
_large_page_size = default_large_page_size;
3776+
log_info(pagesize)("Using the default large page size: " SIZE_FORMAT "%s",
3777+
byte_size_in_exact_unit(_large_page_size),
3778+
exact_unit_for_byte_size(_large_page_size));
3779+
} else {
3780+
if (all_large_pages.contains(LargePageSizeInBytes)) {
3781+
_large_page_size = LargePageSizeInBytes;
3782+
log_info(pagesize)("Overriding default large page size (" SIZE_FORMAT "%s) "
3783+
"using LargePageSizeInBytes: " SIZE_FORMAT "%s",
3784+
byte_size_in_exact_unit(default_large_page_size),
3785+
exact_unit_for_byte_size(default_large_page_size),
3786+
byte_size_in_exact_unit(_large_page_size),
3787+
exact_unit_for_byte_size(_large_page_size));
3788+
} else {
3789+
_large_page_size = default_large_page_size;
3790+
log_info(pagesize)("LargePageSizeInBytes is not a valid large page size (" SIZE_FORMAT "%s) "
3791+
"using the default large page size: " SIZE_FORMAT "%s",
3792+
byte_size_in_exact_unit(LargePageSizeInBytes),
3793+
exact_unit_for_byte_size(LargePageSizeInBytes),
3794+
byte_size_in_exact_unit(_large_page_size),
3795+
exact_unit_for_byte_size(_large_page_size));
3796+
}
3797+
}
3798+
3799+
// Populate _page_sizes with large page sizes less than or equal to
3800+
// _large_page_size.
3801+
for (size_t page_size = _large_page_size; page_size != 0;
3802+
page_size = all_large_pages.next_smaller(page_size)) {
3803+
_page_sizes.add(page_size);
3804+
}
3805+
3806+
LogTarget(Info, pagesize) lt;
3807+
if (lt.is_enabled()) {
3808+
LogStream ls(lt);
3809+
ls.print("Usable page sizes: ");
3810+
_page_sizes.print_on(&ls);
3811+
}
3812+
3813+
// Now determine the type of large pages to use:
3814+
UseLargePages = os::Linux::setup_large_page_type(_large_page_size);
37583815

37593816
set_coredump_filter(LARGEPAGES_BIT);
37603817
}
@@ -3965,6 +4022,7 @@ char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes,
39654022
assert(is_aligned(req_addr, page_size), "Must be");
39664023
assert(is_aligned(alignment, os::vm_allocation_granularity()), "Must be");
39674024
assert(_page_sizes.contains(page_size), "Must be a valid page size");
4025+
assert(page_size > (size_t)os::vm_page_size(), "Must be a large page size");
39684026
assert(bytes >= page_size, "Shouldn't allocate large pages for small sizes");
39694027

39704028
// We only end up here when at least 1 large page can be used.

src/hotspot/os/linux/os_linux.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,8 @@ class Linux {
7878
static GrowableArray<int>* nindex_to_node() { return _nindex_to_node; }
7979

8080
static size_t default_large_page_size();
81-
static size_t find_default_large_page_size();
82-
static size_t find_large_page_size(size_t page_size);
83-
static size_t setup_large_page_size();
81+
static size_t scan_default_large_page_size();
82+
static os::PageSizes scan_multiple_page_support();
8483

8584
static bool setup_large_page_type(size_t page_size);
8685
static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size);

src/hotspot/share/runtime/globals.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ const intx ObjectAlignmentInBytes = 8;
239239
"Use intrinsics for java.util.Base64") \
240240
\
241241
product(size_t, LargePageSizeInBytes, 0, \
242-
"Large page size (0 to let VM choose the page size)") \
242+
"Maximum large page size used (0 will use the default large " \
243+
"page size for the environment as the maximum)") \
243244
range(0, max_uintx) \
244245
\
245246
product(size_t, LargePageHeapSizeThreshold, 128*M, \

0 commit comments

Comments
 (0)