Select OpenCL-内核运行缓慢

Select OpenCL-内核运行缓慢,select,kernel,opencl,Select,Kernel,Opencl,我的内核非常简单。它尝试查看代码是否有效,然后根据前缀扫描输出仅存储唯一代码: __kernel void moveValid(__global int* sortCode, __global int* mark, __global int* processorOffsets, __global int* uniqueCode,__global int* numPoints, __global int* pointIndex) { int ig = get_global_id(0);

我的内核非常简单。它尝试查看代码是否有效,然后根据前缀扫描输出仅存储唯一代码:

__kernel void moveValid(__global int* sortCode, __global int* mark, __global int* processorOffsets, __global int* uniqueCode,__global int* numPoints, __global int* pointIndex) 
{
    int ig = get_global_id(0);
    int m = mark[ig];
    int j= processorOffsets[ig];
    atomic_inc(&numPoints[j-1]);
    // select
    if(m == true)
    {   
            uniqueCode[j] = sortCode[ig];
            pointIndex[j] = ig;
    }

    barrier(CLK_GLOBAL_MEM_FENCE);
}

看起来内核真的很慢。这是因为if语句吗?有人能给我们一些关于如何改进内核的建议吗?也可以选择在这个场景中使用吗?

因此,在不深入查看代码的情况下,我可以给出以下关于其速度的反馈。我假设您正在使用GPU作为您的设备。如果您使用的是CPU作为您的设备,一些信息可能仍然适用

atomic_inc(&numPoints[j-1])

在大多数设备上,原子增量对于全局内存来说非常缓慢。这是因为数据必须提交到全局内存中(不能在本地缓存)

屏障(CLK_GLOBAL_MEM_围栏)

此屏障确保在继续执行之前,工作组中的所有工作项都已存在。为什么在代码中需要这个?特别是当没有什么事情可做时,没有理由不让线程完成执行。这也是一个巨大的性能打击

如果(m==true)

这实际上不是我见过的最糟糕的if语句,因为它只有一个分支。这仍然会降低代码的速度,但不会像其他事情那样显著。在继续之前,将为所有串行线程(对于某些体系结构)计算条件


总的来说,在这段代码中,您将执行4次全局内存访问,就像原子操作一样,而不是数学操作。GPU是执行此类算法的最差设备,因为内存访问对全局内存的速度非常慢,尤其是在合并访问的情况下。你能考虑把你的一些数组移到本地内存吗?我仍然不太确定在内核中设置屏障的位置和时间。我已将atomic_inc更改为本地内存。内核运行得更快。通常你不需要障碍物。只有当你在工作,然后想等待你的工作小组,然后再做更多的工作时,才需要障碍。此外,障碍物的工作方式可能与您认为的不同。如果您想要一个全局屏障(例如,每个工作组完成的工作量相同),那么就通过内核执行而不是使用屏障来实现。还要确保你理解不同记忆(全局、局部、私有)之间的差异,而不是仅仅使用它们。