news 2025/12/26 14:10:01

并行编程实战——CUDA编程的内核循环展开

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
并行编程实战——CUDA编程的内核循环展开

一、循环展开

开发经验相对丰富一些的程序员应该对循环展开并不陌生,特别是有过循环优化方面的经历的可能了解的会更深刻一些。循环是对CPU占用比较多的一种情况,如果在每次循环中再有大量的计算情况下,可能效果会更差。此时可以通过一定的方法手段缩减循环次数,而在每次循环中把多次的计算代码重复执行缩减的次数即可。其实这也有点时间和空间转换的味道。
循环展开可以手动展开也可以通过编译优化自动展开,这就看开发者想如何操作了。其下为示意代码:

//1:手动循环展开// 原始循环for(inti=0;i<16;i++){arr[i]=i*2;}// 展开5次for(inti=0;i<4;i+=4){arr[i]=i*2;arr[i+1]=(i+1)*2;arr[i+2]=(i+2)*2;arr[i+3]=(i+3)*2;arr[i+4]=(i+4)*2;}//2:自动循环展开// 原始循环for(inti=0;i<16;i++){arr[i]=i*2;}//编译器展开// GCC#pragmaGCC unroll4for(inti=0;i<n;i++){arr[i]=i*2;}

循环展开说着可能有点不好理解,但是看到代码估计一眼就看明白了。另外在学习C++的元编程时,还接触过类似于循环展开的例子,此处不展开了,有兴趣自己的去查看一下。

二、CUDA的循环展开

