< prev index next >
src/hotspot/os/linux/os_linux.cpp
Print this page
@@ -2946,10 +2946,25 @@
// Define MAP_HUGETLB here so we can build HotSpot on old systems.
#ifndef MAP_HUGETLB
#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
#endif
@@ -3728,11 +3743,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,22 +3791,70 @@
}
}
}
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;
_page_sizes[1] = default_page_size;
_page_sizes[2] = 0;
@@ -4026,13 +4089,18 @@
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 (!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);
return NULL;
}
@@ -4084,28 +4152,32 @@
::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 (!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
// have regions before and after with small pages. Release these regions.
//
< prev index next >