Skip to content

Commit 7b736ec

Browse files
committed
8266489: Enable G1 to use large pages on Windows when region size is larger than 2m
Reviewed-by: tschatzl, iwalulya
1 parent f422787 commit 7b736ec

File tree

1 file changed

+82
-25
lines changed

1 file changed

+82
-25
lines changed

src/hotspot/os/windows/os_windows.cpp

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3274,48 +3274,105 @@ bool os::can_execute_large_page_memory() {
32743274
return true;
32753275
}
32763276

3277-
char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_size, char* addr,
3278-
bool exec) {
3279-
assert(UseLargePages, "only for large pages");
3280-
assert(page_size == os::large_page_size(), "Currently only support one large page size on Windows");
3277+
static char* reserve_large_pages_individually(size_t size, char* req_addr, bool exec) {
3278+
log_debug(pagesize)("Reserving large pages individually.");
3279+
3280+
const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
3281+
const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
32813282

3282-
if (!is_aligned(bytes, page_size) || alignment > page_size) {
3283-
return NULL; // Fallback to small pages.
3283+
char * p_buf = allocate_pages_individually(size, req_addr, flags, prot, LargePagesIndividualAllocationInjectError);
3284+
if (p_buf == NULL) {
3285+
// give an appropriate warning message
3286+
if (UseNUMAInterleaving) {
3287+
warning("NUMA large page allocation failed, UseLargePages flag ignored");
3288+
}
3289+
if (UseLargePagesIndividualAllocation) {
3290+
warning("Individually allocated large pages failed, "
3291+
"use -XX:-UseLargePagesIndividualAllocation to turn off");
3292+
}
3293+
return NULL;
32843294
}
3295+
return p_buf;
3296+
}
3297+
3298+
static char* reserve_large_pages_single_range(size_t size, char* req_addr, bool exec) {
3299+
log_debug(pagesize)("Reserving large pages in a single large chunk.");
32853300

32863301
const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
32873302
const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
32883303

3304+
return (char *) virtualAlloc(req_addr, size, flags, prot);
3305+
}
3306+
3307+
static char* reserve_large_pages(size_t size, char* req_addr, bool exec) {
32893308
// with large pages, there are two cases where we need to use Individual Allocation
32903309
// 1) the UseLargePagesIndividualAllocation flag is set (set by default on WS2003)
32913310
// 2) NUMA Interleaving is enabled, in which case we use a different node for each page
32923311
if (UseLargePagesIndividualAllocation || UseNUMAInterleaving) {
3293-
log_debug(pagesize)("Reserving large pages individually.");
3312+
return reserve_large_pages_individually(size, req_addr, exec);
3313+
}
3314+
return reserve_large_pages_single_range(size, req_addr, exec);
3315+
}
32943316

3295-
char * p_buf = allocate_pages_individually(bytes, addr, flags, prot, LargePagesIndividualAllocationInjectError);
3296-
if (p_buf == NULL) {
3297-
// give an appropriate warning message
3298-
if (UseNUMAInterleaving) {
3299-
warning("NUMA large page allocation failed, UseLargePages flag ignored");
3300-
}
3301-
if (UseLargePagesIndividualAllocation) {
3302-
warning("Individually allocated large pages failed, "
3303-
"use -XX:-UseLargePagesIndividualAllocation to turn off");
3304-
}
3305-
return NULL;
3317+
static char* find_aligned_address(size_t size, size_t alignment) {
3318+
// Temporary reserve memory large enough to ensure we can get the requested
3319+
// alignment and still fit the reservation.
3320+
char* addr = (char*) virtualAlloc(NULL, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
3321+
// Align the address to the requested alignment.
3322+
char* aligned_addr = align_up(addr, alignment);
3323+
// Free the temporary reservation.
3324+
virtualFree(addr, 0, MEM_RELEASE);
3325+
3326+
return aligned_addr;
3327+
}
3328+
3329+
static char* reserve_large_pages_aligned(size_t size, size_t alignment, bool exec) {
3330+
log_debug(pagesize)("Reserving large pages at an aligned address, alignment=" SIZE_FORMAT "%s",
3331+
byte_size_in_exact_unit(alignment), exact_unit_for_byte_size(alignment));
3332+
3333+
// Will try to find a suitable address at most 20 times. The reason we need to try
3334+
// multiple times is that between finding the aligned address and trying to commit
3335+
// the large pages another thread might have reserved an overlapping region.
3336+
const int attempts_limit = 20;
3337+
for (int attempts = 0; attempts < attempts_limit; attempts++) {
3338+
// Find aligned address.
3339+
char* aligned_address = find_aligned_address(size, alignment);
3340+
3341+
// Try to do the large page reservation using the aligned address.
3342+
aligned_address = reserve_large_pages(size, aligned_address, exec);
3343+
if (aligned_address != NULL) {
3344+
// Reservation at the aligned address succeeded.
3345+
guarantee(is_aligned(aligned_address, alignment), "Must be aligned");
3346+
return aligned_address;
33063347
}
3348+
}
33073349

3308-
return p_buf;
3350+
log_debug(pagesize)("Failed reserving large pages at aligned address");
3351+
return NULL;
3352+
}
33093353

3310-
} else {
3311-
log_debug(pagesize)("Reserving large pages in a single large chunk.");
3354+
char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_size, char* addr,
3355+
bool exec) {
3356+
assert(UseLargePages, "only for large pages");
3357+
assert(page_size == os::large_page_size(), "Currently only support one large page size on Windows");
3358+
assert(is_aligned(addr, alignment), "Must be");
3359+
assert(is_aligned(addr, page_size), "Must be");
33123360

3313-
// normal policy just allocate it all at once
3314-
DWORD flag = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
3315-
char * res = (char *)virtualAlloc(addr, bytes, flag, prot);
3361+
if (!is_aligned(bytes, page_size)) {
3362+
// Fallback to small pages, Windows does not support mixed mappings.
3363+
return NULL;
3364+
}
33163365

3317-
return res;
3366+
// The requested alignment can be larger than the page size, for example with G1
3367+
// the alignment is bound to the heap region size. So this reservation needs to
3368+
// ensure that the requested alignment is met. When there is a requested address
3369+
// this solves it self, since it must be properly aligned already.
3370+
if (addr == NULL && alignment > page_size) {
3371+
return reserve_large_pages_aligned(bytes, alignment, exec);
33183372
}
3373+
3374+
// No additional requirements, just reserve the large pages.
3375+
return reserve_large_pages(bytes, addr, exec);
33193376
}
33203377

33213378
bool os::pd_release_memory_special(char* base, size_t bytes) {

0 commit comments

Comments
 (0)