From 434adb151083a658b498ffb9c3284f6bb471597a Mon Sep 17 00:00:00 2001 From: Vlad Ureche Date: Wed, 1 Aug 2012 12:30:11 +0200 Subject: Want a 25% partest speedup?* ... well then, don't compile twice! Explanation: The compilation process in partest happens in 3 stages: - scala + java files, all fed to scalac (so the java signatures are loaded and the scala bytecode is generated) - java files, fed to javac (so the java bytecode is generated) - scala files, fed to scalac (so the scala bytecode correctly links to the javac-generated bytecode) While this mechanism is great to have, for simple 1-file scala tests it's overkill by compiling scala files twice. So I adjusted the compile procedure to only run the first step if java files are empty, leading to a 25% partest speedup.* Also included Seth Tisue's comment about the tests that require the three-step compilation. * as measured on test.scaladoc --- .../scala/tools/partest/nest/RunnerManager.scala | 30 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala index dc15d4475b..d7d0b5649a 100644 --- a/src/partest/scala/tools/partest/nest/RunnerManager.scala +++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala @@ -323,10 +323,34 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP val (scalaFiles, javaFiles) = g partition isScala val allFiles = javaFiles ++ scalaFiles + /* The test can contain both java and scala files, each of which should be compiled with the corresponding + * compiler. Since the source files can reference each other both ways (java referencing scala classes and + * vice versa, the partest compilation routine attempts to reach a "bytecode fixpoint" between the two + * compilers -- that's when bytecode generated by each compiler implements the signatures expected by the other. + * + * In theory this property can't be guaranteed, as neither compiler can know what signatures the other + * compiler expects and how to implement them. (see SI-1240 for the full story) + * + * In practice, this happens in 3 steps: + * STEP1: feed all the files to scalac + * it will parse java files and obtain their expected signatures and generate bytecode for scala files + * STEP2: feed the java files to javac + * it will generate the bytecode for the java files and link to the scalac-generated bytecode for scala + * STEP3: only if there are both scala and java files, recompile the scala sources so they link to the correct + * java signatures, in case the signatures deduced by scalac from the source files were wrong. Since the + * bytecode for java is already in place, we only feed the scala files to scalac so it will take the + * java signatures from the existing javac-generated bytecode + */ List(1, 2, 3).foldLeft(CompileSuccess: CompilationOutcome) { - case (CompileSuccess, 1) if scalaFiles.nonEmpty => compileMgr.attemptCompile(Some(outDir), allFiles, kind, logFile) // java + scala - case (CompileSuccess, 2) if javaFiles.nonEmpty => javac(outDir, javaFiles, logFile) // java - case (CompileSuccess, 3) if scalaFiles.nonEmpty => compileMgr.attemptCompile(Some(outDir), scalaFiles, kind, logFile) // scala + case (CompileSuccess, 1) if scalaFiles.nonEmpty => + compileMgr.attemptCompile(Some(outDir), allFiles, kind, logFile) + case (CompileSuccess, 2) if javaFiles.nonEmpty => + javac(outDir, javaFiles, logFile) + case (CompileSuccess, 3) if scalaFiles.nonEmpty && javaFiles.nonEmpty => + // TODO: Do we actually need this? SI-1240 is known to require this, but we don't know if other tests + // require it: https://groups.google.com/forum/?fromgroups#!topic/scala-internals/rFDKAcOKciU + compileMgr.attemptCompile(Some(outDir), scalaFiles, kind, logFile) + case (outcome, _) => outcome } } -- cgit v1.2.3