< prev index next > test/lib/jdk/test/lib/cds/CDSAppTester.java
Print this page
/*
* This is a base class used for testing CDS functionalities with complex applications.
* You can define the application by overridding the vmArgs(), classpath() and appCommandLine()
* methods. Application-specific validation checks can be implemented with checkExecution().
+ *
+ * Note: to debug the new workflow, run jtreg with -vmoption:-DCDSAppTester.split.new.workflow=true
+ * This will run the new workflow in two separate processes that you can rerun easily inside a debugger.
+ * Also, the log files are easier to read.
*/
abstract public class CDSAppTester {
private final String name;
private final String classListFile;
private final String classListFileLog;
private final String staticArchiveFileLog;
private final String aotCacheFile;
private final String aotCacheFileLog;
private final String dynamicArchiveFile;
private final String dynamicArchiveFileLog;
+ private final String cdsFile; // new workflow: -XX:CacheDataStore=<foo>.cds
+ private final String cdsFileLog;
+ private final String cdsFilePreImage; // new workflow: -XX:CacheDataStore=<foo>.cds
+ private final String cdsFilePreImageLog;
private final String tempBaseArchiveFile;
private int numProductionRuns = 0;
private String whiteBoxJar = null;
-
+ private boolean inOneStepTraining = false;
+
+ /**
+ * All files created in the CDS/AOT workflow will be name + extension. E.g.
+ * - name.aot
+ * - name.aotconfig
+ * - name.classlist
+ * - name.jsa
+ */
public CDSAppTester(String name) {
if (CDSTestUtils.DYNAMIC_DUMP) {
throw new SkippedException("Tests based on CDSAppTester should be excluded when -Dtest.dynamic.cds.archive is specified");
}
this.name = name;
classListFile = name() + ".classlist";
- classListFileLog = classListFile + ".log";
+ classListFileLog = logFileName(classListFile);
aotConfigurationFile = name() + ".aotconfig";
- aotConfigurationFileLog = aotConfigurationFile + ".log";
+ aotConfigurationFileLog = logFileName(aotConfigurationFile);
staticArchiveFile = name() + ".static.jsa";
- staticArchiveFileLog = staticArchiveFile + ".log";
+ staticArchiveFileLog = logFileName(staticArchiveFile);
aotCacheFile = name() + ".aot";
- aotCacheFileLog = aotCacheFile + ".log";
+ aotCacheFileLog = logFileName(aotCacheFile);;
dynamicArchiveFile = name() + ".dynamic.jsa";
- dynamicArchiveFileLog = dynamicArchiveFile + ".log";
+ dynamicArchiveFileLog = logFileName(dynamicArchiveFile);
+ cdsFile = name() + ".cds";
+ cdsFileLog = logFileName(cdsFile);
+ cdsFilePreImage = cdsFile + ".preimage";
+ cdsFilePreImageLog = logFileName(cdsFilePreImage);
tempBaseArchiveFile = name() + ".temp-base.jsa";
}
private String productionRunLog() {
if (numProductionRuns == 0) {
- return name() + ".production.log";
+ return logFileName(name() + ".production");
} else {
- return name() + ".production." + numProductionRuns + ".log";
+ return logFileName(name() + ".production." + numProductionRuns);
}
}
+ private static String logFileName(String file) {
+ file = file.replace("\"", "%22");
+ file = file.replace("'", "%27");
+ return file + ".log";
+ }
+
private enum Workflow {
STATIC, // classic -Xshare:dump workflow
DYNAMIC, // classic -XX:ArchiveClassesAtExit
AOT, // JEP 483 Ahead-of-Time Class Loading & Linking
+ LEYDEN, // The new "one step training workflow" -- see JDK-8320264
}
public enum RunMode {
TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=record -XX:AOTConfiguration}
+ TRAINING0, // LEYDEN only
+ TRAINING1, // LEYDEN only (assembly phase, app logic not executed)
DUMP_STATIC, // -Xshare:dump
DUMP_DYNAMIC, // -XX:ArchiveClassesArExit
ASSEMBLY, // JEP 483 (assembly phase, app logic not executed)
PRODUCTION; // Running with the CDS archive produced from the above steps
}
// When <code>CDSAppTester::checkExecution(out, runMode)</code> is called, has the application been
// executed? If so, <code>out</code> should contain logs printed by the application's own logic.
public boolean isApplicationExecuted() {
- return (this != ASSEMBLY) && (this != DUMP_STATIC);
+ return (this != TRAINING1) && (this != ASSEMBLY) && (this != DUMP_STATIC);
}
}
public boolean isDumping(RunMode runMode) {
if (isStaticWorkflow()) {
} else if (isDynamicWorkflow()) {
return runMode == RunMode.DUMP_DYNAMIC;
} else if (isAOTWorkflow()) {
return runMode == RunMode.TRAINING || runMode == RunMode.ASSEMBLY;
} else {
- return false;
+ return runMode == RunMode.TRAINING || runMode == RunMode.TRAINING0 || runMode == RunMode.TRAINING1;
}
}
public final String name() {
return this.name;
public final boolean isAOTWorkflow() {
return workflow == Workflow.AOT;
}
+ public final boolean isLeydenWorkflow() {
+ return workflow == Workflow.LEYDEN;
+ }
+
private String logToFile(String logFile, String... logTags) {
StringBuilder sb = new StringBuilder("-Xlog:");
String prefix = "";
for (String tag : logTags) {
sb.append(prefix);
listOutputFile(logFile);
}
if (checkExitValue) {
output.shouldHaveExitValue(0);
}
- output.shouldNotContain(CDSTestUtils.MSG_STATIC_FIELD_MAY_HOLD_DIFFERENT_VALUE);
+ //output.shouldNotContain(CDSTestUtils.MSG_STATIC_FIELD_MAY_HOLD_DIFFERENT_VALUE); // FIXME -- leyden+JEP483 merge
CDSTestUtils.checkCommonExecExceptions(output);
checkExecution(output, runMode);
return output;
}
cmdLine = addCommonVMArgs(runMode, cmdLine);
cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode));
return executeAndCheck(cmdLine, runMode, aotConfigurationFile, aotConfigurationFileLog);
}
+ private OutputAnalyzer createAOTCacheOneStep() throws Exception {
+ RunMode runMode = RunMode.TRAINING;
+ String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode),
+ "-XX:AOTMode=record",
+ "-XX:AOTCacheOutput=" + aotCacheFile,
+ logToFile(aotCacheFileLog,
+ "class+load=debug",
+ "cds=debug",
+ "cds+class=debug"));
+ cmdLine = addCommonVMArgs(runMode, cmdLine);
+ cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode));
+ OutputAnalyzer out = executeAndCheck(cmdLine, runMode, aotCacheFile, aotCacheFileLog);
+ listOutputFile(aotCacheFileLog + ".0"); // the log file for the training run
+ return out;
+ }
+
private OutputAnalyzer createClassList() throws Exception {
RunMode runMode = RunMode.TRAINING;
String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode),
"-Xshare:off",
"-XX:DumpLoadedClassList=" + classListFile,
}
cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode));
return executeAndCheck(cmdLine, runMode, dynamicArchiveFile, dynamicArchiveFileLog);
}
+ private String trainingLog(String file) {
+ return logToFile(file,
+ "cds=debug",
+ "cds+class=debug",
+ "cds+heap=warning",
+ "cds+resolve=debug");
+ }
+
+ // normal training workflow (main JVM process spawns child process)
+ private OutputAnalyzer trainingRun() throws Exception {
+ RunMode runMode = RunMode.TRAINING;
+ File f = new File(cdsFile);
+ f.delete();
+ String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode),
+ "-XX:+AOTClassLinking",
+ "-XX:+ArchiveDynamicProxies",
+ //"-XX:+ArchiveReflectionData",
+ "-XX:CacheDataStore=" + cdsFile,
+ "-cp", classpath(runMode),
+ // Use PID to distinguish the logs of the training process
+ // and the forked final image dump process.
+ "-Xlog:cds::uptime,level,tags,pid",
+ trainingLog(cdsFileLog));
+ cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode));
+ OutputAnalyzer out = executeAndCheck(cmdLine, runMode, cdsFile, cdsFileLog);
+ listOutputFile(cdsFileLog + ".0"); // the preimage dump
+ return out;
+ }
+
+ // "split" training workflow (launch the two processes manually, for easier debugging);
+ private OutputAnalyzer trainingRun0() throws Exception {
+ RunMode runMode = RunMode.TRAINING0;
+ File f = new File(cdsFile);
+ f.delete();
+ String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode),
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+CDSManualFinalImage",
+ "-XX:+AOTClassLinking",
+ "-XX:+ArchiveDynamicProxies",
+ //"-XX:+ArchiveReflectionData",
+ "-XX:CacheDataStore=" + cdsFile,
+ "-cp", classpath(runMode),
+ trainingLog(cdsFilePreImageLog));
+ cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode));
+ return executeAndCheck(cmdLine, runMode, cdsFilePreImage, cdsFilePreImageLog);
+ }
+ private OutputAnalyzer trainingRun1() throws Exception {
+ RunMode runMode = RunMode.TRAINING1;
+ File f = new File(cdsFile);
+ f.delete();
+ String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode),
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+AOTClassLinking",
+ "-XX:+ArchiveDynamicProxies",
+ //"-XX:+ArchiveReflectionData",
+ "-XX:CacheDataStore=" + cdsFile,
+ "-XX:CDSPreimage=" + cdsFilePreImage,
+ "-cp", classpath(runMode),
+ trainingLog(cdsFileLog));
+ cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode));
+ return executeAndCheck(cmdLine, runMode, cdsFile, cdsFileLog);
+ }
+
private OutputAnalyzer productionRun() throws Exception {
return productionRun(null, null);
}
public OutputAnalyzer productionRun(String[] extraVmArgs) throws Exception {
cmdLine = StringArrayUtils.concat(cmdLine, "-Xshare:on", "-XX:SharedArchiveFile=" + staticArchiveFile);
} else if (isDynamicWorkflow()) {
cmdLine = StringArrayUtils.concat(cmdLine, "-Xshare:on", "-XX:SharedArchiveFile=" + dynamicArchiveFile);
} else if (isAOTWorkflow()) {
cmdLine = StringArrayUtils.concat(cmdLine, "-XX:AOTMode=on", "-XX:AOTCache=" + aotCacheFile);
+ } else {
+ cmdLine = StringArrayUtils.concat(cmdLine, "-XX:CacheDataStore=" + cdsFile);
}
if (extraVmArgs != null) {
cmdLine = StringArrayUtils.concat(cmdLine, extraVmArgs);
}
numProductionRuns ++;
return out;
}
public void run(String... args) throws Exception {
- String err = "Must have exactly one command line argument of the following: ";
+ String err = "Must have at least one command line argument of the following: ";
String prefix = "";
for (Workflow wf : Workflow.values()) {
err += prefix;
err += wf;
prefix = ", ";
}
- if (args.length != 1) {
+ if (args.length < 1) {
throw new RuntimeException(err);
} else {
if (args[0].equals("STATIC")) {
runStaticWorkflow();
} else if (args[0].equals("DYNAMIC")) {
runDynamicWorkflow();
} else if (args[0].equals("AOT")) {
- runAOTWorkflow();
+ runAOTWorkflow(args);
+ } else if (args[0].equals("LEYDEN")) {
+ runLeydenWorkflow(false);
+ } else if (args[0].equals("LEYDEN_TRAINONLY")) {
+ runLeydenWorkflow(true);
} else {
throw new RuntimeException(err);
}
}
}
dumpDynamicArchive();
productionRun();
}
// See JEP 483
- public void runAOTWorkflow() throws Exception {
+ public void runAOTWorkflow(String... args) throws Exception {
this.workflow = Workflow.AOT;
- recordAOTConfiguration();
- createAOTCache();
+ if (args.length > 1 && args[1].equals("--onestep-training")) {
+ try {
+ inOneStepTraining = true;
+ createAOTCacheOneStep();
+ } finally {
+ inOneStepTraining = false;
+ }
+ } else {
+ recordAOTConfiguration();
+ createAOTCache();
+ }
productionRun();
}
+
+ private void runLeydenWorkflow(boolean trainOnly) throws Exception {
+ this.workflow = Workflow.LEYDEN;
+ if (System.getProperty("CDSAppTester.split.new.workflow") != null) {
+ trainingRun0();
+ trainingRun1();
+ } else {
+ trainingRun();
+ }
+ if (!trainOnly) {
+ productionRun();
+ }
+ }
}
< prev index next >