8245000: Windows GDI functions don't support large pages
Reviewed-by: kbarrett, sjohanss
This commit is contained in:
parent
6f29ba1991
commit
3d659eff6e
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user