デュアルCortex-A9プロセッサ用に、2つの1次元配列の要素ごとの乗算を最適化しています。Linuxがボード上で実行されており、GCC4.5.2コンパイラを使用しています。
したがって、以下は私のC++インラインアセンブラ関数です。src1、src2、およびdstは16バイトで整列されます。
更新:テスト可能なコード:
void Multiply(
const float* __restrict__ src1,
const float* __restrict__ src2,
float* __restrict__ dst,
const unsigned int width,
const unsigned int height)
{
int loopBound = (width * height) / 4;
asm volatile(
".loop: \n\t"
"vld1.32 {q1}, [%[src1]:128]! \n\t"
"vld1.32 {q2}, [%[src2]:128]! \n\t"
"vmul.f32 q0, q1, q2 \n\t"
"vst1.32 {q0}, [%[dst]:128]! \n\t"
"subs %[lBound], %[lBound], $1 \n\t"
"bge .loop \n\t"
:
:[dst] "r" (dst), [src1] "r" (src1), [src2] "r" (src2),
[lBound] "r" (loopBound)
:"memory", "d0", "d1", "d2", "d3", "d4", "d5
);
}
//The following function describes how to test the element wise multiplication
void Test()
{
const unsigned int width = 1024, height = 1024;
float* src1 __attribute__((aligned(16))) = new float[width * height];
float* src2 __attribute__((aligned(16))) = new float[width * height];
float* dst __attribute__((aligned(16))) = new float[width * height];
for(unsigned int i = 0; i < (width * height); i++)
{
src1[i] = (float)rand();
src2[i] = (float)rand();
}
Multiply(src1, src2, dst, width, height);
std::cout << dst[0] << std::endl;
}
1024 * 1024値の計算には、約0.016秒かかります。(2つのスレッド-各スレッドは配列の半分を計算します)。単純に解釈すると、1回の反復の計算には122サイクルかかります。これは少し遅いようです。しかし、ボトルネックはどこにありますか?
L2キャッシュに要素をプリロードするコマンドを試し、pld
反復ごとに最大20の値を計算してループを「展開」し、プロセッサがメモリを待機していないことを確認するために命令を並べ替えました。私はそれほどスピードアップしませんでした(最大0.001秒速くなりました)。
計算を高速化するための提案はありますか?