web-dev-qa-db-ja.com

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

JVMのJITが生成するネイティブコードを確認する方法はありますか?

73
alsor.net

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

-XX:+ PrintOptoAssembly

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

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

-XX:CompileThreshold =#

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

このコマンドと一般的なJITの機能について詳しくは、 here を参照してください。

43
Falaina

一般的な使用法

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

_-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
_

特定のメソッドでフィルタリングする

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

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

ノート:

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

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

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


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

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

Windowsで_hsdis-AMD64.dll_および_hsdis-i386.dll_をビルドする方法

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

  1. Cygwinのインストール 。 _Select Packages_画面で、次のパッケージを追加します(Develカテゴリを展開し、各パッケージ名の横にあるSkipラベルを1回クリックします)。

    • 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. 最新のGNU binutilsソースパッケージ をダウンロードし、その内容をCygwinホームディレクトリに抽出します。これを書いている時点では、最新のパッケージは_binutils-2.25.tar.bz2_です。 Cygwinホームディレクトリに_binutils-2.25_(または最新バージョンが何であれ)という名前のディレクトリが作成されます。
  4. JDK 8 Updatesリポジトリに移動 でOpenJDKソースをダウンロードし、インストールされているJREバージョンに対応するタグを選択して、bz2をクリックします。 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バージョンに置き換えます。 CygwinはLinuxのような環境ですが、hsdis makefileはそれを認識しないため、_OS=Linux_が必要です。

  7. ビルドは、メッセージ_./chew: No such file or directory_および_gcc: command not found_で失敗します。ワードパッドやメモ帳++などのテキストエディタで_<Cygwin home directory>\hsdis\build\Linux-AMD64\bfd\Makefile_を編集して、_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よりもインテルASM構文を使用する場合は、使用する他のPrintAssemblyオプションとともに_-XX:PrintAssemblyOptions=intel_を指定してください。

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

70
assylias

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

UNIXライクなシステム用にコンパイルでき、WindowsではSourceforgeのFCML download セクションで利用可能なビルド済みライブラリを使用できます。

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

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

コード ニーモニックの前にマシンコードを出力します。
インテル Intel構文を使用します。
ガス AT&Tアセンブラー構文を使用します(GNUアセンブラー互換)。
12月 IMMおよび変位を10進値として出力します。
mpad = XX 命令のニーモニック部分のパディング。
cpad = XX マシンコードのパディング。
ワンセグ デフォルトのセグメントレジスタを表示します。
ゼロ HEXリテラルの場合、先行ゼロを表示します。

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

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

27
swojtasiak

HotSpot(旧Sun)JVMの場合、製品モードでも:

http://wikis.Oracle.com/display/HotSpotInternals/PrintAssembly

いくつかのアセンブリが必要です:プラグインが必要です。

8
John Rose

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

  • 次に、JavaプロセススルーWindbgにアタッチしました
  • コマンドでスレッドを調べました。 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を置く
    そして得た

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

詳細については、ここに プロセスエクスプローラーとWinDbgを使用してメモリダンプからJITされたコードをトレースバックする方法を示します。

5
Andriy Tkach

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

4
Ian

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

0