JMH Java Forward loop vs Reverse loop
By:Roy.LiuLast updated:2019-08-11
A JMH benchmark test about Forward loop vs Reverse loop for a List. There is a myth about reverse loop is faster, is this true?
Tested with
- JMH 1.21
- Java 10
- Maven 3.6
- CPU i7-7700
Forward loop
for (int i = 0; i < aList.size(); i++) { String s = aList.get(i); System.out.println(s);
Reverse loop
for (int i = aList.size() - 1; i >= 0; i--) { String s = aList.get(i); System.out.println(s);
1. Forward loop vs Reverse loop
Loop a List containing 1 million and 10 million String objects.
BenchmarkForwardReverseLoop.java
package com.mkyong.benchmark; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.infra.Blackhole; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Fork(value = 1, jvmArgs = {"-Xms2G", "-Xmx2G"}) @Warmup(iterations = 5) @Measurement(iterations = 10) @State(Scope.Benchmark) public class BenchmarkForwardReverseLoop { @Param({"1000000", "10000000"}) private int N; private List<String> DATA_FOR_TESTING = createData(); public static void main(String[] argv) throws RunnerException { Options opt = new OptionsBuilder() .include(BenchmarkForwardReverseLoop.class.getSimpleName()) .forks(1) .build(); new Runner(opt).run(); @Setup public void setup() { DATA_FOR_TESTING = createData(); @Benchmark public void forwardLoop(Blackhole bh) { for (int i = 0; i < DATA_FOR_TESTING.size(); i++) { String s = DATA_FOR_TESTING.get(i); bh.consume(s); @Benchmark public void reverseLoop(Blackhole bh) { for (int i = DATA_FOR_TESTING.size() - 1; i >= 0; i--) { String s = DATA_FOR_TESTING.get(i); bh.consume(s); private List<String> createData() { List<String> data = new ArrayList<>(); for (int i = 0; i < N; i++) { data.add("Number : " + i); return data;
2. Result
$ java -jar target\benchmarks.jar BenchmarkForwardReverseLoop # JMH version: 1.21 # VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10 # VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe # VM options: -Xms2G -Xmx2G # Warmup: 5 iterations, 10 s each # Measurement: 10 iterations, 10 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop # Parameters: (N = 1000000) # Run progress: 0.00% complete, ETA 00:10:00 # Fork: 1 of 1 # Warmup Iteration 1: 5.333 ms/op # Warmup Iteration 2: 5.300 ms/op # Warmup Iteration 3: 5.210 ms/op # Warmup Iteration 4: 5.241 ms/op # Warmup Iteration 5: 5.236 ms/op Iteration 1: 5.127 ms/op Iteration 2: 5.089 ms/op Iteration 3: 5.110 ms/op Iteration 4: 5.148 ms/op Iteration 5: 5.233 ms/op Iteration 6: 5.156 ms/op Iteration 7: 5.160 ms/op Iteration 8: 5.605 ms/op Iteration 9: 5.169 ms/op Iteration 10: 5.130 ms/op Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop": 5.193 ±(99.9%) 0.227 ms/op [Average] (min, avg, max) = (5.089, 5.193, 5.605), stdev = 0.150 CI (99.9%): [4.966, 5.419] (assumes normal distribution) # JMH version: 1.21 # VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10 # VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe # VM options: -Xms2G -Xmx2G # Warmup: 5 iterations, 10 s each # Measurement: 10 iterations, 10 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop # Parameters: (N = 10000000) # Run progress: 25.00% complete, ETA 00:07:31 # Fork: 1 of 1 # Warmup Iteration 1: 61.361 ms/op # Warmup Iteration 2: 61.189 ms/op # Warmup Iteration 3: 61.570 ms/op # Warmup Iteration 4: 61.662 ms/op # Warmup Iteration 5: 61.604 ms/op Iteration 1: 61.010 ms/op Iteration 2: 61.066 ms/op Iteration 3: 62.129 ms/op Iteration 4: 61.854 ms/op Iteration 5: 61.248 ms/op Iteration 6: 61.104 ms/op Iteration 7: 64.452 ms/op Iteration 8: 62.398 ms/op Iteration 9: 62.766 ms/op Iteration 10: 66.125 ms/op Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop": 62.415 ±(99.9%) 2.535 ms/op [Average] (min, avg, max) = (61.010, 62.415, 66.125), stdev = 1.677 CI (99.9%): [59.880, 64.950] (assumes normal distribution) # JMH version: 1.21 # VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10 # VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe # VM options: -Xms2G -Xmx2G # Warmup: 5 iterations, 10 s each # Measurement: 10 iterations, 10 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop # Parameters: (N = 1000000) # Run progress: 50.00% complete, ETA 00:05:02 # Fork: 1 of 1 # Warmup Iteration 1: 6.220 ms/op # Warmup Iteration 2: 5.861 ms/op # Warmup Iteration 3: 5.955 ms/op # Warmup Iteration 4: 5.919 ms/op # Warmup Iteration 5: 6.142 ms/op Iteration 1: 5.840 ms/op Iteration 2: 5.864 ms/op Iteration 3: 5.892 ms/op Iteration 4: 6.212 ms/op Iteration 5: 5.911 ms/op Iteration 6: 5.906 ms/op Iteration 7: 6.055 ms/op Iteration 8: 6.210 ms/op Iteration 9: 6.095 ms/op Iteration 10: 5.821 ms/op Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop": 5.980 ±(99.9%) 0.227 ms/op [Average] (min, avg, max) = (5.821, 5.980, 6.212), stdev = 0.150 CI (99.9%): [5.754, 6.207] (assumes normal distribution) # JMH version: 1.21 # VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10 # VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe # VM options: -Xms2G -Xmx2G # Warmup: 5 iterations, 10 s each # Measurement: 10 iterations, 10 s each # Timeout: 10 min per iteration # Threads: 1 thread, will synchronize iterations # Benchmark mode: Average time, time/op # Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop # Parameters: (N = 10000000) # Run progress: 75.00% complete, ETA 00:02:30 # Fork: 1 of 1 # Warmup Iteration 1: 55.012 ms/op # Warmup Iteration 2: 54.479 ms/op # Warmup Iteration 3: 54.497 ms/op # Warmup Iteration 4: 54.677 ms/op # Warmup Iteration 5: 54.287 ms/op Iteration 1: 54.361 ms/op Iteration 2: 54.432 ms/op Iteration 3: 54.367 ms/op Iteration 4: 54.518 ms/op Iteration 5: 54.497 ms/op Iteration 6: 54.369 ms/op Iteration 7: 54.698 ms/op Iteration 8: 54.393 ms/op Iteration 9: 54.377 ms/op Iteration 10: 54.675 ms/op Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop": 54.469 ±(99.9%) 0.193 ms/op [Average] (min, avg, max) = (54.361, 54.469, 54.698), stdev = 0.127 CI (99.9%): [54.276, 54.661] (assumes normal distribution) # Run complete. Total time: 00:10:04 REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial experiments, perform baseline and negative tests that provide experimental control, make sure the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts. Do not assume the numbers tell you what you want them to tell. Benchmark (N) Mode Cnt Score Error Units BenchmarkForwardReverseLoop.forwardLoop 1000000 avgt 10 5.193 ± 0.227 ms/op BenchmarkForwardReverseLoop.forwardLoop 10000000 avgt 10 62.415 ± 2.535 ms/op BenchmarkForwardReverseLoop.reverseLoop 1000000 avgt 10 5.980 ± 0.227 ms/op BenchmarkForwardReverseLoop.reverseLoop 10000000 avgt 10 54.469 ± 0.193 ms/op
Result : The normal forward loop is faster in the 1 million loops, but for 10 million loops, the reverse loop is faster. However, the difference isn't that significant.
References
- Java - Reverse loop versus Forward loop
- Java JMH Benchmark Tutorial
- Why reverse loops are not faster
From:一号门
COMMENTS