CvMatのアライメントの問題

  • SSE2の転送命令*1は16バイト境界のメモリアドレスを指定しないと例外が飛ぶ
  • CV_MALLOC_ALIGN=>32なのでCvAllocは32バイト境界でメモリアドレスを返してくれるが、CV_DEFAULT_MAT_ROW_ALIGN=>1になっているので、CvMat->data.ptr[CvMat->step * (CvMat->row / n)]*2が16バイト境界になるとは限らない
  • \(^o^)/

対応方法

  1. 16バイト境界になっていなくてもOKな転送命令*3を使う
  2. CV_DEFAULT_MAT_ROW_ALIGN=>16にしてコンパイルする

1は、パフォーマンス的に不利なようだし、2はコンパイルしたOpenCVごと環境に配置する必要があり悲しい。

*1:MOVDQA,_mm_load_*など

*2:行列の各行の先頭アドレス

*3:MOVDQU,_mm_loadu_*など

CPUとアセンブリ

言語としてのx86アセンブリ(gasとかnasmとか)は微妙に分かってるけど、CPUの動きには詳しくないので、書いてみたもののあまりよい結果にならないことが多い。素人的には計算数が減ればその分速くなるだろうと思っていたけど、ぜんぜんそうでもない。ある程度までの計算なら計算結果をメモリにキャッシュするよりも何度でも再計算したほうが速いことがあるし、SIMDで4つ同時に計算しても逆に遅くなることがある。このへんはCPUのキャッシュとか命令のレイテンシとかが絡んでるんだろうとは思うけど、パッと最適な方法が分からない。試してみてどうだったーレベル。
言語の文法だけ分かっていてもあまり意味ねえという話。
もともと自分がアセンブリ言語をやった理由は、HackersLab にあったsuidされたバッファオーバーフローするプログラムがあるからそれのexploitを書いて乗っ取れみたいな問題のためだったし、その後も犯罪的なプログラムを書いてみたり、Winnyを解析したりとか、そういう怪しげな知識だし、まあこんなものだくそがーという感じなので、もっとがんばろう。