Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CODETOOLS-7902910: jcstress: Avoid creating lots of temporary files #41

Merged
merged 1 commit into from
Apr 29, 2021
Merged
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
68 changes: 30 additions & 38 deletions jcstress-core/src/main/java/org/openjdk/jcstress/TestExecutor.java
Original file line number Diff line number Diff line change
@@ -33,13 +33,11 @@
import org.openjdk.jcstress.link.BinaryLinkServer;
import org.openjdk.jcstress.link.ServerListener;
import org.openjdk.jcstress.os.*;
import org.openjdk.jcstress.util.HashMultimap;
import org.openjdk.jcstress.util.Multimap;
import org.openjdk.jcstress.util.*;
import org.openjdk.jcstress.vm.CompileMode;
import org.openjdk.jcstress.vm.VMSupport;

import java.io.*;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
@@ -174,41 +172,37 @@ private class VM {
private final String host;
private final int port;
private final String token;
private final File stdout;
private final File stderr;
private final File compilerDirectives;
private File compilerDirectives;
private final TestConfig task;
private final CPUMap cpuMap;
private Process process;
private boolean processed;
private IOException pendingException;
private TestResult result;
private InputStreamCollector errCollector;
private InputStreamCollector outCollector;

public VM(String host, int port, String token, TestConfig task, CPUMap cpuMap) {
this.host = host;
this.port = port;
this.token = token;
this.cpuMap = cpuMap;
this.task = task;
try {
this.stdout = File.createTempFile("jcstress", "stdout");
this.stderr = File.createTempFile("jcstress", "stderr");
this.compilerDirectives = File.createTempFile("jcstress", "directives");

if (VMSupport.compilerDirectivesAvailable()) {
if (VMSupport.compilerDirectivesAvailable()) {
try {
generateDirectives();
} catch (IOException e) {
throw new IllegalStateException(e);
}

// Register these files for removal in case we terminate through the uncommon path
this.stdout.deleteOnExit();
this.stderr.deleteOnExit();
this.compilerDirectives.deleteOnExit();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}

void generateDirectives() throws IOException {
compilerDirectives = File.createTempFile("jcstress", "directives");

// Register these files for removal in case we terminate through the uncommon path
compilerDirectives.deleteOnExit();

PrintWriter pw = new PrintWriter(compilerDirectives);
pw.println("[");

@@ -338,9 +332,17 @@ void start() {
command.add(token);

ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectOutput(stdout);
pb.redirectError(stderr);
process = pb.start();

// start the stream drainers and read the streams into memory;
// makes little sense to write them to files, since we would be
// reading them back soon anyway
errCollector = new InputStreamCollector(process.getErrorStream());
outCollector = new InputStreamCollector(process.getInputStream());

errCollector.start();
outCollector.start();

} catch (IOException ex) {
pendingException = ex;
}
@@ -376,35 +378,25 @@ public synchronized boolean checkCompleted(TestResultCollector sink) {
try {
int ecode = process.waitFor();

List<String> out = new ArrayList<>();
try {
out.addAll(Files.readAllLines(stdout.toPath()));
} catch (IOException e) {
out.add("Failed to read stdout: " + e.getMessage());
}

List<String> err = new ArrayList<>();
try {
err.addAll(Files.readAllLines(stderr.toPath()));
} catch (IOException e) {
err.add("Failed to read stderr: " + e.getMessage());
}
outCollector.join();
errCollector.join();

if (ecode != 0) {
result = new TestResult(task, Status.VM_ERROR);
result.addMessage("Failed with error code " + ecode);
}
result.addVMOuts(out);
result.addVMErrs(err);
result.addVMOuts(outCollector.getOutput());
result.addVMErrs(errCollector.getOutput());
sink.add(result);
} catch (InterruptedException ex) {
result = new TestResult(task, Status.VM_ERROR);
result.addMessage(ex.getMessage());
sink.add(result);
} finally {
// The process is definitely dead, remove the temporary files.
stdout.delete();
stderr.delete();
if (compilerDirectives != null) {
compilerDirectives.delete();
}
}
return true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2021, Red Hat, Inc. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 org.openjdk.jcstress.util;

import java.io.*;
import java.nio.Buffer;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class InputStreamCollector extends Thread {

private final InputStream in;
private final List<String> list;

public InputStreamCollector(InputStream in) {
this.in = in;
this.list = new ArrayList<>();
}

public void run() {
try (InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
list.add(line);
}
} catch (IOException e) {
// Do nothing.
}
}

public List<String> getOutput() {
return list;
}

}