GPU 硬件与 CUDA 程序开发工具
笔记内容来自:《CUDA 编程:基础与实践》—樊哲勇 著
GPU 硬件简介
GPU 是英文 graphics processing unit 的首字母缩写,意为图形处理器。GPU 也常被称为显卡(graphics card)。与它对应的一个概念是 CPU,即 central processing unit(中央处理器)的首字母缩写。
GPU 的浮点数运算峰值就比同时期的 CPU 高一个量级;GPU 的内存带宽峰值也比同时期的 CPU 高一个量级。
CPU 和 GPU 的显著区别是:一个典型的 CPU 拥有少数几个快速的计算核心,而一个典型的 GPU 拥有几百到几千个不那么快速的计算核心。
CPU 中有更多的晶体管用于数据缓存和流程控制,但 GPU 中有更多的晶体管用于算术逻辑单元。
所以,GPU 是靠众多的计算核心来获得相对较高的计算性能的。图 1.1 形象地说明了(非集成) GPU 和 CPU 在硬件架构上的显著区别。
GPU 计算不是指单独的 GPU 计算,而是指 CPU + GPU 的异构(heterogeneous)计算。
一块单独的 GPU 是无法独立地完成所有计算任务的,它必须在 CPU 的调度下才能完成特定任务。
在由 CPU 和 GPU 构成的异构计算平台中,通常将起控制作用的 CPU 称为主机(host),将起加速作用的 GPU 称为设备(device)。
主机和(非集成)设备都有自己的 DRAM(dynamic random-access memory,动态随机存取内存),它们之间一般由 PCIe 总线(peripheral component interconnect express bus)连接,如图 1.1 所示。
本书中说的 GPU 都是指英伟达(Nvidia)公司推出的 GPU,因为 CUDA 编程目前只支持该公司的 GPU。以下几个系列的 GPU 都支持 CUDA 编程:
所以老黄真的是牛掰,这个商业判断。从当初押宝GPU、再到CUDA。
- • Tesla 系列:其中的内存为纠错内存(error-correcting code memory,ECC 内存),稳定性好,主要用于高性能、高强度的科学计算。
- • Quadro 系列:支持高速 OpenGL 渲染,主要用于专业绘图设计。
- • GeForce 系列:主要用于游戏与娱乐,但也常用于科学计算。GeForce 系列的 GPU 没有纠错内存,用于科学计算时具有一定的风险。然而,GeForce 系列的 GPU 价格相对低廉、性价比高,用于学习 CUDA 编程是没有任何问题的。即使是便携式计算机中 GeForce 系列的 GPU 也可以用来学习 CUDA 编程。
- • Jetson 系列:嵌入式设备中的 GPU。作者对此无使用经验,本书也不专门讨论。
每一款 GPU 都有一个用以表示其“计算能力”(compute capability)的版本号。该版本号可以写为形如 X.Y 的形式。其中,X 表示主版本号,Y 表示次版本号。
版本号决定了 GPU 硬件所支持的功能,可为应用程序在运行时判断硬件特征提供依据。初学者往往误以为 GPU 的计算能力越高,性能就越高,但后面我们会看到,计算能力和性能没有简单的正比关系。
版本号越大的 GPU 架构(architecture)越新。主版本号与 GPU 的核心架构相关联。很有意思的是,英伟达公司选择用著名科学家(到目前为止,大部分是物理学家)的姓氏作为 GPU 核心架构的代号,见表 1.1。在主版本号相同时,具有较大次版本号的 GPU 的架构稍有更新。
例如,同属于开普勒(Kepler)架构的 Tesla K40 和 Tesla K80 这两款 GPU 有相同的主版本号(X = 3),但有不同的次版本号,它们的计算能力分别是 3.5 和 3.7。
注意:特斯拉(Tesla)既是第一代 GPU 架构的代号,也是科学计算系列 GPU 的统称,其具体含义要根据上下文确定。另外,计算能力为 7.5 的架构虽然和伏特(Volta)架构具有同样的主版本号(X = 7),但它一般被看作一个新的主要架构,代号为图灵(Turing)。
据传,下一代 GPU 架构(X = 8)的代号为安培(Ampere)。表 1.2 列出了不同架构的各种 GPU 的名称。
特斯拉架构和费米(Fermi)架构的 GPU 已不再受到最近几个 CUDA 版本的支持。本书将忽略任何特定于这两个架构的硬件功能。可以预见,开普勒架构的 GPU 也将很快(比如一两年后)不受最新版 CUDA 的支持。
为简洁起见,本书有时也将忽略某些开普勒架构的特征。为简单起见,我们在表 1.2 中忽略了一类被称为 Titan 的 GPU。
读者可以在如下网站查询任何一款支持 CUDA 的 GPU 的信息:http://developer.nvidia.com/cuda-gpus。
计算能力并不等价于计算性能。例如,GeForce RTX 2000 系列的计算能力高于 TeslaV100,但后者在很多方面性能更高(售价也高得多)。
表征计算性能的一个重要参数是浮点数运算峰值,即每秒最多能执行的浮点数运算次数,英文为 Floating-point operations per second,缩写为 FLOPS。
GPU 的浮点数运算峰值在 1012 FLOPS,即 teraFLOPS(简写为 TFLOPS) 的量级。浮点数运算峰值有单精度和双
精度之分。对 Tesla 系列的 GPU 来说,双精度浮点数运算峰值一般是单精度浮点数运算峰值的 1/2 左右(对计算能力为 3.5 和 3.7 的 GPU 来说,是 1/3 左右)。
对 GeForce 系列的 GPU 来说,双精度浮点数运算峰值一般是单精度浮点数运算峰值的 1/32 左右。
另一个影响计算性能的参数是 GPU 中的内存带宽(memory bandwidth)。GPU 中的内存常称为显存。最后,显存容量也是制约应用程序性能的一个因素。如果一个应用程序需要的显存数量超过了一个 GPU 的显存容量,则在不使用统一内存(见第 12 章)的情况下程序就无法正确运行。
表 1.3 列出了作者目前能够使用的几款 GPU 的主要性能指标。在浮点数运算峰值一栏中,括号前和括号中的数字分别对应双精度和单精度的情形。
CUDA 程序开发工具
以下几种软件开发工具都可以用来进行 GPU 编程:
- • CUDA。这是本书的主题。
- • OpenCL。这是一个更为通用的为各种异构平台编写并行程序的框架,也是 AMD(Advanced Micro Devices)公司的 GPU 的主要程序开发工具。本书不涉及 OpenCL 编程,对此感兴趣的读者可参考《OpenCL 异构并行计算:原理、机制与优化实践》(刘文志,陈轶,吴长江,北京:机械工业出版社)。
- • OpenACC。这是一个由多个公司共同开发的异构并行编程标准。本书也不涉及OpenACC 编程,对此感兴趣的读者可参考《OpenACC 并行编程实战》(何沧平,北京:机械工业出版社)
CUDA 编程语言最初主要是基于 C 语言的,但目前越来越多地支持 C++ 语言。还有基于 Fortran 的 CUDA Fortran 版本及由其他编程语言包装的 CUDA 版本,但本书只涉及基于 C++ 的 CUDA 编程。
我们称基于 C++ 的 CUDA 编程语言为 CUDA C++。对 Fortran 版本感兴趣的读者可以参考网站https://www.pgroup.com/。
用户可以免费下载支持 CUDA Fortran 编程的 PGI 开发工具套装的社区版本(Community Edition)。对应的还有收费的专业版本(Professional Edition)。
PGI 是高性能计算编译器公司 Portland Group, Inc. 的简称,已被英伟达公司收购
CUDA 提供了两层 API(Application Programming Interface,应用程序编程接口)给程序员使用,即 CUDA 驱动(driver)API 和 CUDA 运行时(runtime)API。
其中,**CUDA 驱动 API 是更加底层的 API,**它为程序员提供了更为灵活的编程接口;
CUDA 运行时 API 是在 CUDA 驱动 API 的基础上构建的一个更为高级的 API,更容易使用。
这两种 API 在性能上几乎没有差别。从程序的可读性来看,使用 CUDA 运行时 API 是更好的选择。在其他编程语言中使用 CUDA 的时候,驱动 API 很多时候是必需的。因为作者没有使用驱动 API 的经验,故本书只涉及 CUDA 运行时 API。
图 1.2 展示了 CUDA 开发环境的主要组件。开发的应用程序是以主机(CPU)为出发点的。应用程序可以调用 CUDA 运行时 API、CUDA 驱动 API 及一些已有的 CUDA 库。
所有这些调用都将利用设备(GPU)的硬件资源。对 CUDA 运行时 API 的介绍是本书大部分章节的重点内容;第 14 章将介绍若干常用的 CUDA 库。
CUDA 版本也由形如 X.Y 的两个数字表示,但它并不等同于 GPU 的计算能力。可以这样理解:CUDA 版本是 GPU 软件开发平台的版本,而计算能力对应着 GPU 硬件架构的版本。
最早的 CUDA 1.0 于 2007 年发布。当前(笔者交稿之日)最新的版本是 CUDA 10.2。CUDA 版本与 GPU 的最高计算能力都在逐年上升。
虽然它们之间没有严格的对应关系,但一个具有较高计算能力的 GPU 通常需要一个较高的 CUDA 版本才能支持。最近的几个 CUDA 版本对计算能力的支持情况见表 1.4。
一般来说,建议安装一个支持所用 GPU 的较新的 CUDA 工具箱。本书中的所有示例程序都可以在 CUDA 9.0-10.2 中进行测试。目前最新版本的 CUDA 10.2 有两个值得注意的地方。
- 第一,它是最后一个支持 macOS 系统的 CUDA 版本;
- 第二,它将 CUDA C 改名为 CUDA C++,用以强调 CUDA C++ 是基于 C++ 的扩展。
CUDA 开发环境搭建
自行查资料
用 nvidia-smi 检查与设置设备
自行查资料
CUDA 的官方手册
本书将循序渐进地带领读者学习 CUDA C++ 编程的基础知识。虽然本书力求自给自足,但读者在阅读本书的过程中同时参考 CUDA 的官方手册也是有好处的。
任何关于 CUDA 编程的书籍都不可能替代官方提供的手册等资料。以下是几个重要的官方文档,请读者在有一定的基础之后务必查阅。限于作者水平,本书难免存在谬误。
当读者觉得本书中的个别论断与官方资料有冲突时,当以官方资料为标准(官方手册的网址为 https://docs.nvidia.com/cuda)。在这个网站,包括但不限于以下几个方面的文档:
- • 安装指南(installation guides)。读者遇到与 CUDA 安装有关的问题时,应该仔细阅读此处的文档。
- • 编程指南(programming guides)。该部分有很多重要的文档:
– 最重要的文档是《CUDA C++ Programming Guide》,见以下网址:https://docs.nvidia.com/cuda/cuda-c-programming-guide。
– 另一个值得一看的文档是《CUDA C++ Best Practices Guide》,见以下网址:https://docs.nvidia.com/cuda/cuda-c-best-practices-guide。
– 针对最近的几个 GPU 架构进行优化的指南,包括以下网址:
这几个简短的文档可以帮助有经验的用户迅速了解一个新的架构。
CUDA API 手册(CUDA API references)。这里有:
- – CUDA 运 行 时 API 的 手 册:https://docs.nvidia.com/cuda/cuda-runtime-api。
- – CUDA 驱动 API 的手册:https://docs.nvidia.com/cuda/cuda-driver-api。
- – CUDA 数 学 函 数 库 API 的 手 册:https://docs.nvidia.com/cuda/cuda-math-api
- – 其他若干 CUDA 库的手册。
为明确起见,在撰写本书时,作者参考的是与 CUDA 10.2 对应的官方手册。