の最適化:NPOINTS考える2次元空間内の点を回転させるための古典的な式が与えられると、2D回転
cv::Point pt[NPOINTS];
cv::Point rotated[NPOINTS];
float angle = WHATEVER;
float cosine = cos(angle);
float sine = sin(angle);
for (int i = 0; i < NPOINTS; i++)
{
rotated[i].x = pt[i].x * cosine - pt[i].y * sine;
rotated[i].y = pt[i].x * sine + pt[i].y * cosine;
}
が32であり、配列が整列され、どのようにしてSSEまたはAVXのコードを最適化について行きますか?この辺りの検索や他の場所で有益な何かを上げていなかった、と私は約ここに失われてしまった:
__m128i onePoint = _mm_set_epi32(pt[i].x, pt[i].y, pt[i].x, pt[i].y);
__m128 onefPoint = _m128_cvtepi32_ps(onePoint);
__m128 sinCos = _mm_set_ps(cosine, -sine, sine, cosine);
__m128 rotated = _mm_mul_ps(onefPoint, sinCos);
をしかし、どのように[y*cosine, -x*sine, x*sine, y*cosine]
から[y*cosine + -x*sine, x*sine + y*cosine]
に行くために?これが最善のアプローチですか? __m512
に簡単に拡大できますか?
UPDATE:私は少しより多くの研究を行なったし、私は今、約持っている:
__m128i onePoint = _mm_set_epi32(pt[i].x, pt[i].y, pt[i].x, pt[i].y);
__m128 onefPoint = _m128_cvtepi32_ps(onePoint);
__m128i twoPoint = _mm_set_epi32(pt[i+1].x, pt[i+1].y, pt[i+1].x, pt[i+1].y);
__m128 twofPoint = _m128_cvtepi32_ps(twoPoint);
__m128 sinCos = _mm_set_ps(cosine, -sine, sine, cosine);
__m128 rotated1 = _mm_mul_ps(onefPoint, sinCos);
__m128 rotated2 = _mm_mul_ps(twofPoint, sinCos);
__m128 added = _mm_hadd_ps(rotated1, rotated2);
__m128i intResult = _mm_cvtps_epi32(added);
int results[4];
_mm_storeu_si128((__m128i*)results, intResult);
これは、約6%のプロセッサ時間の11%から50%のスピードアップを提供します。 __m256
に拡大し、一度に4つのポイントを実行すると、別のスピードアップが得られます。これはかなりひどいコードに見えますが、私は正しい方向に向かっていますか?
SIMDは、「水平方向」ではなく「垂直方向」に優れています。反復ごとに4ポイントを処理してみてください。 –
@PaulRは正しいです。同時に4つの点を処理すると、より効率的になるだけでなく、代数的にコードがスカラーコードとほとんど同じになります。つまり、組み込み関数を使用してコードを書く方法が明らかになります。 –
AVXの場合は、8点を同時に処理する必要があります(SSEで4点)。 –