1

ベクトル化の最適化問題があります。

'red'、'green'、'blue'という名前の3つのフィールドを持つ構造体pDstがあります。
タイプは「Char」、「Short」、または「Float」の場合があります。これは指定されており、変更できません。
画像を表す別の配列pSrcがあります[RGB]-つまり、3つのポインターの配列であり、それらのすべてが画像のレイヤーを指します。
各レイヤーは、IPPプレーン指向のイメージを使用して構築されます(つまり、各プレーンは独立して形成されます-'ippiMalloc_32f_C1'): http ://software.intel.com/sites/products/documentation/hpc/ipp/ippi/ippi_ch3/functn_Malloc.html 。

次のコードで説明されているようにコピーします。

for(int y = 0; y < imageHeight; ++y)
{
    for(int x = 0; x < imageWidth; ++x)
    {
        pDst[x + y * pDstRowStep].red     = pSrc[0][x + y * pSrcRowStep];
        pDst[x + y * pDstRowStep].green   = pSrc[1][x + y * pSrcRowStep];
        pDst[x + y * pDstRowStep].blue    = pSrc[2][x + y * pSrcRowStep];
    }
} 

ただし、この形式では、コンパイラはコードをベクトル化できません。
最初にそれは言う:

「ループはベクトル化されませんでした:ベクトル依存性の存在。」

#pragma ivdepを使用してコンパイラーを支援すると(依存関係がないため)、次のエラーが発生します。

「ループはベクトル化されませんでした:逆参照が複雑すぎます。」

誰かがベクトル化を許可する方法を知っていますか?
インテル®コンパイラ13.0を使用しています。
ありがとう。

アップデート:

次のようにコードを編集した場合:

Ipp32f *redChannel      = pSrc[0];
Ipp32f *greenChannel  = pSrc[1];
Ipp32f *blueChannel     = pSrc[2];
for(int y = 0; y < imageHeight; ++y)
{
    #pragma ivdep
    for(int x = 0; x < imageWidth; ++x)
    {
        pDst[x + y * pDstRowStep].red     = redChannel[x + y * pSrcRowStep];
        pDst[x + y * pDstRowStep].green   = greenChannel[x + y * pSrcRowStep];
        pDst[x + y * pDstRowStep].blue    = blueChannel[x + y * pSrcRowStep];
    }
}

'char'および'short'の出力タイプの場合、vecotizationを取得します。
しかし、「フロート」のタイプについては、私はしません。
代わりに、次のメッセージが表示されます。

ループはベクトル化されませんでした:ベクトル化は可能ですが、非効率的なようです。

どうしてそうなるのでしょうか?

4

2 に答える 2

1

それらの線に沿った何かが機能するはずです(charバージョン、テストされていません。また、__ m128iポインターが適切に整列されている必要があることに注意してください!)

void interleave_16px_to_rgb0(__m128i *red, __m128i *green, __m128i *blue, __m128i *dest) {
  __m128i zero = _mm_setzero_si128();
  __m128i rg_0 = _mm_unpackhi_epi8(*red, *green);
  __m128i rg_1 = _mm_unpacklo_epi8(*red, *green);
  __m128i bz_0 = _mm_unpackhi_epi8(*blue, zero);
  __m128i bz_1 = _mm_unpacklo_epi8(*blue, zero);
  dest[0] = _mm_unpackhi_epi16(rg_0, bz_0);
  dest[1] = _mm_unpacklo_epi16(rg_0, bz_0);
  dest[2] = _mm_unpackhi_epi16(rg_1, bz_1);
  dest[3] = _mm_unpacklo_epi16(rg_1, bz_1);
}

これは、各プレーンから16バイトかかります。

r0 r1 r2 ... r16
g0 g1 g2 ... g16
b0 b1 b2 ... b16

そして、そのようにそれらをインターリーブし、*dest:から始まる16x4バイトを書き出します。

r0 g0 b0 0 r1 g1 b1 0 r2 g2 b2 0 ... r16 g16 b16 0

言うまでもなく、同じ関数ファミリーを使用して、他のデータ型をインターリーブすることもできます。


更新:さらに良いことに、すでにIPPを持っているので、車輪の再発明ではなく、提供されているものを使用するようにしてください。簡単なチェックから、ippiCopy_8u_P3C3RまたはippiCopy_8u_P4C4Rが探しているものであるように見えます。

于 2012-10-03T12:54:43.627 に答える
1

次のコードでは、プラグマivdepを使用してもベクトルの依存関係は確実に無視されますが、コンパイラのヒューリスティック/コスト分析により、ループのベクトル化は効率的ではないという結論に達しました。

Ipp32f *redChannel      = pSrc[0];
Ipp32f *greenChannel  = pSrc[1];
Ipp32f *blueChannel     = pSrc[2];
for(int y = 0; y < imageHeight; ++y)
{
    #pragma ivdep
    for(int x = 0; x < imageWidth; ++x)
    {
        pDst[x + y * pDstRowStep].red     = redChannel[x + y * pSrcRowStep];
        pDst[x + y * pDstRowStep].green   = greenChannel[x + y * pSrcRowStep];
        pDst[x + y * pDstRowStep].blue    = blueChannel[x + y * pSrcRowStep];
    }
}

この操作では、メモリの連続ブロックをソースから宛先の非連続メモリ位置にコピーする必要があるため、ベクトル化は非効率的です。ですから、ここで散らばっています。それでもベクトル化を実施し、ベクトル化されていないバージョンと比較してパフォーマンスが向上するかどうかを確認する場合は、以下に示すように、pragmaivdepの代わりにpragmasimdを使用してください。

#include<ipp.h>
struct Dest{
float red;
float green;
float blue;
};
void foo(Dest *pDst, Ipp32f **pSrc, int imageHeight, int imageWidth, int pSrcRowStep, int pDstRowStep){
    Ipp32f *redChannel      = pSrc[0];
    Ipp32f *greenChannel  = pSrc[1];
    Ipp32f *blueChannel     = pSrc[2];
    for(int y = 0; y < imageHeight; ++y)
    {
        #pragma simd
        for(int x = 0; x < imageWidth; ++x)
        {
            pDst[x + y * pDstRowStep].red     = redChannel[x + y * pSrcRowStep];
            pDst[x + y * pDstRowStep].green   = greenChannel[x + y * pSrcRowStep];
            pDst[x + y * pDstRowStep].blue    = blueChannel[x + y * pSrcRowStep];
        }
    }
    return;
}

対応するベクトル化レポートは次のとおりです。

$ icpc -c test.cc -vec-report2
test.cc(14): (col. 9) remark: SIMD LOOP WAS VECTORIZED
test.cc(11): (col. 5) remark: loop was not vectorized: not inner loop

プラグマsimdの詳細については、https: //software.intel.com/en-us/node/514582を参照してください。

于 2014-05-07T17:05:55.127 に答える