Controlling code generation in JRockit

JRockit is designed to work well out of the box, and it is generally discouraged to play around too much with its command-line options. Changing the behavior of code generation and optimization is no exception. This section exists mostly for informational purposes and the user should be aware of possible unwanted side effects that can arise from changing the behavior of the code generators.

Note

This section applies mainly to the versions of JRockit from R28 and later. For earlier versions of JRockit, please consult the JRockit documentation for equivalent ways of doing the same thing. Note that all R28 functionality does not have equivalents in earlier versions of JRockit.

Command-line flags and directive files

In the rare case that the code generator causes problems in JRockit, or an application behaves strangely or erroneously, or it just takes too long time to optimize a particular method, the JRockit code generator behavior can be altered and controlled. Naturally, if you know what you are doing, code generation can be controlled for other purposes as well.

Command-line flags

JRockit has several command-lines flags that control code generation behavior in a coarse grained way. For the purpose of this text, we will only mention a few.

Logging

The Xverbose:codegen (and Xverbose:opt) options make JRockit output two lines of information per JIT compiled (or optimized) method to stderr.

Consider the output for a simple HelloWorld program. Every code generation event produces two lines in the log, one when it starts and one when it finishes.

hastur:material marcus$ java Xverbose:codegen HelloWorld
[INFO ][codegen][00004] #1 (Normal) jrockit/vm/RNI.transitToJava(I)V
[INFO ][codegen][00004] #1 0.027-0.027 0x9e5c0000-0x9e5c0023 0 .14 ms (0.00 ms)
[INFO ][codegen][00004] #2 (Normal) jrockit/vm/RNI.transitToJavaFromDbgEvent(I)V
[INFO ][codegen][00004] #2 0.027-0.027 0x9e5c0040-0x9e5c0063 0 .03 ms (0.00 ms)
[INFO ][codegen][00004] #3 (Normal) jrockit/vm/RNI.debuggerEvent()V
[INFO ][codegen][00004] #3 0.027-0.027 0x9e5c0080-0x9e5c0131 0 .40 ms 64KB 0 bc/s (0.40 ms 0 bc/s)
[INFO ][codegen][00004] #4 (Normal) jrockit/vm/ExceptionHandler.enterExceptionHandler() Ljava/lang/Throwable;
[INFO ][codegen][00004] #4 0.027-0.028 0x9e5c0140-0x9e5c01ff 0 .34 ms 64KB 0 bc/s (0.74 ms 0 bc/s)
[INFO ][codegen][00004] #5 (Normal) jrockit/vm/ExceptionHandler.gotoHandler()V
[INFO ][codegen][00004] #5 0.028-0.028 0x9e5c0200-0x9e5c025c 0 .02 ms (0.74 ms)
...
[INFO ][codegen][00044] #1149 (Normal) java/lang/Shutdown.runHooks()V
[INFO ][codegen][00044] #1149 0.347-0.348 0x9e3b4040-0x9e3b4106 0 .26 ms 128KB 219584 bc/s (270.77 ms 215775 bc/s)
hastur:material marcus$

The first log line of a code generation request (event start) contains the following information from left to right:

  • Info tag and log module identifier (code generator).
  • The thread ID of the thread generating the code: Depending on the system configuration, there can be more than one code generator thread and more than one code optimizer thread.
  • The index of the generated method: The first method to be generated starts at index 1. As we notice, at the beginning of the output, code generation is single threaded, and the order between the start and end of a code generation event is maintained, forming consecutive entries. This doesn't have to be the case if multiple code generation and optimization threads are working.
  • The code generation strategy: The code generation strategy tells you how this particular method will be generated. As it is too early to have received runtime feedback information, all methods are generated using a normal code generator strategy, or even a quick one that is even sloppier. The quick strategy is applied for methods that are known to be of exceedingly little importance for the runtime performance. This can be, for example, static initializers that will run only once and thus make no sense to even register allocate properly.
  • The generated method: This is uniquely identified by class name, method name, and descriptor.

The second line of a code generation request (event end) contains the following information from left to right:

  • Info tag and log module identifier (code generator).
  • The thread ID of the thread generating the code.
  • The index of the generated method.
  • Start and end time for the code generation event: This is measured in seconds from the start of the JVM.
  • The address range: This is where the resulting native code is placed in memory.
  • Code generation time: The number of milliseconds it took for the code generator to turn this particular method into machine language (starting from bytecode).
  • Maximum amount of thread local memory used: This is the maximum amount of memory that the code generator thread needed to allocate in order to generate the method.
  • Average number of bytecodes per second: The number of bytecodes processed per second for this method. 0 should be interpreted as infinity—the precision was not good enough
  • Total code generation time: The total number of milliseconds this thread has spent in code generation since JVM startup and average bytecodes compiled per second for the thread so far.

