Androidのアプリで、FFTの計算をNDKでNativeで実装した場合に、速くなるか検証してみた。
測定条件
測定結果
測定結果は以下のようになった。
機種名 | 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内で繰り返し処理を行うようにすれば、場合によっては速度改善することができる。