Eigen::Matrix4fとMatrix4dのSIMDによる速度差

Matrix4fはMatrix4dより速い?

Eigenを使う理由の一つに自動ベクトル化がある.例えば,ベクトルの大きさがSSEであれば128bit (float x 4),AVXであれば256bit (float x 8)以上であれば自動的にSIMD演算を使って処理を高速化してくれる.このときにスカラ型をdoubleでなくfloatにしておけば同時にたくさんのデータを処理できるのでより速くなる...と昔ベンチマークをして思っていたのだが,必ずしもそうでもないことに最近気がついた.せっかくなので最近取り直したベンチマークの記録を残しておく.

ベンチマークに使う式はなるべく実際の用途に近いものが良かったのでGICPコスト風の以下の式を使った(比較を簡単にするため逆行列は外した).
\large d_i = R x^A_i + t - x^B_i \\ e = \sum_i d_i^T (C_i^B + R C_i^A T^T) d_i
\large R \in \mathbb{R}^{N \times N}, t \in \mathbb{R}^{N}, x^*_i \in \mathbb{R}^{N}, C^*_i \in \mathbb{R}^{N \times N}

この式の次元数 N を変えたときに秒数あたりに処理できる点数を計測した結果が以下である.縦軸(対数表示)が大きいほどたくさんのデータを処理できる=処理速度が速いということになる.上図はAVXを有効にしてビルドした結果,下図はSSEのみ有効でビルドした結果となっている.

上図のAVXの結果を見てみると,N=1のときはfloatもdoubleもSIMDが使えないので全く同じ処理速度になっている.N=2およびN=3のときはdoubleのほうが大幅に速い.これはfloat x 3 = 96bitだと小さすぎてSSE演算すら使えないのに対して,double x 3 = 192bitなら128bitよりは大きいため一部の計算にはSSEが使えるからである.floatはN=4のときにようやくSSEが使えるようになるので大幅に高速になるが,doubleもAVXで4データ同時処理できるためほぼ同速度になっている.その後もN=5のときはわずかにfloatが速いが,N=6, 7のときは細かい粒度でSSEを使えるdoubleのほうが速い.安定してfloatのほうが速くなるのはAVXの256bit幅を超えるN=8以上になってからのようだ.

下図のAVX無効でSSEのみ有効のときも基本的には似たような傾向であるが,N=4N=8以上のときはより多くのデータを処理できることが効いてfloatとdouble間の速度が大きくなっている.

まとめ

処理に使う数式やプログラム構造にもよるが,AVXを使える場合には基本的にdoubleを使っておくのがいいように思う.特にN<8の低次元においてはfloatはAVXを活用できないため速度的なアドバンテージはほとんど期待できない(むしろキャストなどで遅くなることもままある).今回は固定サイズ行列でテストしたが動的サイズでも似たような傾向になるのかなと思う.AVXが使えないようなCPU(ARM除く)を使っている場合には早急に買い替えたほうがいいと思う.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください