JVMでJITコンパイルされたコードを表示するにはどうすればよいですか?


84

JVMでJITによって生成されたネイティブコードを確認する方法はありますか?


JITでコンパイルされた(ネイティブ)コード、またはバイトコードだけを見たいですか?ここでこの質問をすることは、本当にネイティブコードを見たいのかどうか疑問につながるので、私は尋ねます...そして、申し訳ありませんが、私もそのようなツールを知りません。
gimpf 2009年

3
JITでコンパイルされたexacltyネイティブコードを見たいです。もちろん、それは私が仕事を成し遂げるために必要なものではなく、むしろ一種の実験と物事の調査です。
alsor.net 2009年

マイナーフレームの課題:最新のJVMで使用されている動的コンパイラには、コンパイルされたコードのバージョンが1つだけではありません。解釈から始めて、メソッドまたはその一部をコンパイルし、クラスがロード/アンロードされるか、使用パターンがシフトするか、パフォーマンス統計に基づいて、複数回再コンパイルされる可能性があります。(コンパイルされたバージョンを破棄して、それが有益と思われる場合は解釈に戻ることもできると思います。)したがって、異なるマシンで異なるコードを取得するだけでなく、同じマシンで異なる実行を行うだけでなく、同じ実行で異なる時間に取得する可能性があります。。
ギッド

回答:


45

Sun Hotspot JVM(つまり、Oracleがjava.comで提供しているもの)を使用していると仮定すると、フラグを追加できます。

-XX:+ PrintOptoAssembly

コードを実行するとき。これにより、JITコンパイラによって生成された最適化されたコードが出力され、残りは省略されます。

最適化されていない部分を含むバイトコード全体を表示したい場合は、次を追加します。

-XX:CompileThreshold =#

コードを実行しているとき。

このコマンドとJITの一般的な機能について詳しくは、こちらをご覧ください


