CUDA 12.4文档4 编程接口之使用NVCC编译

2024-04-13 13:44

本文主要是介绍CUDA 12.4文档4 编程接口之使用NVCC编译,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本博客参考官方文档进行介绍,全网仅此一家进行中文翻译,走过路过不要错过。

官方网址:https://docs.nvidia.com/cuda/cuda-c-programming-guide/

本文档分成多个博客进行介绍,在本人专栏中含有所有内容:

https://blog.csdn.net/qq_33345365/category_12610860.html

CUDA 12.4为2024年3月2日发表,本专栏开始书写日期2024/4/8,当时最新版本4.1

本人会维护一个总版本,一个小章节的版本,总版本会持续更新,小版本会及时的调整错误和不合理的翻译,内容大部分使用chatGPT 4翻译,部分内容人工调整


开始编辑时间:2024/4/8;最后编辑时间:2024/4/13

第六章 编程接口

CUDA C++为熟悉C++编程语言的用户提供了一个简单的路径,可以轻松地编写用于设备执行的程序。

它由C++语言的最小扩展和一个运行时库组成。

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

运行时在CUDA运行时章节中介绍。它提供在主机上执行的C和C++函数,用于分配和释放设备内存,传输主机内存和设备内存之间的数据,管理多设备系统等。运行时的完整描述可以在CUDA参考手册中找到。

运行时是在一个更低级别的C API之上构建的,即CUDA驱动程序API,该API也可由应用程序访问。驱动程序API通过公开诸如CUDA上下文(设备的主机进程的类似物)和CUDA模块(设备的动态加载库的类似物)等较低级别概念,提供了额外的控制级别。大多数应用程序不使用驱动程序API,因为它们不需要这种额外的控制级别,而当使用运行时时,上下文和模块管理是隐式的,从而使代码更加简洁。由于运行时与驱动程序API互通,因此,大多数需要使用驱动程序API功能的应用程序可以默认使用运行时API,并且只在需要的时候使用驱动程序API。驱动程序API在驱动程序API章节中介绍,并在参考手册中完全描述。

6.1 使用NVCC编译

内核可以使用CUDA指令集架构编写,称为PTX,其在PTX参考手册中有描述。然而,通常使用如C++这样的高级编程语言更有效。在这两种情况下,内核必须由nvcc编译成二进制代码以在设备上执行。

nvcc是一个编译器驱动程序,简化了编译C++或PTX代码的过程:它提供简单且熟悉的命令行选项,并通过调用实现不同编译阶段的工具集来执行它们。本节给出了nvcc工作流程和命令选项的概述。完整的描述可以在nvcc用户手册中找到。

6.1.1 编译工作流

6.1.1.1 离线编译

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

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

修改的主机代码输出为C++代码,该代码将留待使用其他工具进行编译,或者通过让nvcc在最后的编译阶段调用主机编译器,直接以对象代码的形式输出。
然后,应用程序可以:

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

任何在运行时由应用程序加载的PTX代码都将由设备驱动程序进一步编译为二进制代码。这被称为即时编译。即时编译会增加应用程序的加载时间,但允许应用程序受益于每个新设备驱动程序带来的任何新的编译器改进。这也是应用程序在编译时尚不存在的设备上运行的唯一方式,如在应用程序兼容性章节中详细描述的那样。

当设备驱动程序为某些应用程序即时编译一些PTX代码时,它会自动缓存生成的二进制代码的一个副本,以避免在随后的应用程序调用中重复编译。缓存 - 称为计算缓存 - 在升级设备驱动程序时会自动失效,以便应用程序可以从内置在设备驱动程序中的新即时编译器的改进中受益。

环境变量可用于控制即时编译,如在CUDA环境变量章节中所描述的那样。

作为使用nvcc编译CUDA C++设备代码的替代方案,可以使用NVRTC在运行时将CUDA C++设备代码编译为PTX。 NVRTC是一个用于CUDA C++的运行时编译库;更多信息可以在NVRTC用户指南中找到。

