0
現在、NEON命令を使用するために画像処理コードの一部を最適化しようとしています。NEONの実行時間が増加する
私は非常に大きなフロート配列を持っていて、最初のもののそれぞれの値に2番目のものの3つの連続する値を掛けたいとしましょう。 (もう一つは、大の3倍である。)
float* l_ptrGauss_pf32 = [...];
float* l_ptrLaplace_pf32 = [...]; // Three times as large
for (uint64_t k = 0; k < l_numPixels_ui64; ++k)
{
float l_weight_f32 = *l_ptrGauss_pf32;
*l_ptrLaplace_pf32 *= l_weight_f32;
++l_ptrLaplace_pf32;
*l_ptrLaplace_pf32 *= l_weight_f32;
++l_ptrLaplace_pf32;
*l_ptrLaplace_pf32 *= l_weight_f32;
++l_ptrLaplace_pf32;
++l_ptrGauss_pf32;
}
私はNEON組み込み関数で上記のコードを交換するときに、実行時間は、約10%長いです。
float32x4_t l_gaussElem_f32x4;
float32x4_t l_laplElem1_f32x4;
float32x4_t l_laplElem2_f32x4;
float32x4_t l_laplElem3_f32x4;
for(uint64_t k=0; k<(l_lastPixelInBlock_ui64/4); ++k)
{
l_gaussElem_f32x4 = vld1q_f32(l_ptrGauss_pf32);
l_laplElem1_f32x4 = vld1q_f32(l_ptrLaplace_pf32);
l_laplElem2_f32x4 = vld1q_f32(l_ptrLaplace_pf32+4);
l_laplElem3_f32x4 = vld1q_f32(l_ptrLaplace_pf32+8);
l_laplElem1_f32x4 = vmulq_f32(l_gaussElem_f32x4, l_laplElem1_f32x4);
l_laplElem2_f32x4 = vmulq_f32(l_gaussElem_f32x4, l_laplElem2_f32x4);
l_laplElem3_f32x4 = vmulq_f32(l_gaussElem_f32x4, l_laplElem3_f32x4);
vst1q_f32(l_ptrLaplace_pf32, l_laplElem1_f32x4);
vst1q_f32(l_ptrLaplace_pf32+4, l_laplElem2_f32x4);
vst1q_f32(l_ptrLaplace_pf32+8, l_laplElem3_f32x4);
l_ptrLaplace_pf32 += 12;
l_ptrGauss_pf32 += 4;
}
両方のバージョンは、Apple LLVM 8.0を使用して-Ofastでコンパイルされます。コンパイラはNEON組み込み関数がなくてもこのコードを最適化することができますか?
あなたは、コンパイラによって生成されたコードを点検しましたか? Clangは、組み込み関数に頼ることなくNeon命令を使用します(インライン展開を使用する場合よりも優れています) intrinsicsは "正確にこのようにする必要がある"とみなされる傾向があります)。 –
手をアンロールしたためにループのアンロールやその他の再配置が異なることもあります。 –
これはarmv7またはarm64用ですか?また、マイナータンジェントですが、 'k 'と' l_lastPixelInBlock_ui64'(armv7は32ビットであるため)に 'size_t'を使うほうが良いでしょう。さらに、ポインターエイリアスはできますか?そうでない場合、それらを 'restrict'とマークすると助けになるはずです。 – Cornstalks