11

2つの画像ブロックが1D配列として格納されており、それらの要素間で次のビット単位のAND演算を実行しています。

int compare(unsigned char *a, int a_pitch, 
            unsigned char *b, int b_pitch, int a_lenx, int a_leny) 
{
    int overlap =0 ;

    for(int y=0; y<a_leny; y++) 
        for(int x=0; x<a_lenx; x++) 
        {
            if(a[x + y * a_pitch] & b[x+y*b_pitch]) 
                overlap++ ;
        }
    return overlap ;
}

実際、私はこの仕事を約22万回しなければならないので、iPhoneデバイスでは非常に遅くなります。

iPhoneでこの仕事を加速するにはどうすればよいですか?

NEONは役に立つと聞きましたが、あまり馴染みがありません。さらに、NEONにはビット単位のANDがないようです...

4

3 に答える 3

2

オプション 1 - プラットフォームのネイティブ幅で作業します (一度に 1 バイトずつデータをフェッチして比較するよりも、レジスタに 32 ビットをフェッチしてからそのレジスタで操作を行う方が高速です)。

int compare(unsigned char *a, int a_pitch, 
            unsigned char *b, int b_pitch, int a_lenx, int a_leny) 
{
    int overlap = 0;
    uint32_t* a_int = (uint32_t*)a;
    uint32_t* b_int = (uint32_t*)b;

    a_leny = a_leny / 4;
    a_lenx = a_lenx / 4;
    a_pitch = a_pitch / 4;
    b_pitch = b_pitch / 4;

    for(int y=0; y<a_leny_int; y++) 
        for(int x=0; x<a_lenx_int; x++) 
        {
            uint32_t aVal = a_int[x + y * a_pitch_int];
            uint32_t bVal = b_int[x+y*b_pitch_int];
            if (aVal & 0xFF) & (bVal & 0xFF)
                overlap++;
            if ((aVal >> 8) & 0xFF) & ((bVal >> 8) & 0xFF)
                overlap++;
            if ((aVal >> 16) & 0xFF) & ((bVal >> 16) & 0xFF)
                overlap++;
            if ((aVal >> 24) & 0xFF) & ((bVal >> 24) & 0xFF)
                overlap++;
        }
    return overlap ;
}

オプション 2 - ヒューリスティックを使用して、より少ない計算で概算結果を取得します (101 回のオーバーラップと 100 回のオーバーラップの絶対差がアプリケーションにとって重要でない場合は、適切な方法です)。

int compare(unsigned char *a, int a_pitch, 
            unsigned char *b, int b_pitch, int a_lenx, int a_leny) 
{
    int overlap =0 ;

    for(int y=0; y<a_leny; y+= 10) 
        for(int x=0; x<a_lenx; x+= 10) 
        {
            //we compare 1% of all the pixels, and use that as the result
            if(a[x + y * a_pitch] & b[x+y*b_pitch]) 
                overlap++ ;
        }
    return overlap * 100;
}

オプション 3 - インライン アセンブリ コードで関数を書き直します。あなたはこれのためにあなた自身です。

于 2011-06-14T03:49:41.183 に答える
1

あなたのコードは CPU の Rambo です - その最悪の悪夢:

  • バイトアクセス。前述のように、ARMはメモリからバイトを読み取るのが非常に遅い
  • ランダムアクセス。その性質上、すでに急激なパフォーマンスの低下に加えて、絶対に不要な 2 つの乗算/加算操作。

簡単に言えば、間違っている可能性があるものはすべて間違っています。

私を無礼と呼ばないでください。代わりに私をあなたの天使にさせてください。

まず、動作する NEON バージョンを提供します。次に、最適化された C バージョンで、何が間違っていたかを正確に示します。

少し時間をください。私は今すぐ寝なければなりません、そして明日は重要な会議があります。

ARMのアセンブリを学びませんか?x86 アセンブリよりもはるかに簡単で便利です。また、C プログラミング機能も大幅に向上します。強く推奨する

ちゃあ

================================================== ============================

OK、これは ARM アセンブリを念頭に置いて C で書かれた最適化されたバージョンです。

ピッチと a_lenx の両方が 4 の倍数でなければならないことに注意してください。そうでないと、適切に動作しません。

このバージョンでは、ARM アセンブリを最適化する余地はあまりありません。(NEON は別の話です - 近日公開)

変数の宣言、ループ、メモリ アクセス、および AND 演算の処理方法をよく見てください。

また、最良の結果を得るには、この関数が Thumb ではなく ARM モードで実行されるようにしてください。

unsigned int compare(unsigned int *a, unsigned int a_pitch, 
            unsigned int *b, unsigned int b_pitch, unsigned int a_lenx, unsigned int a_leny) 
{
    unsigned int overlap =0;
    unsigned int a_gap = (a_pitch - a_lenx)>>2;
    unsigned int b_gap = (b_pitch - a_lenx)>>2;
    unsigned int aval, bval, xcount;

    do
    {
        xcount = (a_lenx>>2);
        do
        {
            aval = *a++;
            // ldr      aval, [a], #4
            bval = *b++;
            // ldr      bavl, [b], #4
            aval &= bval;
            // and      aval, aval, bval

            if (aval & 0x000000ff) overlap += 1;
            // tst      aval, #0x000000ff
            // addne    overlap, overlap, #1
            if (aval & 0x0000ff00) overlap += 1;
            // tst      aval, #0x0000ff00
            // addne    overlap, overlap, #1
            if (aval & 0x00ff0000) overlap += 1;
            // tst      aval, #0x00ff0000
            // addne    overlap, overlap, #1
            if (aval & 0xff000000) overlap += 1;
            // tst      aval, #0xff000000
            // addne    overlap, overlap, #1
        } while (--xcount);

        a += a_gap;
        b += b_gap;
    } while (--a_leny);

    return overlap;
}
于 2011-11-01T15:15:30.927 に答える
0

まず第一に、なぜダブルループなのか?あなたは単一のループといくつかのポインタでそれを行うことができます。

また、すべてのピクセルに対してx + y*pitchを計算する必要はありません。2つのポインタを1つ増やすだけです。1ずつインクリメントする方が、x + y*pitchよりもはるかに高速です。

なぜこの操作を正確に実行する必要があるのですか?NEONのような低レベルのソリューションを検討する前に、利用可能な高レベルの最適化/変更がないことを確認します。

于 2011-06-14T03:42:54.480 に答える