博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第六篇:GPU 并行优化的几种典型策略
阅读量:6759 次
发布时间:2019-06-26

本文共 1807 字,大约阅读时间需要 6 分钟。

前言

       如何对现有的程序进行并行优化,是 GPU 并行编程技术最为关注的实际问题。本文将提供几种优化的思路,为程序并行优化指明道路方向。

优化前准备

       首先,要明确优化的目标 - 是要将程序提速 2 倍?还是 10 倍?100倍?也许你会不假思索的说当然是提升越高越好。

       但这里存在一个优化成本的问题。在同样的技术水平硬件水平下,提升 2 倍也许只要一个下午的工作量,但提高 10 倍可能要考虑到更多的东西,也许是一周的工作量。提高 100 倍, 1000 倍需要的成本,时间就更多了。

       然后,需要将这个问题进行分解。通常来说先对数据集进行分解,然后将任务进行分解。这里要从数据集这样的矩阵角度来分析数据,将输入集和输出集中各个格点的对应关系找出来,然后分派给各个块,各个线程。

策略一:识别代码中的瓶颈所在

       分析程序效率的瓶颈所在一方面靠的是分析。这种方式对于代码结构比较简单的程序非常有用,但对于实际应用中的复杂项目,人脑分析往往会导致错误的结论 - 也许你费尽心思想出来了瓶颈,然后对它做了优化,之后却发现效率仅仅提升了 1%。

       因此更有效的方法是使用分析工具来找出瓶颈,可以使用 CUDA Profiler 或者 Parallel Nsight。

       使用 Parallel Nsight 分析并行程序的方法请参考我的这篇文章:(准备中...)

       还有一点要特别说明的是,在 GPU 进行数据处理的时候,CPU 可以考虑做点别的事情,比如去服务器取数之类的,这样就将 CPU 并行和 GPU 并行结合起来了,程序效率自然会大大提高。

策略二:合理的利用内存

       首先,要灵活的使用显卡中的各类内存结构,如共享内存,常量内存等。特别要注意共享内存的使用,它的速度可是接近一级缓存的。

       此外,必要时对多个内核函数进行融合。因为这样可以避免启动新的内核函数时需要进行的数据传递问题,还可以重用前面的任务遗留下的一些有用的数据。不过,如果是对别人写的多个内核函数进行融合的话,一定要注意其中隐含的同步问题 - 上个内核函数的代码彻底执行完毕之后,下个内核函数才会开始执行。

       然后,对于数据的访问应该采取合并访问的方式 - 尽量使用 cudaMalloc 函数。一次访问的数据应当大于 128 字节,这样才能充分地利用显卡的带宽。

策略三:传输过程的优化

       前面的文章已经提到过很多次了,数据在内存和显存之间进行交换是非常费时的。

       对于这样的问题,首先我们可以以锁页内存的方式使用主机端内存。所谓锁页内存,是指该区域内存和显卡的传递不需要 CPU 来干预,如果某区域不声明为锁页内存,那么在内存往显存中或者显存往内存中传递数据前,会发生一些开销不小的锁定操作(表示该区域内存正在和显存发生数据传递,CPU勿扰)。

       使用方法是调用 cudaHostAlloc 函数。这个函数的功能不单单是声明锁页内存那么简单。通过设置函数的参数,该函数还能实现很多非常实用的功能,个人非常推荐。

       然后,还需要重点推荐的是零复制内存。它是一种特殊的锁页内存,一种特殊的内存映射。它允许你将主机内存映射到 GPU 的内存空间。如果你的程序是计算密集型的,那么这个机制就会非常有用,它会自动将数据传输和计算重叠。具体用法请参考我的这 篇文章。

策略四:线程结构布局的优化

       建立科学的计算网格,通过设定合适的维数,块数,以及块内线程数来尽量实现合并的内存访问,保证最大的内存带宽。

       要学会灵活使用多维度的计算网格,而不是仅仅局限于一维。多维计算网格的使用请参考我的这篇文章。

       尤其在单维度的块数受到限制的时候,多维网格就必须被考虑进来了。

策略五:从算法本身进行任务级的分解

       将算法的步骤分解各个不相关的部分,步骤内采用GPU并行,这几个步骤则采用CPU并行。

策略六:灵活使用 CUDA C 的一些库还有 API

       CUDA C 提供了很多实用的 API,且提供相当多的C++支持 (非全部)。能大大地提高开发效率。如原子操作函数等等,很方便。

       CUDA 提供了许多实用的库:如 cuBlas cuSparse等,不在此一一介绍。尤其是 Thrust 库,简直就是 STL 的并行实现,拿来直接用非常方便。

小结

       优化思路可以说是 CUDA 并行编程最为核心,也是最为关键所在。

       本文仅仅是提供优化的总体策略和思路,至于具体的实现方法,请参考相关资料实现之。

转载地址:http://pefeo.baihongyu.com/

你可能感兴趣的文章
软件开发中关于向后兼容的理解
查看>>
ios开发之 MPMoviePlayerController 视频播放器
查看>>
count(*)、count(val)和count(1)的解释
查看>>
[Leetcode] Largest Rectangle in Histogram
查看>>
final (Java)
查看>>
The Master of Science degree in Computer Scienc
查看>>
利用Stack倒序List,利用Set使List不能添加重复元素
查看>>
移动云计算应用开发入门经典
查看>>
当跳票成了习惯
查看>>
InstallShield 10 Express 使用
查看>>
LightOJ 1230 Placing Lampposts(树形DP)
查看>>
rtems总结
查看>>
艾伟_转载:使用.NET框架自带的Json序列化类
查看>>
一起谈.NET技术,VS 2010 和 .NET 4.0 系列之《VS 2010代码智能提示的改进》篇
查看>>
一起谈.NET技术,改善代码设计 —— 处理概括关系(Dealing with Generalization)
查看>>
iPhone中调用WCF服务“.NET研究”
查看>>
【java开发系列】—— struts2简单入门示例
查看>>
在SharePoint Server 2010 的管理中心,点击“配置管理帐户”,就会在ManagedAccounts.aspx页面出现,“对象不存在”的出错信息应对方法!!!!...
查看>>
20个数据库设计最佳实践
查看>>
jsfl学习
查看>>