一、基于编程模型和执行模型的优化方法

1.选取合适的gridDim和blockDim

blockDim最好为32的整数倍:因为执行指令的基本单位为线程束,线程束内的所有线程统一执行广播下来的命令,而线程束的线程数量基本为32。当block被分到SM中去,其会被划分为多个线程束,若blockDim!=线程束内线程数整数倍,则会造成线程的浪费。

2.减少存在分支的if

因为线程束中的所有线程执行同一条的指令,若出现存在出现分支的if,即线程束内的部分线程符合if条件,部分符合else条件,因cuda编译不具备分支预测能力,则会在一个指令执行if,下一个指令执行else,两个指令中都有部分不符合条件的线程空闲,从而造成浪费,如下述代码所示:

__global__ void mathKernel1(float *c)
{int tid = blockIdx.x* blockDim.x + threadIdx.x;float a = 0.0;float b = 0.0;if (tid % 2 == 0){a = 100.0f;}else{b = 200.0f;}c[tid] = a + b;
}

线程束内奇数线程(threadIdx.x为奇数)会执行else,偶数线程执行if,分化很严重。对此,我们可以更改if条件,使整个线程束内都符合if或else即可:

__global__ void mathKernel2(float *c)
{int tid = blockIdx.x* blockDim.x + threadIdx.x;float a = 0.0;float b = 0.0;if ((tid/warpSize) % 2 == 0){a = 100.0f;}else{b = 200.0f;}c[tid] = a + b;
}

可以得到相同但是错乱的结果C,这个顺序是无所谓的,可以后期调整。

3.循环展开

减少循环判断的次数,本质上也是减少分支

for (int i=0;i<100;i++)
{a[i]=b[i]+c[i];
}
for (int i=0;i<100;i+=2)
{a[i]=b[i]+c[i];a[i+1]=b[i+1]+c[i+1];
}

最新的cuda应该不需要手动展开了,在for前加上#pragma unroll 循环次数命令即可。

二、基于内存的优化方法

1.合并访问和对齐访问

核函数运行时需要从全局内存(DRAM)中读取数据,只有两种粒度:128字节、32字节。粒度可以理解为最小单位,也就是核函数运行时每次读内存,哪怕是读一个字节的变量,也要读128字节,或者32字节。
合并访问是指所有线程访问连续的对齐的内存块,对于L1 cache,内存块大小支持32字节、64字节以及128字节为单位读取数据。前提是,访问必须连续,并且访问的地址是以32字节对齐。
我们把一次内存请求——也就是从内核函数发起请求,到硬件响应返回数据这个过程称为一个内存事务。当一个内存事务的首个访问地址是缓存粒度(32或128字节)的偶数倍的时候:比如二级缓存32字节的偶数倍64,128字节的偶数倍256的时候,这个时候被称为对齐内存访问

规约中可以通过设计累加的位置来实现合并对齐访问,提高效率

__global__ void ReductionSum(float *d_a, float *d_partial_sum)
{//申请共享内存,存在于每个block中 __shared__ float partialSum[threadsPerBlock];//确定索引int i = threadIdx.x + blockIdx.x * blockDim.x;int tid = threadIdx.x;//传global memory数据到shared memorypartialSum[tid]=d_a[i];//传输同步__syncthreads();//在共享存储器中进行规约for(int stride = blockDim.x/2; stride > 0; stride/=2){if(tid<stride) partialSum[tid]+=partialSum[tid+stride];__syncthreads();}//将当前block的计算结果写回输出数组if(tid==0)  d_partial_sum[blockIdx.x] = partialSum[0];
}
2.利用缓存来进行交叉访问(非合并的访问)

在某些情况下,无法避免进行交叉的读或写,如求矩阵的转置。这种情况下可以利用从缓存中读取的高效性,进行交叉内存访问(虽然按照列读是不合并的,但是使用一级缓存加载过来的数据在后面会被使用,虽然一级缓存一次读取128字节的数据,其中只有一个单位是有用的,但是剩下的并不会被马上覆盖,粒度是128字节,但是一级缓存的大小有几k或是更大,这些数据很有可能不会被替换,所以,我们按列读取数据,虽然第一行只用了一个,但是下一列的时候,理想情况是所有需要读取的元素都在一级缓存中,这时候,数据直接从缓存里面读取),从而让写结果到全局内存的过程是合并访问(写的过程不走缓存)。

