< prev index next >

test/lib/jdk/test/lib/cds/CDSAppTester.java

Print this page
@@ -33,10 +33,14 @@
  
  /*
   * 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;

@@ -46,49 +50,74 @@
      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
  

@@ -100,11 +129,11 @@
          }
  
          // 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()) {

@@ -112,11 +141,11 @@
          } 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;

@@ -165,10 +194,14 @@
  
      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);

@@ -196,11 +229,11 @@
              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;
      }
  

@@ -247,10 +280,26 @@
          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,

@@ -345,10 +394,73 @@
          }
          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 {

@@ -369,10 +481,12 @@
              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);
          }

@@ -387,26 +501,30 @@
          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);
              }
          }
      }

@@ -423,12 +541,34 @@
          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 >