10.5 编写自己的内核
选择用一些涉及并不精通的领域内容的函数库也是很重要的。
使用函数库可能遇到的常见的问题是内存分配。大多数基于GPU的解决方案并不分配锁页内存。找那些可以让用户控制管理或者支持锁页内存的函数库。
指令与函数库的下一个问题是,除非特意编写,否则它们对多GPU不敏感。
现在问题是自己编写多少代码,通常关于性能。使用指令时,付出了一定百分比的性能以实现更快的程序开发。通过对比,函数库可能会在减少开发精力的情况下带来显著的加速,但是其可能的副作用是减少程序的灵活性,已经许可证书问题。
使用自己编写的内核是有很多原因的。本书提供的一些基本原则(合并内存访问、充分利用硬件、避免资源竞争、了解硬件局限、数据局部性原理)都是适用的。
优秀的程序员对于C语言与汇编语言的细节都很了解。他们知道什么时候使用C语言已获得生产受益,也知道什么时候要使用汇编写一些函数。使用指令/函数库的问题大体是类似的。
当为GPU编写应用程序时,一个很好的方法是先获得CPU端可以运行的原型。考虑一下如何让CPU版本利用多核以及这是否会给应用程序带来好处。CPU/GPU工作的平衡是怎样的呢?在需要的时候会如何在CPU上创建线程?在一开始,还是一个CPU线程与一个GPU。
现在考虑一下主机/设备传输。传输-计算-传输模型。
接下来考虑一下GPU的内存层次结构。打算利用GPU的那个位置(寄存器、共享内存、缓存、常量内存、纹理内存)?对于这种类型的数据存储你需要怎样的数据格式?
现在我们看看内核设计。分解为线程和线程块的方式会影响线程间/线程块间的通信量以及资源使用情况。可能会遇到怎样的串行和竞争问题呢?
然后,做一些对比测试。这给我们带来了内核实现效率的问题,其中要考虑CUDA/函数/指令的选择。加入已经规划好了如何使用GPU,那么你的选择会如何影响执行的效率呢?关于使用CUDA/函数库/指令的选择会对性能带来正面or负面的影响?影响的百分比多少?
移植到多GPU时。需要怎样对GPU间进行通信?P2P模型通常是这种通信的最佳方法。或者,GPU之间的协调和传输需要由主机来完成。让一个单独的CPU协调N个GPU可能比让多个CPU协调同样多的GPU更容易。
你的指令或函数库是否支持多GPU方法?它们线程安全吗?或者假设只有一个实例或CPU线程,它们是否会维护一个内部状态?对数据交换和并发操作提供了什么支持?是否强制串行与每个GPU交换数据,并在不同的GPU间轮流进行?能否同时执行N个传输?
在选择工具或函数库时,考虑一下它们是否成熟已经编写它们的目的是什么。在代码错误时如何调试、你是自己解决问题还是技术支持?它们是什么时候编写的并且针对哪一种GPU工作做得最好?对于不同代GPU,它们是否优化过?
通过提前思考设计并且搞清楚要在哪里结束,能够决定开始时需要哪一种软件和工具。可以用某种方法创建一个解决方案的原型。