c++ - 为什么 OpenCL 工作组大小对 GPU 性能影响巨大?

标签 c++ caching opencl gpgpu memory-access

我正在 Qualcomm Adreno 630 GPU 上对一个简单的矩阵转置内核进行基准测试,我试图了解不同工作组大小的影响,但令人惊讶的是,我得到了一些我无法解释的有趣结果。这是我的内核代码:

__kernel void transpose(__global float *input, __global float *output, const int width, const int height)
    int i = get_global_id(0);
    int j = get_global_id(1);
    output[i*height + j] = input[j*width + i];
}

宽度和高度均为6400,实验结果为(执行时间为END事件和START事件的差值):

work group size      execution time
x     y
4    64              24ms
64   4               169ms
256  1               654ms
1    256             34ms
8    32              27ms
1    1024            375ms
1024 1               657ms
32   32              26ms

在此之后,我做了另一个实验,将宽度和高度从 6400 更改为 6401(以及 NDRangeKernel 调用中的全局工作大小),结果更加有趣:

work group size      execution time
x     y
4    64              28ms
64   4               105ms
256  1               359ms
1    256             31ms
8    32              32ms
1    1024            99ms
1024 1               358ms
32   32              32ms

大多数场景的执行时间显着下降。我知道内存合并或缓存可以在这里发挥作用,但我无法完全解释这一点。

最佳答案

当连续线程访问 128 字节对齐段内连续全局内存地址处的数据时,就会发生内存合并。然后内存访问被合并为一个,从而显着减少整体延迟。

在 2D 范围内,合并仅沿 get_global_id(1) 或您的情况下的 j 方向发生。在 output[i*height + j] = input[j*width + i]; 行中,input[j*width + i]; 是未对齐的(非-coalesced) 读取,output[i*height + j] 是合并写入。合并内存访问通常比未对齐访问快得多,但合并/未对齐读取的性能损失可能与合并/未对齐写入有很大不同。在大多数桌面 GPU 架构上,未对齐读取和合并写入的组合比相反的方式更快,请参见下图。因此您的实现应该已经是更快的变体了。

coalesced/misaligned memory bandwidth for various devices

由于合并访问只能沿着 j 索引进行,因此如果您的范围为 (x=256,y=1) (i code> 沿 x 方向,j 沿 y 方向),您不会得到任何合并。对于 (x=8,y=32)j 每个线程 block 以 32 为一组合并 8 次,因此内存带宽相当饱和,性能良好。

如果您想要最大可能的性能,我建议您使用一维索引。这样您就可以完全控制合并,并且合并发生在整个线程 block 上。您的矩阵转置内核将如下所示:

#define width 6400
__kernel void transpose(__global float *input, __global float *output) {
    const int n = get_global_id(0);
    int i = n/width;
    int j = n%width;
    output[i*height + j] = input[j*width + i];
}

您可以在 C++ 运行时以及 OpenCL 编译时之前通过字符串连接将 width 烘焙到 OpenCL Ccode 中。

关于c++ - 为什么 OpenCL 工作组大小对 GPU 性能影响巨大?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63297515/

相关文章:

c++ - 将boost::deadline_timer回调匹配到相应的wait_async

c++ - 同一模板的不同模板实例之间的转换

c++ - 函数指针作为模板

c++ - 有 libPNG 64 位吗?

apache - 为什么 Internet Explorer 缓存过期的 SSL 证书(我可以对此做些什么)?

php - 我应该缓存 Gravatar 图标还是直接访问图像?

opencl - 是否有任何OpenCL主机具有多个平台?

linux - 对 nvidia GPU 上的计算单元和预期核心的混淆

java - 用于范围分页的数据库缓存策略

c++ - 在 OpenCL 代码中使用 clamp 函数