2017-02-10 99 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的兩個向量之間差值的絕對值,我們可以做到以下幾點:

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必須快速與此,因爲沒有多餘的乘法,因爲在點積gpu也是快 –

1

該操作被稱爲「減少」,似乎有關於它的一些信息here

在OpenCL特殊功能似乎實施,其中一個work_group_reduce()可能會幫助您:link

並演示包括一些代碼:link

+0

的減少,據我可以理解,對於在工作組的工作項。而在我的代碼中,它是一個工作項目。 –

+0

「減少」是一個通用概念,其中多個變量被「縮減」爲一個。您可以使用不同的操作:添加,乘法,最小值,最大值,XOR,AND,OR等。這些鏈接會顯示一些關於如何編寫高效的並行代碼以實現的代碼。由於每種情況都不同,我不確定是否有簡單的操作來解決您的問題。 – JHBonarius

1

對於float2,float4等,最簡單的版本可能是點積。 (從int到浮充轉換可能是昂貴的)

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的答案是要走的路。只有CPU有這樣的垂直求和操作,我知道,GPU沒有這個,但爲了可移植性,dot產品和work_group_reduce是實現可讀性和性能的最簡單方法。

點積具有多餘的乘積,所以它可能總是不好。

+0

爲什麼此操作不支持整數? –

+0

也許是因爲軟件行業。例如遊戲開發者長時間編寫自己的平方根算法,而不是向硬件供應商詢問。你也可以轉換你的水平添加垂直添加所以你可以添加就像矢量,但至少需要4 5向量 –