Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion make/test/JtregNativeHotspot.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -1512,7 +1512,7 @@ else
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libnativeStack += -lpthread
BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exeGetCreatedJavaVMs := -ljvm -lpthread

BUILD_HOTSPOT_JTREG_EXCLUDE += libNativeException.c
BUILD_HOTSPOT_JTREG_EXCLUDE += libNativeException.c exeGetProcessorInfo.c
endif

ifeq ($(ASAN_ENABLED), true)
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/os/windows/globals_windows.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
range, \
constraint) \
\
product(bool, UseAllWindowsProcessorGroups, false, \
"Use all processor groups on supported Windows versions") \
\
product(bool, UseOSErrorReporting, false, \
"Let VM fatal error propagate to the OS (ie. WER on Windows)")

Expand Down
355 changes: 298 additions & 57 deletions src/hotspot/os/windows/os_windows.cpp

Large diffs are not rendered by default.

40 changes: 40 additions & 0 deletions src/hotspot/os/windows/os_windows.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ class os::win32 {
static julong _physical_memory;
static bool _is_windows_server;
static bool _has_exit_bug;
static bool _processor_group_warning_displayed;
static bool _job_object_processor_group_warning_displayed;

static int _major_version;
static int _minor_version;
static int _build_number;
static int _build_minor;

static void print_windows_version(outputStream* st);
static void print_uptime_info(outputStream* st);
Expand All @@ -56,6 +63,37 @@ class os::win32 {
// Windows-specific interface:
static void initialize_system_info();
static void setmode_streams();
static bool is_windows_11_or_greater();
static bool is_windows_server_2022_or_greater();
static int windows_major_version() {
assert(_major_version > 0, "windows version not initialized.");
return _major_version;
}
static int windows_minor_version() {
assert(_major_version > 0, "windows version not initialized.");
return _minor_version;
}
static int windows_build_number() {
assert(_major_version > 0, "windows version not initialized.");
return _build_number;
}
static int windows_build_minor() {
assert(_major_version > 0, "windows version not initialized.");
return _build_minor;
}

static void set_processor_group_warning_displayed(bool displayed) {
_processor_group_warning_displayed = displayed;
}
static bool processor_group_warning_displayed() {
return _processor_group_warning_displayed;
}
static void set_job_object_processor_group_warning_displayed(bool displayed) {
_job_object_processor_group_warning_displayed = displayed;
}
static bool job_object_processor_group_warning_displayed() {
return _job_object_processor_group_warning_displayed;
}

// Processor info as provided by NT
static int processor_type() { return _processor_type; }
Expand All @@ -79,6 +117,8 @@ class os::win32 {
static int exit_process_or_thread(Ept what, int exit_code);

static void initialize_performance_counter();
static void initialize_windows_version();
static DWORD active_processors_in_job_object(DWORD* active_processor_groups = nullptr);

public:
// Generic interface:
Expand Down
19 changes: 19 additions & 0 deletions test/hotspot/gtest/runtime/test_os_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,25 @@ TEST_VM(os_windows, reserve_memory_special) {
TestReserveMemorySpecial_test();
}

TEST_VM(os_windows, processor_count) {
JVMFlag* flag = JVMFlag::find_flag("UseAllWindowsProcessorGroups");
EXPECT_NE(flag, nullptr) << "Expected UseAllWindowsProcessorGroups product flag to be available";

int processors = os::processor_count();
EXPECT_GT(processors, 0) << "Expected at least 1 processor";

int active_processors = os::active_processor_count();
EXPECT_GT(active_processors, 0) << "Expected at least 1 active processor";

bool schedules_all_processor_groups = os::win32::is_windows_11_or_greater() || os::win32::is_windows_server_2022_or_greater();
if (schedules_all_processor_groups && UseAllWindowsProcessorGroups) {
EXPECT_EQ(active_processors, processors) << "Expected all processors to be active";
} else {
// active_processors should be at most the number of processors in 1 Windows processor group.
EXPECT_LE(active_processors, processors) << "Expected active processors to not exceed available processors";
}
}

class ReserveMemorySpecialRunnable : public TestRunnable {
public:
void runUnitTest() const {
Expand Down
1 change: 1 addition & 0 deletions test/hotspot/jtreg/TEST.groups
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ tier1_common = \
gtest/MetaspaceGtests.java \
gtest/LargePageGtests.java \
gtest/NMTGtests.java \
gtest/WindowsProcessorGroups.java

tier1_compiler = \
:tier1_compiler_1 \
Expand Down
34 changes: 34 additions & 0 deletions test/hotspot/jtreg/gtest/WindowsProcessorGroups.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/

/*
* This runs the os related gtests on Windows with all processor groups enabled.
*/

/* @test id=use-all-windows-processor-groups
* @summary Run gtests with all Windows processor groups enabled
* @library /test/lib
* @requires os.family == "windows"
* @run main/native GTestWrapper --gtest_filter=os* -XX:+UseAllWindowsProcessorGroups
*/
29 changes: 29 additions & 0 deletions test/hotspot/jtreg/runtime/os/windows/GetAvailableProcessors.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/

public class GetAvailableProcessors {
public static void main(String[] args) {
System.out.println("Runtime.availableProcessors: " + Runtime.getRuntime().availableProcessors());
}
}
218 changes: 218 additions & 0 deletions test/hotspot/jtreg/runtime/os/windows/TestAvailableProcessors.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/

/*
* @test
* @bug 6942632
* @requires os.family == "windows"
* @summary This test verifies that OpenJDK can use all available
* processors on Windows 11/Windows Server 2022 and later.
* @requires vm.flagless
* @library /test/lib
* @compile GetAvailableProcessors.java
* @run testng TestAvailableProcessors
*/

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;

import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;

import org.testng.Assert;
import org.testng.annotations.Test;

public class TestAvailableProcessors {

private static final String totalProcessorCountMessage = "Active processor count across all processor groups: ";
private static final String processorCountPerGroupMessage = "Active processors per group: ";
private static final String isWindowsServerMessage = "IsWindowsServer: ";

private static final String runtimeAvailableProcessorsMessage = "Runtime.availableProcessors: ";
private static final String osVersionMessage = "OS Version: ";
private static final String unsupportedPlatformMessage = "The UseAllWindowsProcessorGroups flag is not supported on this Windows version and will be ignored.";

private static String getWindowsVersion() throws IOException {
String systeminfoPath = "systeminfo.exe";

var processBuilder = new ProcessBuilder(systeminfoPath);
OutputAnalyzer outputAnalyzer = new OutputAnalyzer(processBuilder.start());
outputAnalyzer.shouldHaveExitValue(0);
outputAnalyzer.shouldContain(osVersionMessage);
List<String> lines = outputAnalyzer.stdoutAsLines();

String osVersion = null;
for (var line: lines) {
if (line.startsWith(osVersionMessage)) {
osVersion = line.substring(osVersionMessage.length()).trim();
break;
}
}

System.out.println("Found OS version: " + osVersion);
return osVersion;
}

private static boolean getSchedulesAllProcessorGroups(boolean isWindowsServer) throws IOException {
String windowsVer = getWindowsVersion();
String[] parts = windowsVer.split(" ");
String[] versionParts = parts[0].split("\\.");

if (versionParts.length != 3) {
throw new RuntimeException("Unexpected Windows version format.");
}

int major = Integer.parseInt(versionParts[0]);
int minor = Integer.parseInt(versionParts[1]);
int build = Integer.parseInt(versionParts[2]);

if (major > 10) {
return true;
}

if (major < 10) {
return false;
}

if (minor > 0) {
return true;
}

if (isWindowsServer) {
return build >= 20348;
} else {
return build >= 22000;
}
}

private static OutputAnalyzer getAvailableProcessorsOutput(boolean productFlagEnabled) throws IOException {
String productFlag = productFlagEnabled ? "-XX:+UseAllWindowsProcessorGroups" : "-XX:-UseAllWindowsProcessorGroups";

ProcessBuilder processBuilder = ProcessTools.createLimitedTestJavaProcessBuilder(
new String[] {productFlag, "GetAvailableProcessors"}
);

var output = new OutputAnalyzer(processBuilder.start());
output.shouldHaveExitValue(0);
output.shouldContain(runtimeAvailableProcessorsMessage);

return output;
}

private static int getAvailableProcessors(OutputAnalyzer outputAnalyzer) {
int runtimeAvailableProcs = 0;
List<String> output = outputAnalyzer.stdoutAsLines();

for (var line: output) {
if (line.startsWith(runtimeAvailableProcessorsMessage)) {
String runtimeAvailableProcsStr = line.substring(runtimeAvailableProcessorsMessage.length());
runtimeAvailableProcs = Integer.parseInt(runtimeAvailableProcsStr);
}
}

return runtimeAvailableProcs;
}

private static int getAvailableProcessors(boolean productFlagEnabled) throws IOException {
OutputAnalyzer outputAnalyzer = getAvailableProcessorsOutput(productFlagEnabled);
return getAvailableProcessors(outputAnalyzer);
}

private static void verifyAvailableProcessorsWithDisabledProductFlag(Set<Integer> processorGroupSizes) throws IOException {
boolean productFlagEnabled = false;
int runtimeAvailableProcs = getAvailableProcessors(productFlagEnabled);

String error = String.format("Runtime.availableProcessors (%d) is not a valid processor group size on this machine.", runtimeAvailableProcs);
Assert.assertTrue(processorGroupSizes.contains(runtimeAvailableProcs), error);
}

private static void verifyAvailableProcessorsWithEnabledProductFlag(boolean schedulesAllProcessorGroups, int totalProcessorCount, Set<Integer> processorGroupSizes) throws IOException {
boolean productFlagEnabled = true;

OutputAnalyzer outputAnalyzer = getAvailableProcessorsOutput(productFlagEnabled);
int runtimeAvailableProcs = getAvailableProcessors(outputAnalyzer);

if (schedulesAllProcessorGroups) {
String error = String.format("Runtime.availableProcessors (%d) is not equal to the expected total processor count (%d)", runtimeAvailableProcs, totalProcessorCount);
Assert.assertEquals(runtimeAvailableProcs, totalProcessorCount, error);
} else {
outputAnalyzer.shouldContain(unsupportedPlatformMessage);

String error = String.format("Runtime.availableProcessors (%d) is not a valid processor group size on this machine.", runtimeAvailableProcs);
Assert.assertTrue(processorGroupSizes.contains(runtimeAvailableProcs), error);
}
}

@Test
private static void testProcessorAvailability() throws IOException {
// Launch GetProcessorInfo.exe to gather processor counts
Path nativeGetProcessorInfo = Paths.get(Utils.TEST_NATIVE_PATH)
.resolve("GetProcessorInfo.exe")
.toAbsolutePath();

var processBuilder = new ProcessBuilder(nativeGetProcessorInfo.toString());
var outputAnalyzer= new OutputAnalyzer(processBuilder.start());
outputAnalyzer.shouldHaveExitValue(0);
outputAnalyzer.shouldContain(totalProcessorCountMessage);
outputAnalyzer.shouldContain(processorCountPerGroupMessage);
outputAnalyzer.shouldContain(isWindowsServerMessage);

int totalProcessorCount = 0;
boolean isWindowsServer = false;
var processorGroupSizes = new HashSet<Integer>();

List<String> lines = outputAnalyzer.stdoutAsLines();

for (var line: lines) {
if (line.startsWith(totalProcessorCountMessage)) {
String totalProcessorCountStr = line.substring(totalProcessorCountMessage.length());
totalProcessorCount = Integer.parseInt(totalProcessorCountStr);
} else if (line.startsWith(processorCountPerGroupMessage)) {
String processorCountPerGroupStr = line.substring(processorCountPerGroupMessage.length());
String[] processorCountsPerGroup = processorCountPerGroupStr.split(",");

for (var processorCountStr: processorCountsPerGroup) {
int processorCount = Integer.parseInt(processorCountStr);
processorGroupSizes.add(processorCount);
}
} else if (line.startsWith(isWindowsServerMessage)) {
String isWindowsServerStr = line.substring(isWindowsServerMessage.length());
isWindowsServer = Integer.parseInt(isWindowsServerStr) > 0;
}
}

// Launch java without the start command and with the product flag disabled
verifyAvailableProcessorsWithDisabledProductFlag(processorGroupSizes);

// Launch java without the start command and with the product flag enabled
boolean schedulesAllProcessorGroups = getSchedulesAllProcessorGroups(isWindowsServer);
verifyAvailableProcessorsWithEnabledProductFlag(schedulesAllProcessorGroups, totalProcessorCount, processorGroupSizes);
}
}
Loading