打开CL内核 - 每个工作项都会覆盖全局内存?

时间:2017-03-03 13:27:08

标签: parallel-processing opencl histogram

我试图编写一个内核来获取字符串的字符频率。

首先,这是我现在为内核编写的代码:

_kernel void readParallel(__global char * indata, __global int * outdata)
{
        int startId = get_global_id(0) * 8;
        int maxId = startId + 7;

        for (int i = startId; i < maxId; i++)
        {
            ++outdata[indata[i]];
        }
 }

变量inData将字符串保存在全局内存中,outdata是全局内存中256个int值的数组。每个工作项从字符串中读取8个符号,并应在数组中增加相应的ASCII代码。代码编译并执行,但outdata包含的总出现次数少于inData中的字符数。我认为问题是工作项会覆盖全局内存。如果你能给我一些解决这个问题的技巧,那就太好了。

顺便说一下,我是OpenCL的新手;-)而且,是的,我在其他问题中寻找解决方案。

1 个答案:

答案 0 :(得分:1)

您正在体验使用全局记忆不是原子C++-oriented description of what those areanother description by the Intel TBB folks)的效果。按时间顺序发生的是:

  

某些工作组“线程”会将outData[123]加载到某个注册表r1

中      

......很多工作,阅读和写作都会发生,包括在内   outData[123] ...

     

相同的工作组“线程”增加r1

     

......很多工作,阅读和写作都会发生,包括在内   outData[123] ...

     

相同的工作组“线程”将r1写入outData[123]

因此,写入outData[123]的值会丢弃“读取和写入之间的时间段内的更新(我忽略了并行写入相互破坏而不是其中一个获胜的可能性)。

您需要做的是:

  • 使用原子操作 - 对代码进行的修改量最少,但效率非常低,因为它会在很大程度上序列化您的工作,或者
  • 使用特定于工作项,特定于warp和/或特定于工作组的部分结果,这需要更少/更便宜的同步,并在完成大量工作后最终将它们合并它们。

在一个不相关的说明中,正如@huseyintugrulbuyukisik正确指出的那样,您的代码使用带符号的char值来索引数组。要解决此问题,请执行以下操作之一:

  • 为数组索引重新解释那些charunsigned chars(并在读取数组时重新解释。
  • 将char值向上转换为更大的整数类型,并添加128以获得outArray的偏移量。
  • 将内核定义为仅支持ASCII个字符(不高于127),在这种情况下,您可以忽略此问题(尽管如果输入无效,这将是一个潜在的破坏程序。
  • 如果您只关心printable characters的频率(但也可以在输入中包含非打印字符),则可以在计算字符之前执行运行时检查。