- Running JVM-based Apps
- Compiler Configuration on JVM
- Setting Compiler Options with Language Launchers
- JVM Operations Manual
- Measuring Performance
- Troubleshooting the GraalVM Compiler
GraalVM gives you an enhanced performance for JVM-based applications writtenin languages such as Java, Scala, Groovy, Clojure or Kotlin. It uses a dynamiccompiler that dramatically improves the efficiency and the speed of applicationsthrough unique approaches to code analysis and optimization.
In addition to running JVM-based languages, you can also call any other languageimplemented with GraalVM Language Implementation Framework directly from Java.See the Polyglot Reference and theEmbedding documentationfor more information about interoperability with other programming languages.
The GraalVM compiler achieves excellent performance for modern workloadssuch as Scala or usage of the Java Streams API. For examples, see theJava performance examples.
There are two operating modes of the GraalVM compiler when used as a HotSpot JIT compiler:
libgraal: the GraalVM compiler is compiled ahead of time into a native shared library. In this operating mode, the shared library is loaded by the HotSpot VM. The compiler uses memory separate from the HotSpot heap and it runs fast from the start since it does not need to warm-up. This is the default and recommended mode of operation.
jargraal: the GraalVM compiler goes through the same warm-up phase that the rest of Java application does. That is, it is first interpreted before its hot methods are compiled. This mode is selected with the
-XX:-UseJVMCINativeLibrarycommand line option. This will delay the time to reach peak performance as the compileritself needs to be compiled before it produces code quickly. This mode allows you todebug the GraalVM compiler with a Java debugger.
The options for configuring the GraalVM compiler on the JVM are in 3 categories.
These are general options for setting/getting configuration details.
-XX:-UseJVMCICompiler: This disables use of the GraalVM compiler as the top tier JIT.This is useful when wanting to compare performance of the GraalVM compiler against the native JIT compilers.
-Dgraal.CompilerConfiguration=<name>: Selects the GraalVM compiler configuration to use. If omitted, the compilerconfiguration with the highest auto-selection priority is used. To see the setof available configurations, supply the value help to this option.
The current configurations and their semantics are:
enterprise: To produce highly optimized code with a possible trade-off to compilation time.This value is only available in GraalVM EE.
community: To produce reasonably optimized code with a faster compilation time.
economy: To compile as fast as possible with less optimal throughput of the generated code.
-Dgraal.ShowConfiguration=none: Prints information about the GraalVM compiler configuration selected. This option only produces output when the compiler is initialized. By default, the GraalVM compiler is initialized on the first top-tier compilation. For this reason, the way to use this option is as follows:
java -XX:+EagerJVMCI -Dgraal.ShowConfiguration=info -version.
The accepted values for this option are:
none: To show no information.
info: To print one line of output showing the name of the compiler configuration in use and the location it is loaded from.
verbose: To print detailed compiler configuration information.
-Dgraal.MitigateSpeculativeExecutionAttacks=None: Selects a strategy to mitigate speculative execution attacks (e.g., SPECTRE).
Accepted values are:
None: No mitigations are used in JIT compiled code.
AllTargets: All branches are protected against speculative attacks. This has a largeperformance impact.
GuardTargets: Only branches that preserve Java memory safety are protected. This hasreduced performance impact.
NonDeoptGuardTargets: Same as GuardTargets except that branches which deoptimize arenot protected since they can not be executed repeatedly.
-Dgraal.UsePriorityInlining=true: This can be used to disable use of the advanced inliningalgorithm that favors throughput over compilation speed. This option is only available inGraalVM EE.
-Dgraal.Vectorization=true: This can be used to disable the auto vectorization optimization.This option is only available in GraalVM EE.
-Dgraal.OptDuplication=true: This can be used to disable the path duplication optimization. This option is only available inGraalVM EE.
-Dgraal.TraceInlining=false: Enables tracing of inlining decisions. This can be used for advanced tuning where it may be possible to change the source code of the program. The output format is shown below:
compilation of 'Signature of the compilation root method':
at 'Sig of the root method'['Bytecode index']:<'Phase'>'Child method signature':'Decision made about this callsite'
at 'Signature of the child method'['Bytecode index']:
|--<'Phase 1'>'Grandchild method signature':'First decision made about this callsite'
\--<'Phase 2'>'Grandchild method signature':'Second decision made about this callsite'
at 'Signature of the child method'['Bytecode index']:<'Phase'>'Another grandchild method signature':'The only decision made about this callsite.'
compilation of java.lang.Character.toUpperCaseEx(int):
├──<GraphBuilderPhase> java.lang.CharacterData.of(int):no, bytecode parser did not replace invoke
└──<PriorityInliningPhase> java.lang.CharacterData.of(int): yes, worth inlining according to the cost-benefit analysis.
├──<GraphBuilderPhase> java.lang.CharacterDataLatin1.toUpperCaseEx(int):no, bytecode parser did not replace invoke
└──<PriorityInliningPhase> java.lang.CharacterDataLatin1.toUpperCaseEx(int): yes, worth inlining according to the cost-benefit analysis.
├──<GraphBuilderPhase> java.lang.CharacterDataLatin1.getProperties(int):no, bytecode parser did not replace invoke
└──<PriorityInliningPhase> java.lang.CharacterDataLatin1.getProperties(int): yes, worth inlining according to the cost-benefit analysis.
-Dgraal.CompilationFailureAction=Silent: Specifies the action to take when compilation fails by throwing an exception.
The accepted values are:
Silent: Print nothing to the console.
Diagnose: Retry the compilation with extra diagnostics enabled. On VM exit, the collected diagnostics are saved to a zip file that can be submitted along with a bug report. A message is printed to the console describing where the diagnostics file is saved:
Graal diagnostic output saved in/Users/graal/graal_dumps/1549459528316/graal_diagnostics_22774.zip
ExitVM: Same as
Diagnoseexcept that the VM process exits after retrying.For all values except for
ExitVM, the VM continues executing.
-Dgraal.CompilationBailoutAsFailure=false: The compiler may not complete compilation of a method due to some property or code shape in the method (e.g. exotic uses of the jsr and ret bytecodes). In this case the compilation bails out. If you want to be informed of such bailouts, this option makes GraalVM treat bailouts as failures and thus be subject to the action specified by the
-Dgraal.PrintCompilation=false: Prints an informational line to the console for each completed compilation.For example:
HotSpotCompilation-11Ljava/lang/Object; wait ()V |591ms12B92B4371kB
HotSpotCompilation-175Ljava/lang/String; lastIndexOf (II)I |590ms126B309B4076kB
HotSpotCompilation-184Ljava/util/concurrent/ConcurrentHashMap; setTabAt ([Ljava/util/concurrent/ConcurrentHashMap$Node;ILjava/util/concurrent/ConcurrentHashMap$Node;)V |591ms38B67B3411kB
HotSpotCompilation-136Lsun/nio/cs/UTF_8$Encoder; encode ([CII[B)I |591ms740B418B4921
The GraalVM compiler properties above are usable with some other GraalVM launchers such as
lli. The prefix for specifying the properties is slightly different.For example:
$ java -XX:+EagerJVMCI-Dgraal.ShowConfiguration=info -version
$ js --jvm --vm.Dgraal.ShowConfiguration=info -version
-D prefix is replaced by
When running the GraalVM compiler on the JVM, it goes through the same warmup phase that therest of Java application does. That is, it is first interpreted beforeits hot methods are compiled. This can translate into slightly longer timesuntil the application reaches peak performance when compared to the native compilersin the JVM such as C1 and C2.
To address the issue of taking longer to reach to peak performance, libgraalwas introduced – a shared library, produced using Native Imageframework to ahead-of-time compile the compiler itself. That means the GraalVMcompiler is deployed as a native shared library. In this mode, thecompiler uses memory separate from the HotSpot heap and it runs compiled fromthe start. That is, it has execution properties similar to other native HotSpotcompilers such as C1 and C2. Currently, this is the default mode ofoperation in both GraalVM Community and Enterprise images. It can be disabledwith
The first thing to be sure of when measuring the performance is to ensure the JVM is using the GraalVM compiler.In the GraalVM binary, the JVM is configured to use the GraalVM compileras the top tier compiler by default. You can confirm this by adding
-Dgraal.ShowConfiguration=infoto the command line. It will produce a line of output similar to the one belowwhen the compiler is initialized:
UsingGraal compiler configuration 'community' provided by org.graalvm.compiler.hotspot.CommunityCompilerConfigurationFactory loaded from jar:file:/Users/dsimon/graal/graal/compiler/mxbuild/dists/graal.jar!/org/graalvm/compiler/hotspot/CommunityCompilerConfigurationFactory.class
Note that the GraalVM compiler is only initialized on the first top tier JIT compilation requestso if your application is short lived, you may not see this output.
Optimizing JVM-based applications is a science in itself. The compilation may noteven be a factor in the case of poor performance as the problem maylie in any other part of the VM (I/O, garbage collection, threading etc) or inpoorly written application or 3rd party library code. For this reason, it’sworth using profilers such as Java Mission Control todiagnose application behavior.
You can also compare performance against the native top tier compiler in the JVM byadding
-XX:-UseJVMCICompiler to the command line.
If you observe a significant performance regression when using the GraalVM compiler, pleaseopen an issue on GitHub. Attaching a Java Flight Recorder log and instructionsto reproduce the issue makes investigation easier and thuschances of a fix higher. Even better is if you can submit a JMHbenchmark that represents the hottest parts of your application (as identifiedby a profiler). This allows us to very quickly pinpoint missing optimizationopportunities or to offer suggestions on how to restructure the code toavoid or reduce performance bottlenecks.
Like all software, the GraalVM compiler is not guaranteed to be bug free so it is useful toknow how to diagnose and submit useful bug reports if you encounter issues.
If you spot a security vulnerability, please do not report it via GitHub Issues or the public mailing lists,but via the process outlined at Reporting Vulnerabilities guide.
One advantage of the compiler being written in Java is that runtime exceptions duringcompilation are not fatal VM errors. Instead, each compilation has an exceptionhandler that takes an action based on the
The default value is
Diagnose causes failing compilations to be retriedwith extra diagnostics enabled. Just before the VM exits, all diagnostic outputcaptured during retried compilations is written to a
.zip file and its locationis printed on the console:
Graal diagnostic output saved in/Users/demo/graal-dumps/1499768882600/graal_diagnostics_64565.zip
You can then attach the .zip file to an issue on GitHub.
Diagnose the following values for
ExitVM: Same as
Diagnosebut the VM process exits after the re-compilation.
The other type of error compilers can have is producing incorrect machine code.This error can cause a VM crash, which should produce a file that starts with
hs_err_pid in the current working directory of the VM process. In most cases,there is a section in the file that shows the stack at the time of the crash,including the type of code for each frame in the stack, as in the followingexample:
Stack:[0x00007000020b1000,0x00007000021b1000], sp=0x00007000021af7a0, free space=1017k
Native frames:(J=compiled Java code, j=interpreted,Vv=VM code, C=native code)
J 761 JVMCI org.graalvm.compiler.core.gen.NodeLIRBuilder.matchComplexExpressions(Ljava/util/List;)V (299 bytes)@0x0000000108a2fc01[0x0000000108a2fac0+0x141](null)
This example shows that the top frame was compiled (J) by the JVMCI compiler,which is the GraalVM compiler. The crash occurred at offset 0x141 in the machinecode produced for:
The next two frames in the stack were executing in the interpreter (j). Thelocation of the crash is also often indicated near the top of the file withsomething like this:
# Problematic frame:
# J 761 JVMCI org.graalvm.compiler.core.gen.NodeLIRBuilder.matchComplexExpressions(Ljava/util/List;)V (299 bytes) @ 0x0000000108a2fc01 [0x0000000108a2fac0+0x141] (null)
In this example, there is likely an error in the code produced by the GraalVM compiler for
When filing an issue on GitHubfor such a crash, you should first attempt to reproduce the crash with extradiagnostics enabled for the compilation of the problematic method.In this example, you would add the following to your command line:
These options are described in more detail here.In brief, these options tell the compiler to capture snapshots of the compiler state atverbosity level 2 while compiling any method named
matchComplexExpressions ina class with a simple name of
NodeLIRBuilder. The complete format of the
MethodFilter option is described in the output of
Quite often, the crash location does not exist directly in the problematic methodmentioned in the crash log but comes from an inlined method.
In such a case, simply filtering for the problematic method might not capture anerroneous compilation causing a crash.
To improve the likelihood of capturing an erroneous compilation, you need tobroaden the
MethodFilter value. To guide this, add
-Dgraal.PrintCompilation=truewhen trying to reproduce the crash so you can see what was compiled just beforethe crash.
The following shows sample output from the console:
HotSpotCompilation-1218Lorg/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder; peephole (Lorg/graalvm/compiler/nodes/ValueNode;)Z |87ms428B447B1834kB
HotSpotCompilation-1212Lorg/graalvm/compiler/lir/LIRInstructionClass; forEachState (Lorg/graalvm/compiler/lir/LIRInstruction;Lorg/graalvm/compiler/lir/InstructionValueProcedure;)V |359ms92B309B6609kB
HotSpotCompilation-1221Lorg/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator; getResult ()Lorg/graalvm/compiler/hotspot/HotSpotLIRGenerationResult;|54ms18B142B1025kB
# A fatal error has been detected by the Java Runtime Environment:
# SIGSEGV (0xb) at pc=0x000000010a6cafb1, pid=89745, tid=0x0000000000004b03
# JRE version: OpenJDK Runtime Environment (8.0_121-b13) (build 1.8.0_121-graalvm-olabs-b13)
# Java VM: OpenJDK 64-Bit GraalVM (25.71-b01-internal-jvmci-0.30 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# J 1221 JVMCI org.graalvm.compiler.hotspot.amd64.AMD64HotSpotLIRGenerator.getResult()Lorg/graalvm/compiler/hotspot/HotSpotLIRGenerationResult; (18 bytes) @ 0x000000010a6cafb1 [0x000000010a6caf60+0x51] (null)
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
Here we see that the crash happened in a different method than the first crash.As such, we expand the filter argument to be
-Dgraal.MethodFilter=NodeLIRBuilder.matchComplexExpressions,AMD64HotSpotLIRGenerator.getResultand run again.
When the VM crashes in this way, it does not execute the shutdown code thatarchives the GraalVM compiler diagnostic output or delete the directory it was written to.This must be done manually after the crash.
By default, the directory is
$PWD/graal-dumps/<timestamp>; for example,
./graal-dumps/1499938817387.However, you can set the directory with
A message, such as the following, is printed to the console when thisdirectory is first used by the compiler:
Dumping debug output in/Users/demo/graal-dumps/1499768882600
This directory should contain content related to the crashing method, such as:
$ ls -l /Users/demo/graal-dumps/1499768882600
-rw-r--r--1 demo staff 144384Jul1311:46HotSpotCompilation-1162[AMD64HotSpotLIRGenerator.getResult()].bgv
-rw-r--r--1 demo staff 96925Jul1311:46HotSpotCompilation-1162[AMD64HotSpotLIRGenerator.getResult()].cfg
-rw-r--r--1 demo staff 12600725Jul1311:46HotSpotCompilation-791[NodeLIRBuilder.matchComplexExpressions(List)].bgv
-rw-r--r--1 demo staff 1727409Jul1311:46HotSpotCompilation-791[NodeLIRBuilder.matchComplexExpressions(List)].cfg
You should attach a zip of this directory to an issue on GitHub.