2017-02-10 76 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向量 –