TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

AndroidスマホにおけるJavaとNativeの速度比較

Androidのアプリで、FFTの計算をNDKでNativeで実装した場合に、速くなるか検証してみた。

測定条件
  • 大浦版FFTJavaに移植したコードとC言語のコードを使用する
  • FFTのフレームサイズは4096
  • NativeはNDKでJNIのメソッドとして実装する
  • NativeのメソッドはJavaから1回ずつコールする
  • 数回実行して速度が安定してから、1000回実行した時間を測定
  • 10回測定して平均をとる
測定結果

測定結果は以下のようになった。

機種名 OSバージョン CPU FFT Native FFT Java Native/Java
003SH 2.3.4 MSM8255 1GHz 3182 3202 0.99
200SH 4.1.2 MSM8960 1.5GHz 1534 1500 1.02
303SH 4.2.2 MSM8974 2.2GHz 1019 986 1.03
SH-RM02 5.0.2 MSM8926 1.2GHz 2699 2506 1.08
Nexus7(2013) 6.0.1 APQ8064 1.5GHz 1660 2655 0.63
iPad Pro(参考) 10.1.1 A9X 2.25GHz 251

※単位ms


Nexus7(2013)以外、JavaとNativeでほとんど変わらないという結果になった。
むしろNativeの方が遅くなっているものもある。
Nexus7(2013)だけは、Nativeが速くなっているが、CPUによるのか、OSバージョンによるのかは分からない。

参考に測定したiPad Proは、Androidで最速だった303SHよりも、CPUクロックは近いにも関わらず、約4倍速い。

追試

JavaからJNIのメソッドをコールするとオーバーヘッドが発生するので、実用的な使い方とは異なるが、Native内で1000回ループして測定してみた。

機種名 OSバージョン CPU FFT Native FFT Native2 FFT Native2/FFT Native
003SH 2.3.4 MSM8255 1GHz 3182 3143 0.99
200SH 4.1.2 MSM8960 1.5GHz 1534 15130 0.99
303SH 4.2.2 MSM8974 2.2GHz 1019 991 0.97
SH-RM02 5.0.2 MSM8926 1.2GHz 2699 1939 0.72
Nexus7(2013) 6.0.1 APQ8064 1.5GHz 1660 1099 0.66

FFT Native2がNative内でループした版

全ての機種で、Native内でループした方が速くなっている。
このことはJNIの呼び出しにオーバーヘッドがあることを示している。

SH-RM02とNexus7(2013)については、Native内でループした場合の改善が他に比べて顕著である。
AndroidのOSのバージョン5以上で、バージョン5からJava仮想マシンがDalvikからARTに変更になっていることが関係しているかもしれない。


JNI呼び出しのオーバーヘッドをなくした場合でも、Androidで最速だった303SHに比べてiPad Proは3.95倍速い。
CPUクロックは近いので、CPUのアーキテクチャの差によるものなのか、OSがバッテーリー管理との兼ね合いでどれだけCPUをフルで使うかによるのか興味があるが、検証するのは難しそうだ。

結論

測定した機種のサンプルが少ないのではっきり結論は出せないが、測定結果からは、Javaで実装しているメソッドをJNI呼び出しでNativeにすることは速度改善効果がない。
JNIの呼び出しが少なくなるようにNative内で繰り返し処理を行うようにすれば、場合によっては速度改善することができる。