CUDA编程接口介绍

接口/总线/驱动

1125人已加入

描述

Programming Interface

编程模型中介绍了核心语言扩展。它们允许程序员将内核定义为c++函数,并在每次调用函数时使用一些新的语法来指定网格和块维度。在c++语言扩展中可以找到对所有扩展的完整描述。任何包含这些扩展名的源文件都必须用nvcc编译。

CUDA runtime中介绍了运行时。它提供在主机上执行的C和c++函数,用于分配和释放设备内存,在主机内存和设备内存之间传输数据,管理具有多个设备的系统,等等。

运行时构建在较低级的C API (CUDA驱动程序API)之上,该API也可由应用程序访问。驱动程序API通过公开诸如 CUDA contexts (the analogue of host processes for the device)和 CUDA modules (the analogue of dynamically loaded libraries for the device.)等较低级别的概念提供了额外的控制级别。大多数应用程序不使用驱动程序API,因为它们不需要这种额外级别的控制,而且在使用运行时时,上下文和模块管理是隐式的,因此代码更简洁。由于运行时与驱动程序API是互操作的,大多数需要一些驱动程序API特性的应用程序可以默认使用运行时API,并且只在需要的地方使用驱动程序API。

Compilation with NVCC

内核可以使用CUDA指令集体系结构(称为PTX)编写。内核必须被NVCC编译成二进制代码才能在设备上执行。

nvcc是一个编译器驱动程序,它简化了编译c++或PTX代码的过程 :它提供了简单而熟悉的命令行选项,并通过调用实现不同编译阶段的工具集合来执行它们。本节概述了nvcc工作流和命令选项。

Compilation Workflow

Offline Compilation

用nvcc编译的源文件可以包括主机代码(即在主机上执行的代码)和设备代码(即在设备上执行的代码)的混合。nvcc的基本工作流程包括将设备代码从主机代码中分离出来,然后:

  • 将设备代码编译为汇编形式(PTX代码) 和/或二进制形式(cubin对象),
  • 通过替换<<<…>>>语法在kernel中引入(并在执行配置中详细描述),通过必要的CUDA运行时函数调用从PTX代码和/或cubin对象加载和启动每个编译的内核。

修改后的主机代码要么以c++代码的形式输出,留待使用其他工具编译。要么在最后编译阶段让nvcc调用主机编译器,直接以目标代码的形式输出。

应用程序可以:

  • 链接到已编译的主机代码(这是最常见的情况),
  • 或者忽略修改过的主机代码(如果有的话),并使用CUDA驱动程序API(参见驱动程序API)来加载和执行PTX代码或立方体对象。

Just-in-Time Compilation

应用程序在运行时加载的任何 PTXNVVM IR 代码都被设备驱动程序进一步编译为二进制代码。这被称为即时编译。即时编译增加了应用程序的加载时间,但允许应用程序从每个新设备驱动程序带来的任何新的编译器改进中受益。这也是让应用程序在编译应用程序时还不存在的设备上运行的唯一方法,详见应用程序兼容性。

当设备驱动程序为某个应用程序实时编译一些PTX或NVVM IR代码时,它会自动缓存生成的二进制代码的副本,以避免在后续的应用程序调用中重复编译 。当设备驱动程序升级时,缓存(称为compute cache)将自动失效,因此应用程序可以从设备驱动程序中内置的新即时编译器的改进中受益。

作为使用nvcc编译CUDA c++设备代码的替代方案,NVRTC可以在运行时将CUDA c++设备代码编译为PTX。NVRTC是CUDA c++的运行时编译库。

Binary Compatibility

二进制代码是特定于体系结构的 。cubin对象是使用指定目标体系结构的编译器选项-code生成的.例如,使用-code=sm_35编译会为计算能力为3.5的设备生成二进制代码。二进制兼容性可以保证从一个小修订到下一个小修订,但不能保证从一个小修订到前一个小修订或跨多个大修订。换句话说,为计算能力X.y生成的立方对象将只在计算能力X.z的设备上执行,其中z≥y。

设备的compute capability由版本号表示,有时也称为“ SM version

PTX Compatibility

一些PTX指令只在具有较高计算能力的设备上支持。例如,Warp Shuffle Functions仅在计算能力3.0及以上的设备上支持。-arch compiler选项指定在将c++编译为PTX代码时所假定的计算能力。因此,例如,包含warp shuffle的代码必须使用-arch=compute_30(或更高)编译。

为某些特定计算能力而产生的PTX代码总是可以编译成具有更大或同等计算能力的二进制代码 。注意,从较早的PTX版本编译的二进制文件可能不能使用某些硬件特性。例如,由计算能力6.0 (Pascal)生成的PTX编译的计算能力7.0 (Volta)的二进制目标设备将不会使用张量核心指令,因为这些在Pascal上是不可用的。因此,最终的二进制代码可能比使用PTX的最新版本生成的二进制代码的性能更差。

Application Compatibility

要在具有特定计算能力的设备上执行代码,应用程序必须加载与该计算能力兼容的二进制或PTX代码。特别是,为了能够在未来具有更高计算能力的体系结构上执行代码(目前还不能生成二进制代码),应用程序必须加载为这些设备实时编译的PTX代码(参见实时编译)。

哪一个PTX和二进制代码嵌入CUDA c++应用程序是由-arch-code编译器选项或-gencode编译器选项控制的,详见nvcc用户手册。例如:

nvcc x.cu
        -gencode arch=compute_50,code=sm_50
        -gencode arch=compute_60,code=sm_60
        -gencode arch=compute_70,code=\\"compute_70,sm_70\\"

嵌入与计算能力5.0和6.0兼容的二进制代码(第一个和第二个-gencode选项),以及与计算能力7.0兼容的PTX和二进制代码(第三个-gencode选项)。

生成主机代码以在运行时自动选择最合适的代码来加载和执行,在上面的例子中,将是:

  • 5.0二进制代码用于具有5.0和5.2计算能力的设备
  • 6.0二进制代码用于具有6.0和6.1计算能力的设备
  • 7.0二进制代码用于具有7.0和7.5计算能力的设备
  • PTX代码,在运行时编译为二进制代码,用于具有8.0和8.6计算能力的设备。

x.cu可以有一个使用扭曲洗刷操作的优化代码路径,例如,这只在计算能力3.0及更高的设备中得到支持。可以使用__CUDA_ARCH__宏根据计算能力区分不同的代码路径。它仅为设备代码定义。例如,当使用-arch=compute_35编译时,__CUDA_ARCH__等于350.

C++ Compatibility

编译器前端根据c++语法规则处理CUDA源文件。主机代码支持完全c++。然而,设备代码只完全支持c++的一个子集.

64-Bit Compatibility

64位版本的nvcc以64位模式编译设备代码(即指针为64位)。64位编译的设备代码只支持64位编译的主机代码。

同样,32位版本的nvcc以32位模式编译设备代码,32位模式编译的设备代码只支持32位模式编译的主机代码。

  • 32位版本的nvcc可以使用-m64编译器选项在64位模式下编译设备代码。
  • 64位版本的nvcc可以使用-m32编译器选项在32位模式下编译设备代码。
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分