diff --git a/.gitignore b/.gitignore index 9145a9fa67b06..852b692f99b50 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ NashornProfile.txt **/core.[0-9]* *.rej *.orig +test/benchmarks/**/target diff --git a/test/benchmarks/micros-javac/README.md b/test/benchmarks/micros-javac/README.md new file mode 100644 index 0000000000000..66ca073a7636f --- /dev/null +++ b/test/benchmarks/micros-javac/README.md @@ -0,0 +1,61 @@ +# Javac microbenchmarks + +The Javac Microbenchmarks is a collection of microbenchmarks for measuring +the performance of Javac API using the +[JMH](http://openjdk.java.net/projects/code-tools/jmh/) framework. + + +## Building and running the project + +Currently, the project can be built and run with JDK 9 and later. This is +a Maven project and is built by: + + $ mvn clean install + +After building, the executable jar is target/micros-javac-[version].jar. +Run the benchmarks with: + + $ java -jar target/micros-javac-*.jar [optional jmh parameters] + +See the entire list of benchmarks using: + + $ java -jar target/micros-javacs-*.jar -l [optional regex to select benchmarks] + +For example: + + $ java -jar target/micros-javac-1.0-SNAPSHOT.jar -l + Benchmarks: + org.openjdk.bench.langtools.javac.GroupJavacBenchmark.coldGroup + org.openjdk.bench.langtools.javac.GroupJavacBenchmark.hotGroup + org.openjdk.bench.langtools.javac.SingleJavacBenchmark.compileCold + org.openjdk.bench.langtools.javac.SingleJavacBenchmark.compileHot + +And the same regex syntax works to run some test: + + $ java -jar target/micros-javac-1.0-SNAPSHOT.jar SingleJavacBenchmark.compileHot + +## Troubleshooting + +### Build of micros-javac module got stuck + +If you build got stuck on `[get] Getting: https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip` then you are probably experiencing some networking or web proxy obstacles. + +One solution is to download required reference JDK from [https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip](https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip) manually and then build the project with property pointing to the local copy: + + $ mvn clean install -Djavac.benchmark.openjdk.zip.download.url=file:////openjdk-11+28_windows-x64_bin.zip + +Note: Please use `openjdk-11+28_windows-x64_bin.zip` to build the project no matter what target platform is. + +Another solution might be to add proxy settings: + + $ mvn -Dhttps.proxyHost=... -Dhttps.proxyPort=... clean install + +### Execution of micros-javac benchmarks takes several hours + +micros-javac benchmarks consist of two sets of benchmarks: + * `SingleJavacBenchmark` (which is parametrized) measures each single javac compilation stage in an isolated run. This benchmark is designed for exact automated performance regression testing and it takes several hours to execute completely. + * `GroupJavacBenchmark` is grouping the measurements of all javac compilation stages into one run and its execution should take less than 30 minutes on a regular developers computer. + +Solution to speed up javac benchmarking is to select only `GroupJavacBenchmark` for execution using following command line: + + $ java -jar target/micros-javac-1.0-SNAPSHOT.jar .*GroupJavacBenchmark.* diff --git a/test/benchmarks/micros-javac/pom.xml b/test/benchmarks/micros-javac/pom.xml new file mode 100644 index 0000000000000..5a8a40d7a9afc --- /dev/null +++ b/test/benchmarks/micros-javac/pom.xml @@ -0,0 +1,139 @@ + + + 4.0.0 + org.openjdk + micros-javac + jar + 1.0-SNAPSHOT + OpenJDK Microbenchmark of Java Compile + + https://download.java.net/openjdk/jdk11/ri/openjdk-11+28_windows-x64_bin.zip + UTF-8 + 1.36 + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.1 + + + package + + shade + + + + + org.openjdk.jmh.Main + + + META-INF/BenchmarkList + + + META-INF/CompilerHints + + + false + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.1 + + 1.8 + 1.8 + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + + + + org.apache.maven.plugins + maven-release-plugin + 3.1.1 + + + maven-deploy-plugin + 3.1.4 + + + maven-antrun-plugin + 3.1.0 + + + process-resources + + + + + + + + + + + + + +------------------------------------------------- +Bundling JDK sources with following release info: +------------------------------------------------- +${release.info} +------------------------------------------------- + + + + + run + + + + + + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + provided + + + diff --git a/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/GroupJavacBenchmark.java b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/GroupJavacBenchmark.java new file mode 100644 index 0000000000000..5ca3f0bf6483a --- /dev/null +++ b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/GroupJavacBenchmark.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. 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.bench.langtools.javac; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Group; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +public class GroupJavacBenchmark extends JavacBenchmark { + + public static final String COLD_GROUP_NAME = "coldGroup"; + public static final int COLD_ITERATION_WARMUPS = 0; + public static final int COLD_ITERATIONS = 1; + public static final int COLD_FORK_WARMUPS = 1; + public static final int COLD_FORKS = 15; + + public static final String HOT_GROUP_NAME = "hotGroup"; + public static final int HOT_ITERATION_WARMUPS = 8; + public static final int HOT_ITERATIONS = 10; + public static final int HOT_FORK_WARMUPS = 0; + public static final int HOT_FORKS = 1; + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold1_Init() throws InterruptedException { + Stage.Init.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold2_Parse() throws InterruptedException { + Stage.Parse.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold3_InitModules() throws InterruptedException { + Stage.InitModules.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold4_Enter() throws InterruptedException { + Stage.Enter.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold5_Attribute() throws InterruptedException { + Stage.Attribute.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold6_Flow() throws InterruptedException { + Stage.Flow.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold7_Desugar() throws InterruptedException { + Stage.Desugar.waitFor(); + } + + @Benchmark + @Group(COLD_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = COLD_ITERATION_WARMUPS) + @Measurement(iterations = COLD_ITERATIONS) + @Fork(warmups = COLD_FORK_WARMUPS, value = COLD_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void cold8_Generate(Blackhole bh) throws IOException { + compile(bh, Stage.Generate); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot1_Init() throws InterruptedException { + Stage.Init.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot2_Parse() throws InterruptedException { + Stage.Parse.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot3_InitModules() throws InterruptedException { + Stage.InitModules.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot4_Enter() throws InterruptedException { + Stage.Enter.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot5_Attribute() throws InterruptedException { + Stage.Attribute.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot6_Flow() throws InterruptedException { + Stage.Flow.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot7_Desugar() throws InterruptedException { + Stage.Desugar.waitFor(); + } + + @Benchmark + @Group(HOT_GROUP_NAME) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = HOT_ITERATION_WARMUPS) + @Measurement(iterations = HOT_ITERATIONS) + @Fork(warmups = HOT_FORK_WARMUPS, value = HOT_FORKS, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void hot8_Generate(Blackhole bh) throws IOException { + compile(bh, Stage.Generate); + } +} diff --git a/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java new file mode 100644 index 0000000000000..1afffc6d0442f --- /dev/null +++ b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/JavacBenchmark.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. 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.bench.langtools.javac; + +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.main.Main; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Context.Factory; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Pair; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.Queue; +import static java.util.logging.Level.FINE; +import static java.util.logging.Level.CONFIG; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileObject; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +public class JavacBenchmark { + + static final Logger LOG = Logger.getLogger(JavacBenchmark.class.getName()); + + public enum Stage { + Init, Parse, InitModules, Enter, Attribute, Flow, Desugar, Generate; + + public synchronized void waitFor() throws InterruptedException { + wait(); + } + public synchronized void notifyDone() { + notifyAll(); + LOG.log(FINE, "{0} finished.", this.name()); + } + public boolean isAfter(Stage other) { + return ordinal() > other.ordinal(); + } + } + + private Path root; + private Path srcList; + + @Setup(Level.Trial) + public void setup(Blackhole bh) throws IOException, InterruptedException { + LOG.log(CONFIG, "Release info of the sources to be compiled by the benchmark:\n{0}", new String(JavacBenchmark.class.getResourceAsStream("/release").readAllBytes(), StandardCharsets.UTF_8)); + root = Files.createTempDirectory("JavacBenchmarkRoot"); + srcList = root.resolve("sources.list"); + int i = 0; + try (PrintStream srcListOut = new PrintStream(srcList.toFile())) { + try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(JavacBenchmark.class.getResourceAsStream("/src.zip")))) { + for (ZipEntry entry; (entry = zis.getNextEntry()) != null;) { + final String ename = entry.getName(); + if (!ename.startsWith("java.desktop") && !ename.startsWith("jdk.internal.vm.compiler") && !ename.startsWith("jdk.aot") && !ename.startsWith("jdk.accessibility")) { + if (!entry.isDirectory() && ename.endsWith(".java")) { + Path dst = root.resolve(ename); + Files.createDirectories(dst.getParent()); + Files.copy(zis, dst); + Files.readAllBytes(dst); //reads all the file back to exclude antivirus scanning time from following measurements + srcListOut.println(dst.toString()); + i++; + } + } + } + } + } + Files.walk(root).map(Path::toFile).forEach(File::deleteOnExit); //mark all files and folders for deletion on JVM exit for cases when tearDown is not executed + Thread.sleep(10000); //give some more time for the system to catch a breath for more precise measurement + LOG.log(FINE, "Extracted {0} sources.", i); + } + + @TearDown(Level.Trial) + public void tearDown() throws IOException { + Files.walk(root).sorted(Comparator.reverseOrder()).map(Path::toFile).forEachOrdered(File::delete); + LOG.fine("Sources deleted."); + } + + protected void compile(Blackhole bh, final Stage stopAt) throws IOException { + final OutputStream bhos = new OutputStream() { + @Override + public void write(int b) throws IOException { + bh.consume(b); + } + @Override + public void write(byte[] b, int off, int len) throws IOException { + bh.consume(b); + } + }; + final Context ctx = new Context(); + //inject JavaCompiler wrapping all measured methods so they directly report to the benchmark + ctx.put(JavaCompiler.compilerKey, (Factory)(c) -> { + return new JavaCompiler(c) { + @Override + public List parseFiles(Iterable fileObjects) { + Stage.Init.notifyDone(); + return stopAt.isAfter(Stage.Init) ? super.parseFiles(fileObjects) : List.nil(); + } + + @Override + public List initModules(List roots) { + Stage.Parse.notifyDone(); + return stopAt.isAfter(Stage.Parse) ? super.initModules(roots) : List.nil(); + } + + @Override + public List enterTrees(List roots) { + Stage.InitModules.notifyDone(); + return stopAt.isAfter(Stage.InitModules) ? super.enterTrees(roots) : List.nil(); + } + + @Override + public Queue> attribute(Queue> envs) { + Stage.Enter.notifyDone(); + return stopAt.isAfter(Stage.Enter) ? super.attribute(envs) : new ListBuffer<>(); + } + + @Override + public Queue> flow(Queue> envs) { + Stage.Attribute.notifyDone(); + return stopAt.isAfter(Stage.Attribute) ? super.flow(envs) : new ListBuffer<>(); + } + + @Override + public Queue, JCTree.JCClassDecl>> desugar(Queue> envs) { + Stage.Flow.notifyDone(); + return stopAt.isAfter(Stage.Flow) ? super.desugar(envs) : new ListBuffer<>(); + } + + @Override + public void generate(Queue, JCTree.JCClassDecl>> queue) { + Stage.Desugar.notifyDone(); + if (stopAt.isAfter(Stage.Desugar)) super.generate(queue); + } + }; + }); + //JavaFileManager directing all writes to a Blackhole to avoid measurement fluctuations due to delayed filesystem writes + try (JavacFileManager mngr = new JavacFileManager(ctx, true, null) { + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location arg0, String arg1, JavaFileObject.Kind arg2, FileObject arg3) throws IOException { + return new ForwardingJavaFileObject(super.getJavaFileForOutput(arg0, arg1, arg2, arg3)) { + @Override + public OutputStream openOutputStream() throws IOException { + return bhos; + } + }; + } + }) { + String[] cmdLine = new String[] {"-XDcompilePolicy=simple", "-implicit:none", "-nowarn", "--module-source-path", root.toString(), "-d", root.toString(), "-XDignore.symbol.file=true", "@" + srcList.toString()}; + if (new Main("javac").compile(cmdLine, ctx).exitCode != 0) { + throw new IOException("compilation failed"); + } + } + LOG.fine("Compilation finished."); + } +} diff --git a/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/SingleJavacBenchmark.java b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/SingleJavacBenchmark.java new file mode 100644 index 0000000000000..2cc5c1a7c83eb --- /dev/null +++ b/test/benchmarks/micros-javac/src/main/java/org/openjdk/bench/langtools/javac/SingleJavacBenchmark.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020, 2021, Oracle and/or its affiliates. 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.bench.langtools.javac; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +public class SingleJavacBenchmark extends JavacBenchmark { + + @Param + public Stage stopStage; + + @Benchmark + @Threads(1) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = 0) + @Measurement(iterations = 1) + @Fork(warmups = 1, value = 15, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void compileCold(Blackhole bh) throws IOException { + compile(bh, stopStage); + } + + @Benchmark + @Threads(1) + @BenchmarkMode(Mode.SingleShotTime) + @Warmup(iterations = 8) + @Measurement(iterations = 10) + @Fork(warmups = 0, value = 1, jvmArgsPrepend = { "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" }) + @OutputTimeUnit(TimeUnit.SECONDS) + public void compileHot(Blackhole bh) throws IOException { + compile(bh, stopStage); + } +}