OpenCL的成本get_local_id()

时间:2013-09-26 12:12:15

标签: cuda opencl nvidia

我有一个简单的扫描内核,它可以计算循环中几个块的扫描。我注意到当get_local_id()存储在局部变量中而不是在循环内调用它时,性能会有所上升。所以总结一下代码,这个:

__kernel void LocalScan_v0(__global const int *p_array, int n_array_size, __global int *p_scan)
{
    const int n_group_offset = get_group_id(0) * SCAN_BLOCK_SIZE;
    p_array += n_group_offset;
    p_scan += n_group_offset;
    // calculate group offset

    const int li = get_local_id(0); // *** local id cached ***
    const int gn = get_num_groups(0);
    __local int p_workspace[SCAN_BLOCK_SIZE];
    for(int i = n_group_offset; i < n_array_size; i += SCAN_BLOCK_SIZE * gn) {
        LocalScan_SingleBlock(p_array, p_scan, p_workspace, li);

        p_array += SCAN_BLOCK_SIZE * gn;
        p_scan += SCAN_BLOCK_SIZE * gn;
    }
    // process all the blocks in the array (each block size SCAN_BLOCK_SIZE)
}

GTX-780的吞吐量为74 GB / s,而这个:

__kernel void LocalScan_v0(__global const int *p_array, int n_array_size, __global int *p_scan)
{
    const int n_group_offset = get_group_id(0) * SCAN_BLOCK_SIZE;
    p_array += n_group_offset;
    p_scan += n_group_offset;
    // calculate group offset

    const int gn = get_num_groups(0);
    __local int p_workspace[SCAN_BLOCK_SIZE];
    for(int i = n_group_offset; i < n_array_size; i += SCAN_BLOCK_SIZE * gn) {
        LocalScan_SingleBlock(p_array, p_scan, p_workspace, get_local_id(0));
        // *** local id polled inside the loop ***

        p_array += SCAN_BLOCK_SIZE * gn;
        p_scan += SCAN_BLOCK_SIZE * gn;
    }
    // process all the blocks in the array (each block size SCAN_BLOCK_SIZE)
}

在同一硬件上只有70 GB / s。唯一的区别是对get_local_id()的调用是在循环内部还是外部。 LocalScan_SingleBlock()中的代码在this GPU Gems article中有很多描述。

现在这带来了一些问题。我总是想象线程id存储在某个寄存器中,对它的访问速度与任何线程局部变量一样快。似乎并非如此。我一直习惯于在一个变量中缓存本地id,而不愿意在一个循环中不调用函数的旧“C”程序员,如果他希望它每次返回相同的值,但我没有'认真思考它会有所作为。

关于为什么会出现这种情况的任何想法?我没有检查编译的二进制代码。有没有人有相同的经历?与CUDA中的threadIdx.x相同吗? ATI平台怎么样?这种行为是在某处描述的吗?我很快通过CUDA最佳实践进行了扫描,但没有找到任何结果。

1 个答案:

答案 0 :(得分:5)

这只是猜测,但根据Khronos页面

http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/get_local_id.html

get_local_id()未定义为返回常量值(仅为size_t)。这可能意味着,就编译器而言,与常量local_id相比,可能不允许执行某些优化,因为函数值的返回可能会在编译器的眼中发生变化(即使它不是每个线程)