Skip to content

Commit c70a5e4

Browse files
author
duke
committed
Backport 4ded283
1 parent 69d97e0 commit c70a5e4

File tree

4 files changed

+153
-12
lines changed

4 files changed

+153
-12
lines changed

src/hotspot/os/windows/globals_windows.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
product(bool, UseAllWindowsProcessorGroups, false, \
3939
"Use all processor groups on supported Windows versions") \
4040
\
41+
product(bool, EnableAllLargePageSizesForWindows, false, \
42+
"Enable support for multiple large page sizes on " \
43+
"Windows Server") \
44+
\
4145
product(bool, UseOSErrorReporting, false, \
4246
"Let VM fatal error propagate to the OS (ie. WER on Windows)")
4347

src/hotspot/os/windows/os_windows.cpp

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,7 +3104,7 @@ class NUMANodeListHolder {
31043104

31053105
static size_t _large_page_size = 0;
31063106

3107-
static bool request_lock_memory_privilege() {
3107+
bool os::win32::request_lock_memory_privilege() {
31083108
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
31093109
os::current_process_id());
31103110

@@ -3288,14 +3288,14 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags,
32883288
return p_buf;
32893289
}
32903290

3291-
static size_t large_page_init_decide_size() {
3291+
size_t os::win32::large_page_init_decide_size() {
32923292
// print a warning if any large page related flag is specified on command line
32933293
bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) ||
32943294
!FLAG_IS_DEFAULT(LargePageSizeInBytes);
32953295

3296-
#define WARN(msg) if (warn_on_failure) { warning(msg); }
3296+
#define WARN(...) if (warn_on_failure) { warning(__VA_ARGS__); }
32973297

3298-
if (!request_lock_memory_privilege()) {
3298+
if (!os::win32::request_lock_memory_privilege()) {
32993299
WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory.");
33003300
return 0;
33013301
}
@@ -3306,15 +3306,26 @@ static size_t large_page_init_decide_size() {
33063306
return 0;
33073307
}
33083308

3309-
#if defined(IA32) || defined(AMD64)
3310-
if (size > 4*M || LargePageSizeInBytes > 4*M) {
3309+
#if defined(IA32)
3310+
if (size > 4 * M || LargePageSizeInBytes > 4 * M) {
33113311
WARN("JVM cannot use large pages bigger than 4mb.");
33123312
return 0;
33133313
}
3314+
#elif defined(AMD64)
3315+
if (!EnableAllLargePageSizesForWindows) {
3316+
if (size > 4 * M || LargePageSizeInBytes > 4 * M) {
3317+
WARN("JVM cannot use large pages bigger than 4mb.");
3318+
return 0;
3319+
}
3320+
}
33143321
#endif
33153322

3316-
if (LargePageSizeInBytes > 0 && LargePageSizeInBytes % size == 0) {
3317-
size = LargePageSizeInBytes;
3323+
if (LargePageSizeInBytes > 0) {
3324+
if (LargePageSizeInBytes % size == 0) {
3325+
size = LargePageSizeInBytes;
3326+
} else {
3327+
WARN("The specified large page size (%d) is not a multiple of the minimum large page size (%d), defaulting to minimum page size.", LargePageSizeInBytes, size);
3328+
}
33183329
}
33193330

33203331
#undef WARN
@@ -3327,12 +3338,23 @@ void os::large_page_init() {
33273338
return;
33283339
}
33293340

3330-
_large_page_size = large_page_init_decide_size();
3341+
_large_page_size = os::win32::large_page_init_decide_size();
33313342
const size_t default_page_size = os::vm_page_size();
33323343
if (_large_page_size > default_page_size) {
3344+
#if !defined(IA32)
3345+
if (EnableAllLargePageSizesForWindows) {
3346+
size_t min_size = GetLargePageMinimum();
3347+
3348+
// Populate _page_sizes with large page sizes less than or equal to _large_page_size, ensuring each page size is double the size of the previous one.
3349+
for (size_t page_size = min_size; page_size < _large_page_size; page_size *= 2) {
3350+
_page_sizes.add(page_size);
3351+
}
3352+
}
3353+
#endif
3354+
33333355
_page_sizes.add(_large_page_size);
33343356
}
3335-
3357+
// Set UseLargePages based on whether a large page size was successfully determined
33363358
UseLargePages = _large_page_size != 0;
33373359
}
33383360

@@ -3596,7 +3618,6 @@ static char* reserve_large_pages_aligned(size_t size, size_t alignment, bool exe
35963618
char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_size, char* addr,
35973619
bool exec) {
35983620
assert(UseLargePages, "only for large pages");
3599-
assert(page_size == os::large_page_size(), "Currently only support one large page size on Windows");
36003621
assert(is_aligned(addr, alignment), "Must be");
36013622
assert(is_aligned(addr, page_size), "Must be");
36023623

@@ -3605,11 +3626,17 @@ char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_
36053626
return nullptr;
36063627
}
36073628

3629+
// Ensure GetLargePageMinimum() returns a valid positive value
3630+
size_t large_page_min = GetLargePageMinimum();
3631+
if (large_page_min <= 0) {
3632+
return nullptr;
3633+
}
3634+
36083635
// The requested alignment can be larger than the page size, for example with G1
36093636
// the alignment is bound to the heap region size. So this reservation needs to
36103637
// ensure that the requested alignment is met. When there is a requested address
36113638
// this solves it self, since it must be properly aligned already.
3612-
if (addr == nullptr && alignment > page_size) {
3639+
if (addr == nullptr && alignment > large_page_min) {
36133640
return reserve_large_pages_aligned(bytes, alignment, exec);
36143641
}
36153642

src/hotspot/os/windows/os_windows.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class os::win32 {
6565
static void setmode_streams();
6666
static bool is_windows_11_or_greater();
6767
static bool is_windows_server_2022_or_greater();
68+
static bool request_lock_memory_privilege();
69+
static size_t large_page_init_decide_size();
6870
static int windows_major_version() {
6971
assert(_major_version > 0, "windows version not initialized.");
7072
return _major_version;

test/hotspot/gtest/runtime/test_os_windows.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,114 @@ TEST_VM(os_windows, processor_count) {
722722
}
723723
}
724724

725+
TEST_VM(os_windows, large_page_init_multiple_sizes) {
726+
// Call request_lock_memory_privilege() and check the result
727+
if (!os::win32::request_lock_memory_privilege()) {
728+
GTEST_SKIP() << "Skipping test because lock memory privilege is not granted.";
729+
}
730+
// Set globals to make sure we hit the correct code path
731+
AutoSaveRestore<bool> guardUseLargePages(UseLargePages);
732+
AutoSaveRestore<bool> guardEnableAllLargePageSizesForWindows(EnableAllLargePageSizesForWindows);
733+
AutoSaveRestore<size_t> guardLargePageSizeInBytes(LargePageSizeInBytes);
734+
FLAG_SET_CMDLINE(UseLargePages, true);
735+
FLAG_SET_CMDLINE(EnableAllLargePageSizesForWindows, true);
736+
737+
// Determine the minimum page size
738+
const size_t min_size = GetLargePageMinimum();
739+
740+
// End the test if GetLargePageMinimum returns 0
741+
if (min_size == 0) {
742+
GTEST_SKIP() << "Large pages are not supported on this system.";
743+
return;
744+
}
745+
746+
// Set LargePageSizeInBytes to 4 times the minimum page size
747+
FLAG_SET_CMDLINE(LargePageSizeInBytes, 4 * min_size); // Set a value for multiple page sizes
748+
749+
// Initialize large page settings
750+
os::large_page_init();
751+
752+
// Verify that large pages are enabled
753+
EXPECT_TRUE(UseLargePages) << "UseLargePages should be true after initialization for LargePageSizeInBytes = 4 * min_size";
754+
755+
// Verify that decided_large_page_size is greater than the default page size
756+
const size_t default_page_size = os::vm_page_size();
757+
size_t decided_large_page_size = os::win32::large_page_init_decide_size();
758+
EXPECT_GT(decided_large_page_size, default_page_size) << "Large page size should be greater than the default page size for LargePageSizeInBytes = 4 * min_size";
759+
760+
#if !defined(IA32)
761+
size_t page_size_count = 0;
762+
size_t page_size = os::page_sizes().largest();
763+
764+
do {
765+
++page_size_count;
766+
page_size = os::page_sizes().next_smaller(page_size);
767+
} while (page_size >= os::page_sizes().smallest());
768+
769+
EXPECT_GT(page_size_count, 1u) << "There should be multiple large page sizes available.";
770+
771+
size_t large_page_size = decided_large_page_size;
772+
773+
for (size_t page_size = os::page_sizes().largest(); page_size >= min_size; page_size = os::page_sizes().next_smaller(page_size)) {
774+
EXPECT_TRUE(page_size % min_size == 0) << "Each page size should be a multiple of the minimum large page size.";
775+
EXPECT_LE(page_size, large_page_size) << "Page size should not exceed the determined large page size.";
776+
}
777+
#endif
778+
}
779+
780+
TEST_VM(os_windows, large_page_init_decide_size) {
781+
// Initial setup
782+
// Call request_lock_memory_privilege() and check the result
783+
if (!os::win32::request_lock_memory_privilege()) {
784+
GTEST_SKIP() << "Skipping test because lock memory privilege is not granted.";
785+
}
786+
AutoSaveRestore<bool> guardUseLargePages(UseLargePages);
787+
AutoSaveRestore<size_t> guardLargePageSizeInBytes(LargePageSizeInBytes);
788+
FLAG_SET_CMDLINE(UseLargePages, true);
789+
FLAG_SET_CMDLINE(LargePageSizeInBytes, 0); // Reset to default
790+
791+
// Test for large page support
792+
size_t decided_size = os::win32::large_page_init_decide_size();
793+
size_t min_size = GetLargePageMinimum();
794+
if (min_size == 0) {
795+
EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 when large page is not supported by the processor";
796+
return;
797+
}
798+
799+
// Scenario 1: Test with 2MB large page size
800+
if (min_size == 2 * M) {
801+
FLAG_SET_CMDLINE(LargePageSizeInBytes, 2 * M); // Set large page size to 2MB
802+
decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size
803+
EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page and OS reported size are both 2M";
804+
}
805+
806+
// Scenario 2: Test with 1MB large page size
807+
if (min_size == 2 * M) {
808+
FLAG_SET_CMDLINE(LargePageSizeInBytes, 1 * M); // Set large page size to 1MB
809+
decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size
810+
EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page is 1M and OS reported size is 2M";
811+
}
812+
813+
#if defined(IA32) || defined(AMD64)
814+
FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * M); // Set large page size to 5MB
815+
if (!EnableAllLargePageSizesForWindows) {
816+
decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size
817+
EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 for large pages bigger than 4mb on IA32 or AMD64";
818+
}
819+
#endif
820+
821+
// Additional check for non-multiple of minimum size
822+
// Set an arbitrary large page size which is not a multiple of min_size
823+
FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * min_size + 1);
824+
825+
// Recalculate decided size
826+
decided_size = os::win32::large_page_init_decide_size();
827+
828+
// Assert that the decided size defaults to minimum page size when LargePageSizeInBytes
829+
// is not a multiple of the minimum size, assuming conditions are always met
830+
EXPECT_EQ(decided_size, 0) << "Expected decided size to default to 0 when LargePageSizeInBytes is not a multiple of minimum size";
831+
}
832+
725833
class ReserveMemorySpecialRunnable : public TestRunnable {
726834
public:
727835
void runUnitTest() const {

0 commit comments

Comments
 (0)