12.2_CUDA工具
12.2 CUDA工具
在本书中,我们用到了CUDA C软件系统的数个部件。我们编写的应用程序需要通过CUDA C编译器将核函数编译为可在NVIDIA GPU上执行的代码。CUDA运行时负责完成在核函数调用以及与GPU通信幕后的部分繁琐工作,它将调用CUDA驱动程序直接与系统中的硬件进行会话。除了这些已经使用的部件外,NVIDIA还提供了其他一组软件来帮助简化CUDA应用程序的开发工作。本节并不会对这些产品做详细介绍,而只是给出这些软件的用途。
12.2.1 CUDA工具箱
在你编写代码的机器上肯定已经安装了CUDA工具箱(CUDA Toolkit),因为在这个软件包中包含了CUDA C编译器工具集。如果在机器上没有CUDA工具箱,那么肯定就没有编写过或者编译过任何CUDA C代码。当然,没有安装CUDA工具箱也不是什么大问题(但我们怀疑你为什么要读这本书)。相反,如果亲手实现了书中的所有示例,那么就已经拥有了接下来将要讨论的一些库。
12.2.2 CUFFT
CUDA工具箱包含了两个重要的工具库,它们可以帮助你在应用程序中实现GPU编程。第一个库是NVIDIA提供的一个优化后的快速傅里叶变换(Fast Fourier Transform)库,也称为CUFFT。从3.0版本开始,CUFFT库支持一组非常有用的功能,包括以下:
在实数值与复数值之间进行一维变换、二维变换和三维变换。
以批处理的方式并行执行多个一维变换。
二维变换和三维变换,其中每一维的大小范围为2到16384。
一维变换,其中元素的数量最高可达8百万。
实数值数据和复数值数据的就地(In-Place)变换和非就地(Out-of-Place)变换。
NVIDIA提供免费的CUFFT库和一个许可,这个许可使得我们可以在任意应用程序中免费使用CUFFT库,而不论程序是属于个人兴趣,学术研究还是商业开发。
12.2.3 CUBLAS
除了快速傅里叶变换库外,NVIDIA还提供了一个线性代数函数(Linear Algebra Routine)库,其中包含了著名的基本线程代数子程序(Basic Linear Algebra Subprograms,BLAS)。这个库被命名为CUBLAS,同样是免费的,它包含了BLAS的一个子功能集。这个库中的每个函数都有多个版本,函数参数可以是单精度类型或者双精度类型,既可以是实数值,也可以是复数值。由于BLAS最初是一个由FORTRAN编写的线性代数函数库,NVIDIA尝试最大程度地兼容这些已有的实现。特别是,在CUBLAS库中,数组采用了列主(Column-Major)形式的存储布局,而不是像C和C++中才用行主(Row-Major)形式的布局。在实际情况中通常不需要考虑这种差异,从而使得使用BLAS的用户只需很小的代价就可以将应用程序修改为使用CUBLAS。NVIDIA还发布了对CUBLAS的FORTRAN绑定,用来说明如何将现有的FORTRAN应用程序链接到CUDA库。
12.2.4 NVIDIA GPU Computing SDK
除了NVIDIA驱动程序和CUDA工具箱外,在GPU Computing SDK中还包含了许多GPU计算示例程序。我们在本书前面提到过这个SDK,它包含的示例能很好地补充本书前11章的内容。这些示例代码涵盖了CUDA C的各个不同应用领域,分布在不同的主题文档中。这些示例大致可分为以下类别:
CUDA基本主题
CUDA高级主题
CUDA系统集成
数据并行算法
图形互操作
纹理
性能策略
线性代数
图像/视频处理
计算金融
数据压缩
物理模拟
这些示例可以在任何支持CUDA C的平台上运行,也可以作为你自己编写应用程序的基础。对于在这些领域有着丰富经验的读者,需要提醒的是,在GPU computing SDK中通常不会包含算法的最新/最优实现。这些代码不应作为产品级别的库代码,而只能作为CUDA C程序的学习材料,它们与本书的示例没有差别。
12.2.5 NVIDIA性能原语
除了在CUFFT和CUBLAS等库中提供的函数外,NVIDIA还提供了一个函数库来执行基于CUDA加速的数据处理操作,称为NVIDIA性能原语(NVIDIA Performance Primitives,NPP)。当前,NPP的基本功能集合主要侧重于图像处理和视频处理,这些功能广泛适用于这些领域的开发人员。NVIDIA计划在将来进一步增强NPP的功能以便解决更广泛领域中的计算任务。如果你对高性能的图像处理或者视频应用程序感兴趣,那么应该优先考虑是否能使用NPP,可以从网址www.nvidia.com/object/npp.html上免费下载(或者从网页搜索引擎中访问)。
12.2.6 调试CUDA C
很少有计算机软件能够在第一次执行时就完全无误地按照最初的设计执行。通常,有些代码计算得到不正确的值,有些代码无法结束,还有些代码甚至使计算机死机,只有按下电源开关才能重新恢复。虽然我个人从来没有写过这样的代码,但还是意识到,有些软件工程师可能希望获得某些工具对他们的CUDA C核函数进行调试。NVIDIA提供了一些工具来降低调试过程的复杂性。
1.CUDA-GDB
CUDA-GDB是其中最有用的CUDA工具之一,Linux系统上的CUDA C程序员在开发代码时可以下载这个工具。NVIDIA对开源的GUN调试器(gdb)进行了扩展,使其支持设备代码的实时调试,同时保持gdb的常规接口不变。在CUDA-GDB之前,除了在CPU上模拟设备代码的运行外,程序员没有其他更好的方法来调试设备代码。这种方法使调试工作的进展非常缓慢,而且也只能对核函数在GPU上的实际执行做非常粗略的估计。而NVIDIA的CUDA-GDB使程序员能够直接在GPU上调试核函数,为程序员提供了他们熟悉的CPU调试器的控制方式。CUDA-GDB包括以下功能:
·观察CUDA状态,例如已安装的GPU及其支持的功能等信息。
在CUDA C源代码中设置断点。
分析GPU内存,包括全局内存和共享内存。
分析当前驻留在GPU上的线程块和线程。
单步调试线程束。
中断并进入到当前正在运行的应用程序,包括挂起的或者发生死锁的应用程序。
除了调试器外,NVIDIA还提供了CUDA内存检查器(CUDA Memory Checker),我们可以通过CUDA-GDB或者独立的工具Cuda-Memcheck来使用CUDA内存检查器的功能。由于在CUDA架构中包含基于硬件构建的完备内存管理单元,因此所有的非法内存访问都可以通过硬件来检测和阻止。内存访问违例造成的结果是,程序将无法执行预期的功能,因此你肯定希望找出这种类型的错误。当启用CUDA内存检查器时,它将检测出核函数的全局内存访问违例或者未对齐的全局内存访问等错误,并以非常详细的方式来报告这些错误。
2. NVIDIA Parallel Nsight
对于在硬件上实时调试CUDA C核函数来说,CUDA-GDB无疑是一种成熟的和功能强大的工具,但NVIDIA意识到,并不是每个开发人员都喜欢使用Linux。Windows用户同样需要某种方式来调试CUDA应用程序。在2009年,NVIDIA推出了NVIDIA Parellel Nsight(最初称为Nexus),这是第一个集成在Microsoft Visual Studio中的GPU/CPU调试器。Parallel Nsight类似于CUDA-GDB,它能够调试包含数千个线程的CUDA应用程序。用户可以在CUDA C源代码中设置任意数量的断点,包括在写入内存位置时触发的断点。用户可以直接在Visual Studio Memroy窗口中直接查看内存,以及检查越界的内存访问。在本书出版时已经发布了这个工具的Beta版本,并且马上会发布最终版本。
12.2.7 CUDA Visual Profiler
我们经常宣称CUDA架构是开发高性能计算应用程序的重要基础组件。然而,事实却是,即使在找出应用程序中所有的错误后,那些所谓的“高性能计算”应用程序,更准确地说只能叫做“计算”应用程序,它们表现出的行为与“高性能”不符。我们经常会遇到一些类似的疑问:为什么代码在Sam Hill中运行的性能如此糟糕?在这些情况中,如果能通过某个可视化的分析工具来运行核函数,那么将是非常有帮助的。NVIDIA就提供了一个这样的工具Visual Profiler,可以从CUDA Zone网址上下载。在图12.1中给出了在Visual Profiler中比较矩阵转置运算两种不同实现的性能。虽然看不到任何一行代码,但仍然很容易判断核函数transpose()在内存吞吐量和指令吞吐量上都要优于核函数transpose_naive()。(通常,如果在函数名中带有“native”,那么这个函数的性能通常不是最优的。)
CUDA Visual Profiler将执行应用程序,同时分析GPU中内置的特殊性能计数器。在执行完成后,性能分析器可以根据这些计数器来统计数据并给出报告。Visual Profiler可以统计应用程序在执行每个核函数时花了多少时间,并判断线程块的数量、核函数的内存访问操作是否被合并了、在代码执行中的分支数量等。如果你需要解决某些复杂的性能问题,那么我们建议通过CUDA Visual Profiler来分析。

图12.1 在CUDA Visual Profiler中对矩阵转置应用程序进行分析