当前位置: 首页 > 知识库问答 >
问题:

opencl,整数向量元素的和

耿弘阔
2023-03-14

问题:

在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)的所有元素求和(减少)为一个长变量,与串行代码相比,其速度仅为0。如果它能启用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到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编译器无法使用SSE/AVX指令。

最接近的内置浮动版本是

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

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

编辑:

我不确定int int int是否会有一个合适的long结果,或者只是有一个溢出的int变成long。

opencl版本:1.2在CPU上运行(Java----

CPU: AMD fx-8150

操作系统:64位Windows 10

司机:amd最新一款。

日期:2015年9月23日

供比较:

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

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

Java-1.8的IntStream平均耗时13.5ms(X.减少(0,整数::总和))

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

本题中的并行代码平均耗时5.8 ms(使用四个工作组)

并行但溢出的非长版本需要5毫秒。(命中内存带宽)

外交部的回答:

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

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

我不确定一个浮点数是否能始终保持其精度,在一个非常大的fp数上加1.0(甚至0.0)。

共有2个答案

富建章
2023-03-14

4整数之和将适用于双精度浮点。你试过这个吗?

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

你能把这个时间也贴出来吗?

编辑:添加更多信息。

双版本平均耗时13.2毫秒,而浮点版本平均耗时12.2毫秒,但我不确定浮点加法是否总是保持整数的量子步长。它在大浮点数上的精确度是否足以让它增加1.0或0.0?

额外的精度肯定会增加额外的1毫秒。在一些旧的AMD GPU硬件上,双操作实际上需要两倍的时间,因为它们实际上同时使用两个浮点寄存器。当你认为在数学上说双精度操作达到8个单独的单精度OPS组合时,你正在测量的性能的轻微下降也可以考虑。总的来说,我认为你的CPU做得很好,相对于浮点数来说是双倍的。

如果总和长度小于24位,则单精度不会溢出。这里有更多关于这个的信息。双精度允许54位精度(此处)。也许当你知道总数很小的时候,有一个单独的“小”内核是值得的?

郭凯
2023-03-14

减少的速度是多少?说不定也没那么糟。

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

此外,如果你真正想要的是减少多个项目,而不是一个单一的int4。然后用长4空间求和,然后只减少最后一个。

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;

注意:如果这是你正在做的唯一操作,内存瓶颈可能是这里的主要问题。因此,测量内核执行时间将给出一个高度偏差的结果。

 类似资料:
  • 这应该很容易,但我一直在撞我的头。 我有数字向量 我有一个数值向量v2。v2始终是v1的子集。 我想从v1中删除v2中的所有元素,但每个v2元素只删除一个(而且完全是一个)v1元素。 所需输出 如果我希望将保留在v1之外。使用很容易。 如果我希望将与v1保持一致。此外,也能起到作用。 如果我希望将与v1保持一致。现在返回。不是我想要的。 当答案输入时,我很可能会用头撞我的键盘,但现在我还没有得到最

  • 我想从包含每个组中元素数量的向量创建一个包含每个元素的组标识符的向量。 例子: 我正在寻找一个向量如下: 我找到了一个涉及循环的解决方案: 但这看起来不太优雅。欢迎提出任何改进建议。

  • 我有一组向量,我需要用java编写算法,找到这个集合的最小元素。问题是,有些元素是无与伦比的。例如minset{(1,4,6),(3,2,5),(2,3,4),(5,4,6)} = {(1,4,6),(3,2,5),(2,3,4)}。对于最小元素集“minset”,以下内容成立:原始集的每个向量要么在“minset”中,要么在“minset”中

  • 我目前正试图通过改变算法来优化一些MATLAB/Octave代码,但不知道如何处理一些随机性。假设我有一个整数向量V,每个元素代表一些东西的计数,在我的例子中是光子。现在,我想随机选取一些“东西”,创建一个大小相同的新向量,但要调整计数。 以下是我目前的做法: 这是上面描述的一个相当简单的实现。但是它有一个明显的性能缺陷:函数创建一个向量(idxV),每个光子包含一个元素。所以如果我的V只有100

  • Khronos组织也在后续的OpenCL标准中定义了一套C++ Wapper API。C++ API与C API是对应的(比如,cl::Memory对应cl_mem),不过C++需要对异常和类进行处理。下面的代码对应的与代码清单3.4中的C代码相对应。 {%ace edit=false, lang=’c_cpp’%} define __CL_ENABLE_EXCEPTIONS include in

  • 我正在尝试将嵌套列表结构转换为DataFrame。该列表类似于以下内容(它是来自解析的JSON的序列化数据,使用httr包读取)。 编辑:我最初的示例数据太简单了。实际数据是不完整的,这意味着并非每个对象都存在所有变量,并且一些列表元素是空的。我编辑了数据来反映这一点。