How to use -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print option with JVM HotSpot
Asked Answered
H

2

21

I 'm trying to use -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod command lines as described in this post.

It seems thats it's available with open-jdk (https://wikis.oracle.com/display/HotSpotInternals/PrintAssembly).

How can I use those options (or similar equivalents) with oracle JDK7 and the JVM HotSpot?

Holozoic answered 18/2, 2012 at 12:19 Comment(4)
it doesn't look too difficult to tryShook
Ofc I've tried but it doesn't work, my question is how to make them work? I'll edit.Holozoic
Have you tried "If you get no output, use -XX:+PrintCompilation to verify that your method is getting compiled at all."Herod
Yes it does nothing just a row of number like with above options. By the way this doc is for openjdk. I think it won't work with Java HotSpot. I try to find an equivalent.Holozoic
D
28

These instructions apply to Linux (Ubuntu 10.04.4 LTS), but should be applicable for your OS. After downloading Oracle JDK 7u3 and appropriately setting your JAVA_HOME and PATH environment variables, execute the following to check available options:

java -XX:+AggressiveOpts -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version

You should see the UnlockDiagnosticVMOptions, CompileCommand and PrintAssembly options are available. Using the CompileCommand option will also enable the PrintAssembly option. However, you will need the HotSpot disassembler plugin for PrintAssembly to work; without it, you might see something like the following:

$ java -version
java version "1.7.0_03"
Java(TM) SE Runtime Environment (build 1.7.0_03-b04)
Java HotSpot(TM) Server VM (build 22.1-b02, mixed mode)
$ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main
CompilerOracle: print *Main.main
Java HotSpot(TM) Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
Compiled method (c2)      68    1 %           Main::main @ 4 (49 bytes)
 total in heap  [0xb3a97548,0xb3a979ec] = 1188
 relocation     [0xb3a97610,0xb3a97624] = 20
 main code      [0xb3a97640,0xb3a97840] = 512
 stub code      [0xb3a97840,0xb3a97850] = 16
 oops           [0xb3a97850,0xb3a97858] = 8
 scopes data    [0xb3a97858,0xb3a97898] = 64
 scopes pcs     [0xb3a97898,0xb3a979e8] = 336
 dependencies   [0xb3a979e8,0xb3a979ec] = 4
Could not load hsdis-i386.so; library not loadable; PrintAssembly is disabled
OopMapSet contains 1 OopMaps

To get the HotSpot disassembler plugin, you will need to build it. Looking at the OpenJDK 7u2 source, the hsdis plugin readme says:

To use the plugin with a JVM, you need a new version that can load it. If the product mode of your JVM does not accept -XX:+PrintAssembly, you do not have a version that is new enough.

To build this project you [need] a copy of GNU binutils to build against.

In theory this should be buildable on Windows but getting a working GNU build environment on Windows has proven difficult.

We have confirmed above that Oracle JDK 7u3 supports PrintAssembly. I followed the hsdis plugin readme instructions, downloaded GNU binutils 2.22, placed it in the hsdis build/binutils directory and ran make. This eventually produced the following error:

hsdis.c:32:20: error: sysdep.h: No such file or directory

To correct this, I changed hsdis.c using the following patch:

diff -r 6259c6d3bbb7 src/share/tools/hsdis/hsdis.c
--- a/src/share/tools/hsdis/hsdis.c Mon Dec 12 23:08:01 2011 -0800
+++ b/src/share/tools/hsdis/hsdis.c Thu Feb 23 09:26:37 2012 -0500
@@ -29,7 +29,7 @@

 #include "hsdis.h"

-#include <sysdep.h>
+#include <errno.h>
 #include <libiberty.h>
 #include <bfd.h>
 #include <dis-asm.h>

Running make was then successful. Now just copy the hsdis-i386.so plugin in the hsdis build directory to the Oracle JDK 7u3 jre/lib/i386 directory.

Now you can see the disassembled compiled code:

