Skip to content

Commit 78babaf

Browse files
authoredMar 18, 2021
CODETOOLS-7902851: jcstress: Provide the ability to capture VM output
1 parent 9df88ef commit 78babaf

File tree

7 files changed

+161
-68
lines changed

7 files changed

+161
-68
lines changed
 

‎jcstress-core/src/main/java/org/openjdk/jcstress/EmbeddedExecutor.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import java.util.concurrent.Executors;
3939
import java.util.concurrent.ThreadFactory;
4040
import java.util.concurrent.atomic.AtomicInteger;
41-
import java.util.function.Consumer;
4241

4342
public class EmbeddedExecutor {
4443

@@ -83,11 +82,11 @@ private Runnable task(TestConfig config, List<Integer> acquiredCPUs) {
8382
o.run();
8483
} catch (ClassFormatError | NoClassDefFoundError | NoSuchMethodError | NoSuchFieldError e) {
8584
TestResult result = new TestResult(config, Status.API_MISMATCH);
86-
result.addAuxData(StringUtils.getStacktrace(e));
85+
result.addMessage(StringUtils.getStacktrace(e));
8786
sink.add(result);
8887
} catch (Throwable ex) {
8988
TestResult result = new TestResult(config, Status.TEST_ERROR);
90-
result.addAuxData(StringUtils.getStacktrace(ex));
89+
result.addMessage(StringUtils.getStacktrace(ex));
9190
sink.add(result);
9291
} finally {
9392
if (acquiredCPUs != null) {

‎jcstress-core/src/main/java/org/openjdk/jcstress/TestExecutor.java

+68-46
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public TestConfig onJobRequest(String token) {
8080

8181
@Override
8282
public void onResult(String token, TestResult result) {
83-
sink.add(result);
83+
vmByToken.get(token).recordResult(result);
8484
}
8585
}) : null;
8686
embeddedExecutor = new EmbeddedExecutor(sink, cpuLayout);
@@ -127,19 +127,10 @@ private List<Integer> acquireCPUs(int cpus) {
127127

128128
private void processReadyVMs() {
129129
for (VM vm : vmByToken.values()) {
130-
try {
131-
if (!vm.checkTermination()) continue;
132-
} catch (ForkFailedException e) {
133-
TestConfig task = vm.getTask();
134-
TestResult result = new TestResult(task, Status.VM_ERROR);
135-
for (String i : e.getInfo()) {
136-
result.addAuxData(i);
137-
}
138-
sink.add(result);
130+
if (vm.checkCompleted(sink)) {
131+
vmByToken.remove(vm.token, vm);
132+
cpuLayout.release(vm.claimedCPUs);
139133
}
140-
141-
vmByToken.remove(vm.token, vm);
142-
cpuLayout.release(vm.claimedCPUs);
143134
}
144135
}
145136

@@ -155,6 +146,7 @@ private static class VM {
155146
private Process process;
156147
private boolean processed;
157148
private IOException pendingException;
149+
private TestResult result;
158150

159151
public VM(String host, int port, String token, TestConfig task, List<Integer> claimedCPUs) {
160152
this.host = host;
@@ -258,52 +250,82 @@ void start() {
258250
}
259251
}
260252

261-
boolean checkTermination() {
253+
public synchronized TestConfig jobRequest() {
254+
if (processed) {
255+
return null;
256+
}
257+
processed = true;
258+
return getTask();
259+
}
260+
261+
public TestConfig getTask() {
262+
return task;
263+
}
264+
265+
public boolean checkCompleted(TestResultCollector sink) {
266+
// There is a pending exception that terminated the target VM.
262267
if (pendingException != null) {
263-
throw new ForkFailedException(pendingException.getMessage());
268+
dumpFailure(sink, Collections.singleton(pendingException.getMessage()), Collections.emptyList());
269+
return true;
264270
}
265271

272+
// Process is still alive, no need to ask about the status.
266273
if (process.isAlive()) {
267274
return false;
268-
} else {
269-
// Try to poll the exit code, and fail if it's not zero.
275+
}
276+
277+
// Try to poll the exit code, and fail if it's not zero.
278+
try {
279+
int ecode = process.waitFor();
280+
281+
List<String> out = new ArrayList<>();
270282
try {
271-
int ecode = process.waitFor();
272-
if (ecode != 0) {
273-
List<String> output = new ArrayList<>();
274-
try {
275-
output.addAll(Files.readAllLines(stdout.toPath()));
276-
} catch (IOException e) {
277-
output.add("Failed to read stdout: " + e.getMessage());
278-
}
279-
try {
280-
output.addAll(Files.readAllLines(stderr.toPath()));
281-
} catch (IOException e) {
282-
output.add("Failed to read stderr: " + e.getMessage());
283-
}
284-
throw new ForkFailedException(output);
285-
}
286-
} catch (InterruptedException ex) {
287-
throw new ForkFailedException(ex.getMessage());
288-
} finally {
289-
// The process is definitely dead, remove the temporary files.
290-
stdout.delete();
291-
stderr.delete();
283+
out.addAll(Files.readAllLines(stdout.toPath()));
284+
} catch (IOException e) {
285+
out.add("Failed to read stdout: " + e.getMessage());
292286
}
293-
return true;
287+
288+
List<String> err = new ArrayList<>();
289+
try {
290+
err.addAll(Files.readAllLines(stderr.toPath()));
291+
} catch (IOException e) {
292+
err.add("Failed to read stderr: " + e.getMessage());
293+
}
294+
295+
if (ecode != 0) {
296+
dumpFailure(sink, out, err);
297+
} else {
298+
result.addVMOut(out);
299+
result.addVMErr(err);
300+
sink.add(result);
301+
}
302+
} catch (InterruptedException ex) {
303+
dumpFailure(sink, Collections.singleton(ex.getMessage()), Collections.emptyList());
304+
} finally {
305+
// The process is definitely dead, remove the temporary files.
306+
stdout.delete();
307+
stderr.delete();
294308
}
309+
return true;
295310
}
296311

297-
public synchronized TestConfig jobRequest() {
298-
if (processed) {
299-
return null;
312+
private void dumpFailure(TestResultCollector sink, Collection<String> out, Collection<String> err) {
313+
TestConfig task = getTask();
314+
TestResult result = new TestResult(task, Status.VM_ERROR);
315+
for (String i : out) {
316+
result.addMessage(i);
300317
}
301-
processed = true;
302-
return getTask();
318+
for (String i : err) {
319+
result.addMessage(i);
320+
}
321+
sink.add(result);
303322
}
304323

305-
public TestConfig getTask() {
306-
return task;
324+
public void recordResult(TestResult r) {
325+
if (result != null) {
326+
throw new IllegalStateException("VM had already published a result.");
327+
}
328+
result = r;
307329
}
308330
}
309331

‎jcstress-core/src/main/java/org/openjdk/jcstress/infra/collectors/TestResult.java

+34-6
Original file line numberDiff line numberDiff line change
@@ -45,21 +45,41 @@ public class TestResult implements Serializable {
4545
private final Status status;
4646
private final Multiset<String> states;
4747
private volatile Environment env;
48-
private final List<String> auxData;
48+
private final List<String> messages;
49+
private final List<String> vmOut;
50+
private final List<String> vmErr;
4951

5052
public TestResult(TestConfig config, Status status) {
5153
this.config = config;
5254
this.status = status;
5355
this.states = new HashMultiset<>();
54-
this.auxData = new ArrayList<>();
56+
this.messages = new ArrayList<>();
57+
this.vmOut = new ArrayList<>();
58+
this.vmErr = new ArrayList<>();
5559
}
5660

5761
public void addState(String result, long count) {
5862
states.add(result, count);
5963
}
6064

61-
public void addAuxData(String data) {
62-
auxData.add(data);
65+
public void addMessage(String msg) {
66+
messages.add(msg);
67+
}
68+
69+
public void addVMOut(String msg) {
70+
vmOut.add(msg);
71+
}
72+
73+
public void addVMOut(Collection<String> msg) {
74+
vmOut.addAll(msg);
75+
}
76+
77+
public void addVMErr(String msg) {
78+
vmErr.add(msg);
79+
}
80+
81+
public void addVMErr(Collection<String> msg) {
82+
vmErr.addAll(msg);
6383
}
6484

6585
public void setEnv(Environment e) {
@@ -78,8 +98,16 @@ public Status status() {
7898
return status;
7999
}
80100

81-
public List<String> getAuxData() {
82-
return auxData;
101+
public List<String> getMessages() {
102+
return messages;
103+
}
104+
105+
public List<String> getVmOut() {
106+
return vmOut;
107+
}
108+
109+
public List<String> getVmErr() {
110+
return vmErr;
83111
}
84112

85113
public long getTotalCount() {

‎jcstress-core/src/main/java/org/openjdk/jcstress/infra/grading/HTMLReportPrinter.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -427,10 +427,10 @@ public void emitTestReport(PrintWriter o, Collection<TestResult> results, TestIn
427427
o.println("<h3>Auxiliary data</h3>");
428428

429429
for (TestResult r : sorted) {
430-
if (!r.getAuxData().isEmpty()) {
430+
if (!r.getMessages().isEmpty()) {
431431
o.println("<p><b>" + r.getConfig() + "</b></p>");
432432
o.println("<pre>");
433-
for (String data : r.getAuxData()) {
433+
for (String data : r.getMessages()) {
434434
o.println(data);
435435
}
436436
o.println("</pre>");

‎jcstress-core/src/main/java/org/openjdk/jcstress/infra/grading/ReportUtils.java

+52-8
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ private static TestResult merged(TestConfig config, Collection<TestResult> merge
9191
stateCounts.add(s, r.getCount(s));
9292
}
9393
env = r.getEnv();
94-
auxData.addAll(r.getAuxData());
94+
auxData.addAll(r.getMessages());
9595
}
9696

9797
TestResult root = new TestResult(config, status);
@@ -103,7 +103,7 @@ private static TestResult merged(TestConfig config, Collection<TestResult> merge
103103
root.setEnv(env);
104104

105105
for (String data : auxData) {
106-
root.addAuxData(data);
106+
root.addMessage(data);
107107
}
108108
return root;
109109
}
@@ -160,19 +160,63 @@ public static void printDetails(PrintWriter pw, TestResult r, boolean inProgress
160160
}
161161

162162
public static void printMessages(PrintWriter pw, TestResult r) {
163-
if (!r.getAuxData().isEmpty()) {
164-
pw.println(" Messages: ");
165-
for (String data : r.getAuxData()) {
166-
if (skipMessage(data)) continue;
167-
pw.println(" " + data);
163+
boolean errMsgsPrinted = false;
164+
for (String data : r.getMessages()) {
165+
if (skipMessage(data)) continue;
166+
if (!errMsgsPrinted) {
167+
pw.println(" Messages: ");
168+
errMsgsPrinted = true;
168169
}
170+
pw.println(" " + data);
171+
}
172+
if (errMsgsPrinted) {
173+
pw.println();
174+
}
175+
176+
boolean vmOutPrinted = false;
177+
for (String data : r.getVmOut()) {
178+
if (skipMessage(data)) continue;
179+
if (!vmOutPrinted) {
180+
pw.println(" VM output stream: ");
181+
vmOutPrinted = true;
182+
}
183+
pw.println(" " + data);
184+
}
185+
if (vmOutPrinted) {
186+
pw.println();
187+
}
188+
189+
boolean vmErrPrinted = false;
190+
for (String data : r.getVmErr()) {
191+
if (skipMessage(data)) continue;
192+
if (!vmErrPrinted) {
193+
pw.println(" VM error stream: ");
194+
vmErrPrinted = true;
195+
}
196+
pw.println(" " + data);
197+
}
198+
if (vmErrPrinted) {
169199
pw.println();
170200
}
171201
}
172202

173203
private static boolean skipMessage(String data) {
174-
if (data != null && data.startsWith("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox"))
204+
if (data == null) {
175205
return true;
206+
}
207+
208+
if (data.startsWith("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox")) {
209+
return true;
210+
}
211+
212+
if (data.contains("Option MaxRAMFraction was deprecated in version") ||
213+
data.contains("Option MinRAMFraction was deprecated in version")) {
214+
return true;
215+
}
216+
217+
if (data.contains("compiler directives added")) {
218+
return true;
219+
}
176220

177221
return false;
178222
}

‎jcstress-core/src/main/java/org/openjdk/jcstress/infra/runners/Runner.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public void run() {
9797
private TestResult prepareResult(Status status) {
9898
TestResult result = new TestResult(config, status);
9999
for (String msg : messages) {
100-
result.addAuxData(msg);
100+
result.addMessage(msg);
101101
}
102102
messages.clear();
103103
return result;
@@ -112,7 +112,7 @@ protected void dumpFailure(Status status, String message) {
112112
protected void dumpFailure(Status status, String message, Throwable aux) {
113113
messages.add(message);
114114
TestResult result = prepareResult(status);
115-
result.addAuxData(StringUtils.getStacktrace(aux));
115+
result.addMessage(StringUtils.getStacktrace(aux));
116116
collector.add(result);
117117
}
118118

‎jcstress-core/src/test/java/org/openjdk/jcstress/EmbeddedExecutorTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void testReportTestError() throws IOException {
5555
TestResult testResult = sink.getTestResults().iterator().next();
5656
Assert.assertEquals("Should report a test error", Status.TEST_ERROR, testResult.status());
5757

58-
String errorMessage = testResult.getAuxData().get(0);
58+
String errorMessage = testResult.getMessages().get(0);
5959
Assert.assertEquals("Should report the test error reason", "java.lang.ClassNotFoundException: my.missing.ClassName",
6060
getFirstLine(errorMessage));
6161
}

0 commit comments

Comments
 (0)
Please sign in to comment.