このオプションは、デバッグビルドなどにのみ存在しますか?。私のJVM(「ジャワ(TM)SEランタイム環境(ビルド1.6.0_16-B01」)がそれを認識しないので、ウェブ上のソースは、SunのJava 6とOpenJDKの中で利用可能であること、この機能を示しているにもかかわらず
ヨアヒム・ザウアー

2
はい、DEBUGバイナリが必要です。blogs.warwick.ac.uk/richardwarburton/entry/...
alsor.net

3
それは(今日)-XX:+ PrintAssembly、少なくとも今日ではそうではありませんか?私のマシンでテストされ、ここで述べられていることと一致します:wikis.sun.com/display/HotSpotInternals/PrintAssemblyこのオプションと逆アセンブラープラグインの前に-XX:+ UnlockDiagnosticVMOptionsが必要です。
Blaisorblade 2011

@Blaisorblade取得中:VMオプション 'PrintAssembly'が正しく指定されていませんエラー:Java仮想マシンを作成できませんでした。エラー:致命的な例外が発生しました。プログラムは終了します。
Koray Tugay 2015年

@KorayTugay他の回答を参照してください—更新されたリンクはwikis.oracle.com/display/HotSpotInternals/PrintAssemblyでstackoverflow.com / a / 15146962/53974またはstackoverflow.com/a/4149878/53974に記載されています。指示に従うことがうまくいかない場合は、適切な場所で詳細を尋ねてください(これを参照して、あなたのケースに別の質問が必要かどうかわからない)。
Blaisorblade 2015

76

一般的な使用法

他の回答で説明されているように、次のJVMオプションを使用して実行できます。

-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly

特定の方法でフィルタリングする

次の構文を使用して、特定のメソッドでフィルタリングすることもできます。

-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*MyClass.myMethod

ノート:

  • OSなどによっては、2番目の引数を引用符で囲む必要がある場合があります。
  • メソッドがインライン化されると、いくつかの最適化を見逃す可能性があります

方法:必要なライブラリをWindowsにインストールする

Windowsを実行している場合、このページには、ビルドとインストールの方法、hsdis-amd64.dllおよびhsdis-i386.dllそれを機能させるために必要な手順が記載されています。以下をコピーし、参照用にそのページ*のコンテンツを拡張します。


ビルド済みのバイナリを入手する場所

fcmlプロジェクトからWindows用のビルド済みバイナリをダウンロードできます

どのように構築するhsdis-amd64.dllと、hsdis-i386.dllWindows上で

このバージョンのガイドは、64ビットのCygwinを使用し、hsdis-amd64.dllを生成するWindows 8.164ビットで作成されました。

  1. Cygwinをインストールします。時Select Packagesの画面、(拡張することにより、以下のパッケージを追加しDevel、その後、カテゴリを上に一度クリックするSkip次の各パッケージ名にラベル):

    • make
    • mingw64-x86_64-gcc-core(にのみ必要hsdis-amd64.dll
    • mingw64-i686-gcc-core(にのみ必要hsdis-i386.dll
    • diffutilsUtilsカテゴリー内)
  2. Cygwinターミナルを実行します。これは、インストーラーによって作成されたデスクトップまたはスタートメニューアイコンを使用して実行でき、Cygwinホームディレクトリ(C:\cygwin\home\<username>\またはC:\cygwin64\home\<username>\デフォルト)を作成します。

  3. 最新のGNUbinutilsソースパッケージダウンロードし、その内容をCygwinホームディレクトリに抽出します。執筆時点では、最新のパッケージはbinutils-2.25.tar.bz2です。これにより、binutils-2.25Cygwinホームディレクトリに(または最新バージョンの)名前のディレクトリが作成されます。
  4. JDK 8 Updatesリポジトリに移動し、インストールされているJREバージョンに対応するタグを選択して、bz2をクリックして、OpenJDKソースをダウンロードします。hsdisディレクトリ(src\share\toolsにあります)をCygwinホームディレクトリに抽出します。
  5. Cygwinターミナルで、と入力しcd ~/hsdisます。
  6. ビルドするにはhsdis-amd64.dll

    make OS=Linux MINGW=x86_64-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25

    ビルドするにはhsdis-i386.dll

    make OS=Linux MINGW=i686-w64-mingw32 'AR=$(MINGW)-ar' BINUTILS=~/binutils-2.25

    いずれの場合も、2.25ダウンロードしたbinutilsバージョンに置き換えてください。OS=LinuxCygwinはLinuxに似た環境ですが、hsdismakefileはそれをそのように認識できないために必要です。

  7. ビルドはメッセージ./chew: No such file or directoryとで失敗しますgcc: command not found<Cygwin home directory>\hsdis\build\Linux-amd64\bfd\MakefileWordpadやNotepad ++などのテキストエディタで編集してSUBDIRS = doc po(binutils 2.25を使用している場合は342行目)をに変更しSUBDIRS = poます。前のコマンドを再実行してください。

DLLは、今からそれをコピーしてインストールすることができるhsdis\build\Linux-amd64か、hsdis\build\Linux-i586あなたのJREのにbin\serverまたはbin\clientディレクトリ。を検索すると、システム上のそのようなディレクトリをすべて見つけることができますjava.dll

ボーナスのヒント:AT&TよりもIntel ASM構文を-XX:PrintAssemblyOptions=intel使用する場合は、使用する他のPrintAssemblyオプションと一緒に指定してください。

*ページライセンスはクリエイティブコモンズです


1
他のプラットフォーム用のビルド済みバイナリ-kenai.com/projects/base-hsdis/downloads–
Ashwin Jayaprakash

@AshwinJayaprakashこれらのファイルをMacOSのどこに置くことになっていますか?
Koray Tugay 2015年

@KorayTugayがそれらを入れました–Jean /usr/lib/
-FrançoisSavard

リンク先ページの最新バージョンからコピーして回答を更新しましたが、これは、外部リソースを逐語的にコピーするのではなく、一般的に外部リソースにリンクする理由を浮き彫りにします。
Aleksandr Dubinsky

@AleksandrDubinsky更新していただきありがとうございます。私はそれを
故意

29

を使用するには、hsdisプラグインが必要PrintAssemblyです。便利な選択は、FCMLライブラリに基づくhsdisプラグインです。

UNIXライクなシステム用にコンパイルでき、WindowsではSourceforgeのFCMLダウンロードセクションにあるビルド済みライブラリを使用できます。

Windowsにインストールするには:

  • dllを解凍します(hsdis-1.1.2-win32-i386.zipおよびhsdis-1.1.2-win32-amd64.zipにあります)。
  • 存在する場所にdllをコピーしますjava.dll(Windowsサーチを使用)。私のシステムでは、次の2つの場所で見つかりました。
    • C:\Program Files\Java\jre1.8.0_45\bin\server
    • C:\Program Files\Java\jdk1.8.0_45\jre\bin\server

Linuxにインストールするには:

  • ソースコードをダウンロードして抽出します
  • cd <source code dir>
  • ./configure && make && sudo make install
  • cd example/hsdis && make && sudo make install
  • sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/lib/amd64/hsdis-amd64.so
  • sudo ln -s /usr/local/lib/libhsdis.so <JDK PATH>/jre/lib/amd64/hsdis-amd64.so
  • 私のシステムでは、JDKは /usr/lib/jvm/java-8-oracle

それを実行する方法:

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly 
-XX:+LogCompilation -XX:PrintAssemblyOptions=intel,mpad=10,cpad=10,code 
-jar fcml-test.jar

追加の構成パラメーター:

codeニーモニックの前にマシンコードを印刷します。
intelIntel構文を使用します。
gas AT&Tアセンブラ構文(GNUアセンブラ互換)を使用します。
12月プリントIMMと小数点値として変位。
mpad = XX命令のニーモニック部分のパディング。
cpad = XXマシンコードのパディング。
segデフォルトのセグメントレジスタを表示します。
ゼロHEXリテラルの場合、先行ゼロを表示します。

Windowsの場合はIntel構文がデフォルトですが、GNU / Linuxの場合はAT&T構文がデフォルトです。

詳細については、FCMLライブラリリファレンスマニュアルを参照してください。


libを修正していただきありがとうございます。Linuxでもうまく機能しています。混乱を避けるために、古いコメントを削除しています。
Aleksandr Dubinsky 2015年

Linuxでは、libhsdis.soをインストールしてhsdis-amd64.soへのソフトリンクを作成した後、javaコマンドを実行すると、prmptsがhsdis-amd64.soを見つけることができません。再起動してからJavaを再実行します。問題ありません。ソフトリンクを即座に機能させるために再起動を回避するにはどうすればよいですか?ログアウト?
gfan 2017

2
ほんの少しの追加:一部のLinuxディストリビューションでは、たとえばUbuntuにパッケージをインストールできます:apt-get install libhsdis0-fcmlaskubuntu.com/a/991166/489909)。これを自分で作成する必要はないかもしれません。
David GeorgReichelt19年


5

WinDbgは、Windowsマシンで実行している場合に役立つと思います。私はちょうど1つの瓶を実行しました。

  • 次に、Windbgを介してJavaプロセスに接続しました
  • コマンドでスレッドを調べました。11スレッドあり、0スレッドがメインワーカースレッドでした
  • 0スレッドに切り替え-〜0s
  • kbによって管理されていないコールスタックを調べたところ、次のようになりました。

    0008fba8 7c90e9c0 NTDLL!KiFastSystemCallRet
    0008fbac 7c8025cb NTDLL!ZwWaitForSingleObject +から0xC
    0008fc10 7c802532 KERNEL32!WaitForSingleObjectEx + 0xa8
    0008fc24 00403a13 KERNEL32!のWaitForSingleObject + 0x12を
    0008fc40 00402f68のJava + 0x3a13
    0008fee4 004087b8のJava + 0x2f68
    0008ffc0 7c816fd7のJava + 0x87b8

    0008fff0 00000000 KERNEL32!BaseProcessStart + 0x23

強調表示されている行は、JVMで直接実行されているJITコードです。

  • 次に、メソッドアドレスを探すことができます
    。java+ 0x2f68は00402f68です。

  • WinDBGの場合:
    [表示]-> [逆アセンブリ]をクリックします。
    [編集]-> [アドレスに移動]をクリックします。
    入れ00402f68そこ
    とGOT

    00402f68 55 push ebp
    00402f69 8bec mov ebp、esp
    00402f6b 81ec80020000 sub esp、280h
    00402f71 53 push ebx
    00402f72 56 push esi
    00402f73 57 push edi
    ...など

追加情報については、ProcessExplorerとWinDbgを使用してメモリダンプからJITされたコードをトレースバックする方法の例を示します。


4

マシンコードと一部のパフォーマンスデータを確認するもう1つの方法は、AMDのCodeAnalystまたはOProfileを使用することです。これらには、Javaコードの実行をマシンコードとして視覚化するJavaプラグインがあります。


0

JMHのパフォーマンスプロファイラー(LinuxPerfAsmProfilerまたはWinPerfAsmProfiler)を使用して、ホットスポットのアセンブリを印刷します。JMHはhsdisに依存しているため、ライブラリは必要ですPrintAssembly

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.