$ java -server -XX:+UnlockDiagnosticVMOptions '-XX:CompileCommand=print,*Main.main' Main
CompilerOracle: print *Main.main
Java HotSpot(TM) Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output
Compiled method (c2)      68    1 %           Main::main @ 4 (49 bytes)
 total in heap  [0xb3999548,0xb39999ec] = 1188
 relocation     [0xb3999610,0xb3999624] = 20
 main code      [0xb3999640,0xb3999840] = 512
 stub code      [0xb3999840,0xb3999850] = 16
 oops           [0xb3999850,0xb3999858] = 8
 scopes data    [0xb3999858,0xb3999898] = 64
 scopes pcs     [0xb3999898,0xb39999e8] = 336
 dependencies   [0xb39999e8,0xb39999ec] = 4
Loaded disassembler from [snip]/jdk1.7.0_03/jre/lib/i386/hsdis-i386.so
Decoding compiled method 0xb3999548:
Code:
[Disassembling for mach='i386']
[Entry Point]
[Verified Entry Point]
[Constants]
  # {method} 'main' '([Ljava/lang/String;)V' in 'Main'
  0xb3999640: call   0xb6ff8510         ;   {runtime_call}
  0xb3999645: data32 xchg %ax,%ax
  0xb3999648: mov    %eax,-0x3000(%esp)
  0xb399964f: push   %ebp
  0xb3999650: sub    $0x38,%esp
  0xb3999656: mov    %ecx,%esi
  0xb3999658: mov    0x4(%esi),%ebp
  0xb399965b: mov    0x8(%esi),%edi
  0xb399965e: mov    (%ecx),%esi
  0xb3999660: mov    %ecx,(%esp)
  0xb3999663: call   0xb7078cf0         ;*iload_3
[snip]
  0xb399983e: hlt    
  0xb399983f: hlt    
[Exception Handler]
[Stub Code]
  0xb3999840: jmp    0xb39981e0         ;   {no_reloc}
[Deopt Handler Code]
  0xb3999845: push   $0xb3999845        ;   {section_word}
  0xb399984a: jmp    0xb397e220         ;   {runtime_call}
  0xb399984f: .byte 0x0
OopMapSet contains 1 OopMaps

#0 
OopMap{off=468}

The test class I've used is:

public class Main {
    public static void main(final String[] args) {
        long x = 0;
        for (int i = 0; i < 1000000; i++) {
            x += calculate(i);
        }
        System.out.println("x=" + x);
    }

    private static long calculate(final int i) {
        return (long)i * (long)i;
    }
}
Dobsonfly answered 23/2, 2012 at 14:52 Comment(4)
Thanks a lot for the reply, I have a problem understanding where I found hsdis and how I install it? I don't understand where should I create this build directory. From now I've dl the files here hg.openjdk.java.net/jdk7/hotspot/hotspot/file/tip/src/share/… and I have download binutils-2.22. When you speak of binutils its the whole directory are just the sub directory named binutils?Holozoic
@Holozoic From the hsdis readme: The makefile looks for the sources in build/binutils or you can specify it's location to the makefile using BINTUILS=path. build/binutils is relative to the directory the hsdis files are in. From this directory, you could try something like mkdir build ; cd build ; wget -O - http://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2 | tar xjvf - ; ln -s binutils-2.2.22 binutils. Or try BINUTILS=path_to_where_you_extracted_binutils make.Dobsonfly
@DanCruz - I think that last line should be ln -s binutils-2.22 binutils rather than ln -s binutils-2.2.22 binutils, but other than that, awesome.Fauve
@DanCruz I tried to compile it, but I get a compiler errer "bad reloc address 0x0". Did you ran into such a problem? If so you can answer my question here #21043309.Hirundine
T
1

in my case to see the disassembled compiled code:

$ java -XX:CompileThreshold=1 -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand="compileonly pac/kage/MyClass myMethod" MyClass

in example above has is cycle: for (int i = 0; i < 1 000 000; i++) {...}, that is why in our case without 1 000 000 iterations we need -XX:CompileThreshold=1 option (by default 10 000 for -server) to see our disassembled compiled code.

Twine answered 13/12, 2015 at 7:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.