/*
* Copyright (c) 2012 Aleksey Shipilev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.shipilev.concurrent.torture;
import net.shipilev.concurrent.torture.tests.ConcurrencyTest;
import net.shipilev.concurrent.torture.tests.OneActorOneObserverTest;
import net.shipilev.concurrent.torture.tests.TwoActorsOneArbiterTest;
import net.shipilev.concurrent.torture.util.InputStreamDrainer;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import javax.xml.bind.JAXBException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Modifier;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException, IOException, IllegalAccessException, InstantiationException, JAXBException {
System.out.println("Java Concurrency Torture Tests");
System.out.println("---------------------------------------------------------------------------------");
Options opts = new Options(args);
if (!opts.parse()) {
System.exit(1);
}
if (!opts.shouldParse()) {
if (opts.shouldFork()) {
System.out.println("Running in forked mode...");
System.out.println();
for (Class<? extends ConcurrencyTest> test : filterTests(opts.getTestFilter(), OneActorOneObserverTest.class)) {
runForked(opts, test);
}
for (Class<? extends ConcurrencyTest> test : filterTests(opts.getTestFilter(), TwoActorsOneArbiterTest.class)) {
runForked(opts, test);
}
} else {
System.out.println("Running in embedded mode...");
System.out.println();
runAll(opts);
}
} else {
System.out.println("Re-interpreting the results...");
System.out.println("Look at " + opts.getResultDest() + "/index.html for the results");
System.out.println();
}
XMLtoHTMLResultPrinter p = new XMLtoHTMLResultPrinter(opts);
p.parse();
}
private static void runForked(Options opts, Class<? extends ConcurrencyTest> test) {
try {
String commandString = getSeparateExecutionCommand(opts, test.getName());
// System.err.println("Invoking: " + commandString);
Process p = Runtime.getRuntime().exec(commandString);
InputStreamDrainer errDrainer = new InputStreamDrainer(p.getErrorStream(), System.err);
InputStreamDrainer outDrainer = new InputStreamDrainer(p.getInputStream(), System.out);
errDrainer.start();
outDrainer.start();
int ecode = p.waitFor();
if (ecode != 0) {
throw new IllegalStateException("WARNING: Forked process returned code: " + ecode);
}
errDrainer.join();
outDrainer.join();
} catch (IOException ex) {
ex.printStackTrace();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
private static void runAll(Options opts) throws FileNotFoundException, InstantiationException, IllegalAccessException, ExecutionException, InterruptedException, JAXBException {
System.out.println("Running each test for " + opts.getTime() + "ms");
System.out.println("Each test does " + opts.getLoops() + " internal loops");
System.out.println("Look in results.html for the results");
System.out.println();
Runner r = new Runner(opts);
for (Class<? extends OneActorOneObserverTest> test : filterTests(opts.getTestFilter(), OneActorOneObserverTest.class)) {
OneActorOneObserverTest<?> instance = test.newInstance();
r.run(instance);
}
for (Class<? extends TwoActorsOneArbiterTest> test : filterTests(opts.getTestFilter(), TwoActorsOneArbiterTest.class)) {
TwoActorsOneArbiterTest<?> instance = test.newInstance();
r.run(instance);
}
r.close();
}
public static String getSeparateExecutionCommand(Options opts, String test) {
Properties props = System.getProperties();
String javaHome = (String) props.get("java.home");
String separator = File.separator;
String osName = props.getProperty("os.name");
boolean isOnWindows = osName.contains("indows");
String platformSpecificBinaryPostfix = isOnWindows ? ".exe" : "";
String classPath = (String) props.get("java.class.path");
if (isOnWindows) {
classPath = '"' + classPath + '"';
}
// else find out which one parent is and use that
StringBuilder javaExecutable = new StringBuilder();
javaExecutable.append(javaHome);
javaExecutable.append(separator);
javaExecutable.append("bin");
javaExecutable.append(separator);
javaExecutable.append("java");
javaExecutable.append(platformSpecificBinaryPostfix);
String javaExecutableString = javaExecutable.toString();
// else use same jvm args given to this runner
StringBuilder jvmArguments = new StringBuilder();
RuntimeMXBean RuntimemxBean = ManagementFactory.getRuntimeMXBean();
List<String> args = RuntimemxBean.getInputArguments();
for (String arg : args) {
jvmArguments.append(arg);
jvmArguments.append(' ');
}
if (jvmArguments.length() > 0) {
jvmArguments.setLength(jvmArguments.length() - 1);
}
String jvmArgumentsString = jvmArguments.toString();
// assemble final process command
StringBuilder command = new StringBuilder();
command.append(javaExecutableString);
if (!jvmArgumentsString.isEmpty()) {
command.append(' ');
command.append(jvmArgumentsString);
}
command.append(" -cp ");
command.append(classPath);
command.append(' ');
command.append(ForkedMain.class.getName());
return command.toString() + " " + opts.buildForkedCmdLine() + " -t " + test;
}
private static <T> SortedSet<Class<? extends T>> filterTests(final String filter, Class<T> klass) {
// God I miss both diamonds and lambdas here.
Pattern pattern = Pattern.compile(filter);
Reflections r = new Reflections(
new ConfigurationBuilder()
.filterInputsBy(new FilterBuilder().include("net.shipilev.concurrent.torture.*"))
.setUrls(ClasspathHelper.forClassLoader())
.setScanners(new SubTypesScanner(), new TypeAnnotationsScanner()));
SortedSet<Class<? extends T>> s = new TreeSet<Class<? extends T>>(new Comparator<Class<? extends T>>() {
@Override
public int compare(Class<? extends T> o1, Class<? extends T> o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (Class<? extends T> k : r.getSubTypesOf(klass)) {
// System.err.println("matching " + k);
if (!pattern.matcher(k.getName()).matches()) {
continue;
}
if (Modifier.isAbstract(k.getModifiers())) {
continue;
}
s.add(k);
}
return s;
}
}