|
@@ -2716,9 +2716,6 @@ int os::vm_allocation_granularity() { |
|
|
#define MEM_LARGE_PAGES 0x20000000 |
|
|
#endif |
|
|
|
|
|
static HANDLE _hProcess; |
|
|
static HANDLE _hToken; |
|
|
|
|
|
#define VirtualFreeChecked(mem, size, type) \ |
|
|
do { \ |
|
|
bool ret = VirtualFree(mem, size, type); \ |
|
@@ -2784,12 +2781,12 @@ static bool gdi_can_use_memory(void* mem) { |
|
|
|
|
|
// Test if GDI functions work when memory spans |
|
|
// two adjacent memory reservations. |
|
|
static bool gdi_can_use_split_reservation_memory() { |
|
|
size_t granule = os::vm_allocation_granularity(); |
|
|
static bool gdi_can_use_split_reservation_memory(bool use_large_pages, size_t granule) { |
|
|
DWORD mem_large_pages = use_large_pages ? MEM_LARGE_PAGES : 0; |
|
|
|
|
|
// Find virtual memory range |
|
|
// Find virtual memory range. Two granules for regions and one for alignment. |
|
|
void* reserved = VirtualAlloc(NULL, |
|
|
granule * 2, |
|
|
granule * 3, |
|
|
MEM_RESERVE, |
|
|
PAGE_NOACCESS); |
|
|
if (reserved == NULL) { |
|
@@ -2798,13 +2795,14 @@ static bool gdi_can_use_split_reservation_memory() { |
|
|
} |
|
|
VirtualFreeChecked(reserved, 0, MEM_RELEASE); |
|
|
|
|
|
void* res0 = reserved; |
|
|
void* res1 = (char*)reserved + granule; |
|
|
// Ensure proper alignment |
|
|
void* res0 = align_up(reserved, granule); |
|
|
void* res1 = (char*)res0 + granule; |
|
|
|
|
|
// Reserve and commit the first part |
|
|
void* mem0 = VirtualAlloc(res0, |
|
|
granule, |
|
|
MEM_RESERVE|MEM_COMMIT, |
|
|
MEM_RESERVE|MEM_COMMIT|mem_large_pages, |
|
|
PAGE_READWRITE); |
|
|
if (mem0 != res0) { |
|
|
// Can't proceed with test - pessimistically report false |
|
@@ -2814,7 +2812,7 @@ static bool gdi_can_use_split_reservation_memory() { |
|
|
// Reserve and commit the second part |
|
|
void* mem1 = VirtualAlloc(res1, |
|
|
granule, |
|
|
MEM_RESERVE|MEM_COMMIT, |
|
|
MEM_RESERVE|MEM_COMMIT|mem_large_pages, |
|
|
PAGE_READWRITE); |
|
|
if (mem1 != res1) { |
|
|
VirtualFreeChecked(mem0, 0, MEM_RELEASE); |
|
@@ -2881,17 +2879,17 @@ class NUMANodeListHolder { |
|
|
|
|
|
} numa_node_list_holder; |
|
|
|
|
|
|
|
|
|
|
|
static size_t _large_page_size = 0; |
|
|
|
|
|
static bool request_lock_memory_privilege() { |
|
|
_hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, |
|
|
os::current_process_id()); |
|
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, |
|
|
os::current_process_id()); |
|
|
|
|
|
bool success = false; |
|
|
HANDLE hToken = NULL; |
|
|
LUID luid; |
|
|
if (_hProcess != NULL && |
|
|
OpenProcessToken(_hProcess, TOKEN_ADJUST_PRIVILEGES, &_hToken) && |
|
|
if (hProcess != NULL && |
|
|
OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken) && |
|
|
LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &luid)) { |
|
|
|
|
|
TOKEN_PRIVILEGES tp; |
|
@@ -2901,20 +2899,21 @@ static bool request_lock_memory_privilege() { |
|
|
|
|
|
// AdjustTokenPrivileges() may return TRUE even when it couldn't change the |
|
|
// privilege. Check GetLastError() too. See MSDN document. |
|
|
if (AdjustTokenPrivileges(_hToken, false, &tp, sizeof(tp), NULL, NULL) && |
|
|
if (AdjustTokenPrivileges(hToken, false, &tp, sizeof(tp), NULL, NULL) && |
|
|
(GetLastError() == ERROR_SUCCESS)) { |
|
|
return true; |
|
|
success = true; |
|
|
} |
|
|
} |
|
|
|
|
|
return false; |
|
|
} |
|
|
// Cleanup |
|
|
if (hProcess != NULL) { |
|
|
CloseHandle(hProcess); |
|
|
} |
|
|
if (hToken != NULL) { |
|
|
CloseHandle(hToken); |
|
|
} |
|
|
|
|
|
static void cleanup_after_large_page_init() { |
|
|
if (_hProcess) CloseHandle(_hProcess); |
|
|
_hProcess = NULL; |
|
|
if (_hToken) CloseHandle(_hToken); |
|
|
_hToken = NULL; |
|
|
return success; |
|
|
} |
|
|
|
|
|
static bool numa_interleaving_init() { |
|
@@ -2935,7 +2934,7 @@ static bool numa_interleaving_init() { |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (!gdi_can_use_split_reservation_memory()) { |
|
|
if (!gdi_can_use_split_reservation_memory(UseLargePages, min_interleave_granularity)) { |
|
|
WARN("Windows GDI cannot handle split reservations."); |
|
|
WARN("...Ignoring UseNUMAInterleaving flag."); |
|
|
return false; |
|
@@ -3072,51 +3071,84 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, |
|
|
return p_buf; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void os::large_page_init() { |
|
|
if (!UseLargePages) return; |
|
|
|
|
|
static size_t large_page_init_decide_size() { |
|
|
// print a warning if any large page related flag is specified on command line |
|
|
bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) || |
|
|
!FLAG_IS_DEFAULT(LargePageSizeInBytes); |
|
|
bool success = false; |
|
|
|
|
|
#define WARN(msg) if (warn_on_failure) { warning(msg); } |
|
|
if (request_lock_memory_privilege()) { |
|
|
size_t s = GetLargePageMinimum(); |
|
|
if (s) { |
|
|
#if defined(IA32) || defined(AMD64) |
|
|
if (s > 4*M || LargePageSizeInBytes > 4*M) { |
|
|
WARN("JVM cannot use large pages bigger than 4mb."); |
|
|
} else { |
|
|
#endif |
|
|
if (LargePageSizeInBytes && LargePageSizeInBytes % s == 0) { |
|
|
_large_page_size = LargePageSizeInBytes; |
|
|
} else { |
|
|
_large_page_size = s; |
|
|
} |
|
|
success = true; |
|
|
|
|
|
if (!request_lock_memory_privilege()) { |
|
|
WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory."); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
size_t size = GetLargePageMinimum(); |
|
|
if (size == 0) { |
|
|
WARN("Large page is not supported by the processor."); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
#if defined(IA32) || defined(AMD64) |
|
|
} |
|
|
if (size > 4*M || LargePageSizeInBytes > 4*M) { |
|
|
WARN("JVM cannot use large pages bigger than 4mb."); |
|
|
return 0; |
|
|
} |
|
|
#endif |
|
|
} else { |
|
|
WARN("Large page is not supported by the processor."); |
|
|
} |
|
|
} else { |
|
|
WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory."); |
|
|
|
|
|
if (LargePageSizeInBytes > 0 && LargePageSizeInBytes % size == 0) { |
|
|
size = LargePageSizeInBytes; |
|
|
} |
|
|
|
|
|
// Now test allocating a page |
|
|
void* large_page = VirtualAlloc(NULL, |
|
|
size, |
|
|
MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, |
|
|
PAGE_READWRITE); |
|
|
if (large_page == NULL) { |
|
|
WARN("JVM cannot allocate one single large page."); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
// Detect if GDI can use memory backed by large pages |
|
|
if (!gdi_can_use_memory(large_page)) { |
|
|
WARN("JVM cannot use large pages because of bug in Windows GDI."); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
// Release test page |
|
|
VirtualFreeChecked(large_page, 0, MEM_RELEASE); |
|
|
|
|
|
#undef WARN |
|
|
|
|
|
return size; |
|
|
} |
|
|
|
|
|
void os::large_page_init() { |
|
|
if (!UseLargePages) { |
|
|
return; |
|
|
} |
|
|
|
|
|
_large_page_size = large_page_init_decide_size(); |
|
|
|
|
|
const size_t default_page_size = (size_t) vm_page_size(); |
|
|
if (success && _large_page_size > default_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; |
|
|
} |
|
|
|
|
|
cleanup_after_large_page_init(); |
|
|
UseLargePages = success; |
|
|
UseLargePages = _large_page_size != 0; |
|
|
|
|
|
if (UseLargePages && UseLargePagesIndividualAllocation) { |
|
|
if (!gdi_can_use_split_reservation_memory(true /* use_large_pages */, _large_page_size)) { |
|
|
if (FLAG_IS_CMDLINE(UseLargePagesIndividualAllocation)) { |
|
|
warning("Windows GDI cannot handle split reservations."); |
|
|
warning("...Ignoring UseLargePagesIndividualAllocation flag."); |
|
|
} |
|
|
UseLargePagesIndividualAllocation = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
int os::create_file_for_heap(const char* dir) { |
|
|