先日のテストでは Atom に匹敵する実行速度を出していながら、浮動小数演算では
大きく差をつけられる結果となりました。
もう少し詳しく調べたところ、いろいろわかってきました。
結論は
・VFP が遅い
・NEON の SIMD 2/4 を使えばかなり速い
・NEON の単精度スカラー同士の演算は VFP なので遅い
今回は直接命令毎の実行速度を測ってみます。例えば整数乗算なら下記のような感じで。
省略していますが実際には mul 命令を 40 個並べています。
これを 100M 回 (1億) ループします。
static void Start_ASMINT_MUL() { TimerClass timer; timer.Begin(); __asm__ __volatile__( "\ mov r2, #123 \n\ " : : : "r2","cc" ); for( int i= 0 ; i< VECTOR_LOOP ; i++ ){ __asm__ __volatile__( "\ mul r3, r2, r2 \n\ mul r3, r2, r2 \n\ ~ " : : : "r3","cc" ); } timer.End( "ASMINT_MUL" ); }
各種演算命令を並べてテストした結果が下記の通りです。
4000M 命令の実行時間の実測値 (秒) です。
i.MX515 Cortex-A8 (ARM) 800MHz 命令 実行時間 演算ユニットと演算単位 --------------------------------------------------------------- mul r,r,r 10.21 sec ALU 32bit add r,r,r 5.16 sec ALU 32bit fmuls s,s,s 50.45 sec VFP 32bit fadds s,s,s 45.45 sec VFP 32bit fmuld d,d,d 55.49 sec VFP 64bit vmul.f32 s,s,s 50.45 sec VFP 32bit vmul.f32 q,q,q 10.07 sec NEON 128bit (32bit x4) vadd.f32 q,q,q 10.08 sec NEON 128bit (32bit x4) vmla.f32 q,q,q 10.09 sec NEON 128bit (32bit x4) 積和 vmul.f32 d,d,d 5.04 sec NEON 64bit (32bit x2)
命令はパイプラインがストールしないよう、意味がないけど依存が発生しない組み合わせで
並べています。
整数演算は mul でおよそ 392M命令/sec です。add の場合は 775M 命令なので、
ほぼ 1命令/cycle に近い数値で実行出来ていることがわかります。
問題の VFP による浮動小数演算は乗算で 5倍、add 比で 9倍も遅くなっています。
倍精度の乗算でも 10% ほどしか増えていないので、オーバーヘッドは別のところに
あるのかもしれません。
丸めモードや Flush-to-Zero モードなど、FPSCR も書き換えてみましたが結果は同じでした。
なお乗算する値が 0 の場合のみ、fmuls は 3割ほど速い速度で完了します。
対照的に NEON がかなり高速です。4要素(128bit) の SIMD 演算であるにもかかわらず
整数演算と同速度で実行しており、2要素(64bit) の SIMD の場合はむしろ整数演算よりも
高速です。ほぼ 1cycle 毎に 2 float の演算をしています。
さらに積和演算が可能なので、SIMD で vmla を用いた場合
40命令 × 100Mループ × 4 (SIMD) × 2 (積和) / 10sec = およそ 3.2G FLOPS
となります。
ではなぜ普通にコンパイルしたプログラムの浮動小数演算が遅いのかと言えば、NEON の
スカラー演算命令は VFP と共有されているからです。
sレジスタ を用いた演算は、NEON ではなく VFP で実行されます。
実際に vmul.f32 s,s,s は fmuls s,s,s と全く同じバイトコードでした。
コンパイラは一般の浮動小数演算では VFP 命令を出力しています。
結局最初に書いたとおり VFP が非常に遅いという結論になります。
そのためスカラー演算であっても 2/4 ベクタとみなして NEON 命令を使った方が
高速になるわけです。
例えば fmuls s,s,s → vmul.f32 d,d,d なら 10 倍です。
実際のアプリケーションで使ったわけではありませんが、周辺を考えなければ Atom 比でも
結構良い結果になるのではないでしょうか。
これが iPod touch 3G/iPhone 3GS の大きさにも収まっていると考えればなおさらです。
vmla は破壊代入するため、他の命令のように同じオペランドのまま並べると依存が発生して
ストールします。5倍ほど遅くなるので、このテストでは代入側レジスタを 5個用いて
インターリーブしています。quad 時スループット 2 のレイテンシ 10 くらいでしょうか。
関連エントリ
・NetWalker PC-Z1 Atom と速度比較
・NetWalker PC-Z1 Bluetooth とキーカスタムその他
・NetWalker PC-Z1 意外にいける
・Netwalker PC-Z1 買いました
・タッチタイプの境界
・NetWalker PC-Z1