CUDA复制测试

这篇博客探讨了CUDA内核中针对二维数组的内存读写操作的多种优化策略,包括线程配置、内存对齐和事务合并。测试结果显示,使用合适的数据类型和内存访问模式可以显著提高读写性能,例如int2类型比int类型快约两倍。文章强调了内存事务合并的重要性,未合并事务可能导致性能下降,并给出了最佳实践建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  这里主要是测试了内存数据读写操作的几种方式,记录了一些测试结果,对于二维数组(10244)(1024*4)。

  • (1)二维线程格,每个线程对应一个元素。
  • (2)转换为int2类型,线程宽度减半。
  • (3)线程宽度和高度减半,单个线程操作邻近的4个元素。
  • (4)线程宽度和高度减四分之一,单个线程操作邻近的16个元素。
  • (5)线程宽度和高度减半,单个线程操作完一个元素后,跨区域循环。
  • (6)为单个线程处理16个元素,采用表面引用。
  • (7)为单个线程处理64*64个元素,采用表面引用。
  • (8)跨区域循环,单线程处理16个元素,采用设备内存。
  • (9)跨区域循环,单线程处理16个元素,采用表面引用。
  • (10)跨区域循环,单线程处理64*64元素,采用表面引用。
  • (11)跨区域循环,单线程处理64*64元素,采用设备内存。
  • (12)跨区域循环,单线程处理2*2元素,采用表面引用。
  • (13)单线程处理单个元素,采用表面引用。
序号
(1)123.38129.02129.22295.72304.6261.97
(2)48.1154.8267.93306.24305.16305.50
(3)24.3122.4029.42393.10394.25386.28
(4)6.325.856.02485.72469.24467.52
(5)24.7122.2022.27385.06356.74365.97
(6)6.305.825.81845.41815.74811.05
(7)0.5960.5920.6013046.63056.92988.5
(8)5.865.905.80356.65355.79357.08
(9)5.845.886.06207.64207.91217.58
(10)0.5920.6520.543240.72240.63240.23
(11)0.5800.5900.591433.59430.95431.52
(12)22.5721.6522.33205.68206.82207.69
(13)91.3689.3789.07208.97209.02208.97

  在上面测试结果中,第一个和第二个的读取速度数据中,int2类型的速度是int类型的速度的大约两倍,这是来自于内存事务的合并。为了达到读写数据时的最佳性能,CUDA内核必须执行内存事务合并处理。任何不满足合并所需的全套标准的内存事务称为“未合并的”,未合并内存事务的性能惩罚由2~8倍不等,在最近的硬件上,合并内存事务对性能的影响显著减少。
  事务在每一个线程束的基础上被合并,为了由束执行内存读写事务的合并,一些简化的标准必须要满足。

  • 字至少为32位,读写字节或16位字的事务总是非合并的。
  • 束上的线程访问的地址是连续并递增的(即,依线程ID偏移)。
  • 束的基地址(束中第一个线程访问的地址)需要对齐。
字大小对齐
8位未合并
16位未合并
32位64字节
64位128字节
128位256字节
template<class T, const int n>
__global__ void GlobalWrites(T *out, T value, size_t N){
    size_t i;
    for(i = n*blockIdx.x*blockDim.x+threadIdx.x;
        i < N-n*blockDim.x*gridDim.x;
        i += n*blockDim.x*gridDim.x){
        for(int j = 0; j < n; j++){
            size_t index = i+j*blockDim.x;
            out[index] = value;
        }
    }
    // to avoid the (index<N) conditional in the inner loop,
    // we left off some work at the end
    for(int j = 0; j < n; j++){
        size_t index = i+j*blockDim.x;
        if(index < N) out[index] = value;
    }
}
template<class T, const int n, bool bOffset>
double ReportRow(size_t, N, size_t threadStart, size_t threadStop, size_t cBlocks){
    int maxThreads = 0;
    double maxBW = 0.0;
    printf("%d\t", n);
    for(int cThreads = threadStart; cThreads <= threadStop; cThreads *= 2){
        double bw;
        bw = BandwidthWrites<T, n, bOffset>(N, cBlocks, cThreads);
        if(bw > maxBW){
            maxBW = bw;
            maxThreads = cThreads;
        }
        printf("%.2f\t", bw);
    }
    printf("%.2f\t%d\n", maxBW, maxThreads);
    return maxBW;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值