--- old/src/hotspot/os/linux/os_linux.cpp 2020-05-11 18:33:50.000000000 +0200 +++ new/src/hotspot/os/linux/os_linux.cpp 2020-05-11 18:33:49.000000000 +0200 @@ -2948,6 +2948,21 @@ #define MAP_HUGETLB 0x40000 #endif +// mmap: If MAP_HUGETLB is set, and the system supports multiple huge page sizes, +// flag bits [26:31] can be used to encode the log2 of the desired huge page size. +// Otherwise the system's default huge page size will be used. +#ifndef MAP_HUGE_SHIFT + #define MAP_HUGE_SHIFT 26 +#endif + +#ifndef MAP_HUGE_2MB + #define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT) +#endif + +#ifndef MAP_HUGE_1GB + #define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) +#endif + // Define MADV_HUGEPAGE here so we can build HotSpot on old systems. #ifndef MADV_HUGEPAGE #define MADV_HUGEPAGE 14 @@ -3730,7 +3745,7 @@ static size_t _large_page_size = 0; -size_t os::Linux::find_large_page_size() { +size_t os::Linux::find_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 @@ -3778,18 +3793,66 @@ } fclose(fp); } + return large_page_size; +} - if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) { - warning("Setting LargePageSizeInBytes has no effect on this OS. Large page size is " - SIZE_FORMAT "%s.", byte_size_in_proper_unit(large_page_size), - proper_unit_for_byte_size(large_page_size)); +void os::Linux::find_large_page_sizes() { + _page_sizes[0] = 0; + // We need to scan /sys/kernel/mm/hugepages + // to discover the available page sizes + const char* sys_hugepages = "/sys/kernel/mm/hugepages"; + if (dir_is_empty(sys_hugepages)) { + return; } - return large_page_size; + DIR *dir = opendir(sys_hugepages); + if (dir == NULL) { + return; + } + + struct dirent *entry; + size_t page_size; + int count = 0; + + while (count < page_sizes_max - 1 && (entry = readdir(dir)) != NULL) { + if(entry->d_type == DT_DIR && + sscanf(entry->d_name, "hugepages-%zukB", &page_size) ) { + + // The kernel is using kB, hotspot uses bytes + _page_sizes[count] = page_size * K; + count++; + } + } + _page_sizes[count] = 0; + closedir(dir); + return; +} + +bool os::Linux::is_valid_large_page_size(size_t page_size) { + find_large_page_sizes(); + int count = 0; + while (_page_sizes[count] != 0) { + if (_page_sizes[count++] == page_size) { + return true; + } + } + return false; } size_t os::Linux::setup_large_page_size() { - _large_page_size = Linux::find_large_page_size(); + _large_page_size = Linux::find_default_large_page_size(); + + if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != _large_page_size ) { + if (is_valid_large_page_size(LargePageSizeInBytes)) { + _large_page_size = LargePageSizeInBytes; + } else { + warning("Setting LargePageSizeInBytes=" SIZE_FORMAT " has no effect on this OS. Default large page size is " + SIZE_FORMAT "%s.", + LargePageSizeInBytes, + byte_size_in_proper_unit(_large_page_size), proper_unit_for_byte_size(_large_page_size)); + } + } + const size_t default_page_size = (size_t)Linux::page_size(); if (_large_page_size > default_page_size) { _page_sizes[0] = _large_page_size; @@ -4028,9 +4091,14 @@ assert(is_aligned(req_addr, os::large_page_size()), "Unaligned address"); int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; - char* addr = (char*)::mmap(req_addr, bytes, prot, - MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, - -1, 0); + int flags = MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB; + + if (!FLAG_IS_DEFAULT(LargePageSizeInBytes)) { + flags |= (os::large_page_size() > (1 << (MAP_HUGE_2MB >> MAP_HUGE_SHIFT))) + ? MAP_HUGE_1GB + : MAP_HUGE_2MB; + } + char* addr = (char*)::mmap(req_addr, bytes, prot, flags, -1, 0); if (addr == MAP_FAILED) { warn_on_large_pages_failure(req_addr, bytes, errno); @@ -4086,14 +4154,12 @@ } int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; - + int flags = MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED; void* result; // Commit small-paged leading area. if (start != lp_start) { - result = ::mmap(start, lp_start - start, prot, - MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, - -1, 0); + result = ::mmap(start, lp_start - start, prot, flags, -1, 0); if (result == MAP_FAILED) { ::munmap(lp_start, end - lp_start); return NULL; @@ -4101,9 +4167,15 @@ } // Commit large-paged area. - result = ::mmap(lp_start, lp_bytes, prot, - MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_HUGETLB, - -1, 0); + flags |= MAP_HUGETLB; + + if (!FLAG_IS_DEFAULT(LargePageSizeInBytes)) { + flags |= (os::large_page_size() > (1 << (MAP_HUGE_2MB >> MAP_HUGE_SHIFT))) + ? MAP_HUGE_1GB + : MAP_HUGE_2MB; + } + + result = ::mmap(lp_start, lp_bytes, prot, flags, -1, 0); if (result == MAP_FAILED) { warn_on_large_pages_failure(lp_start, lp_bytes, errno); // If the mmap above fails, the large pages region will be unmapped and we