Everyone who tries to utilize JMH framework to create some meaningful tests will come across JMH sample tests (http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/). As we went through them we stucked by the dead code elemination (JMHSample_08_DeadCode.java).
Excerpt:
private double x = Math.PI;
@Benchmark
public void baseline() {
// do nothing, this is a baseline
}
@Benchmark
public void measureWrong() {
// This is wrong: result is not used, and the entire computation is optimized out.
Math.log(x);
}
The measurement of measureWrong() will be approximately the same as for the baseline test. Because the return value of the Math.log() is never used. Therefore the HotSpot compiler will eliminate the dead code. Ok, understood but how can the compiler decide that Math.log() can be eliminated.
As we looked closely to the test we note that Math.log() is a native method. And native calls go down to the OS and execute a corresponding lib. Right? This lead us to the assumption that native calls could be eliminated by the compiler if their return value is not used and they don't perform io operations.
We wonder what if the lib which resides somewhere in the OS and which handles the native calls from the java world provides no return value but does io operations (e.g. logging). Will those instructions completely be wiped out?
To proof our assumption we reconstructed the scenario with a simple JMH test and a native call. We compiled three c-native libs to perform:
- returning 42
- parameter addition
- empty file creation
As we called them in a JMH test (similarly to measureWrong() test) none of them has been eliminated, not even the one which doesn't perform an io operation. Due to the test result our assumption cannot be confirmed. Native calls cannot be optimized out, meaning that Math.log() and custom native calls do not have the same basis. They are not equaly native. Maybe we made a mistake in our native lib code and at least the native call of test 1 should have been eleminated. If this is true we will share our code with you.
So we searched further and found a term Intrinsics where java code will be replaced with a corresponding to the architecture very optimized code. java.lang.Math.log() is having such intrinsic implementation. Are there any relations between the Natives and Intrinsics? If the above assumption of the relationship between Natives and Intrinsics is valid will the compiler perform the following steps to eliminate the native call?
- At the compile time the HotSpot checks the existence of the intrinsic implementation (in jdk?) for the Math.log() and replaces Math.log() with that code.
- Afterwards the second check happens where HotSpot looks after the return value of a method. And on this outcome the HotSpot decides to eliminate the Math.log() call completely.