From 14cb5ddfc561a248206eeb54cbbc554c6889aaca Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 24 Feb 2026 07:23:41 +0000 Subject: [PATCH] 8376291: [IR Framework] Create classes for separate Test VM messages Reviewed-by: mchevalier, dfenacci, epeter --- .../ir_framework/driver/TestVMProcess.java | 1 + .../driver/irmatching/irmethod/IRMethod.java | 2 +- .../parser/ApplicableIRRulesParser.java | 23 +--- .../irmatching/parser/TestClassParser.java | 2 +- .../irmatching/parser/VMInfoParser.java | 22 +-- .../driver/network/TestVMData.java | 64 ++------- .../network/testvm/TestVmMessageReader.java | 20 ++- .../network/testvm/java/ExecutedTests.java | 55 ++++++++ .../network/testvm/java/JavaMessage.java | 35 +++++ .../testvm/java/JavaMessageParser.java | 125 ++++++++++++++++++ .../network/testvm/java/JavaMessages.java | 42 ++++-- .../network/testvm/java/MethodTimes.java | 85 ++++++++++++ .../network/testvm/java/StdoutMessages.java | 54 ++++++++ .../test/ApplicableIRRulesPrinter.java | 15 +-- .../lib/ir_framework/test/TestVM.java | 20 +-- .../lib/ir_framework/test/VMInfoPrinter.java | 9 +- .../ir_framework/test/network/MessageTag.java | 1 + .../test/network/TestVmSocket.java | 15 +++ 18 files changed, 444 insertions(+), 146 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/ExecutedTests.java create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessage.java create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java create mode 100644 test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java index 9a55db01fa0..00a9b93d124 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/TestVMProcess.java @@ -75,6 +75,7 @@ public class TestVMProcess { checkTestVMExitCode(); String hotspotPidFileName = String.format("hotspot_pid%d.log", oa.pid()); testVmData = socket.testVmData(hotspotPidFileName, allowNotCompilable); + testVmData.printJavaMessages(); } public String getCommandLine() { diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java index 893312c5196..5fbe90f0e72 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/irmethod/IRMethod.java @@ -98,7 +98,7 @@ public class IRMethod implements IRMethodMatchable { List match = matcher.match(); long endTime = System.nanoTime(); long duration = (endTime - startTime); - System.out.println("Verifying IR rules for " + name() + ": " + duration + " ns = " + (duration / 1000000) + " ms"); + System.out.println("Verifying IR rules for " + name() + ": " + duration + " ns = " + (duration / 1_000_000) + " ms"); return new IRMethodMatchResult(method, match); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java index be44c3f3d91..d251c574e47 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/ApplicableIRRulesParser.java @@ -36,8 +36,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Class to parse the Applicable IR Rules emitted by the Test VM and creating {@link TestMethod} objects for each entry. @@ -45,11 +43,6 @@ import java.util.regex.Pattern; * @see TestMethod */ public class ApplicableIRRulesParser { - - private static final boolean PRINT_APPLICABLE_IR_RULES = Boolean.parseBoolean(System.getProperty("PrintApplicableIRRules", "false")); - private static final Pattern APPLICABLE_IR_RULES_PATTERN = - Pattern.compile("(?<=" + ApplicableIRRulesPrinter.START + "\r?\n).*\\R([\\s\\S]*)(?=" + ApplicableIRRulesPrinter.END + ")"); - private final Map testMethods; private final Class testClass; @@ -63,10 +56,6 @@ public class ApplicableIRRulesParser { * entry for each method that needs to be IR matched on. */ public TestMethods parse(String applicableIRRules) { - if (TestFramework.VERBOSE || PRINT_APPLICABLE_IR_RULES) { - System.out.println("Read Applicable IR Rules from Test VM:"); - System.out.println(applicableIRRules); - } createTestMethodMap(applicableIRRules, testClass); // We could have found format errors in @IR annotations. Report them now with an exception. TestFormat.throwIfAnyFailures(); @@ -105,15 +94,11 @@ public class ApplicableIRRulesParser { * Parse the Applicable IR Rules lines without header, explanation line and footer and return them in an array. */ private String[] getApplicableIRRulesLines(String applicableIRRules) { - Matcher matcher = APPLICABLE_IR_RULES_PATTERN.matcher(applicableIRRules); - TestFramework.check(matcher.find(), "Did not find Applicable IR Rules in:" + - System.lineSeparator() + applicableIRRules); - String lines = matcher.group(1).trim(); - if (lines.isEmpty()) { + if (applicableIRRules.isEmpty()) { // Nothing to IR match. return new String[0]; } - return lines.split("\\R"); + return applicableIRRules.split("\\R"); } /** @@ -148,7 +133,7 @@ public class ApplicableIRRulesParser { private void validateIRRuleIds(Method m, IR[] irAnnos, IRRuleIds irRuleIds) { TestFramework.check(irRuleIds != null, "Should find method name in validIrRulesMap for " + m); TestFramework.check(!irRuleIds.isEmpty(), "Did not find any rule indices for " + m); - TestFramework.check((irRuleIds.first() >= 1 || irRuleIds.first() == ApplicableIRRulesPrinter.NO_RULE_APPLIED) + TestFramework.check((irRuleIds.first() >= 1 || irRuleIds.first() == ApplicableIRRulesPrinter.NO_RULES) && irRuleIds.last() <= irAnnos.length, "Invalid IR rule index found in validIrRulesMap for " + m); } @@ -157,6 +142,6 @@ public class ApplicableIRRulesParser { * Does the list of IR rules contain any applicable IR rules for the given conditions? */ private boolean hasAnyApplicableIRRules(IRRuleIds irRuleIds) { - return irRuleIds.first() != ApplicableIRRulesPrinter.NO_RULE_APPLIED; + return irRuleIds.first() != ApplicableIRRulesPrinter.NO_RULES; } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java index 6c899af2116..ca36a3e9f72 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/TestClassParser.java @@ -57,7 +57,7 @@ public class TestClassParser { public Matchable parse(TestVMData testVmData) { ApplicableIRRulesParser applicableIRRulesParser = new ApplicableIRRulesParser(testClass); TestMethods testMethods = applicableIRRulesParser.parse(testVmData.applicableIRRules()); - VMInfo vmInfo = VMInfoParser.parseVMInfo(testVmData.applicableIRRules()); + VMInfo vmInfo = VMInfoParser.parseVMInfo(testVmData.vmInfo()); if (testMethods.hasTestMethods()) { HotSpotPidFileParser hotSpotPidFileParser = new HotSpotPidFileParser(testClass.getName(), testMethods); LoggedMethods loggedMethods = hotSpotPidFileParser.parse(testVmData.hotspotPidFileName()); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java index 2b17303f1a7..44013839754 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/irmatching/parser/VMInfoParser.java @@ -23,14 +23,10 @@ package compiler.lib.ir_framework.driver.irmatching.parser; -import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.shared.TestFrameworkException; -import compiler.lib.ir_framework.test.VMInfoPrinter; import java.util.HashMap; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Class to parse the VMInfo emitted by the Test VM and creating {@link VMInfo} objects for each entry. @@ -39,15 +35,12 @@ import java.util.regex.Pattern; */ public class VMInfoParser { - private static final Pattern VM_INFO_PATTERN = - Pattern.compile("(?<=" + VMInfoPrinter.START_VM_INFO + "\r?\n).*\\R([\\s\\S]*)(?=" + VMInfoPrinter.END_VM_INFO + ")"); - /** - * Extract VMInfo from the applicableIRRules. + * Create a new VMInfo object from the vmInfo string. */ - public static VMInfo parseVMInfo(String applicableIRRules) { + public static VMInfo parseVMInfo(String vmInfo) { Map map = new HashMap<>(); - String[] lines = getVMInfoLines(applicableIRRules); + String[] lines = getVMInfoLines(vmInfo); for (String s : lines) { String line = s.trim(); String[] splitLine = line.split(":", 2); @@ -64,14 +57,11 @@ public class VMInfoParser { /** * Extract the VMInfo from the applicableIRRules string, strip away the header and return the individual key-value lines. */ - private static String[] getVMInfoLines(String applicableIRRules) { - Matcher matcher = VM_INFO_PATTERN.matcher(applicableIRRules); - TestFramework.check(matcher.find(), "Did not find VMInfo in:" + System.lineSeparator() + applicableIRRules); - String lines = matcher.group(1).trim(); - if (lines.isEmpty()) { + private static String[] getVMInfoLines(String vmInfo) { + if (vmInfo.isEmpty()) { // Nothing to IR match. return new String[0]; } - return lines.split("\\R"); + return vmInfo.split("\\R"); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/TestVMData.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/TestVMData.java index daa6a590ddf..413cf3347d8 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/TestVMData.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/TestVMData.java @@ -26,25 +26,30 @@ package compiler.lib.ir_framework.driver.network; import compiler.lib.ir_framework.driver.irmatching.IRMatcher; import compiler.lib.ir_framework.driver.network.testvm.java.JavaMessages; import compiler.lib.ir_framework.shared.TestFrameworkSocket; -import compiler.lib.ir_framework.test.network.MessageTag; - -import java.util.Scanner; /** * This class collects all the parsed data received over the {@link TestFrameworkSocket}. This data is required later * in the {@link IRMatcher}. */ public class TestVMData { + private final JavaMessages javaMessages; private final boolean allowNotCompilable; private final String hotspotPidFileName; - private final String applicableIRRules; public TestVMData(JavaMessages javaMessages, String hotspotPidFileName, boolean allowNotCompilable) { - this.applicableIRRules = processOutput(javaMessages); + this.javaMessages = javaMessages; this.hotspotPidFileName = hotspotPidFileName; this.allowNotCompilable = allowNotCompilable; } + public String applicableIRRules() { + return javaMessages.applicableIRRules(); + } + + public String vmInfo() { + return javaMessages.vmInfo(); + } + public String hotspotPidFileName() { return hotspotPidFileName; } @@ -53,52 +58,7 @@ public class TestVMData { return allowNotCompilable; } - public String applicableIRRules() { - return applicableIRRules; - } - - /** - * Process the socket output: All prefixed lines are dumped to the standard output while the remaining lines - * represent the Applicable IR Rules used for IR matching later. - */ - private String processOutput(JavaMessages javaMessages) { - String output = javaMessages.output(); - if (javaMessages.hasStdOut()) { - StringBuilder testListBuilder = new StringBuilder(); - StringBuilder messagesBuilder = new StringBuilder(); - StringBuilder nonStdOutBuilder = new StringBuilder(); - Scanner scanner = new Scanner(output); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - if (line.startsWith(MessageTag.STDOUT)) { - // Exclude [STDOUT] from message. - line = line.substring(MessageTag.STDOUT.length()); - if (line.startsWith(MessageTag.TEST_LIST)) { - // Exclude [TEST_LIST] from message for better formatting. - line = "> " + line.substring(MessageTag.TEST_LIST.length() + 1); - testListBuilder.append(line).append(System.lineSeparator()); - } else { - messagesBuilder.append(line).append(System.lineSeparator()); - } - } else { - nonStdOutBuilder.append(line).append(System.lineSeparator()); - } - } - System.out.println(); - if (!testListBuilder.isEmpty()) { - System.out.println("Run flag defined test list"); - System.out.println("--------------------------"); - System.out.println(testListBuilder); - System.out.println(); - } - if (!messagesBuilder.isEmpty()) { - System.out.println("Messages from Test VM"); - System.out.println("---------------------"); - System.out.println(messagesBuilder); - } - return nonStdOutBuilder.toString(); - } else { - return output; - } + public void printJavaMessages() { + javaMessages.print(); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/TestVmMessageReader.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/TestVmMessageReader.java index b438794964d..a203fd367f7 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/TestVmMessageReader.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/TestVmMessageReader.java @@ -23,10 +23,10 @@ package compiler.lib.ir_framework.driver.network.testvm; +import compiler.lib.ir_framework.driver.network.testvm.java.JavaMessageParser; import compiler.lib.ir_framework.driver.network.testvm.java.JavaMessages; import compiler.lib.ir_framework.shared.TestFrameworkException; import compiler.lib.ir_framework.shared.TestFrameworkSocket; -import compiler.lib.ir_framework.test.network.MessageTag; import java.io.BufferedReader; import java.net.Socket; @@ -35,33 +35,29 @@ import java.util.concurrent.Future; /** * Dedicated reader for Test VM messages received by the {@link TestFrameworkSocket}. The reader is used as a task - * wrapped in a {@link Future}. The received messages are returned in a new {@link JavaMessages} wrapper. Once the - * Test VM is terminated, the client connection is closed and the parsed messages can be fetched with - * {@link Future#get()} which calls {@link #call()}. + * wrapped in a {@link Future}. The received messages are parsed with the {@link JavaMessageParser}. Once the Test VM + * is terminated, client connection is closed and the parsed messages can be fetched with {@link Future#get()} which + * calls {@link #call()}. */ public class TestVmMessageReader implements Callable { private final Socket socket; private final BufferedReader reader; - private boolean receivedStdOut; + private final JavaMessageParser messageParser; public TestVmMessageReader(Socket socket, BufferedReader reader) { this.socket = socket; this.reader = reader; - this.receivedStdOut = false; + this.messageParser = new JavaMessageParser(); } @Override public JavaMessages call() { try (socket; reader) { - StringBuilder builder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { - builder.append(line).append(System.lineSeparator()); - if (line.startsWith(MessageTag.STDOUT)) { - receivedStdOut = true; - } + messageParser.parseLine(line); } - return new JavaMessages(builder.toString(), receivedStdOut); + return messageParser.output(); } catch (Exception e) { throw new TestFrameworkException("Error while reading Test VM socket messages", e); } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/ExecutedTests.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/ExecutedTests.java new file mode 100644 index 00000000000..f17d7eb5d74 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/ExecutedTests.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2026, 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. + */ + +package compiler.lib.ir_framework.driver.network.testvm.java; + +import compiler.lib.ir_framework.test.network.MessageTag; + +import java.util.List; + +/** + * Class to collect all Java Messages sent with tag {@link MessageTag#TEST_LIST}. These are only generated when the + * user runs with {@code -DTest=myTest} and represent the executed tests. + */ +class ExecutedTests implements JavaMessage { + private final List tests; + + public ExecutedTests(List tests) { + this.tests = tests; + } + + @Override + public void print() { + if (tests.isEmpty()) { + return; + } + + System.out.println(); + System.out.println("Executed Subset of Tests"); + System.out.println("------------------------"); + for (String test : tests) { + System.out.println("- " + test); + } + System.out.println(); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessage.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessage.java new file mode 100644 index 00000000000..7eef84dbbbc --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessage.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026, 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. + */ + +package compiler.lib.ir_framework.driver.network.testvm.java; + +import compiler.lib.ir_framework.shared.TestFrameworkSocket; +import compiler.lib.ir_framework.test.network.MessageTag; + +/** + * Interface for a message sent from Java code to the Driver VM via the {@link TestFrameworkSocket}. We differentiate + * between different messages depending on the leading {@link MessageTag} of a received message. + */ +public interface JavaMessage { + void print(); +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java new file mode 100644 index 00000000000..896aef38f1f --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessageParser.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2026, 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. + */ + +package compiler.lib.ir_framework.driver.network.testvm.java; + +import compiler.lib.ir_framework.TestFramework; +import compiler.lib.ir_framework.shared.TestFrameworkException; +import compiler.lib.ir_framework.test.network.MessageTag; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static compiler.lib.ir_framework.test.network.MessageTag.*; + +/** + * Dedicated parser for {@link JavaMessages} received from the Test VM. Depending on the parsed {@link MessageTag}, the + * message is parsed differently. + */ +public class JavaMessageParser { + private static final Pattern TAG_PATTERN = Pattern.compile("^(\\[[^]]+])\\s*(.*)$"); + + private final List stdoutMessages; + private final List executedTests; + private final Map methodTimes; + private final StringBuilder vmInfoBuilder; + private final StringBuilder applicableIrRules; + + private StringBuilder currentBuilder; + + public JavaMessageParser() { + this.stdoutMessages = new ArrayList<>(); + this.methodTimes = new HashMap<>(); + this.executedTests = new ArrayList<>(); + this.vmInfoBuilder = new StringBuilder(); + this.applicableIrRules = new StringBuilder(); + this.currentBuilder = null; + } + + public void parseLine(String line) { + line = line.trim(); + Matcher tagLineMatcher = TAG_PATTERN.matcher(line); + if (tagLineMatcher.matches()) { + // New tag + assertNoActiveParser(); + parseTagLine(tagLineMatcher); + return; + } + + assertActiveParser(); + if (line.equals(END_MARKER)) { + // End tag + parseEndTag(); + return; + } + + // Multi-line message for single tag. + currentBuilder.append(line).append(System.lineSeparator()); + } + + private void assertNoActiveParser() { + TestFramework.check(currentBuilder == null, "Unexpected new tag while parsing block"); + } + + private void parseTagLine(Matcher tagLineMatcher) { + String tag = tagLineMatcher.group(1); + String message = tagLineMatcher.group(2); + switch (tag) { + case STDOUT -> stdoutMessages.add(message); + case TEST_LIST -> executedTests.add(message); + case PRINT_TIMES -> parsePrintTimes(message); + case VM_INFO -> currentBuilder = vmInfoBuilder; + case APPLICABLE_IR_RULES -> currentBuilder = applicableIrRules; + default -> throw new TestFrameworkException("unknown tag"); + } + } + + private void parsePrintTimes(String message) { + String[] split = message.split(","); + TestFramework.check(split.length == 2, "unexpected format"); + String methodName = split[0]; + try { + long duration = Long.parseLong(split[1]); + methodTimes.put(methodName, duration); + } catch (NumberFormatException e) { + throw new TestFrameworkException("invalid duration", e); + } + } + + private void assertActiveParser() { + TestFramework.check(currentBuilder != null, "Received non-tag line outside of any tag block"); + } + + private void parseEndTag() { + currentBuilder = null; + } + + public JavaMessages output() { + return new JavaMessages(new StdoutMessages(stdoutMessages), + new ExecutedTests(executedTests), + new MethodTimes(methodTimes), + applicableIrRules.toString(), + vmInfoBuilder.toString()); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java index b8a3f39c637..e47ecff4b2a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/JavaMessages.java @@ -23,28 +23,44 @@ package compiler.lib.ir_framework.driver.network.testvm.java; -import compiler.lib.ir_framework.test.network.MessageTag; +import compiler.lib.ir_framework.TestFramework; /** * Class to collect all Java messages sent from the Test VM to the Driver VM. */ public class JavaMessages { - private final String output; - private final boolean receivedStdOut; + private static final boolean PRINT_APPLICABLE_IR_RULES = Boolean.parseBoolean(System.getProperty("PrintApplicableIRRules", "false")); - public JavaMessages(String output, boolean receivedStdOut) { - this.output = output; - this.receivedStdOut = receivedStdOut; + private final StdoutMessages stdoutMessages; + private final ExecutedTests executedTests; + private final MethodTimes methodTimes; + private final String applicableIrRules; + private final String vmInfo; + + JavaMessages(StdoutMessages stdoutMessages, ExecutedTests executedTests, MethodTimes methodTimes, + String applicableIrRules, String vmInfo) { + this.stdoutMessages = stdoutMessages; + this.executedTests = executedTests; + this.methodTimes = methodTimes; + this.applicableIrRules = applicableIrRules; + this.vmInfo = vmInfo; } - public String output() { - return output; + public String applicableIRRules() { + return applicableIrRules; } - /** - * Return whether Test VM sent messages to be put on stdout (starting with {@link MessageTag#STDOUT}). - */ - public boolean hasStdOut() { - return receivedStdOut; + public String vmInfo() { + return vmInfo; + } + + public void print() { + stdoutMessages.print(); + methodTimes.print(); + executedTests.print(); + if (TestFramework.VERBOSE || PRINT_APPLICABLE_IR_RULES) { + System.out.println("Read Applicable IR Rules from Test VM:"); + System.out.println(applicableIrRules); + } } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java new file mode 100644 index 00000000000..1b4cad52270 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/MethodTimes.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2026, 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. + */ + +package compiler.lib.ir_framework.driver.network.testvm.java; + +import compiler.lib.ir_framework.test.network.MessageTag; + +import java.util.List; +import java.util.Map; + + +/** + * Class to collect all Java Messages sent with tag {@link MessageTag#PRINT_TIMES}. These are only generated when the + * user runs with {@code -DPrintTimes=true} and represent the execution times for methods. + */ +class MethodTimes implements JavaMessage { + private final Map methodTimes; + + public MethodTimes(Map methodTimes) { + this.methodTimes = methodTimes; + } + + @Override + public void print() { + if (methodTimes.isEmpty()) { + return; + } + + System.out.println(); + System.out.println("Test Execution Times"); + System.out.println("--------------------"); + + int maxWidthNames = maxMethodNameWidth(); + int maxDurationsWidth = maxDurationsWidth(); + List> sortedMethodTimes = sortByDurationAsc(); + + for (Map.Entry entry : sortedMethodTimes) { + System.out.printf("- %-" + (maxWidthNames + 3) + "s %" + maxDurationsWidth + "d ns%n", + entry.getKey() + ":", entry.getValue()); + } + + System.out.println(); + } + + private int maxMethodNameWidth() { + return methodTimes.keySet().stream() + .mapToInt(String::length) + .max() + .orElseThrow(); + } + + private int maxDurationsWidth() { + return methodTimes.values().stream() + .mapToInt(v -> Long.toString(v).length()) + .max() + .orElseThrow(); + } + + private List> sortByDurationAsc() { + return methodTimes.entrySet().stream() + .sorted(Map.Entry.comparingByValue()) + .toList(); + } + +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java new file mode 100644 index 00000000000..11b23ad4237 --- /dev/null +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/driver/network/testvm/java/StdoutMessages.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026, 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. + */ + +package compiler.lib.ir_framework.driver.network.testvm.java; + +import compiler.lib.ir_framework.test.network.MessageTag; + +import java.util.List; + + +/** + * Class to collect all Java Messages sent with tag {@link MessageTag#STDOUT}. These messages are generated at various + * places in the Test VM and are unconditionally shown in the Driver VM output. + */ +class StdoutMessages implements JavaMessage { + private final List messages; + + public StdoutMessages(List messages) { + this.messages = messages; + } + + @Override + public void print() { + if (messages.isEmpty()) { + return; + } + System.out.println(); + System.out.println("Test VM Messages"); + System.out.println("----------------"); + for (String message : messages) { + System.out.println("- " + message); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java index 15d9a2e4e34..4b4ec0f8b26 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/ApplicableIRRulesPrinter.java @@ -47,9 +47,7 @@ import java.util.function.Function; * termination of the Test VM. IR rule indices start at 1. */ public class ApplicableIRRulesPrinter { - public static final String START = "##### ApplicableIRRules - used by TestFramework #####"; - public static final String END = "----- END -----"; - public static final int NO_RULE_APPLIED = -1; + public static final int NO_RULES = -1; private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); private static final List> LONG_GETTERS = Arrays.asList( @@ -131,11 +129,6 @@ public class ApplicableIRRulesPrinter { "zvkn" )); - public ApplicableIRRulesPrinter() { - output.append(START).append(System.lineSeparator()); - output.append(",{comma separated applied @IR rule ids}").append(System.lineSeparator()); - } - /** * Emits ",{ids}" where {ids} is either: * - indices of all @IR rules that should be applied, separated by a comma @@ -162,7 +155,7 @@ public class ApplicableIRRulesPrinter { if (irAnnos.length != 0) { output.append(m.getName()); if (validRules.isEmpty()) { - output.append("," + NO_RULE_APPLIED); + output.append("," + NO_RULES); } else { for (i = 0; i < validRules.size(); i++) { output.append(",").append(validRules.get(i)); @@ -524,8 +517,8 @@ public class ApplicableIRRulesPrinter { } public void emit() { - output.append(END); - TestVmSocket.sendWithTag(MessageTag.APPLICABLE_IR_RULES, output.toString()); + output.append(MessageTag.END_MARKER); + TestVmSocket.sendMultiLine(MessageTag.APPLICABLE_IR_RULES, output.toString()); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java index c5e94c32c08..ac52bcaaa98 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/TestVM.java @@ -594,8 +594,8 @@ public class TestVM { "Cannot overload @Test methods, but method " + m + " has " + overloads.size() + " overload" + (overloads.size() == 1 ? "" : "s") + ":" + overloads.stream().map(String::valueOf).collect(Collectors.joining("\n - ", "\n - ", "")) ); - TestFormat.check(!testMethodMap.containsKey(m.getName()), - "Cannot overload two @Test methods: " + m + ", " + testMethodMap.get(m.getName())); + TestFramework.check(!testMethodMap.containsKey(m.getName()), + "Cannot overload two @Test methods: " + m + ", " + testMethodMap.get(m.getName())); TestFormat.check(testAnno != null, m + " must be a method with a @Test annotation"); Check checkAnno = getAnnotation(m, Check.class); @@ -836,7 +836,6 @@ public class TestVM { * Once all framework tests are collected, they are run in this method. */ private void runTests() { - TreeMap durations = PRINT_TIMES ? new TreeMap<>() : null; long startTime = System.nanoTime(); List testList; boolean testFilterPresent = testFilterPresent(); @@ -865,7 +864,7 @@ public class TestVM { System.out.println("Run " + test.toString()); } if (testFilterPresent) { - TestVmSocket.send(MessageTag.TEST_LIST + "Run " + test.toString()); + TestVmSocket.sendWithTag(MessageTag.TEST_LIST, "Run " + test.toString()); } try { test.run(); @@ -880,10 +879,11 @@ public class TestVM { if (PRINT_TIMES) { long endTime = System.nanoTime(); long duration = (endTime - startTime); - durations.put(duration, test.getName()); if (VERBOSE) { - System.out.println("Done " + test.getName() + ": " + duration + " ns = " + (duration / 1000000) + " ms"); + System.out.println("Done " + test.getName() + ": " + duration + " ns = " + (duration / 1_000_000) + " ms"); } + // Will be correctly formatted later. + TestVmSocket.sendWithTag(MessageTag.PRINT_TIMES, test.getName() + "," + duration); } if (GC_AFTER) { System.out.println("doing GC"); @@ -891,14 +891,6 @@ public class TestVM { } } - // Print execution times - if (PRINT_TIMES) { - TestVmSocket.send(MessageTag.PRINT_TIMES + " Test execution times:"); - for (Map.Entry entry : durations.entrySet()) { - TestVmSocket.send(MessageTag.PRINT_TIMES + String.format("%-25s%15d ns%n", entry.getValue() + ":", entry.getKey())); - } - } - if (failures > 0) { // Finally, report all occurred exceptions in a nice format. String msg = System.lineSeparator() + System.lineSeparator() + "Test Failures (" + failures + ")" diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java index 2227c7760d5..8fc61ee9bad 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/VMInfoPrinter.java @@ -31,15 +31,10 @@ import jdk.test.whitebox.WhiteBox; * Prints some Test VM info to the socket. */ public class VMInfoPrinter { - public static final String START_VM_INFO = "##### IRMatchingVMInfo - used by TestFramework #####"; - public static final String END_VM_INFO = "----- END VMInfo -----"; - private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); public static void emit() { StringBuilder vmInfo = new StringBuilder(); - vmInfo.append(START_VM_INFO).append(System.lineSeparator()); - vmInfo.append(":").append(System.lineSeparator()); // CPU feature independent info String cpuFeatures = WHITE_BOX.getCPUFeatures(); @@ -65,7 +60,7 @@ public class VMInfoPrinter { .append(useAVXIsDefault ? 1 : 0) .append(System.lineSeparator()); - vmInfo.append(END_VM_INFO); - TestVmSocket.sendWithTag(MessageTag.VM_INFO, vmInfo.toString()); + vmInfo.append(MessageTag.END_MARKER); + TestVmSocket.sendMultiLine(MessageTag.VM_INFO, vmInfo.toString()); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/MessageTag.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/MessageTag.java index 2981f203e65..66b89dc122d 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/MessageTag.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/MessageTag.java @@ -29,4 +29,5 @@ public class MessageTag { public static final String PRINT_TIMES = "[PRINT_TIMES]"; public static final String VM_INFO = "[VM_INFO]"; public static final String APPLICABLE_IR_RULES = "[APPLICABLE_IR_RULES]"; + public static final String END_MARKER = "#END#"; } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/TestVmSocket.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/TestVmSocket.java index c1065c84320..37e59b9dcae 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/TestVmSocket.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/network/TestVmSocket.java @@ -25,6 +25,7 @@ package compiler.lib.ir_framework.test.network; import compiler.lib.ir_framework.TestFramework; import compiler.lib.ir_framework.shared.TestRunException; +import compiler.lib.ir_framework.test.TestVM; import java.io.IOException; import java.io.PrintWriter; @@ -46,6 +47,20 @@ public class TestVmSocket { sendWithTag(MessageTag.STDOUT, message); } + /** + * Send a message with multiple lines to the Driver VM with a {@link MessageTag}. Not all messages are shown by + * default in the Driver VM output and require setting some property flags first like {@code -DPrintTimes=true}. + */ + public static void sendMultiLine(String tag, String message) { + if (REPRODUCE) { + // Debugging Test VM: Skip writing due to -DReproduce; + return; + } + + TestFramework.check(socket != null, "must be connected"); + writer.println(tag + System.lineSeparator() + message); + } + /** * Send a message to the Driver VM with a {@link MessageTag}. Not all messages are shown by default in the * Driver VM output and require setting some property flags first like {@code -DPrintTimes=true}.