其实好的优化技术或方法基本都是通用的,只是对实际场景的匹配度大小罢了。CUDA线程中也是可以通过减少或消除循环控制来提高任务的运行效率。单纯的循环计算还是相对容易展开的,比较麻烦的可能是会有一些分支惩罚的情况。
如果开发者能够显式的控制循环迭代(比如使用#pargma unroll)或者CUDA本身可以识别循环的迭代次数,那么就可以进行分支循环的展开(即自动展开小循环)。当然,如果能够直接在代码中拆分循环会更方便,只不过这种情景可能很少遇到。看一下代码示意:

template<typenamegroup_t>__inline__ __device__floatwarp_test(group_tg,floatnum){//未指定参数,完全展开#pragmaunrollfor(intcount=g.size()/2;ofcountfset>0;count>>=1)num+=g.shfl_down(num,count);returnnum;}

不过还是那句话,循环展开如果应用场景不好,除了上面的分支惩罚,还有可能展开的代码占用了过多的寄存器导致效率的降低,也就是指令缓存未命中的惩罚。总之,开发者对于各种优化技术要灵活应用,千万不要教条。

三、例程

下面看一个循环展开优化的例程:

#include"cuda_runtime.h"#include"device_launch_parameters.h"#include<stdio.h>#include<iostream>#include<vector>#include<algorithm>// 手动展开__global__voidvecAddUnroll4(constfloat*A,constfloat*B,float*C,intn){inti=(blockIdx.x*blockDim.x+threadIdx.x)*4;if(i+3<n){// 处理4个元素C[i]=A[i]+B[i];C[i+1]=A[i+1]+B[i+1];C[i+2]=A[i+2]+B[i+2];C[i+3]=A[i+3]+B[i+3];}else{// 处理边界for(intj=0;j<4&&(i+j)<n;j++){C[i+j]=A[i+j]+B[i+j];}}}template<intUNROLL>__global__voidvecAddUnrollSet(constfloat*A,constfloat*B,float*C,intn){inttid=blockIdx.x*blockDim.x+threadIdx.x;inti=tid*UNROLL;#pragmaunrollfor(intj=0;j<UNROLL;j++){intid=i+j;if(id<n){C[id]=A[id]+B[id];}}}__global__voidvecAddUnroll(constfloat*A,constfloat*B,float*C,intn){inti=blockIdx.x*blockDim.x+threadIdx.x;if(i<n){floatsum=0.0f;// 编译器展开这个循环#pragmaunrollfor(intj=0;j<4;j++){intid=i+j*(blockDim.x*gridDim.x);if(id<n){sum+=A[id]+B[id];}}C[i]=sum;}}// pragma__global__voidvecAddUnrollSetPragma(constfloat*A,constfloat*B,float*C,intn){inti=blockIdx.x*blockDim.x+threadIdx.x;#pragmaunroll4for(intj=0;j<4;j++){intid=i*4+j;if(id<n){C[id]=A[id]+B[id];}}}intmain(){constintN=1<<20;//1Mconstsize_tsize=N*sizeof(float);std::vector<float>hA(N),hB(N),hC(N);std::generate(hA.begin(),hA.end(),[](){returnrand()/(float)RAND_MAX;});std::generate(hB.begin(),hB.end(),[](){returnrand()/(float)RAND_MAX;});float*dA,*dB,*dC;cudaMalloc(&dA,size);cudaMalloc(&dB,size);cudaMalloc(&dC,size);// 拷贝数据到设备cudaMemcpy(dA,hA.data(),size,cudaMemcpyHostToDevice);cudaMemcpy(dB,hB.data(),size,cudaMemcpyHostToDevice);// 设置执行配置intbSize=256;intgSize=(N+bSize-1)/bSize;vecAddUnroll4<<<gSize/4,bSize>>>(dA,dB,dC,N);cudaDeviceSynchronize();vecAddUnrollSet<4><<<gSize/4,bSize>>>(dA,dB,dC,N);cudaDeviceSynchronize();// pragma unrollvecAddUnroll<<<gSize,bSize>>>(dA,dB,dC,N);cudaDeviceSynchronize();vecAddUnrollSetPragma<<<gSize,bSize>>>(dA,dB,dC,N);cudaDeviceSynchronize();// 清理cudaFree(dA);cudaFree(dB);cudaFree(dC);return0;}

代码并不复杂,大家看一看就明白了,不再展开说明。

四、总结

很多技术它的思想都是一致的,只是在不同的范围内应用。特别是在语言应用上,虽然各种语言面对的场景多少都有不同,但其本质的目的是相通的。都是为了让解决问题的手段变得更容易。所以语言内对技术的引入同样是相通的,只不过运用和实现的方式根据自身的特点会有各自的不同罢了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/25 7:11:40

基于Web的智能家教服务平台设计与实现-计算机毕业设计源码+LW文档

摘 要 在智能家教服务平台的运营实践中&#xff0c;智能化的管理方式相较于传统的手工管理手段&#xff0c;其优势显得尤为突出。它不仅大幅度削减了运营所需的人力资源成本&#xff0c;还有力地推动了网站管理向标准化、制度化和程序化的方向迈进&#xff0c;从而有效杜绝了管…

作者头像 李华
网站建设 2025/12/25 20:19:18

Open-AutoGLM异地设备协同管理实战(20年专家私藏方案曝光)

第一章&#xff1a;Open-AutoGLM异地设备管理核心理念Open-AutoGLM 是一种面向分布式环境的智能设备管理框架&#xff0c;专为跨地域、多终端的自动化运维场景设计。其核心理念在于通过统一的语义理解与指令生成机制&#xff0c;实现自然语言到设备操作的无缝映射&#xff0c;降…

作者头像 李华
网站建设 2025/12/25 15:26:03

在Bug爆发前“排雷”:预防性测试

在快速迭代的软件开发世界中&#xff0c;Bug的爆发往往像一场突如其来的风暴&#xff0c;轻则导致用户抱怨&#xff0c;重则引发系统崩溃和业务损失。传统的测试方法侧重于在代码完成后进行检测和修复&#xff0c;但这常被视为“事后救火”&#xff0c;成本高且效率低。相比之下…

作者头像 李华
网站建设 2025/12/26 3:44:47

你真的懂Open-AutoGLM回滚吗?:从原理到实操的4层防护体系构建

第一章&#xff1a;你真的懂Open-AutoGLM回滚吗&#xff1f;在持续集成与模型部署实践中&#xff0c;Open-AutoGLM 的版本控制机制常被忽视&#xff0c;而回滚操作正是保障系统稳定性的关键防线。当新版本模型引发推理异常或服务延迟时&#xff0c;能否快速、准确地执行回滚&am…

作者头像 李华
网站建设 2025/12/23 21:52:29

毕业设计 yolo深度学习动物识别

文章目录 0 前言1 深度学习实现动物识别与检测2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存…

作者头像 李华
网站建设 2025/12/24 16:54:57

31、SharePoint Web Parts 开发全解析

SharePoint Web Parts 开发全解析 1. Silverlight Web Parts 简介 Silverlight Web Parts 能为用户提供更丰富的界面体验。幸运的是,我们无需编写大量自定义代码来创建此类 Web Part,因为微软发布了项目扩展,其中包含 Web Part 模板。该扩展及相关文档可从 MSDN Code Gal…

作者头像 李华