[論文レビュー] Performance comparison between Java and JNI for optimal implementation of computational micro-kernels
この論文は、HPC分野における計算マイクロカーネルの実装としてJavaとJNIの性能を比較し、JITコンパイルとネイティブコードの間の性能的トレードオフを分析している。JNIは、ベクトル化や順序入れ替え実行といった優れた最適化のおかげで、計算集約的カーネルにおいてJavaを上回る性能を発揮するが、JNI呼び出しのオーバーヘッドが、1回の呼び出しあたりの計算量が閾値を超えない限り性能向上を制限する。データのアラインメントやネイティブメモリアクセスの影響が性能に顕著に現れる。
General purpose CPUs used in high performance computing (HPC) support a vector instruction set and an out-of-order engine dedicated to increase the instruction level parallelism. Hence, related optimizations are currently critical to improve the performance of applications requiring numerical computation. Moreover, the use of a Java run-time environment such as the HotSpot Java Virtual Machine (JVM) in high performance computing is a promising alternative. It benefits from its programming flexibility, productivity and the performance is ensured by the Just-In-Time (JIT) compiler. Though, the JIT compiler suffers from two main drawbacks. First, the JIT is a black box for developers. We have no control over the generated code nor any feedback from its optimization phases like vectorization. Secondly, the time constraint narrows down the degree of optimization compared to static compilers like GCC or LLVM. So, it is compelling to use statically compiled code since it benefits from additional optimization reducing performance bottlenecks. Java enables to call native code from dynamic libraries through the Java Native Interface (JNI). Nevertheless, JNI methods are not inlined and require an additional cost to be invoked compared to Java ones. Therefore, to benefit from better static optimization, this call overhead must be leveraged by the amount of computation performed at each JNI invocation. In this paper we tackle this problem and we propose to do this analysis for a set of micro-kernels. Our goal is to select the most efficient implementation considering the amount of computation defined by the calling context. We also investigate the impact on performance of several different optimization schemes which are vectorization, out-of-order optimization, data alignment, method inlining and the use of native memory for JNI methods.
研究の動機と目的
- HotSpot JVMを用いたHPC分野における計算マイクロカーネルの最適な実装(純粋なJava対JNI)を特定すること。
- JITコンパイルの制限(制御不能、最適化の減少)と、JNIの高い呼び出しオーバーヘッドだが深い静的最適化という性能的トレードオフを分析すること。
- 算術強度、ベクトル化、順序入れ替え実行、データアラインメント、メモリアクセス(ヒープ対ネイティブ)といった要因が性能に与える影響を定量化すること。
- JNIが純粋なJavaよりも効率的になる、flop/呼び出しの閾値を特定すること。この閾値では、より良い最適化の機会が得られる。
提案手法
- AVX対応のx86-64 Sandy Bridgeシステム上で、数値マイクロカーネル(例:配列加算、水平和、ホーナー法)のセットをベンチマークした。
- 複数の設定(純粋なJava、ヒープメモリを使用したJNI、ネイティブメモリを使用したJNI、さまざまな最適化レベル)における性能(flop/s)を測定した。
- 算術強度(AI = 呼び出しあたりのflop / 呼び出しあたりのメモリ)を用いて、カーネルをメモリ制限型またはCPU制限型に分類した。
- JNIコードに対して静的コンパイル(GCC)を適用し、ベクトル化、順序入れ替え実行、インライン展開の影響を分析した。
- アラインメントの影響を評価するために、配列のアラインメント(8バイト対16バイト)を変更し、性能劣化を測定した。
- 呼び出しオーバーヘッドを測定するために、インライン展開を無効化し、JNIとJavaのメソッド呼び出しコストを比較した。
実験結果
リサーチクエスチョン
- RQ1どのflop/呼び出しの閾値でJNIが純粋なJavaを上回るのか?
- RQ2ネイティブコードにおけるベクトル化と順序入れ替え実行は、JITコンパイルされたJavaに比べてどの程度性能を向上させるのか?
- RQ3データの非アラインメントが、JavaおよびJNIにおけるベクトル化マイクロカーネルに与える性能への影響は何か?
- RQ4ヒープメモリではなくネイティブメモリを使用することで、JNIの呼び出しオーバーヘッドと性能にどのような影響があるのか?
- RQ5メソッドインライン展開は、JNIメソッド呼び出しの性能ペナルティをどの程度軽減するのか?
主な発見
- JNIは、1回あたりのメモリ使用量がL3キャッシュサイズ未満のマイクロカーネルに対して、最大2倍のスループット向上を達成した。これは、効果的なベクトル化と順序入れ替え最適化のおかげである。
- ホーナー法(データ優先)カーネルでは、JNIにおけるベクトル化と順序入れ替え実行の組み合わせにより、CPUのピーク性能に到達したが、JITはこのようなイディオムをベクトル化できなかった。
- 配列の一方が8バイトアライン、他方が16バイトアラインの場合、非アラインメモリアクセスのため、配列加算カーネルの性能が45%劣化した。
- JNIの呼び出しオーバーヘッドは、ヒープメモリアクセスに起因する:Javaヒープから配列ポインタを取得・解放する処理が約40%の性能ペナルティを引き起こすが、ネイティブメモリを使用すればこのペナルティが軽減される。
- Javaメソッドのインライン展開を無効化したところ、性能が約20%低下した。これは、インライン展開がメソッド呼び出しコストを顕著に軽減していることを示している。
- 低メモリ使用マイクロカーネルでは、呼び出しコストが性能のボトルネックとなり、ループの定数コストが支配的である。このペナルティは、コールバックオーバーヘッドがあるため、JNIではより顕著に現れる。
より良い研究を、今すぐ始めましょう
論文の読解から最終レビューまで、研究時間を劇的に削減しましょう。
クレジットカード登録不要
このレビューはAIが作成し、人間の編集者が確認しました。