diff --git a/jmh/build.gradle b/jmh/build.gradle index dab4c25883..edc2679494 100644 --- a/jmh/build.gradle +++ b/jmh/build.gradle @@ -125,6 +125,7 @@ jmh { // for more examples see https://github.com/melix/jmh-gradle-plugin/blob/master/README.adoc#configuration-options // iterations = 5 // fork = 5 + // includes = ['DFlowMicro'] } // don't run test task on pre-JDK-11 VMs diff --git a/jmh/src/jmh/java/com/uber/nullaway/jmh/DFlowMicroBenchmark.java b/jmh/src/jmh/java/com/uber/nullaway/jmh/DFlowMicroBenchmark.java new file mode 100644 index 0000000000..fa45073261 --- /dev/null +++ b/jmh/src/jmh/java/com/uber/nullaway/jmh/DFlowMicroBenchmark.java @@ -0,0 +1,24 @@ +package com.uber.nullaway.jmh; + +import java.io.IOException; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; + +@State(Scope.Benchmark) +public class DFlowMicroBenchmark { + + private DataFlowMicroBenchmarkCompiler compiler; + + @Setup + public void setup() throws IOException { + compiler = new DataFlowMicroBenchmarkCompiler(); + } + + @Benchmark + public void compile(Blackhole bh) { + bh.consume(compiler.compile()); + } +} diff --git a/jmh/src/main/java/com/uber/nullaway/jmh/DataFlowMicroBenchmarkCompiler.java b/jmh/src/main/java/com/uber/nullaway/jmh/DataFlowMicroBenchmarkCompiler.java new file mode 100644 index 0000000000..ef0f1c3350 --- /dev/null +++ b/jmh/src/main/java/com/uber/nullaway/jmh/DataFlowMicroBenchmarkCompiler.java @@ -0,0 +1,47 @@ +package com.uber.nullaway.jmh; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +public class DataFlowMicroBenchmarkCompiler { + + private final NullawayJavac nullawayJavac; + + public DataFlowMicroBenchmarkCompiler() throws IOException { + nullawayJavac = NullawayJavac.createFromSourceString("DFlowBench", SOURCE, "com.uber"); + } + + public boolean compile() { + return nullawayJavac.compile(); + } + + private static final String SOURCE; + + static { + // For larger benchmarks, we pass file paths to NullawayJavac, based on JVM properties computed + // in build.gradle. Here, to avoid creating and passing yet another JVM property, we just store + // the benchmark source code in a resource file and then load it eagerly into a String via the + // classloader + ClassLoader classLoader = DataFlowMicroBenchmarkCompiler.class.getClassLoader(); + try (InputStream inputStream = classLoader.getResourceAsStream("DFlowBench.java")) { + SOURCE = readFromInputStream(inputStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static String readFromInputStream(InputStream inputStream) throws IOException { + StringBuilder result = new StringBuilder(); + try (BufferedReader br = + new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + result.append(line).append("\n"); + } + } + return result.toString(); + } +} diff --git a/jmh/src/main/java/com/uber/nullaway/jmh/NullawayJavac.java b/jmh/src/main/java/com/uber/nullaway/jmh/NullawayJavac.java index 7baca48ff8..1d094d8869 100644 --- a/jmh/src/main/java/com/uber/nullaway/jmh/NullawayJavac.java +++ b/jmh/src/main/java/com/uber/nullaway/jmh/NullawayJavac.java @@ -118,6 +118,26 @@ public static NullawayJavac create( compilationUnits, annotatedPackages, classpath, extraErrorProneArgs, extraProcessorPath); } + /** + * Create a NullawayJavac object to compile a single source file given as a String. This only + * supports cases where no additional classpath, Error Prone arguments, or processor path + * arguments need to be specified. + * + * @param className name of the class to compile + * @param source source code of the class to compile + * @param annotatedPackages argument to pass for "-XepOpt:NullAway:AnnotatedPackages" option + * @throws IOException if a temporary output directory cannot be created + */ + public static NullawayJavac createFromSourceString( + String className, String source, String annotatedPackages) throws IOException { + return new NullawayJavac( + Collections.singletonList(new JavaSourceFromString(className, source)), + annotatedPackages, + null, + Collections.emptyList(), + ""); + } + /** * Configures compilation with javac and NullAway. * diff --git a/jmh/src/main/resources/DFlowBench.java b/jmh/src/main/resources/DFlowBench.java new file mode 100644 index 0000000000..22c073a816 --- /dev/null +++ b/jmh/src/main/resources/DFlowBench.java @@ -0,0 +1,587 @@ +package com.uber.nullaway.testdata; + +import javax.annotation.Nullable; + +public final class DFlowBench { + @Nullable Object f; + + public static void test(boolean b) { + DFlowBench x0 = new DFlowBench(); + DFlowBench x1 = new DFlowBench(); + DFlowBench x2 = new DFlowBench(); + DFlowBench x3 = new DFlowBench(); + DFlowBench x4 = new DFlowBench(); + DFlowBench x5 = new DFlowBench(); + DFlowBench x6 = new DFlowBench(); + DFlowBench x7 = new DFlowBench(); + DFlowBench x8 = new DFlowBench(); + DFlowBench x9 = new DFlowBench(); + DFlowBench x10 = new DFlowBench(); + DFlowBench x11 = new DFlowBench(); + DFlowBench x12 = new DFlowBench(); + DFlowBench x13 = new DFlowBench(); + DFlowBench x14 = new DFlowBench(); + DFlowBench x15 = new DFlowBench(); + DFlowBench x16 = new DFlowBench(); + DFlowBench x17 = new DFlowBench(); + DFlowBench x18 = new DFlowBench(); + DFlowBench x19 = new DFlowBench(); + DFlowBench x20 = new DFlowBench(); + DFlowBench x21 = new DFlowBench(); + DFlowBench x22 = new DFlowBench(); + DFlowBench x23 = new DFlowBench(); + DFlowBench x24 = new DFlowBench(); + DFlowBench x25 = new DFlowBench(); + DFlowBench x26 = new DFlowBench(); + DFlowBench x27 = new DFlowBench(); + DFlowBench x28 = new DFlowBench(); + DFlowBench x29 = new DFlowBench(); + DFlowBench x30 = new DFlowBench(); + DFlowBench x31 = new DFlowBench(); + DFlowBench x32 = new DFlowBench(); + DFlowBench x33 = new DFlowBench(); + DFlowBench x34 = new DFlowBench(); + DFlowBench x35 = new DFlowBench(); + DFlowBench x36 = new DFlowBench(); + DFlowBench x37 = new DFlowBench(); + DFlowBench x38 = new DFlowBench(); + DFlowBench x39 = new DFlowBench(); + DFlowBench x40 = new DFlowBench(); + DFlowBench x41 = new DFlowBench(); + DFlowBench x42 = new DFlowBench(); + DFlowBench x43 = new DFlowBench(); + DFlowBench x44 = new DFlowBench(); + DFlowBench x45 = new DFlowBench(); + DFlowBench x46 = new DFlowBench(); + DFlowBench x47 = new DFlowBench(); + DFlowBench x48 = new DFlowBench(); + DFlowBench x49 = new DFlowBench(); + DFlowBench x50 = new DFlowBench(); + DFlowBench x51 = new DFlowBench(); + DFlowBench x52 = new DFlowBench(); + DFlowBench x53 = new DFlowBench(); + DFlowBench x54 = new DFlowBench(); + DFlowBench x55 = new DFlowBench(); + DFlowBench x56 = new DFlowBench(); + DFlowBench x57 = new DFlowBench(); + DFlowBench x58 = new DFlowBench(); + DFlowBench x59 = new DFlowBench(); + DFlowBench x60 = new DFlowBench(); + DFlowBench x61 = new DFlowBench(); + DFlowBench x62 = new DFlowBench(); + DFlowBench x63 = new DFlowBench(); + DFlowBench x64 = new DFlowBench(); + DFlowBench x65 = new DFlowBench(); + DFlowBench x66 = new DFlowBench(); + DFlowBench x67 = new DFlowBench(); + DFlowBench x68 = new DFlowBench(); + DFlowBench x69 = new DFlowBench(); + DFlowBench x70 = new DFlowBench(); + DFlowBench x71 = new DFlowBench(); + DFlowBench x72 = new DFlowBench(); + DFlowBench x73 = new DFlowBench(); + DFlowBench x74 = new DFlowBench(); + DFlowBench x75 = new DFlowBench(); + DFlowBench x76 = new DFlowBench(); + DFlowBench x77 = new DFlowBench(); + DFlowBench x78 = new DFlowBench(); + DFlowBench x79 = new DFlowBench(); + DFlowBench x80 = new DFlowBench(); + DFlowBench x81 = new DFlowBench(); + DFlowBench x82 = new DFlowBench(); + DFlowBench x83 = new DFlowBench(); + DFlowBench x84 = new DFlowBench(); + DFlowBench x85 = new DFlowBench(); + DFlowBench x86 = new DFlowBench(); + DFlowBench x87 = new DFlowBench(); + DFlowBench x88 = new DFlowBench(); + DFlowBench x89 = new DFlowBench(); + DFlowBench x90 = new DFlowBench(); + DFlowBench x91 = new DFlowBench(); + DFlowBench x92 = new DFlowBench(); + DFlowBench x93 = new DFlowBench(); + DFlowBench x94 = new DFlowBench(); + DFlowBench x95 = new DFlowBench(); + DFlowBench x96 = new DFlowBench(); + DFlowBench x97 = new DFlowBench(); + DFlowBench x98 = new DFlowBench(); + DFlowBench x99 = new DFlowBench(); + if (x0.f != null) { + x0.f.toString(); + if (x1.f != null) { + x1.f.toString(); + if (x2.f != null) { + x2.f.toString(); + if (x3.f != null) { + x3.f.toString(); + if (x4.f != null) { + x4.f.toString(); + if (x5.f != null) { + x5.f.toString(); + if (x6.f != null) { + x6.f.toString(); + if (x7.f != null) { + x7.f.toString(); + if (x8.f != null) { + x8.f.toString(); + if (x9.f != null) { + x9.f.toString(); + if (x10.f != null) { + x10.f.toString(); + if (x11.f != null) { + x11.f.toString(); + if (x12.f != null) { + x12.f.toString(); + if (x13.f != null) { + x13.f.toString(); + if (x14.f != null) { + x14.f.toString(); + if (x15.f != null) { + x15.f.toString(); + if (x16.f != null) { + x16.f.toString(); + if (x17.f != null) { + x17.f.toString(); + if (x18.f != null) { + x18.f.toString(); + if (x19.f != null) { + x19.f.toString(); + if (x20.f != null) { + x20.f.toString(); + if (x21.f != null) { + x21.f.toString(); + if (x22.f != null) { + x22.f.toString(); + if (x23.f != null) { + x23.f.toString(); + if (x24.f != null) { + x24.f.toString(); + if (x25.f != null) { + x25.f.toString(); + if (x26.f != null) { + x26.f.toString(); + if (x27.f != null) { + x27.f.toString(); + if (x28.f != null) { + x28.f.toString(); + if (x29.f != null) { + x29.f.toString(); + if (x30.f != null) { + x30.f.toString(); + if (x31.f != null) { + x31.f.toString(); + if (x32.f != null) { + x32.f.toString(); + if (x33.f != null) { + x33.f.toString(); + if (x34.f != null) { + x34.f.toString(); + if (x35.f != null) { + x35.f.toString(); + if (x36.f != null) { + x36.f.toString(); + if (x37.f != null) { + x37.f.toString(); + if (x38.f != null) { + x38.f.toString(); + if (x39.f + != null) { + x39.f + .toString(); + if (x40.f + != null) { + x40.f + .toString(); + if (x41.f + != null) { + x41.f + .toString(); + if (x42.f + != null) { + x42.f + .toString(); + if (x43.f + != null) { + x43.f + .toString(); + if (x44.f + != null) { + x44.f + .toString(); + if (x45.f + != null) { + x45 + .f + .toString(); + if (x46.f + != null) { + x46 + .f + .toString(); + if (x47.f + != null) { + x47 + .f + .toString(); + if (x48.f + != null) { + x48 + .f + .toString(); + if (x49.f + != null) { + x49 + .f + .toString(); + if (x50.f + != null) { + x50 + .f + .toString(); + if (x51.f + != null) { + x51 + .f + .toString(); + if (x52.f + != null) { + x52 + .f + .toString(); + if (x53.f + != null) { + x53 + .f + .toString(); + if (x54.f + != null) { + x54 + .f + .toString(); + if (x55.f + != null) { + x55 + .f + .toString(); + if (x56.f + != null) { + x56 + .f + .toString(); + if (x57.f + != null) { + x57 + .f + .toString(); + if (x58.f + != null) { + x58 + .f + .toString(); + if (x59.f + != null) { + x59 + .f + .toString(); + if (x60.f + != null) { + x60 + .f + .toString(); + if (x61.f + != null) { + x61 + .f + .toString(); + if (x62.f + != null) { + x62 + .f + .toString(); + if (x63.f + != null) { + x63 + .f + .toString(); + if (x64.f + != null) { + x64 + .f + .toString(); + if (x65.f + != null) { + x65 + .f + .toString(); + if (x66.f + != null) { + x66 + .f + .toString(); + if (x67.f + != null) { + x67 + .f + .toString(); + if (x68.f + != null) { + x68 + .f + .toString(); + if (x69.f + != null) { + x69 + .f + .toString(); + if (x70.f + != null) { + x70 + .f + .toString(); + if (x71.f + != null) { + x71 + .f + .toString(); + if (x72.f + != null) { + x72 + .f + .toString(); + if (x73.f + != null) { + x73 + .f + .toString(); + if (x74.f + != null) { + x74 + .f + .toString(); + if (x75.f + != null) { + x75 + .f + .toString(); + if (x76.f + != null) { + x76 + .f + .toString(); + if (x77.f + != null) { + x77 + .f + .toString(); + if (x78.f + != null) { + x78 + .f + .toString(); + if (x79.f + != null) { + x79 + .f + .toString(); + if (x80.f + != null) { + x80 + .f + .toString(); + if (x81.f + != null) { + x81 + .f + .toString(); + if (x82.f + != null) { + x82 + .f + .toString(); + if (x83.f + != null) { + x83 + .f + .toString(); + if (x84.f + != null) { + x84 + .f + .toString(); + if (x85.f + != null) { + x85 + .f + .toString(); + if (x86.f + != null) { + x86 + .f + .toString(); + if (x87.f + != null) { + x87 + .f + .toString(); + if (x88.f + != null) { + x88 + .f + .toString(); + if (x89.f + != null) { + x89 + .f + .toString(); + if (x90.f + != null) { + x90 + .f + .toString(); + if (x91.f + != null) { + x91 + .f + .toString(); + if (x92.f + != null) { + x92 + .f + .toString(); + if (x93.f + != null) { + x93 + .f + .toString(); + if (x94.f + != null) { + x94 + .f + .toString(); + if (x95.f + != null) { + x95 + .f + .toString(); + if (x96.f + != null) { + x96 + .f + .toString(); + if (x97.f + != null) { + x97 + .f + .toString(); + if (x98.f + != null) { + x98 + .f + .toString(); + if (x99.f + != null) { + x99 + .f + .toString(); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java b/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java index 264ebe53f3..d9adff9e46 100644 --- a/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java +++ b/jmh/src/test/java/com/uber/nullaway/jmh/BenchmarkCompilationTest.java @@ -22,4 +22,9 @@ public void testCaffeine() throws IOException { public void testNullawayRelease() throws IOException { assertTrue(new NullawayReleaseCompiler().compile()); } + + @Test + public void testDFlowMicro() throws IOException { + assertTrue(new DataFlowMicroBenchmarkCompiler().compile()); + } }