2017-02-10 27 views
1

私は一連の操作をループで実行しています。OpenCLでベクターを累積する方法は?

for(int i = 0; i < row; i++) 
{ 
    sum += arr1[0] - arr2[0] 
    sum += arr1[0] - arr2[0] 
    sum += arr1[0] - arr2[0] 
    sum += arr1[0] - arr2[0] 

    arr1 += offset1; 
    arr2 += offset2; 
} 

今、私はこの

for(int i = 0; i < row; i++) 
{ 
    convert_int4(vload4(0, arr1) - vload4(0, arr2)); 

    arr1 += offset1; 
    arr2 += offset2; 
} 

のような操作をベクトル化しようとしている。しかし、どのように私は、ループを使用せずに、スカラsumで得られたベクターを蓄積していますか?

私はOpenCL 2.0を使用しています。

答えて

1

私は自分の問題を解決するために最も近い方法と思われる解決策を見つけました。

uint sum = 0; 
uint4 S; 

for(int i = 0; i < row; i++) 
{ 
    S += convert_uint4(vload4(0, arr1) - vload4(0, arr2)); 

    arr1 += offset1; 
    arr2 += offset2; 
} 

S.s01 = S.s01 + S.s23; 
sum = S.s0 + S.s1; 

のOpenCL 2.0は、上記のようにベクトルの要素を順次加算演算で置き換えることができるベクターで、この機能を提供します。これは、最大16のベクトルまでサポートできます。大きな操作は、小さな操作の要素に分割できます。たとえば、サイズ32の2つのベクトルの差の絶対値を加算するには、次のようにします。

uint sum = 0; 
uint16 S0, S1; 

for(int i = 0; i < row; i++) 
{ 
    S0 += convert_uint16(abs(vload16(0, arr1) - vload16(0, arr2))); 
    S1 += convert_uint16(abs(vload16(1, arr1) - vload16(1, arr2))); 

    arr1 += offset1; 
    arr2 += offset2; 
} 

S0 = S0 + S1; 
S0.s= S0.sS0.s89abcdef; 
S0.s= S0.sS0.s4567; 
S0.s01 = S0.s01 + S0.s23; 
sum = S0.s0 + S0.s1; 
+0

次にcpuはこれと高速でなければならず、ドットプロダクトと同様に余分な乗算がないためです。 –

1

操作は「縮小」と呼ばれ、いくつかの情報があるようです。here

OpenCLの特殊関数が実装されているようですが、work_group_reduce()のように、linkが役に立ちます。

いくつかのコードを含むプレゼンテーション:link

+0

私が理解できる限り、作業グループ内の作業項目です。一方、私のコードでは、それは単一の作業項目です。 –

+0

「削減」は、複数の変数を1つに減らした一般的な概念です。 add、multiply、min、max、XOR、AND、ORなど、さまざまな操作を行うことができます。リンクは、実現のために効率的な並列コードを書く方法のコードを表示します。あらゆる状況が異なるので、私はあなたの問題を解決する簡単な操作があるとは確信していません。 – JHBonarius

1

float2、float4などの場合、最も簡単なバージョンはドットプロダクトである可能性があります。 (int型からfloatへの変換が高価になる可能性があります)

float4 v1=(float4)(1,2,3,4); 
float4 v2=(float4)(5,6,7,8); 

float sum=dot(v1-v2,(float4)(1,1,1,1)); 

これは

(v1.x-v2.x)*1 + (v1.y-v2.y)*1+(v1.z-v2.z)*1+(v1.w-v2.w)*1 

に等しく、それのための任意のハードウェアサポートがある場合、コンパイラの慈悲にそれを残すことは大丈夫でなければなりません。より大きなベクトルや特に配列については、J.H.Bonariusの答えが行く方法です。 GPUにはこのような垂直方向の和演算はありませんが、GPUにはこれがありませんが、移植性のためにドットプロダクトとwork_group_reduceは読みやすさとパフォーマンスを達成する最も簡単な方法です。

ドットプロダクトには余分な乗算があるため、常に良いとは限りません。

+0

なぜこの操作は整数に対してサポートされていませんか? –

+0

ソフトウェア業界の可能性があります。ハードウェアベンダーに求めるのではなく、長年自分の平方根アルゴリズムを書いているゲーム開発者など。また、水平方向の加算を垂直方向の加算に変換することができます。ベクトルと同じように追加できますが、少なくとも4 5個のベクトルが必要です –