Cuda GPU内存带宽理论与实践

Cuda GPU内存带宽理论与实践,cuda,opencl,linear-algebra,gpgpu,bandwidth,Cuda,Opencl,Linear Algebra,Gpgpu,Bandwidth,作为在GPU上运行的算法评测的一部分,我觉得我正在占用内存带宽 我有几个复杂的内核执行一些复杂的操作(稀疏矩阵乘法、约化等)和一些非常简单的操作,当我计算每个内核的读/写总数据时,似乎所有(重要的)都达到了~79GB/s带宽墙,而不管它们的复杂程度如何,而理论GPU带宽为112GB/s(nVidia GTX 960) 数据集非常大,在大约10000000个浮点条目的向量上运行,因此我从clGetEventProfilingInfo在COMMAND\u START和COMMAND\u END之间获

作为在GPU上运行的算法评测的一部分,我觉得我正在占用内存带宽

我有几个复杂的内核执行一些复杂的操作(稀疏矩阵乘法、约化等)和一些非常简单的操作,当我计算每个内核的读/写总数据时,似乎所有(重要的)都达到了~79GB/s带宽墙,而不管它们的复杂程度如何,而理论GPU带宽为112GB/s(nVidia GTX 960)

数据集非常大,在大约10000000个浮点条目的向量上运行,因此我从
clGetEventProfilingInfo
COMMAND\u START
COMMAND\u END
之间获得了良好的测量/统计数据。在算法运行期间,所有数据都保留在GPU内存中,因此实际上没有主机/设备内存传输(也不通过评测计数器测量)

即使对于一个非常简单的内核(见下文),它解决了
x=x+alpha*b
,其中x和b是约10000000个条目的巨大向量,我也没有接近理论带宽(112GB/s),而是在最大值的约70%(约79GB/s)上运行

\uuuuuu内核无效添加向量(int N,\uuuuu全局浮点*x,\uuuu全局浮点常量*b,浮点因子)
{
int gid=获取全局id(0);
if(gid
我将此特定内核每次运行的数据传输计算为N*(2+1)*4:

  • N-向量大小=~10000000
  • 每个向量条目2次加载和1次存储
  • 浮球尺寸为4
我希望对于这样一个简单的内核,我需要更接近带宽限制,我错过了什么


附言:我从CUDA对同一算法的实现中得到了类似的数字

我认为评估您是否达到峰值带宽的更现实的方法是将您得到的数据与简单的D2D拷贝进行比较

例如,内核读取x和b一次,写入x一次,因此执行时间的上限应该是从b复制到x一次的1.5倍。如果您发现时间远高于1.5倍,这意味着您可能还有改进的空间。在这个内核中,工作非常简单,因此开销(启动和结束函数、计算索引等)可能会限制性能。如果这是一个问题,您可能会发现使用网格跨步循环增加每个线程的工作量会有所帮助


<>理论带宽,至少应该考虑ECC的开销,如果启用的话。p> cuda示例代码
带宽测试中已经为您打包了一个简单的D2D副本。只需编译并运行该示例代码,报告的设备到设备带宽是GPU上最大可用内存带宽的合理代理测量值。好的,CUDA、OpenCL都可以通过cudaMemcopy/Clenqueumory或使用简单内存复制内核复制内存。。。以78GB/s传输数据,Nvidia的样本带宽测试给出78GB/s。。。i、 e.其工作效率约为报告的70%。此外,GTX 960没有ECC功能(至少通过nvidia smi对其进行控制-不适用)。这很令人伤心,但至少我得到了正确的答案measurement@Artyom这与特斯拉K40c相同-ECC关闭时约70%,ECC打开时约64%。谢谢。。。你给了我宝贵的意见
__kernel void add_vectors(int N,__global float *x,__global float const *b,float factor)
{
    int gid = get_global_id(0);
    if(gid < N)
        x[gid]+=b[gid]*factor;
}