FULL PRODUCT VERSION : java version "1.8.0_161" Java(TM) SE Runtime Environment (build 1.8.0_161-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode) FULL OS VERSION : Windows 7 x64 (Microsoft Windows [Version 6.1.7601]) EXTRA RELEVANT SYSTEM CONFIGURATION : CPU: Intel Core i7-4710MQ @ 2.50GHz, Laptop: Lenovo ThinkPad T440p. A DESCRIPTION OF THE PROBLEM : The scalar replacement optimization produces for two almost identical classes different code with different performance (up to 3 times). One class has final fields, but the second one doesn't. It seems to be a bug in JRE 1.8.0, because the same benchmark works with no performance difference on JRE 9.0.4. THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: No THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Touch this gist https://gist.github.com/gnkoshelev/97bdff9a645197a3903a3e43eaab72a7 - simple benchmark demonstrates strange performance results. I've run JMH benchmarks without any specific options: java -jar benchmarks.jar EXPECTED VERSUS ACTUAL BEHAVIOR : Both benchmarks should provide the same results on JRE 1.8.0 as on JRE 9.0.4. REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- package ru.gnkoshelev.performance.tests; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OperationsPerInvocation; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; /** * Created by kgn on 20.03.2018. */ @Fork(value = 1, warmups = 0) @Warmup(iterations = 5, time = 1_000, timeUnit = TimeUnit.MILLISECONDS) @Measurement(iterations = 10, time = 1_000, timeUnit = TimeUnit.MILLISECONDS) @OutputTimeUnit(value = TimeUnit.NANOSECONDS) @BenchmarkMode(Mode.AverageTime) @State(Scope.Benchmark) public class FinalOrNotFinalBenchmark { private double x1, y1, z1; private double x2, y2, z2; @Setup(value = Level.Iteration) public void setup() { x1 = 123.4; y1 = 234.5; z1 = 345.6; x2 = 456.7; y2 = 567.8; z2 = 678.9; } @Benchmark @OperationsPerInvocation(10_000) public void computeWithFinalsBenchmark(Blackhole bh) { double sum = 0; for (int i = 0; i < 10_000; i++) { sum += computeWithFinals(x1, y1, z1, x2, y2, z2); } bh.consume(sum); } @Benchmark @OperationsPerInvocation(10_000) public void computeWithNonFinalsBenchmark(Blackhole bh) { double sum = 0; for (int i = 0; i < 10_000; i++) { sum += computeWithNonFinals(x1, y1, z1, x2, y2, z2); } bh.consume(sum); } public static double computeWithFinals( double x1, double y1, double z1, double x2, double y2, double z2) { FinalVector v1 = new FinalVector(x1, y1, z1); FinalVector v2 = new FinalVector(x2, y2, z2); return v1.crossProduct(v2).squared(); } public static double computeWithNonFinals( double x1, double y1, double z1, double x2, double y2, double z2) { NonFinalVector v1 = new NonFinalVector(x1, y1, z1); NonFinalVector v2 = new NonFinalVector(x2, y2, z2); return v1.crossProduct(v2).squared(); } public final static class FinalVector { private final double x, y, z; public FinalVector(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public double squared() { return x * x + y * y + z * z; } public FinalVector crossProduct(FinalVector v) { return new FinalVector( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } } public final static class NonFinalVector { private double x, y, z; public NonFinalVector(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } public double squared() { return x * x + y * y + z * z; } public NonFinalVector crossProduct(NonFinalVector v) { return new NonFinalVector( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); } } } ---------- END SOURCE ----------
|