__global__ void transformNaiveCol(float * MatA,float * MatB,int nx,int ny)
{int ix=threadIdx.x+blockDim.x*blockIdx.x;int iy=threadIdx.y+blockDim.y*blockIdx.y;int idx_row=ix+iy*nx;int idx_col=ix*ny+iy;if (ix<nx && iy<ny){MatB[idx_row]=MatA[idx_col];//MatB[idx_col]=MatA[idx_row];   slower}
}
3.基于共享内存的优化

共享内存是在他所属的线程块被执行时建立,线程块执行完毕后共享内存释放,线程块和他的共享内存有相同的生命周期。
共享内存读写速度较快,且可编程,故可用它来存储中间变量,或者先将内存中的数据读到共享内存中来,再做后续的操作。

__global__ void setRowReadColIpad(int * out)
{__shared__ int tile[BDIMY][BDIMX+IPAD];unsigned int idx=threadIdx.y*blockDim.x+threadIdx.x;tile[threadIdx.y][threadIdx.x]=idx;__syncthreads();out[idx]=tile[threadIdx.x][threadIdx.y];
}

共享内存按列读取不会导致交叉访问那么严重的延迟,代码中申请了共享内存来进行交叉访问,避免了交叉的全局内存访问,还对申请的动态内存做了填充,防止读取冲突(有疑问)。

CUDA基本优化方法相关推荐

  1. ONNX 实时graph优化方法

    ONNX 实时graph优化方法 ONNX实时提供了各种图形优化来提高模型性能.图优化本质上是图级别的转换,从小型图简化和节点消除,到更复杂的节点融合和布局优化. 图形优化根据其复杂性和功能分为几个类 ...

  2. CUDA 并行计算优化策略总结

    作者 | LustofLife@知乎 来源 | https://zhuanlan.zhihu.com/p/297201517 编辑 | 极市平台 导读 并行计算为了提高算法运行效率,本文通过以矩阵乘法 ...

  3. 推荐CUDA程序优化的15个策略

    推荐CUDA程序优化的15个策略 0条评论 2011-07-06 09:48   来源:潇湘学子岳麓生的博客 作者: 潇湘学子岳麓生 编辑: 王玉圆 [IT168 技术]在<CUDA程序优化策略 ...

  4. CUDA程序优化技巧

    CUDA程序优化技巧 2013-11-18 23:41 1469人阅读 评论(4) 收藏 举报 分类: CUDA(24) 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 有如下 ...

  5. CUDA: 程序优化的15个策略

    在<CUDA程序优化策略>这篇文章中,我们介绍过CUDA优化的常见策略.今天我们会对CUDA优化策略进行详细讲解.具体策略如下: 1. memory coalescing,保证内存融合.因 ...

  6. CUDA|并行计算优化策略

    点击上方"计算机视觉工坊",选择"星标" 干货第一时间送达 作者丨LustofLife@知乎(已授权) 来源丨https://zhuanlan.zhihu.co ...

  7. 【显存优化】深度学习显存优化方法

    深度学习gpu的显存至关重要,显存过小的话,模型根本无法跑起来,本文介绍几种显存不足时的优化方法,能够降低深度学习模型的显存要求. 目录 一.梯度累加 二.混合精度 1.权重备份 2.损失缩放 3.精 ...

  8. 普通粒子群算法和优化方法

    粒子群优化(PSO, particle swarm optimization) 是由Kennedy和Eberhart在1995年提出的一 种群智能优化方法. 优点:好理解容易实现,适合解决极值问题 缺 ...

  9. 大主子表关联的性能优化方法

    [摘要] 主子表是数据库最常见的关联关系之一,最典型的包括合同和合同条款.订单和订单明细.保险保单和保单明细.银行账户和账户流水.电商用户和订单.电信账户和计费清单或流量详单.当主子表的数据量较大时, ...

最新文章

  1. 荣耀有可能搭载鸿蒙系统吗,如果荣耀Magic3搭载了屏下镜头和鸿蒙系统,你会做第一批吗?...
  2. 已解决AttributeError set object has no attribute items(亲测)
  3. 一加7pro运动计步功能_测血压、心率、血氧、运动计步,来电微信消息等提醒,多种模式可选,这款智能手环功能实在是太全了吧!...
  4. PE文件RV转FOA及FOA转RVA
  5. 研究大华3G设备接入自主视频开发平台
  6. 使用开源ASR框架在Mono和.NET C#中进行语音识别
  7. 有双面打印功能的打印机,安装驱动后,无法选择自动双面打印的解决方法
  8. XiaoXin 13Pro-Hackintosh 小新13pro崇尚极简的黑苹果双系统
  9. JS编写华氏度转摄氏度
  10. BTA12A-ASEMI高效mos管BTA12A
  11. 邮件开头结尾一些不同的表达
  12. 2143.replace.favo.xrcch.com Dns劫持解决方案
  13. 2010高分传记剧情《国王的演讲》DVD中英双字1024高清
  14. 如何又下预防XSS?这几招管用!!!
  15. 可燃气体泄漏监控报警系统_独立式可燃气体泄漏探测报警系统软件整体解决方案
  16. [圆反演][笛卡尔定理]Rohith and Circles
  17. Android 增量升级原理及实现方式分享
  18. 在线域名批量查询工具
  19. 淮北卫生学校可有计算机专业,浅谈卫生学校计算机教学的发展
  20. How to use even ?

热门文章

  1. 【电机控制理论】三相BLDC/PMSM电机的数学模型及其双环数字控制
  2. python怎么关闭ping窗口_Python检查ping终端的方法
  3. 【优化覆盖】基于matlab果蝇算法求解无线传感器覆盖优化问题【含Matlab源码 2215期】
  4. linux dns子域服务器,Linux DNS服务器子域授权、转发器和转发域配置实例(三)
  5. js获取css值的方法:style、getComputedStyle和currentStyle
  6. 论『建议』寻仙的可持续性发展!!!
  7. jsp--学生信息管理系统
  8. 锂电池充放电管理芯片和输出芯片
  9. Android静态安全检查(十三):剪切板使用检测
  10. 谷歌信息技术 中国 有限公司和北京谷歌科技有限公司的官司