问题:
在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)。
答案 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)。当你知道总和很小时,或许值得拥有一个单独的“小”内核?