第二章编程模型 13 2.5计算能力 设备的计算能力由主修订号和次修订号定义。 主修订号相同的设备基于相同的核心架构。Fermi架构的主修订号为2。以 前的设备的计算能力都是1.x(它们的主修订号为1)。 次修订号对应着对核心架构的增量提升,也可能包含了新特性。 附录A列出了所有支持CUDA的设备,包括它们的计算能力。附录G给出 了各计算能力设备的技术规范
第二章 编程模型 13 2.5 计算能力 设备的计算能力由主修订号和次修订号定义。 主修订号相同的设备基于相同的核心架构。Fermi 架构的主修订号为 2。以 前的设备的计算能力都是 1.x(它们的主修订号为 1)。 次修订号对应着对核心架构的增量提升,也可能包含了新特性。 附录 A 列出了所有支持 CUDA 的设备,包括它们的计算能力。附录 G 给出 了各计算能力设备的技术规范
第三章编程接口 15 第三章编程接口 CUDA C向熟悉C语言的用户提供了一种编写设备上执行的代码的简单路 径。 CUDA C包括C的最小扩展集和一个运行时库。 第二章已经介绍了语言的核心扩展,这些扩展允许程序员像定义C函数一 样定义内核和在每次内核调用时使用新的语法指定网格和块的尺寸。附录B提 供了所有扩展的详尽描述。任何包含某些扩展的源文件必须使用nvCc编译,如 3.1节概述。 3.2节介绍运行时API,运行时API在主机上执行,它提供了分配和释放设 备存储器、在主机和显存间传输数据、管理多设备的系统的函数等等。详尽的描 述请查看CUDA参考手册。 运行时API是基于驱动API构建的,应用也可以访问驱动API。驱动API 通过展示低层的概念提供了额外的控制,如CUDA上下文一类似设备上的主机 进程、CUDA模块一类似设备上的动态链接库。初始化、上下文和模块管理都是 隐式的,因此代码更简明。一个应用典型的只能使用运行时API或者驱动API 中一种,但是遵守3.4节描述的限制时,可以同时使用两种。 3.3节介绍了驱动API。详尽的描述请查看CUDA参考手册。 3.2节引入了CUDA C和驱动API共有的概念:线性存储器、CUDA数组、 共享存储器、纹理存储器、分页锁定主机存储器、设备枚举、异步执行和与图形 学API互操作。3.3节会介绍有关这些概念的知识和描述它们在驱动API中是怎 样表示的。 3.1用nvcc编译 内核可以使用PTX编写,PTX就是CUDA指令集架构,PTX参考手册中描 述了PTX。通常PTX效率高于像C一样的高级语言。无论是使用PTX还是高级 语言,内核都必须使用vcc编译成二进制代码才能在设备上执行。 vcc是一个编译器驱动,简化了C或PTX的编译流程:它提供了简单熟悉 的命令行选项,同时通过调用一系列实现了不同编译步骤的工具集来执行它们。 本节简介了nvcc的编译流程和命令选项.完整的描述可在nvcc用户手册中找到。 3.1.1编译流程 3.1.1.1离线编译 vcc可编译同时包含主机代码(在主机上执行的代码)和设备代码(在设
第三章 编程接口 15 第三章 编程接口 CUDA C 向熟悉 C 语言的用户提供了一种编写设备上执行的代码的简单路 径。 CUDA C 包括 C 的最小扩展集和一个运行时库。 第二章已经介绍了语言的核心扩展,这些扩展允许程序员像定义 C 函数一 样定义内核和在每次内核调用时使用新的语法指定网格和块的尺寸。附录 B 提 供了所有扩展的详尽描述。任何包含某些扩展的源文件必须使用 nvcc 编译,如 3.1 节概述。 3.2 节介绍运行时 API,运行时 API 在主机上执行,它提供了分配和释放设 备存储器、在主机和显存间传输数据、管理多设备的系统的函数等等。详尽的描 述请查看 CUDA 参考手册。 运行时 API 是基于驱动 API 构建的,应用也可以访问驱动 API。驱动 API 通过展示低层的概念提供了额外的控制,如 CUDA 上下文-类似设备上的主机 进程、CUDA 模块-类似设备上的动态链接库。初始化、上下文和模块管理都是 隐式的,因此代码更简明。一个应用典型的只能使用运行时 API 或者驱动 API 中一种,但是遵守 3.4 节描述的限制时,可以同时使用两种。 3.3 节介绍了驱动 API。详尽的描述请查看 CUDA 参考手册。 3.2 节引入了 CUDA C 和驱动 API 共有的概念:线性存储器、CUDA 数组、 共享存储器、纹理存储器、分页锁定主机存储器、设备枚举、异步执行和与图形 学 API 互操作。3.3 节会介绍有关这些概念的知识和描述它们在驱动 API 中是怎 样表示的。 3.1 用 nvcc 编译 内核可以使用 PTX 编写,PTX 就是 CUDA 指令集架构,PTX 参考手册中描 述了 PTX。通常 PTX 效率高于像 C 一样的高级语言。无论是使用 PTX 还是高级 语言,内核都必须使用 nvcc 编译成二进制代码才能在设备上执行。 nvcc 是一个编译器驱动,简化了 C 或 PTX 的编译流程:它提供了简单熟悉 的命令行选项,同时通过调用一系列实现了不同编译步骤的工具集来执行它们。 本节简介了 nvcc 的编译流程和命令选项。完整的描述可在 nvcc 用户手册中找到。 3.1.1 编译流程 3.1.1.1 离线编译 nvcc 可编译同时包含主机代码(在主机上执行的代码)和设备代码(在设
CUDA编程指南4.0中文版 16 备上执行的代码)的源文件。vCc的基本流程包括分离主机和设备代码然后: ■将设备代码编译成汇编形式(PTX代码)或者二进制形式(cubin对象) ■将2.1节引入的<<<…>>>语法转化为必要的CUDA C运行时函数调用以 加载和启动每个已编译的内核(来自PTX代码或者cubin对象)。 修改后的主机代码要么被输出为C代码供其它工具编译,要么在编译的最 后阶段被nvcc调用主机编译器输出为目标代码。 应用然后能够: ■要么链接到生成的主机代码, ■要么忽略生成的主机代码(如果有)在设备上使用CUDA驱动API装载 和执行PTX源码或cubin对象(参见3.3节)。 应用在运行时装载的任何PTX代码被设备驱动进一步编译成二进制代码。 这称为即时编译。即时编译增加了应用装载时间,但是可以享受编译器的最新改 进带来的好处。也是当前应用能够在未来的设备上运行的唯一方式,细节参见 3.1.4节。 3.1.1.2即时编译 任何在运行时被应用加载的PTX代码会被设备驱动进一步编译成二进制代 码,这称为即时编译。即时编译增加了应用加载时间,但允许应用从最新编译器 改进中获益,也是应用能够在应用编译时不存在的硬件上运行的唯一方法,细节 在3.1.4节。 当设备驱动为某些应用即时编译某些PTX代码,它自动缓存生成的二进制代 码的一个副本以避免在以后调用应用时重复编译。当设备驱动升级蛙该缓存(称 为计算缓存)自动失效,所以应用能够从设备驱动内置的新的即时编译器获益。 环境变量可用于控制即时编译: ■设置CUDA CACHE DISABLE为1使缓存失效(也就是没有二进制代 码增加到缓存或从缓存中检索)。 ■CUDA CACHE MAXSIZE以字节为单位指定了计算缓存的大小:默认 尺寸是32MB,最大尺寸是4GB:大小超过缓存尺寸的二进制代码不会 被缓存;需要时会清理旧的二进制代码以为新二进制代码提供空间。 ■ CUDA CACHE PATH指定了计算缓存文件存储的目录;默认值是: >Windows系统上,%APPDATA\NVIDIA\ComputeCache,. >MacOS系统上, $HOME/Library/Application\Support/NVIDIA/ComputeCache, >Linux系统上,~/.nv/ComputeCache. ■设置CUDA FORCE PTX JIT为1强制设备驱动忽略任何嵌入在应用中 的二进制代码(参见3.1.4节)而即时编译嵌入的PTX代码:如果内核 没有嵌入的PTX代码,加载失败:这个环境变量可以用于验证应用中 是否嵌入了PTX代码和即时是否如预期工作以保证应用能够和将来的 设备向前兼容
CUDA 编程指南 4.0 中文版 16 备上执行的代码)的源文件。nvcc 的基本流程包括分离主机和设备代码然后: 将设备代码编译成汇编形式(PTX 代码)或者二进制形式(cubin 对象) 将 2.1 节引入的<<<„>>>语法转化为必要的 CUDA C 运行时函数调用以 加载和启动每个已编译的内核(来自 PTX 代码或者 cubin 对象)。 修改后的主机代码要么被输出为 C 代码供其它工具编译,要么在编译的最 后阶段被 nvcc 调用主机编译器输出为目标代码。 应用然后能够: 要么链接到生成的主机代码, 要么忽略生成的主机代码(如果有)在设备上使用 CUDA 驱动 API 装载 和执行 PTX 源码或 cubin 对象(参见 3.3 节)。 应用在运行时装载的任何 PTX 代码被设备驱动进一步编译成二进制代码。 这称为即时编译。即时编译增加了应用装载时间,但是可以享受编译器的最新改 进带来的好处。也是当前应用能够在未来的设备上运行的唯一方式,细节参见 3.1.4 节。 3.1.1.2 即时编译 任何在运行时被应用加载的 PTX 代码会被设备驱动进一步编译成二进制代 码,这称为即时编译。即时编译增加了应用加载时间,但允许应用从最新编译器 改进中获益,也是应用能够在应用编译时不存在的硬件上运行的唯一方法,细节 在 3.1.4 节。 当设备驱动为某些应用即时编译某些 PTX 代码,它自动缓存生成的二进制代 码的一个副本以避免在以后调用应用时重复编译。当设备驱动升级蛙该缓存(称 为计算缓存)自动失效,所以应用能够从设备驱动内置的新的即时编译器获益。 环境变量可用于控制即时编译: 设置 CUDA_CACHE_DISABLE 为 1 使缓存失效(也就是没有二进制代 码增加到缓存或从缓存中检索)。 CUDA_CACHE_MAXSIZE 以字节为单位指定了计算缓存的大小;默认 尺寸是 32MB,最大尺寸是 4 GB;大小超过缓存尺寸的二进制代码不会 被缓存;需要时会清理旧的二进制代码以为新二进制代码提供空间。 CUDA_CACHE_PATH 指定了计算缓存文件存储的目录;默认值是: Windows 系统上,%APPDATA\NVIDIA\ComputeCache, MacOS 系统上, $HOME/Library/Application\Support/NVIDIA/ComputeCache, Linux 系统上,~/.nv/ComputeCache. 设置CUDA_FORCE_PTX_JIT为1强制设备驱动忽略任何嵌入在应用中 的二进制代码(参见 3.1.4 节)而即时编译嵌入的 PTX 代码;如果内核 没有嵌入的 PTX 代码,加载失败;这个环境变量可以用于验证应用中 是否嵌入了 PTX 代码和即时是否如预期工作以保证应用能够和将来的 设备向前兼容
第三章编程接口 17 3.1.2二进制兼容性 二进制代码是由架构特定的。生成cubin对象时,使用编译器选项-code指 定目标架构:例如,用-code=sm13编译时,为计算能力1.3的设备生成二进制 代码。二进制兼容性保证向后兼容,但不保证向前兼容,也不保证跨越主修订 号兼容。换句话说,为计算能力为Xy生成的cubin对象只能保证在计算能力为 Xz的设备上执行,这里,z>y。 3.1.3PTX兼容性 一些PTX指令只被高计算能力的设备支持。例如,全局存储器上的原子指 令只在计算能力1.1及以上的设备上支持:双精度指令只在1.3及以上的设备上 支持。将C编译成PTX代码时,-arch编译器选项指定假定的计算能力。因此包 含双精度计算的代码,必须使用“-arch=sm13”(或更高计算能力)编译,否则 双精度计算将被降级为单精度计算。 为某些特殊计算能力生成的PTX代码始终能够被编译成相等或更高计算能 力设备上的二进制代码。(译者注:PTX保证完全的向后兼容,而二进制只保证 主修订号相同的向后兼容) 3.14应用兼容性 为了在特定计算能力的设备上执行代码,应用加载的二进制或PTX代码必 须满足如3.1.2节和3.1.3节说明的计算能力兼容性。特别地,为了能在将来更高 计算能力(不能产生二进制代码)的架构上执行,应用必须装载PTX代码并为 那些设备即时编译(参见3.1.1.2节)。 CUDA C应用中嵌入的PTX和二进制代码由-arch和-code编译器选项或 -gencode编译器选项控制,详见nvcc用户手册。例如, nvec x.cu -gencode arch=compute_10,code=sm_10 -gencode arch=compute_11,code=\'compute_11,sm_11\' 嵌入与计算能力l.0兼容的二进制代码(第一个-gencode选项)和PTX和与 计算能力1.1兼容的二进制代码(第二个-gencode选项)。 生成的主机代码在运行时自动选择最合适的代码装载并执行,对于上面例子, 将会是: ■1.0二进制代码为计算能力1.0设备, ■1.1二进制代码为计算能力1.1,1.2,1.3的设备, ■通过为计算能力2.0或更高的设备编译1.1PTX代码获得的二进制代码。 例如,x.cu可有一个使用原子指令的优化代码途径,只能支持计算能力1.1 或更高的设备。CUDA ARCH宏可以基于计算能力用于不同的代码途径
第三章 编程接口 17 3.1.2 二进制兼容性 二进制代码是由架构特定的。生成 cubin 对象时,使用编译器选项-code 指 定目标架构:例如,用-code=sm_13 编译时,为计算能力 1.3 的设备生成二进制 代码 。二进制兼容性保证向后兼容,但不保证向前兼容,也不保证跨越主修订 号兼容。换句话说,为计算能力为 X.y 生成的 cubin 对象只能保证在计算能力为 X.z 的设备上执行,这里,z>=y。 3.1.3 PTX 兼容性 一些 PTX 指令只被高计算能力的设备支持。例如,全局存储器上的原子指 令只在计算能力 1.1 及以上的设备上支持;双精度指令只在 1.3 及以上的设备上 支持。将 C 编译成 PTX 代码时,-arch 编译器选项指定假定的计算能力。因此包 含双精度计算的代码,必须使用“-arch=sm_13”(或更高计算能力)编译,否则 双精度计算将被降级为单精度计算。 为某些特殊计算能力生成的 PTX 代码始终能够被编译成相等或更高计算能 力设备上的二进制代码。(译者注:PTX 保证完全的向后兼容,而二进制只保证 主修订号相同的向后兼容) 3.1.4 应用兼容性 为了在特定计算能力的设备上执行代码,应用加载的二进制或 PTX 代码必 须满足如 3.1.2 节和 3.1.3 节说明的计算能力兼容性。特别地,为了能在将来更高 计算能力(不能产生二进制代码)的架构上执行,应用必须装载 PTX 代码并为 那些设备即时编译(参见 3.1.1.2 节)。 CUDA C 应用中嵌入的 PTX 和二进制代码由-arch 和-code 编译器选项或 -gencode 编译器选项控制,详见 nvcc 用户手册。例如, 嵌入与计算能力 1.0 兼容的二进制代码(第一个-gencode 选项)和 PTX 和与 计算能力 1.1 兼容的二进制代码(第二个-gencode 选项)。 生成的主机代码在运行时自动选择最合适的代码装载并执行,对于上面例子, 将会是: 1.0 二进制代码为计算能力 1.0 设备, 1.1 二进制代码为计算能力 1.1,1.2,1.3 的设备, 通过为计算能力 2.0 或更高的设备编译 1.1PTX 代码获得的二进制代码。 例如,x.cu 可有一个使用原子指令的优化代码途径,只能支持计算能力 1.1 或更高的设备。__CUDA_ARCH__宏可以基于计算能力用于不同的代码途径。 nvcc x.cu –gencode arch=compute_10, code=sm_10 –gencode arch=compute_11, code=\‘compute_11,sm_11\‘
CUDA编程指南4.0中文版 e 它只为设备代码定义.例如,当使用“arch=compte11”编译时,_CUDA ARCH 等于110。 使用驱动API的应用必须将代码编译成分立的文件,且在运行时显式装载 和执行最合适的文件。 nvcc用户手册为-arch,-code和-gencode编译器选项列出了多种简写。如 “arch=sm_13”是“arch=compute_13code=compute_13,sm_13”的简写(等 价于“-gencode arch=compute_13,code=|'compute_13,sm_131'”)。 3.1.5C/C++兼容性 编译器前端依据C++语法规则处理CUDA源文件。主机代码完整支持C++。 设备代码只完整支持C+的一个子集,详见附录D。由于使用了C+的语法规则, 空指针(如malloc(0的返回值)不能赋值给非空指针,必须转型后才能赋值。 3.1.664位兼容性 在计算能力2.0的设备上,设备代码可以使用64位模式编译(也就是指针 是64位的)。只有在主机代码是以64位模式编译的时候,设备代码才支持64 位模式。 类似地,32位的nv℃c以32位模式编译设备代码,使用32位模式编译的设 备代码只支持以32位模式编译的主机代码。 32位的nvcc使用-m64编译选项以64位模式编译设备代码。 64位的nvcc使用-m32编译选项以32位模式编译设备代码。 3.2 CUDA C运行时 cudart动态库是运行时的实现,它包含在应用的安装包里,所有的入口点前 缀都是cuda。 如2.4节所述,CUDA编程模型假设系统包含主机和设备,它们都有自己独 立的存储器。3.2.2节给出了一个操纵设备存储器的函数的简介。 3.2.3节描述了如何使用2.2节引入的共享存储器以最大化性能。 3.2.4节引入了分布锁定主机存储器,需要它以重叠内核执行和主机和设备 间的数据传输。 3.2.5节描述了支持系统中不同层次的异步并发执行的概念和API。 3.2.6节描述了展示了编程模型如何扩展到拥有连接多个设备的主机系统。 3.2.8节描述了如何合适的检查主机产生的错误。 3.2.9节提到操纵CUDA C调用栈的运行时函数。 3.2.10节展现了纹理和表面存储器空间,它们提供了另一种访问设备存储器 的方式:它们是GPU纹理硬件的一个子集
CUDA 编程指南 4.0 中文版 18 它只为设备代码定义。例如,当使用“arch=compte_11”编译时,__CUDA_ARCH__ 等于 110。 使用驱动 API 的应用必须将代码编译成分立的文件,且在运行时显式装载 和执行最合适的文件。 nvcc 用户手册为-arch,-code 和-gencode 编译器选项列出了多种简写。如 “arch=sm_13”是“arch=compute_13 code=compute_13,sm_13”的简写(等 价于“-gencode arch=compute_13,code=\’compute_13,sm_13\’”)。 3.1.5 C/C++兼容性 编译器前端依据 C++语法规则处理 CUDA 源文件。主机代码完整支持 C++。 设备代码只完整支持 C++的一个子集,详见附录 D。由于使用了 C++的语法规则, 空指针(如 malloc()的返回值)不能赋值给非空指针,必须转型后才能赋值。 3.1.6 64 位兼容性 在计算能力 2.0 的设备上,设备代码可以使用 64 位模式编译(也就是指针 是 64 位的)。只有在主机代码是以 64 位模式编译的时候,设备代码才支持 64 位模式。 类似地,32 位的 nvcc 以 32 位模式编译设备代码,使用 32 位模式编译的设 备代码只支持以 32 位模式编译的主机代码。 32 位的 nvcc 使用-m64 编译选项以 64 位模式编译设备代码。 64 位的 nvcc 使用-m32 编译选项以 32 位模式编译设备代码。 3.2 CUDA C 运行时 cudart 动态库是运行时的实现,它包含在应用的安装包里,所有的入口点前 缀都是 cuda。 如 2.4 节所述,CUDA 编程模型假设系统包含主机和设备,它们都有自己独 立的存储器。3.2.2 节给出了一个操纵设备存储器的函数的简介。 3.2.3 节描述了如何使用 2.2 节引入的共享存储器以最大化性能。 3.2.4 节引入了分布锁定主机存储器,需要它以重叠内核执行和主机和设备 间的数据传输。 3.2.5 节描述了支持系统中不同层次的异步并发执行的概念和 API。 3.2.6 节描述了展示了编程模型如何扩展到拥有连接多个设备的主机系统。 3.2.8 节描述了如何合适的检查主机产生的错误。 3.2.9 节提到操纵 CUDA C 调用栈的运行时函数。 3.2.10 节展现了纹理和表面存储器空间,它们提供了另一种访问设备存储器 的方式;它们是 GPU 纹理硬件的一个子集