8245000: Windows GDI functions don't support large pages

Reviewed-by: kbarrett, sjohanss
This commit is contained in:
Stefan Karlsson 2020-05-20 08:56:40 +02:00
parent 6f29ba1991
commit 3d659eff6e

View File

@ -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 defined(IA32) || defined(AMD64)
}
#endif
} else {
WARN("Large page is not supported by the processor.");
}
} else {
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
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) {