1

我有一组循环运行的操作。

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。

4

3 回答 3

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 

如果有任何硬件支持,让它交给编译器处理应该没问题。对于较大的向量,尤其是数组,JHBonarius 的答案是要走的路。据我所知,只有 CPU 有这样的垂直求和运算,GPU 没有,但为了便携性,点积和 work_group_reduce 是实现可读性甚至性能的最简单方法。

点积有额外的乘法,所以它可能并不总是好的。

于 2017-02-10T15:22:50.343 回答
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.s01234567 = S0.s01234567 + S0.s89abcdef;
S0.s0123 = S0.s0123 + S0.s4567;
S0.s01 = S0.s01 + S0.s23;
sum = S0.s0 + S0.s1;
于 2017-02-11T12:53:37.417 回答
1

该操作称为“减少”,这里似乎有一些信息。

在 OpenCL 中似乎实现了特殊功能,其中一个work_group_reduce()可能对您有所帮助:link

还有一个包含一些代码的演示文稿:链接

于 2017-02-10T10:18:40.520 回答