Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does dead code elimination of Math.log() work in JMH sample

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:

  1. returning 42
  2. parameter addition
  3. 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.
like image 914
mwa Avatar asked Jul 31 '15 16:07

mwa


People also ask

What is JMH in Java?

JMH is short for Java Microbenchmark Harness. JMH is a toolkit that helps you implement Java microbenchmarks correctly. JMH is developed by the same people who implement the Java virtual machine, so these guys know what they are doing.

Does Java do dead code elimination?

Eclipse compiler for Java (ECJ) is open source incremented compiler. We reform features of ECJ, related to optimization technique called as dead code detection and elimination. ECJ identifies the dead code. We are extending this compiler to eliminate the dead code.

How do you run JMH benchmarks?

There are two ways to run the JMH benchmark, uses Maven or run it via a JMH Runner class directly. 3.1 Maven, package it as a JAR and run it via org. openjdk.

What is JMH fork?

org.openjdk.jmh.annotations Fork annotation allows to set the default forking parameters for the benchmark. This annotation may be put at Benchmark method to have effect on that method only, or at the enclosing class instance to have the effect over all Benchmark methods in the class.


1 Answers

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?

Native calls don't go to the OS, they go to a native library via JNI. That may end up going to the OS, or it may go into some user provided lib. In the case of native methods in the JDK we can also expect some native calls to be compiled as intrinsics.

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.

The JVM does not look into arbitrary native calls to determine what sort of side effects they may or may not have. This means native calls are indeed made as method calls (on the assembly level, you jump into foriegn code somewhere, another frame on the stack etc.). This also means that the JVM cannot eliminate them or their dependant inputs.

Native calls cannot be optimized out, meaning that Math.log() and custom native calls do not have the same basis.

Yes.

Are there any relations between the Natives and Intrinsics?

Some native JDK methods are intrinsics. But normal JDK methods can be intrinsics too. The set of intrinsic methods is also different from one JVM to the next.

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?

The Math.log function is transformed into a special node in the C2 compiler IR (intermediate representation). This node can be optimized away because it is known to have no side effects and it's value is never used. If the value is used the JVM knows to emit specialized machine code for this node.

In summary: Intrinsics are optimized method replacements built into the JVM compiler. They can be used to replace any method (native or otherwise) with:

  1. Specialized assembly code
  2. Specialized IR code
  3. An internal JVM method call
  4. A combination of the above
like image 125
Nitsan Wakart Avatar answered Oct 03 '22 16:10

Nitsan Wakart