Skip to content

Commit 48436cd

Browse files
committed
[GR-68627] Add TimeLimit utility and use it in DumpPathTest.
PullRequest: graal/21833
2 parents 64f8948 + a8a8bc7 commit 48436cd

File tree

5 files changed

+279
-65
lines changed

5 files changed

+279
-65
lines changed

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DumpPathTest.java

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
import java.util.ArrayList;
3232
import java.util.List;
3333

34-
import jdk.graal.compiler.core.GraalCompilerOptions;
3534
import org.graalvm.collections.EconomicMap;
3635
import org.junit.Test;
3736

37+
import jdk.graal.compiler.core.GraalCompilerOptions;
3838
import jdk.graal.compiler.debug.DebugOptions;
3939
import jdk.graal.compiler.debug.DebugOptions.PrintGraphTarget;
4040
import jdk.graal.compiler.debug.TTY;
@@ -45,46 +45,61 @@
4545
* Check that setting the dump path results in files ending up in the right directory with matching
4646
* names.
4747
*/
48-
public class DumpPathTest extends GraalCompilerTest {
48+
public class DumpPathTest extends SubprocessTest {
49+
50+
/**
51+
* If this test does not complete in 60 seconds, something is very wrong.
52+
*/
53+
private static final int TIME_LIMIT = 60000;
4954

5055
public static Object snippet() {
5156
return new String("snippet");
5257
}
5358

5459
@Test
55-
public void testDump() throws Exception {
60+
public void test() throws IOException, InterruptedException {
61+
launchSubprocess(this::runInSubprocess, "-Xmx50M");
62+
63+
}
64+
65+
public void runInSubprocess() {
5666
assumeManagementLibraryIsLoadable();
57-
try (TemporaryDirectory temp = new TemporaryDirectory("DumpPathTest")) {
58-
String[] extensions = {".cfg", ".bgv", ".graph-strings"};
59-
EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
60-
overrides.put(DebugOptions.DumpPath, temp.toString());
61-
overrides.put(DebugOptions.ShowDumpFiles, false);
62-
overrides.put(DebugOptions.PrintBackendCFG, true);
63-
overrides.put(DebugOptions.PrintGraph, PrintGraphTarget.File);
64-
overrides.put(DebugOptions.PrintCanonicalGraphStrings, true);
65-
overrides.put(DebugOptions.Dump, "*");
66-
overrides.put(GraalCompilerOptions.DumpHeapAfter, "<compilation>:Schedule");
67-
overrides.put(DebugOptions.MethodFilter, null);
67+
try (var _ = new TTY.Filter();
68+
TimeLimit _ = TimeLimit.create(TIME_LIMIT, "DumpPathTest")) {
69+
try (TemporaryDirectory temp = new TemporaryDirectory("DumpPathTest")) {
70+
String[] extensions = {".cfg", ".bgv", ".graph-strings"};
71+
EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
72+
overrides.put(DebugOptions.DumpPath, temp.toString());
73+
overrides.put(DebugOptions.ShowDumpFiles, false);
74+
overrides.put(DebugOptions.PrintBackendCFG, true);
75+
overrides.put(DebugOptions.PrintGraph, PrintGraphTarget.File);
76+
overrides.put(DebugOptions.PrintCanonicalGraphStrings, true);
77+
overrides.put(DebugOptions.Dump, "*");
78+
overrides.put(GraalCompilerOptions.DumpHeapAfter, "<compilation>:Schedule");
79+
overrides.put(DebugOptions.MethodFilter, null);
6880

69-
try (AutoCloseable _ = new TTY.Filter()) {
70-
// Generate dump files.
71-
test(new OptionValues(getInitialOptions(), overrides), "snippet");
72-
}
73-
// Check that IGV files got created, in the right place.
74-
List<Path> paths = checkForFiles(temp.path, extensions);
75-
List<Path> compilationHeapDumps = new ArrayList<>();
76-
List<Path> phaseHeapDumps = new ArrayList<>();
77-
for (Path path : paths) {
78-
String name = path.toString();
79-
if (name.endsWith(".compilation.hprof")) {
80-
compilationHeapDumps.add(path);
81-
} else if (name.endsWith(".hprof")) {
82-
phaseHeapDumps.add(path);
81+
try (var _ = new TTY.Filter()) {
82+
// Generate dump files.
83+
test(new OptionValues(getInitialOptions(), overrides), "snippet");
84+
}
85+
// Check that IGV files got created, in the right place.
86+
List<Path> paths = checkForFiles(temp.path, extensions);
87+
List<Path> compilationHeapDumps = new ArrayList<>();
88+
List<Path> phaseHeapDumps = new ArrayList<>();
89+
for (Path path : paths) {
90+
String name = path.toString();
91+
if (name.endsWith(".compilation.hprof")) {
92+
compilationHeapDumps.add(path);
93+
} else if (name.endsWith(".hprof")) {
94+
phaseHeapDumps.add(path);
95+
}
8396
}
84-
}
8597

86-
assertTrue(!compilationHeapDumps.isEmpty());
87-
assertTrue(!phaseHeapDumps.isEmpty());
98+
assertTrue(!compilationHeapDumps.isEmpty());
99+
assertTrue(!phaseHeapDumps.isEmpty());
100+
}
101+
} catch (IOException e) {
102+
throw new AssertionError(e);
88103
}
89104
}
90105

@@ -99,6 +114,7 @@ private static List<Path> checkForFiles(Path directoryPath, String[] extensions)
99114
for (Path filePath : stream) {
100115
result.add(filePath);
101116
String fileName = filePath.getFileName().toString();
117+
System.out.printf("%s -> %,d bytes%n", filePath, Files.size(filePath));
102118
for (int i = 0; i < extensions.length; i++) {
103119
String extension = extensions[i];
104120
if (fileName.endsWith(extensions[i])) {

compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubprocessTest.java

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,16 @@
3636
import java.util.List;
3737
import java.util.function.Predicate;
3838

39+
import jdk.graal.compiler.test.GraalTest;
3940
import jdk.graal.compiler.test.SubprocessUtil;
4041
import jdk.graal.compiler.test.SubprocessUtil.Subprocess;
4142

4243
/**
4344
* Utility class for executing Graal compiler tests in a subprocess. This can be useful for tests
4445
* that need special VM arguments or that produce textual output or a special process termination
45-
* status that need to be analyzed. The class to be executed may be the current class or any other
46-
* unit test class.
46+
* status that need to be analyzed. Another use case is a test that behaves very differently when
47+
* run after many other tests (that fill up the heap and pollute profiles). The class to be executed
48+
* may be the current class or any other unit test class.
4749
* <p/>
4850
* If the test class contains multiple {@code @Test} methods, they will all be executed in the
4951
* subprocess, except when using one of the methods that take a {@code testSelector} argument. All
@@ -59,24 +61,24 @@
5961
public abstract class SubprocessTest extends GraalCompilerTest {
6062

6163
/**
62-
* Launches the {@code runnable} in a subprocess, with any extra {@code args} passed as
63-
* arguments to the subprocess VM. Checks that the subprocess terminated successfully, i.e., an
64-
* exit code different from 0 raises an error.
65-
*
66-
* @return Inside the subprocess, returns {@code null}. Outside the subprocess, returns a
67-
* {@link Subprocess} instance describing the process after its successful termination.
64+
* Calls {@link #launchSubprocess(Predicate, boolean, Class, String, Runnable, String...)} with
65+
* the given args, {@code vmArgsFilter=null}, {@code check=true}, {@code testClass=getClass()}
66+
* and {@code testSelector=currentUnitTestName()}.
6867
*/
69-
public SubprocessUtil.Subprocess launchSubprocess(Runnable runnable, String... args) throws InterruptedException, IOException {
70-
return launchSubprocess(null, null, true, getClass(), currentUnitTestName(), runnable, args);
71-
}
72-
73-
public SubprocessUtil.Subprocess launchSubprocess(Predicate<String> vmArgsFilter, Runnable runnable, String... args) throws InterruptedException, IOException {
74-
return launchSubprocess(null, vmArgsFilter, true, getClass(), currentUnitTestName(), runnable, args);
68+
public SubprocessUtil.Subprocess launchSubprocess(Runnable runnable, String... extraVmArgs) throws InterruptedException, IOException {
69+
return launchSubprocess(null, true, getClass(), currentUnitTestName(), runnable, extraVmArgs);
7570
}
7671

77-
public static SubprocessUtil.Subprocess launchSubprocess(Class<? extends GraalCompilerTest> testClass, String testSelector, Runnable runnable, String... args)
78-
throws InterruptedException, IOException {
79-
return launchSubprocess(null, null, true, testClass, testSelector, runnable, args);
72+
/**
73+
* Calls {@link #launchSubprocess(Predicate, boolean, Class, String, Runnable, String...)} with
74+
* the given args, {@code vmArgsFilter=null} and {@code check=true}.
75+
*/
76+
public static SubprocessUtil.Subprocess launchSubprocess(
77+
Class<? extends GraalCompilerTest> testClass,
78+
String testSelector,
79+
Runnable runnable,
80+
String... extraVmArgs) throws InterruptedException, IOException {
81+
return launchSubprocess(null, true, testClass, testSelector, runnable, extraVmArgs);
8082
}
8183

8284
private static List<String> filter(List<String> args, Predicate<String> vmArgsFilter) {
@@ -106,17 +108,36 @@ private static String getRecursionPropName(Class<? extends GraalCompilerTest> te
106108
return "test." + testClass.getName() + ".subprocess";
107109
}
108110

109-
public static SubprocessUtil.Subprocess launchSubprocess(Predicate<List<String>> testPredicate, Predicate<String> vmArgsFilter, boolean expectNormalExit,
110-
Class<? extends GraalCompilerTest> testClass, String testSelector, Runnable runnable, String... args)
111-
throws InterruptedException, IOException {
111+
/**
112+
* Launches {@code runnable} in a subprocess.
113+
*
114+
* @param runnable task to be run in the subprocess
115+
* @param vmArgsFilter filters the VM args to only those matching this predicate
116+
* @param check if true, and the process exits with a non-zero exit code, an AssertionError
117+
* exception will be thrown
118+
* @param testClass the class defining the test
119+
* @param testSelector name of the current test. This is typically provided by
120+
* {@link GraalTest#currentUnitTestName()}. Use {@link #ALL_TESTS} to denote that all
121+
* tests in {@code testClass} are to be run.
122+
* @param extraVmArgs extra VM args to pass to the subprocess
123+
* @return returns {@code null} when run in the subprocess. Outside the subprocess, returns a
124+
* {@link Subprocess} instance describing the process after its successful termination.
125+
*/
126+
public static SubprocessUtil.Subprocess launchSubprocess(
127+
Predicate<String> vmArgsFilter,
128+
boolean check,
129+
Class<? extends GraalCompilerTest> testClass,
130+
String testSelector,
131+
Runnable runnable,
132+
String... extraVmArgs) throws InterruptedException, IOException {
112133
if (isRecursiveLaunch(testClass)) {
113134
runnable.run();
114135
return null;
115136
} else {
116137
List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
117138
vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS);
118139
vmArgs.add("-D" + getRecursionPropName(testClass) + "=true");
119-
vmArgs.addAll(Arrays.asList(args));
140+
vmArgs.addAll(Arrays.asList(extraVmArgs));
120141
if (vmArgsFilter != null) {
121142
vmArgs = filter(vmArgs, vmArgsFilter);
122143
}
@@ -132,13 +153,9 @@ public static SubprocessUtil.Subprocess launchSubprocess(Predicate<List<String>>
132153
}
133154
SubprocessUtil.Subprocess proc = java(vmArgs, mainClassAndArgs);
134155

135-
if (testPredicate != null && !testPredicate.test(proc.output)) {
136-
fail("Subprocess produced unexpected output:%n%s", proc.preserveArgfile());
137-
}
138156
int exitCode = proc.exitCode;
139-
if ((exitCode == 0) != expectNormalExit) {
140-
String expectExitCode = expectNormalExit ? "0" : "non-0";
141-
fail("Subprocess produced exit code %d, but expected %s%n%s", exitCode, expectExitCode, proc.preserveArgfile());
157+
if (check && exitCode != 0) {
158+
fail("Subprocess produced non-0 exit code %d%n%s", exitCode, proc.preserveArgfile());
142159
}
143160

144161
// Test passed
@@ -148,5 +165,4 @@ public static SubprocessUtil.Subprocess launchSubprocess(Predicate<List<String>>
148165
return proc;
149166
}
150167
}
151-
152168
}

0 commit comments

Comments
 (0)