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
|
#define MEM_LARGE_PAGES 0x20000000
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static HANDLE _hProcess;
|
|
||||||
static HANDLE _hToken;
|
|
||||||
|
|
||||||
#define VirtualFreeChecked(mem, size, type) \
|
#define VirtualFreeChecked(mem, size, type) \
|
||||||
do { \
|
do { \
|
||||||
bool ret = VirtualFree(mem, size, type); \
|
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
|
// Test if GDI functions work when memory spans
|
||||||
// two adjacent memory reservations.
|
// two adjacent memory reservations.
|
||||||
static bool gdi_can_use_split_reservation_memory() {
|
static bool gdi_can_use_split_reservation_memory(bool use_large_pages, size_t granule) {
|
||||||
size_t granule = os::vm_allocation_granularity();
|
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,
|
void* reserved = VirtualAlloc(NULL,
|
||||||
granule * 2,
|
granule * 3,
|
||||||
MEM_RESERVE,
|
MEM_RESERVE,
|
||||||
PAGE_NOACCESS);
|
PAGE_NOACCESS);
|
||||||
if (reserved == NULL) {
|
if (reserved == NULL) {
|
||||||
@ -2798,13 +2795,14 @@ static bool gdi_can_use_split_reservation_memory() {
|
|||||||
}
|
}
|
||||||
VirtualFreeChecked(reserved, 0, MEM_RELEASE);
|
VirtualFreeChecked(reserved, 0, MEM_RELEASE);
|
||||||
|
|
||||||
void* res0 = reserved;
|
// Ensure proper alignment
|
||||||
void* res1 = (char*)reserved + granule;
|
void* res0 = align_up(reserved, granule);
|
||||||
|
void* res1 = (char*)res0 + granule;
|
||||||
|
|
||||||
// Reserve and commit the first part
|
// Reserve and commit the first part
|
||||||
void* mem0 = VirtualAlloc(res0,
|
void* mem0 = VirtualAlloc(res0,
|
||||||
granule,
|
granule,
|
||||||
MEM_RESERVE|MEM_COMMIT,
|
MEM_RESERVE|MEM_COMMIT|mem_large_pages,
|
||||||
PAGE_READWRITE);
|
PAGE_READWRITE);
|
||||||
if (mem0 != res0) {
|
if (mem0 != res0) {
|
||||||
// Can't proceed with test - pessimistically report false
|
// 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
|
// Reserve and commit the second part
|
||||||
void* mem1 = VirtualAlloc(res1,
|
void* mem1 = VirtualAlloc(res1,
|
||||||
granule,
|
granule,
|
||||||
MEM_RESERVE|MEM_COMMIT,
|
MEM_RESERVE|MEM_COMMIT|mem_large_pages,
|
||||||
PAGE_READWRITE);
|
PAGE_READWRITE);
|
||||||
if (mem1 != res1) {
|
if (mem1 != res1) {
|
||||||
VirtualFreeChecked(mem0, 0, MEM_RELEASE);
|
VirtualFreeChecked(mem0, 0, MEM_RELEASE);
|
||||||
@ -2881,17 +2879,17 @@ class NUMANodeListHolder {
|
|||||||
|
|
||||||
} numa_node_list_holder;
|
} numa_node_list_holder;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static size_t _large_page_size = 0;
|
static size_t _large_page_size = 0;
|
||||||
|
|
||||||
static bool request_lock_memory_privilege() {
|
static bool request_lock_memory_privilege() {
|
||||||
_hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
|
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
|
||||||
os::current_process_id());
|
os::current_process_id());
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
HANDLE hToken = NULL;
|
||||||
LUID luid;
|
LUID luid;
|
||||||
if (_hProcess != NULL &&
|
if (hProcess != NULL &&
|
||||||
OpenProcessToken(_hProcess, TOKEN_ADJUST_PRIVILEGES, &_hToken) &&
|
OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken) &&
|
||||||
LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &luid)) {
|
LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &luid)) {
|
||||||
|
|
||||||
TOKEN_PRIVILEGES tp;
|
TOKEN_PRIVILEGES tp;
|
||||||
@ -2901,20 +2899,21 @@ static bool request_lock_memory_privilege() {
|
|||||||
|
|
||||||
// AdjustTokenPrivileges() may return TRUE even when it couldn't change the
|
// AdjustTokenPrivileges() may return TRUE even when it couldn't change the
|
||||||
// privilege. Check GetLastError() too. See MSDN document.
|
// 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)) {
|
(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() {
|
return success;
|
||||||
if (_hProcess) CloseHandle(_hProcess);
|
|
||||||
_hProcess = NULL;
|
|
||||||
if (_hToken) CloseHandle(_hToken);
|
|
||||||
_hToken = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool numa_interleaving_init() {
|
static bool numa_interleaving_init() {
|
||||||
@ -2935,7 +2934,7 @@ static bool numa_interleaving_init() {
|
|||||||
return false;
|
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("Windows GDI cannot handle split reservations.");
|
||||||
WARN("...Ignoring UseNUMAInterleaving flag.");
|
WARN("...Ignoring UseNUMAInterleaving flag.");
|
||||||
return false;
|
return false;
|
||||||
@ -3072,51 +3071,84 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags,
|
|||||||
return p_buf;
|
return p_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t large_page_init_decide_size() {
|
||||||
|
|
||||||
void os::large_page_init() {
|
|
||||||
if (!UseLargePages) return;
|
|
||||||
|
|
||||||
// print a warning if any large page related flag is specified on command line
|
// print a warning if any large page related flag is specified on command line
|
||||||
bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
|
bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
|
||||||
!FLAG_IS_DEFAULT(LargePageSizeInBytes);
|
!FLAG_IS_DEFAULT(LargePageSizeInBytes);
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
#define WARN(msg) if (warn_on_failure) { warning(msg); }
|
#define WARN(msg) if (warn_on_failure) { warning(msg); }
|
||||||
if (request_lock_memory_privilege()) {
|
|
||||||
size_t s = GetLargePageMinimum();
|
if (!request_lock_memory_privilege()) {
|
||||||
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 {
|
|
||||||
WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory.");
|
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
|
#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();
|
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[0] = _large_page_size;
|
||||||
_page_sizes[1] = default_page_size;
|
_page_sizes[1] = default_page_size;
|
||||||
_page_sizes[2] = 0;
|
_page_sizes[2] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup_after_large_page_init();
|
UseLargePages = _large_page_size != 0;
|
||||||
UseLargePages = success;
|
|
||||||
|
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) {
|
int os::create_file_for_heap(const char* dir) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user