6

フロートのタブが2つあります。最初のタブの要素に2番目のタブの対応する要素を掛けて、結果を3番目のタブに保存する必要があります。

NEONを使用してfloat乗算を並列化したいと思います。1つではなく4つのfloat乗算を同時に実行します。

大幅な加速を期待していましたが、実行時間の短縮は約20%しか達成できませんでした。これは私のコードです:

#include <stdlib.h>
#include <iostream>
#include <arm_neon.h>

const int n = 100; // table size

/* fill a tab with random floats */
void rand_tab(float *t) {
    for (int i = 0; i < n; i++)
        t[i] = (float)rand()/(float)RAND_MAX;
}

/* Multiply elements of two tabs and store results in third tab
 - STANDARD processing. */
void mul_tab_standard(float *t1, float *t2, float *tr) {
    for (int i = 0; i < n; i++)
         tr[i] = t1[i] * t2[i]; 
}

/* Multiply elements of two tabs and store results in third tab 
- NEON processing. */
void mul_tab_neon(float *t1, float *t2, float *tr) {
    for (int i = 0; i < n; i+=4)
        vst1q_f32(tr+i, vmulq_f32(vld1q_f32(t1+i), vld1q_f32(t2+i)));
}

int main() {
    float t1[n], t2[n], tr[n];

    /* fill tables with random values */
    srand(1); rand_tab(t1); rand_tab(t2);


    // I repeat table multiplication function 1000000 times for measuring purposes:
    for (int k=0; k < 1000000; k++)
        mul_tab_standard(t1, t2, tr);  // switch to next line for comparison:
    //mul_tab_neon(t1, t2, tr);  
    return 1;
}

次のコマンドを実行してコンパイルします:g ++ -mfpu = neon -ffast-math neon_test.cpp

私のCPU:ARMv7プロセッサrev 0(v7l)

より大幅なスピードアップを実現する方法について何かアイデアはありますか?

4

2 に答える 2

5

Cortex-A8 と Cortex-A9 は、1 サイクルあたり 2 つの SP FP 乗算しか実行できないため、これらの (最も一般的な) CPU のパフォーマンスはせいぜい 2 倍になります。実際には、ARM CPU の IPC は非常に低いため、可能な限りループを展開することをお勧めします。究極のパフォーマンスが必要な場合は、アセンブリで記述します。ARM 用の gcc のコード ジェネレーターは、x86 ほど優れていません。

また、CPU 固有の最適化オプションを使用することをお勧めします。Cortex-A15、Cortex-A8、および Cortex-A5 の場合は、それに応じて -mcpu=-mtune=cortex-a15/a8/a5 を置き換えます。gcc には Qualcomm CPU 用の最適化がないため、Qualcomm Scorpion の場合は Cortex-A8 パラメータを使用し (また、通常よりも多く展開します)、Qualcomm Krait の場合は Cortex-A15 パラメータを試してください (サポートする gcc の最新バージョンが必要です)。それ)。

于 2012-09-14T08:49:10.573 に答える
2

ネオン組み込みの欠点の 1 つは、ロード時に自動インクリメントを使用できないことです。これは、ネオンの実装で追加の命令として表示されます。

gcc バージョン 4.4.3 およびオプション-c -std=c99 -mfpu=neon -O3でコンパイルされ、objdump でダンプされます。これは、mul_tab_neon のループ部分です。

000000a4 <mul_tab_neon>:
  ac:   e0805003    add r5, r0, r3
  b0:   e0814003    add r4, r1, r3
  b4:   e082c003    add ip, r2, r3
  b8:   e2833010    add r3, r3, #16
  bc:   f4650a8f    vld1.32 {d16-d17}, [r5]
  c0:   f4642a8f    vld1.32 {d18-d19}, [r4]
  c4:   e3530e19    cmp r3, #400    ; 0x190
  c8:   f3400df2    vmul.f32    q8, q8, q9
  cc:   f44c0a8f    vst1.32 {d16-d17}, [ip]
  d0:   1afffff5    bne ac <mul_tab_neon+0x8>

これは mul_tab_standard のループ部分です

00000000 <mul_tab_standard>:
  58:   ecf01b02    vldmia  r0!, {d17}
  5c:   ecf10b02    vldmia  r1!, {d16}
  60:   f3410db0    vmul.f32    d16, d17, d16
  64:   ece20b02    vstmia  r2!, {d16}
  68:   e1520003    cmp r2, r3
  6c:   1afffff9    bne 58 <mul_tab_standard+0x58>

標準的なケースでわかるように、コンパイラはよりタイトなループを作成します。

于 2012-09-30T20:39:06.027 に答える