< prev index next >
src/hotspot/os/linux/os_linux.cpp
Print this page
@@ -151,10 +151,11 @@
pthread_t os::Linux::_main_thread;
int os::Linux::_page_size = -1;
bool os::Linux::_supports_fast_thread_cpu_time = false;
const char * os::Linux::_glibc_version = NULL;
const char * os::Linux::_libpthread_version = NULL;
+size_t os::Linux::_default_large_page_size = 0;
static jlong initial_time_count=0;
static int clock_tics_per_sec = 100;
@@ -2946,10 +2947,19 @@
// Define MAP_HUGETLB here so we can build HotSpot on old systems.
#ifndef MAP_HUGETLB
#define MAP_HUGETLB 0x40000
#endif
+// 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.
+// See mmap(2) man page for more info (since Linux 3.8).
+// https://lwn.net/Articles/533499/
+#ifndef MAP_HUGE_SHIFT
+ #define MAP_HUGE_SHIFT 26
+#endif
+
// Define MADV_HUGEPAGE here so we can build HotSpot on old systems.
#ifndef MADV_HUGEPAGE
#define MADV_HUGEPAGE 14
#endif
@@ -3728,11 +3738,11 @@
// Large page support
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
// 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
@@ -3776,32 +3786,72 @@
}
}
}
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));
+bool os::Linux::is_valid_large_page_size(size_t large_page_size) {
+ // 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 false;
}
- return large_page_size;
+ DIR *dir = opendir(sys_hugepages);
+ if (dir == NULL) {
+ return false;
+ }
+
+ struct dirent *entry;
+ size_t page_size;
+ bool is_valid = false;
+ while ( (entry = readdir(dir)) != NULL) {
+ if (entry->d_type == DT_DIR &&
+ sscanf(entry->d_name, "hugepages-%zukB", &page_size) == 1) {
+ // The kernel is using kB, hotspot uses bytes
+ if (large_page_size == page_size * K) {
+ is_valid = true;
+ break;
+ }
+ }
+ }
+ closedir(dir);
+ return is_valid;
}
size_t os::Linux::setup_large_page_size() {
- _large_page_size = Linux::find_large_page_size();
+ _default_large_page_size = Linux::find_default_large_page_size();
+ _large_page_size = _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;
_page_sizes[1] = default_page_size;
_page_sizes[2] = 0;
}
return _large_page_size;
}
+size_t os::Linux::default_large_page_size() {
+ return _default_large_page_size;
+}
+
bool os::Linux::setup_large_page_type(size_t page_size) {
if (FLAG_IS_DEFAULT(UseHugeTLBFS) &&
FLAG_IS_DEFAULT(UseSHM) &&
FLAG_IS_DEFAULT(UseTransparentHugePages)) {
@@ -4026,13 +4076,16 @@
assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages");
assert(is_aligned(bytes, os::large_page_size()), "Unaligned size");
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 (os::large_page_size() != default_large_page_size()) {
+ flags |= (exact_log2(os::large_page_size()) << MAP_HUGE_SHIFT);
+ }
+ char* addr = (char*)::mmap(req_addr, bytes, prot, flags, -1, 0);
if (addr == MAP_FAILED) {
warn_on_large_pages_failure(req_addr, bytes, errno);
return NULL;
}
@@ -4084,28 +4137,30 @@
::munmap(start, end - start);
return NULL;
}
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;
}
}
// 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 (os::large_page_size() != default_large_page_size()) {
+ flags |= (exact_log2(os::large_page_size()) << MAP_HUGE_SHIFT);
+ }
+
+ 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
// have regions before and after with small pages. Release these regions.
//
< prev index next >