Opencl,整数向量元素的总和

时间:2015-09-23 13:30:59

标签: integer sum opencl long-integer reduce

问题:

在Opencl 1.2中,没有像

这样的内置函数
long sum_int4_elements_into_long(int4 v);

我尝试过的事情:

所以我使用下面的代码(预先展开的循环的内部部分)

// acc is long
int4 tmp=arr[i+7];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+6];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+5];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+4];"
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+3];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+2];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i+1];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;
tmp=arr[i];
acc+=tmp.x+tmp.y+tmp.z+tmp.w;       

将整数数组(int4 arr)的所有元素求和(减少)为一个长变量,与串行代码相比,加速度仅为+%20到+%30。如果能够启用SSE或AVX,它会更快。

也尝试过:

使用纯整数累加器将求和运算加速3倍但整数溢出,所以我只能使用长变量。然后我尝试使用long4和long2变量作为

   // acc is a long4, arr is an int4 array
   acc+=convert_long4(arr[...]) 

  //  acc is a long2, arr is an int2 array
   acc+=convert_long2(arr[...])   

但它失败并锁定了计算机(检查了索引和限制,没有问题)所以在与AMD CPU的硬件指令映射下longn to intn一定存在问题。

澄清:

必须有一些AMD和INTEL的等效SIMD(SSE或AVX)汇编指令

        32 bit integers in a 128-bit SSE register
         |       |       |      |        
  acc+=tmp.x + tmp.y + tmp.z + tmp.w
   ^    
   | 
  64-bit register 

但不知何故opencl没有映射到这个或我没有包装C99 指令很好,所以cl-compiler不能使用SSE / AVX指令。

最近的内置浮动版本是

 acc=dot(v,(float4)(1,1,1,1));

但我需要一个整数版本,因为fp需要Kahan的求和校正,这需要额外的时间。

修改

我不确定int + int + int + int是否会有一个正确的长结果,或者只是将一个溢出的int转换为long。

Opencl版本:1.2在CPU上运行(Java ----> Jocl)

CPU:AMD fx-8150

OS:64位Windows 10

司机:最新的amd。

日期:2015年9月23日

进行比较:

16M 32位整数,FX8150 @ 3300MHz(8个核心中使用6个核心)

java 1.8_25上的串行代码平均需要16.5 ms。

Java-1.8的IntStream平均需要13.5毫秒(X.reduce(0,Integer :: sum))

此问题中的并行代码平均需要12.5毫秒 (使用单个工作组

此问题中的并行代码平均需要5.8毫秒 (使用四个工作组

并行但溢出的非长版需要5ms。 (达到内存带宽)

mfa的回答:

 acc=dot(v,(double4)(1,1,1,1));

平均需要13.5 ms,但浮动版本平均需要12.2 ms。

我不确定浮点数是否可以保持其精度始终为一个非常大的fp数加1.0(或甚至0.0)。

2 个答案:

答案 0 :(得分:2)

减少的速度是多少?也许并不是那么糟糕。

long4 lv = (long4)v;
long2 t = lv.xy + lv.zw;
acc += t.x + t.y;

另外,如果您真正想要的是减少多个项目,而不是单个int4。然后在long4空间中对它们求和,然后仅减少最后一个。

long4 sums = long4(0);
sums += convert_long4(arr[0]);
sums += convert_long4(arr[1]);
sums += convert_long4(arr[2]);
...
sums += convert_long4(arr[N-1]);
sums += convert_long4(arr[N]);
long2 t = sums.xy + sums.zw;
long res = t.x + t.y;

注意:如果这是您正在进行的唯一操作,则内​​存瓶颈可能是此处的主要问题。因此,测量内核执行时间会产生高度偏向的结果。

答案 1 :(得分:1)

4个整数的总和将适合双精度浮点数。你试过这个吗?

   double acc;
   acc=dot(v,(double4)(1,1,1,1));

你能发布这个时间吗?

编辑:添加更多信息。

  

双版本平均花费13.2毫秒,而浮动版本花费12.2毫秒   ms平均但我不确定浮动加法是否保持整数'   量子步骤永远。它在大型浮筒上的精确度是否足以满足要求   它要添加1.0还是0.0?

额外的精度绝对可以增加1ms。在一些较旧的AMD GPU硬件上,双重操作实际上需要两倍的时间,因为它们实际上一起使用两个浮点寄存器。当您考虑到数学上说双精度运算最多可以组合8个单独的精度运算时,您可以计算出您正在测量的性能略有下降。总的来说,我认为你的CPU在浮点数方面的表现相当不错。

如果总和保持在24位长以下,则单精度不会溢出。 More about this here.双打允许54位精度(here)。当你知道总和很小时,或许值得拥有一个单独的“小”内核?