What is dead code?
Dead code is the one that never executed in run time.
DeadCodeEx.java
package com.sample.app;
public class DeadCodeEx {
public static void main(String[] args) {
final boolean b = true;
if(b) {
System.out.println("b is set to true");
}else {
System.out.println("b is set to false");
}
}
}
Notice above code snippet, the code is else block will never get executed, this is an example of dead code.
Now a days compilers are smart enough to identify and delete the dead code. If the eliminated part was our benchmarked code, then we will get wrong benchmarking results.
Let me explain it with an example.
DeadcodeEliminationDemo.java
package com.sample.app;
import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
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.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
@State(Scope.Thread)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class DeadcodeEliminationDemo {
private double fib(int n) {
if (n <= 1) {
return n;
}
int fib = 1;
int prevFib = 1;
for (int i = 2; i < n; i++) {
int temp = fib;
fib += prevFib;
prevFib = temp;
}
return fib;
}
@Benchmark
public void baseline() {
// do nothing
}
@Benchmark
public void measureWrong() {
fib(20);
}
@Benchmark
public double measureRight() {
// Here result is returned to the calling function.
return fib(20);
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(DeadcodeEliminationDemo.class.getSimpleName()).forks(1)
.measurementIterations(2).warmupIterations(2).build();
new Runner(opt).run();
}
}
When I ran the application, I got below benchmark results.
Benchmark Mode Cnt Score Error Units DeadcodeEliminationDemo.baseline avgt 2 0.398 ns/op DeadcodeEliminationDemo.measureRight avgt 2 2.398 ns/op DeadcodeEliminationDemo.measureWrong avgt 2 0.570 ns/op
Even though both ‘measureWrong’ and ‘measureRight’ methods calling fib(20) internally, measureWrong method took 0.57 nano seconds per operation, where as measureRight took 2.398 nano seconds per operation.
Why measureWrong taking very less time as compared to measureRight?
As you see the definition of ‘measureWrong’ method, it is not using the result of fib(20) anywhere, so compiler treat this as dead code and eliminate it.
public void measureWrong() {
fib(20);
}
Be cautious, while measuring the benchmark with these kind of scenarios.
There are two approaches to handle this scenario.
Approach 1: Just return the created data.
public void measureWrong() {
return fib(20);
}
Approach 2: Let the Blackhole consume the data.
@Benchmark
public void measureWrong(Blackhole blackhole) {
blackhole.consume(fib(20));
}
Previous Next Home
No comments:
Post a Comment