Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

JITWatchでJITコンパイルを見よう!

この記事は JVM Advent Calendar 4日目 の記事です。

JVM Advent Calendar 2014 - Qiita

JITWatchについて

JVMなみなさんは、JITコンパイルをご存知だと思います。

JITWatchは、アプリケーションにおけるJITコンパイルについて、可視化し分析するためのツールです。

GitHubで公開されており、すぐに使うことができます。ライセンスはBSDなので、とくに問題ありません。

GitHub - AdoptOpenJDK/jitwatch: Log analyser / visualiser for Java HotSpot JIT compiler. Inspect inlining decisions, hot methods, bytecode, and assembly. View results in the JavaFX user interface.

JITWatchで見るための設定

JITWatchで可視化、分析するためには、アプリケーションでログを出力する必要があります。そのためにJVM引数に次のものを追加します。

-XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation

こうすることで、アプリケーションを実行すると、実行したディレクトリに「hotspot_pid9999.log」(9999は起動したプロセスのIDとなる)というファイルが出力されます。

マシンコードも見る

さらに、JITコンパイラによって生成されたマシンコードを見たい場合、次のオプションも合わせて記述します。

-XX:+PrintAssembly

そしてHSDIS(HotSpot disAssembler)をセットアップします。

HSDISは以下のサイトからダウンロードできます。

https://kenai.com/projects/base-hsdis/downloads

Macの場合、「bsd-libhsdis-i386.dylib」をダウンロードし、「hsdis-amd64.dylib」にリネームします。

Project Kenaiのビルドは古いため、自分でビルドしましょう。

www.sakatakoichi.com

JDK8の場合、そのファイルを「JAVA_HOME/jre/lib/server/」に配置してください。JDK9以降は、「JAVA_HOME/lib/」です。

なお、HSDISはデフォルトではAT&Tのシンタックスとなります。Intelのシンタックスにすることもできるようです(詳細は不明)-XX:PrintAssemblyOptions=intelでintelのシンタックスにできます。こちらの出力フォーマットのほうが読みやすい感じです。

JITWatchの使い方

GitHubからcloneし、mvn packageします。targetディレクトリにjitwatch-1.0.0-SNAPSHOT.jarができます。

なお、ログファイルを簡単に生成したい場合、JITWatchがサンプルアプリを用意してくれているのでそれを利用するとよいです。makeDemoLogFile.shを実行するだけで、ログファイルを生成します。ここからは、そのサンプルが作ったログファイルを使って説明します。

JITWatchのルートディレクトリにlaunchUI.sh(.bat)があるのでそれを実行します。次のようなウィンドウが表示されます。

f:id:jyukutyo:20141204201758p:plain

あとはOpen Logで先ほど出力するようにした「hotspot_pid9999.log」を指定します。次にJITWatch ConfigurationでSource locationsにJDKのsrc.zipとアプリケーションのsrcディレクトリを、Class locationsにはアプリケーションのclassファイルの場所を指定します。

f:id:jyukutyo:20141204201802p:plain

Startボタンを押すとログファイルの解析を開始します。終了すると、次のような画面になります。

f:id:jyukutyo:20141204201806p:plain

ChartやStats、Histo、TopList、Code Cache、TriView、Suggestを押すと、詳細な情報を見ることができます。 これらの画面で出てくるC1やC2という単語はコンパイラレベルです。OSRはOn-Stack replacementのことで、ループ内の最適化のことを指します。

JITWatchで一番おもしろい部分はTriViewです。この画面でソースコードとバイトコード、アセンブリコードを対比させて見ることができます。

f:id:jyukutyo:20141204201809p:plain

メソッド内の該当コードにポインタを合わせると、その部分のバイトコードとアセンブリコードに色がつきます。もしPrintAssemblyしていないときは、アセンブリコードは表示されません。

さらにこの画面でView Compile Chainを押すと、コンパイルのチェーンを見れます。

f:id:jyukutyo:20141204201813p:plain

おもしろい機能はSuggestです。

f:id:jyukutyo:20141204201816p:plain

たとえば以下のようなことが書かれています。

The call at bytecode 3 to
Class: org.adoptopenjdk.jitwatch.demo.MakeHotSpotLog
Member: private long bigMethod(long,int)
was not inlined for reason: 'hot method too big'
The callee method is 'hot' but is too big to be inlined into the caller.
You may want to consider refactoring the callee into smaller methods.
Invocations: 20000
Size of callee bytecode: 350

ホットなメソッドだけれども、メソッドが大きすぎてインライン化できないとあります。リファクタリングしてより小さいメソッドにしようという提案があります。

こういった提案を利用して、よりJITコンパイルを促進するようにアプリケーションを作成することができます。

最後に注意

JITコンパイルには静的なルールと動的なルールがあります。サンプル程度の場合、静的なルールだけが使われますが、実際の環境では動的なルールがほとんどを占めます。ある場合のJITコンパイルのルールが他のアプリケーションでも常に適用できるわけではないので、注意しましょう。

さあ

JITWatchでみんなもHotSpotのJITコンパイルを楽しもう!!

参考

Java Magazine 2014 September October ※閲覧には登録が必要です

http://www.oraclejavamagazine-digital.com/javamagazine/november_december_2014#pg37