Turning off optimizations

The command-line flag -XnoOpt, or -XX:DisableOptsAfter=<time> turns off all optimization in the compiler, optionally after a specified number of seconds after the start of the JVM. The flag -XnoOpt makes programs compile faster, but run slower, and can be used if there is a suspected problem with the JRockit optimizer or if compile time turns out to be a very big issue, for example in application response time.

Changing the number of code generation threads

Depending on the machine configuration, it might make sense to change the number of code generation and optimization threads that the JVM should use. Code generation and code optimization is a process that can, with the exception of emitting code into native code buffers and some aspects of class loading, be parallelized. The number of JIT compiler threads can be changed with the -XX:JITThreads=<n> option. The number of optimizing threads can be changed with the -XX:OptThreads=<n> option. Note that optimizations typically are quite memory and CPU intensive, even if the machine has plenty of cores.

Directive files

A more versatile method for code generation control is provided by directive files. Here, wild card patterns for interesting methods can be specified, for which the code generator should customize its behavior. The amount of available customizations is very large, and this section serves merely to introduce the concept of directive files, not serve as a reference of any kind.

Note

Warning! Directive files are a completely unsupported way of controlling JRockit code generation. The directives in the files are undocumented externally and are subject to change without notice. Oracle will not give support to JRockit configurations that use directive files.

A directive file is passed to JRockit by the flag -XX:OptFile=<filename>. It can also be added to or removed from the runtime state using JRCMD or through the JRockit Java API, both of which will be covered later in this book. In order to be able to use directive files, the command-line switch -XX:+UnlockDiagnosticVMOptions needs to be passed on the command line as well. Diagnostic VM options are subject to change without notice between releases and should be used at your own risk.

A directive file is a tuple of directives in a format compatible with the JavaScript Object Notation (JSON) format. An example would be:

{
//pattern to match against class+method+signature
match: "java.dingo.Dango.*",
enable: jit
}

This is a very simple file that forbids the optimization of any method whose descriptor matches java.dingo.Dango.*. This is because the enable directive only contains the word jit, not the word hotspot, which would allow the matched methods to be selected for optimization through sampling.

If, on the other hand, we want to force optimization of the matched methods on their first code generation, we'd use something like this:

{
match: "java.dingo.Dango.*",
//types of "reasons" for codegen we allow
enable: jit,
jit: {
preset : opt
}
}

This means that we only allow the JIT strategy for the method, but when it is compiled we should use the preset optimization strategy on it. JRockit contains a number of preset strategies that are also directives, and opt means "immediately generate this method with full optimization".

Note

Applying full optimization to a method the first time it is generated by the system doesn't necessarily produce the same code or performance as it would have done if that method was detected to be hot and queued for normal optimization by the runtime. If a method is optimized too early, the risk is that we don't know enough about the program yet to do a good enough job. The fact is that the method might even have been queued for optimization, since the runtime has learned new things about the running program, but not optimized yet. Forcing the immediate optimization of many methods is not only expensive in clock cycles, but it is also not guaranteed to perform as well as it would by just letting things run their natural course.

The code generation strategy can be overridden in a more fine-grained way as well, for example, by turning off individual optimizations that are normally run, or by forbidding the inlining of a particular method.

The following is an example of a directive file with multiple directives:

//Using more than one directive, should use an array '['.
[
//directive 1
{
match: "java.dingo.Dango.*",
enable: [ jit, hotspot ], //allow both jit and optimization
hotspot: {
fusion_regalloc : false; //forbid graph fusion for opt
},
jit_inline : false, //forbid jit inlining
},
//directive 2
{
match: [ "java.lang.*", "com.sun.*" ],
enable: jit ,
jit: {
//copy the opt preset, i.e. force optimization
//for jit, but disable inlining
preset : opt,
opt_inline : false,
},
},
//directive 3
{
match: "com.oracle.*",
//force optimizer to always inline java.util methods
//force optimizer to NEVER inline com.sun.methods
inline: [ "+java.util.*", "-com.sun.*" ],
}
]

Note

Practically, any part of compilation to native code for each kind of code generation strategy in JRockit, down to individual optimizations, can be controlled through a directive file. All aspects of directive files and names of directives are generally not documented. While directive files are a great instrument for helping you track down problems in a dialogue with JRockit support, playing around too much with them on your own is generally discouraged.

When using a directive file, it is a good idea to run with the -Xverbose:opt command-line flag enabled, in order to make sure that the file is actually read and understood by the JVM.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.226.120