Experiments with Graal

This chapter details the list of experiments done to use Graal compiler instead of C2 compiler in JVM to compile Java bytecode.

  • Compiling Graal

Using Graal compiler

(15Nov'16)

Execution of a program WITHOUT using Graal compiler

To experiment with Graal compiler we will use a simple Java code first.

public class GraalTest {
    private int count;

    private void callFun(int i){
        int a = 3;
        count = count + i % 7;
    }

    public void runBench(){
        for(int i=0; i< 255; i++){
            callFun(10);
        }
     }

    public static void main(String[] args) {
        GraalTest obj = new GraalTest();
                for(int i=0; i< Integer.parseInt(args[0]); i++){
          obj.runBench();
                }
        System.out.println("HEELO");
    }
}
  • An execution of the Java code without using Graal compiler. By adding -XX:+PrintCompilation we are printing the compilation information. It prints all the methods getting compiled including the java standard library methods e.g. java.lang.Integer::parseInt etc. Therefore we are just printing compiled methods from GraalTest class.

java -XX:+PrintCompilation GraalTest 10000000 |grep GraalTest

It prints the following compilation information.

     95   14       3       GraalTest::callFun (16 bytes)
     95   15       4       GraalTest::callFun (16 bytes)
     96   14       3       GraalTest::callFun (16 bytes)   made not entrant
     97   21       3       GraalTest::runBench (22 bytes)
     98   24 %     4       GraalTest::runBench @ 2 (22 bytes)
    101   30       4       GraalTest::runBench (22 bytes)
    103   21       3       GraalTest::runBench (22 bytes)   made not entrant
    116   33 %     3       GraalTest::main @ 10 (39 bytes)
    117   34       3       GraalTest::main (39 bytes)
    119   35 %     4       GraalTest::main @ 10 (39 bytes)
    132   33 %     3       GraalTest::main @ -2 (39 bytes)   made not entrant
    644   35 %     4       GraalTest::main @ -2 (39 bytes)   made not entrant

Here 3rd column prints a compilation level with 4 as the highest while % symbol represents On Stack Replace (OSR). More information about PrintCompilation flag output could be found here.

  • In above example we are not sure which compiler is getting used for different levels of compilation. To see the compiler information we can use -XX:CompileCommand=print,*GraalTest.* command which will print the assembly code of methods getting compiled as well as the compiler name used for compiling a method. We will use grep to print the line containing compiler name.
$ java '-XX:CompileCommand=print,*GraalTest.*'  GraalTest 1000000 |grep 'Compiled method'

Java HotSpot(TM) 64-Bit Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
Compiled method (c1)     102   14       3       GraalTest::callFun (16 bytes)
Compiled method (c2)     105   17       4       GraalTest::callFun (16 bytes)
Compiled method (c1)     106   21       3       GraalTest::runBench (22 bytes)
Compiled method (c2)     114   24 %     4       GraalTest::runBench @ 2 (22 bytes)
Compiled method (c2)     119   30       4       GraalTest::runBench (22 bytes)
Compiled method (c1)     132   32 %     3       GraalTest::main @ 10 (39 bytes)
Compiled method (c1)     143   33       3       GraalTest::main (39 bytes)
Compiled method (c2)     161   34 %     4       GraalTest::main @ 10 (39 bytes)

In above output the name of compiler (C1 or C2) can be seen.

Execution of a program using Graal compiler

To use graal compiler we need to,

  • use graal.jar file built from graal-core project (first step).
  • use flag -XX:+UseJVMCICompiler to use JVMCI enabled compiler
$ java -Djvmci.class.path.append=/home/sgaikwad/sandbox/graal/graal.jar \
-XX:+UseJVMCICompiler  \
'-XX:CompileCommand=print,*GraalTest.*'  \
GraalTest 1000000 |grep 'Compiled '

Java HotSpot(TM) 64-Bit Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
Compiled method (c1)      72   13       3       GraalTest::callFun (16 bytes)
Compiled method (c1)      76   20       3       GraalTest::runBench (22 bytes)
Compiled method (c1)     208  217 %     3       GraalTest::main @ 10 (39 bytes)
Compiled method (c1)     222  219       3       GraalTest::main (39 bytes)
Compiled method (JVMCI)     898   16       4       GraalTest::callFun (16 bytes)
Compiled method (JVMCI)     922   24 %     4       GraalTest::runBench @ 2 (22 bytes)
Compiled method (JVMCI)    1369 1386       4       GraalTest::runBench (22 bytes)
Compiled method (JVMCI)    1467  904 %     4       GraalTest::main @ 10 (39 bytes)
  • As mentioned in JEP 243 for adding JVMCI, one can provide name of the JVMCI enabled compiler using a flag e.g. for graal compiler -Djvmci.Compiler=graal. However, it is important to note that incorrect name of the compiler will throw an exception when it triggers Tier 4 compilation.
$ java -Djvmci.class.path.append=/home/sgaikwad/sandbox/graal/graal.jar \
-XX:+UseJVMCICompiler  \
-Djvmci.Compiler=grall \
'-XX:CompileCommand=print,*GraalTest.*'  \
GraalTest 1000000

Java HotSpot(TM) 64-Bit Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
.
---skipped output----
.
Compiled method (c1)     110   14       3       GraalTest::callFun (16 bytes)
Compiled method (c1)     115   21       3       GraalTest::runBench (22 bytes)
---skipped output----
Uncaught exception at /scratch/graaluser/buildslave/buildlog/ci_executor/main/graal-jvmci-8/src/share/vm/jvmci/jvmciCompiler.cpp:127
jdk.vm.ci.common.JVMCIError: JVMCI compiler 'grall' not found
    at jdk.vm.ci.hotspot.HotSpotJVMCICompilerConfig.getCompilerFactory(HotSpotJVMCICompilerConfig.java:82)
    at jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.<init>(HotSpotJVMCIRuntime.java:281)
    at jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.<init>(HotSpotJVMCIRuntime.java:65)
    at jdk.vm.ci.hotspot.HotSpotJVMCIRuntime$DelayedInit.<clinit>(HotSpotJVMCIRuntime.java:73)
    at jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime(HotSpotJVMCIRuntime.java:83)
    at jdk.vm.ci.runtime.JVMCI.initializeRuntime(Native Method)
    at jdk.vm.ci.runtime.JVMCI.<clinit>(JVMCI.java:58)

$

Using only Graal compiler for bytecode compilation

  • Graal compiler is used when Tier 4 compilation is requested by the JVM (Graal compiler is available along with necessary flags to use it).
  • We can force JVM to use only Graal compiler by disabling the Tiered compilation mode of the JVM. Ofcouse, it impacts the overall execution time, especially the startup time.
  • Tiered compilation is disabled using flag -XX:-TieredCompilation.
$ java -Djvmci.class.path.append=/home/sgaikwad/sandbox/graal/graal.jar \
-XX:+UseJVMCICompiler  \
'-XX:CompileCommand=print,*GraalTest.*' \
-XX:-TieredCompilation \
GraalTest 1000000|grep 'Compiled '

Java HotSpot(TM) 64-Bit Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
Compiled method (JVMCI)    2389    2             GraalTest::runBench (22 bytes)
Compiled method (JVMCI)    2390    1             GraalTest::callFun (16 bytes)
$

Resources

[1] Document about 'Printcompilation' flag: https://gist.github.com/rednaxelafx/1165804

results matching ""

    No results matching ""