6.1.2 二进制兼容性 Binary Compatibility

二进制代码是特定于架构的。 使用编译器选项-code生成cubin对象,该选项指定目标架构:例如,使用-code=sm_80编译将为计算能力为8.0的设备生成二进制代码。 从一个次要版本到下一个次要版本保证了二进制兼容性,但在一个次要版本到上一个次要版本或者在主要版本之间并不保证。换句话说,为计算能力X.y生成的cubin对象只能在计算能力为X.z的设备上执行,其中 z > y z>y z>y

6.1.3 PTX兼容性

一些PTX指令只在具有更高计算能力的设备上支持。例如,Warp Shuffle函数只在计算能力为5.0及以上的设备上支持。-arch编译器选项指定在将C++编译为PTX代码时假定的计算能力。因此,包含warp shuffle的代码,例如,必须使用-arch=compute_50(或更高)进行编译。

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

编译为目标架构条件特性的PTX代码只在完全相同的物理架构上运行,其他地方无法运行。架构条件PTX代码不具有向前和向后的兼容性。例如,使用sm_90a或compute_90a编译的代码只能在计算能力为9.0的设备上运行,而且不向后或向前兼容。

6.1.4 应用兼容性

要在具有特定计算能力的设备上执行代码,应用程序必须加载与此计算能力兼容的二进制或PTX代码,如在二进制兼容性章节PTX兼容性章节中所述。特别是,要能够在具有更高计算能力的未来架构上执行代码(对于这些架构,尚无法生成二进制代码),应用程序必须加载将为这些设备进行即时编译的PTX代码(参见即时编译章节)。

在CUDA C++应用程序中嵌入哪些PTX和二进制代码由-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.2的设备,执行5.0的二进制代码,
  • 对于计算能力为6.0和6.1的设备,执行6.0的二进制代码,
  • 对于计算能力为7.0和7.5的设备,执行7.0的二进制代码,
  • 对于计算能力为8.0和8.6的设备,执行在运行时编译为二进制代码的PTX代码。

例如,x.cu可以有一个优化的代码路径,该路径使用Warp Reduction操作,这些操作只在计算能力为8.0及以上的设备上支持。__CUDA_ARCH__宏可以用来区分基于计算能力的各种代码路径。它仅为设备代码定义。例如,使用-arch=compute_80编译时,__CUDA_ARCH__等于800。

如果x.cu针对架构条件特性以sm_90a或compute_90a编译,代码只能在计算能力为9.0的设备上运行。

使用驱动API的应用程序必须将代码编译为单独的文件,并在运行时显式加载和执行最合适的文件。

Volta架构引入了独立线程调度,这改变了GPU上线程的调度方式。对于依赖于前一架构中SIMT调度的特定行为的代码,独立线程调度可能会改变参与的线程集,导致结果不正确。为了在实施独立线程调度中详细描述的的纠正操作时帮助迁移,Volta开发者可以选择使用编译器选项组合-arch=compute_60 -code=sm_70以选择Pascal的线程调度。
nvcc用户手册列出了-arch、-code和-gencode编译器选项的各种简写。例如,-arch=sm_70是-arch=compute_70 -code=compute_70,sm_70的简写(它与-gencode arch=compute_70,code="compute_70,sm_70"相同)。

6.1.5 C++兼容性

编译器的前端按照C++语法规则处理CUDA源文件。主机代码支持完整的C++。然而,对于设备代码,只有一部分C++得到了完全支持,如在C++语言支持章节中所述。

6.1.6 64位兼容性

nvcc的64位版本以64位模式编译设备代码(即,指针为64位)。只有与64位模式的主机代码结合使用时,64位模式编译的设备代码才受支持。

这篇关于CUDA 12.4文档4 编程接口之使用NVCC编译的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/900301

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三