当下大模型推理、AI训练、高性能计算场景遍地开花,绝大多数开发者日常都在和CUDA打交道。很多人能够熟练调用CUDA API、跑通cuda‑samples示例工程,会编写Kernel核函数、熟练使用cudaMalloc、cudaMemcpy,以及通过<<<>>>语法启动核函数,但极少有人能完整吃透底层逻辑:一份.cu源代码,究竟如何一步步转化为GPU硬件可识别的二进制指令?用户态程序发起Kernel调用后,会经过哪些软件层级?如何穿透操作系统内核驱动交付至GPU硬件调度单元?流多处理器SM如何完成并行计算?计算完成后,结果又是如何逐层回传给主机应用程序的?
市面上绝大多数CUDA教程,仅停留在API实操层面,将异构计算流程简单概括为“CPU分配内存、拷贝数据、启动Kernel、回传结果”四步极简流程,对核心的编译链路、Runtime与驱动的层级交互、Linux内核协同逻辑、GPU硬件内部调度机制等关键底层原理一笔带过。而cuda‑samples作为NVIDIA官方配套CUDA Toolkit的标准示例仓库,涵盖了最标准、最纯粹的CUDA基础实现。其中经典的vectorAdd向量加法示例,是我们复盘CUDA全链路运行逻辑的最佳范本。本文将以该示例为核心解剖对象,完整拆解从源码编译、二进制指令生成、Runtime调度、内核驱动任务下发、GPU硬件并行执行到结果回传的全流程,层层拆解技术黑盒,理清每一个环节的运行细节,帮助开发者跳出“只会调用API”的浅层阶段,真正掌握CUDA算力运行的底层核心逻辑。
阅读建议:本文偏向底层原理,适合有基础 CUDA 开发经验、做性能调优、GPU 底层调试、算子开发的技术人员阅读,会涉及编译链、用户态‑内核态交互、GPU 硬件调度概念。 |
一、先认识我们的解剖样本:cuda‑samples 中的 vectorAdd 示例
cuda‑samples是NVIDIA官方随CUDA Toolkit同步发布的开源示例工程集合,覆盖CUDA入门基础、内存模型、流同步机制、自定义算子、多卡协同、性能调优、底层调试等全场景技术案例。其中vectorAdd是CUDA入门最经典、链路最完整的示例,核心逻辑简洁清晰:依托GPU并行算力,完成两个浮点数组的逐元素加法运算,最终输出全新的结果数组,完整覆盖CUDA异构计算的全部核心操作。
整个示例代码逻辑可以简单概括:
主机 CPU 侧分配内存,初始化输入数组 A、B;
通过cudaMalloc在 GPU 显存上分配设备内存;
cudaMemcpyHostToDevice把 CPU 内存数据拷贝到 GPU 显存;
使用vectorAddKernel<<>>启动 GPU 核函数,在 GPU 完成大规模向量加法;
核函数执行完毕,调用cudaMemcpyDeviceToHost把计算结果从 GPU 显存拷贝回主机内存;
CPU 校验计算结果正确性,释放主机、设备内存,程序退出。
绝大多数开发者仅掌握了这套表层业务逻辑,但从执行nvcc编译命令,到Kernel真正在GPU硬件上完成并行运算,背后隐藏着一套超长、精密的软硬件流水线。很多开发者始终存在诸多疑惑:相同的CUDA源码,为何能兼容不同架构的GPU?看似特殊的<<>>启动语法,底层究竟对应何种调用逻辑?Kernel二进制指令编译后存储在何处?是否程序启动就会加载到GPU?CPU发起Kernel调用后,GPU是如何感知并接收任务的?接下来我们从编译阶段切入,逐层拆解、完整复盘CUDA程序的全生命周期运行流程。
二、编译阶段:.cu 源码到包含 GPU 二进制的主机可执行文件
在Linux环境中,我们常用nvcc vectorAdd.cu ‑o vectorAdd命令编译CUDA程序。很多人误以为nvcc是独立的编译工具,实则不然,nvcc的核心定位是编译驱动程序(compiler driver)。它不直接完成全部编译工作,而是统筹调度整套CUDA专属编译工具链,自动拆分主机端与设备端代码,分别完成编译优化,最终将两套目标文件链接合并,生成Linux平台下ELF格式的可执行程序,适配CPU启动、GPU运算的双端运行特性。
整个编译流水线分为源码拆分、设备代码编译、主机代码编译、胖二进制打包、链接五大步骤,为了方便大家直观理解整体链路,我先放出完整编译流程图,后续再逐环节拆解细节:
A[CUDA .cu 混合源码] B[预处理 & 双端代码拆分] C[设备端编译: CUDA C++ → PTX 汇编] D[汇编编译: PTX → SASS(cubin)机器码] E[打包生成 FatBinary 胖二进制] F[主机端编译: 生成 CPU 目标文件] G[链接 libcudart.so 运行时库] H[输出 ELF 可执行文件内嵌GPU完整指令集] A --> B B --> C --> D --> E B --> F E & F --> G --> H |
2.1 源码分离:区分 Host 主机代码与 Device 设备代码
cu 文件里面混合两种代码:
Host 主机代码:普通 C++ 代码,运行在 CPU,main 函数、cudaMalloc、cudaMemcpy 这些 Runtime API 调用全部属于主机代码;
Device 设备代码:被__global__修饰的 kernel 核函数,只能运行在 GPU 硬件内部。
nvcc会调用内置的cudafe++工具,对.cu源码进行预处理、语法解析与语义校验,将混合的源码切分为两套独立的代码体系:主机端标准C++代码、GPU设备端专属代码。这里有一个90%开发者都不了解的核心细节:源码中用于启动核函数的vectorAddKernel<<>>(d_A, d_B, d_C, N)语法,并非C++原生语法。在编译预处理阶段,cudafe++会自动将该特殊语法,改写为CUDA Runtime底层的标准函数调用。<<<>>>因此编译完成后的主机二进制文件中,完全不存在语法标识,全部转化为libcudart运行库的内置调用逻辑,这也是核函数能够正常启动的底层核心前提。
2.2 设备代码编译:CUDA C++ Kernel → PTX 中间汇编 → cubin (SASS) GPU 硬件二进制
分离出来的__global__kernel 设备代码,会送入 GPU 编译链路,分为两级编译:
第一步:编译生成PTX中间汇编代码。PTX全称为Parallel Thread Execution,是NVIDIA定义的硬件无关型虚拟GPU汇编指令集,属于跨架构中间表示,不绑定任何一代GPU硬件架构。其作用类似于LLVM-IR,仅用于描述Kernel的运算逻辑、线程调度规则与数据读写逻辑,无法直接被GPU硬件识别执行。PTX的核心价值是实现CUDA程序的向前兼容,编译阶段无需适配具体GPU型号,程序运行时可通过驱动JIT即时编译,动态转化为对应硬件的专属指令。
第二步:汇编生成SASS硬件二进制指令。nvcc配套的ptxas汇编器,会将通用PTX中间代码编译为cubin格式二进制文件,文件内部封装的SASS指令,是对应特定SM架构的GPU原生机器码,也是唯一能被GPU硬件直接解码、执行的指令格式。sm_86、sm_90等不同架构的GPU,指令集互不兼容,单份cubin文件仅能适配对应架构的硬件,无法跨架构直接运行。
nvcc支持一次性编译生成多架构适配的cubin二进制文件,同时保留通用PTX中间代码。这些跨架构指令文件不会单独输出,而是统一打包封装为FatBinary(胖二进制)数据块。该数据块会以专属二进制段的形式,嵌入主机端目标obj文件中,最终随链接流程整合进ELF可执行程序。简单来说,我们编译得到的vectorAdd可执行文件,并非单纯的CPU运行程序,其内部封存了整套GPU Kernel的PTX中间代码与多架构SASS硬件二进制指令。在程序未运行时,这些GPU指令仅静态存储在磁盘文件中,完全不会加载至GPU显存。
划重点:编译完成后,GPU可执行的SASS二进制指令仅存储在主机可执行文件的胖二进制段中,尚未加载至GPU设备显存。只有程序运行后,首次启动对应Kernel时,CUDA Runtime才会读取解析胖二进制数据,匹配当前设备GPU架构:若存在预编译的适配cubin文件,直接调用原生SASS指令;若无适配指令,则调取通用PTX代码,通过驱动JIT即时编译动态生成对应硬件的SASS指令,再加载至GPU显存执行。这也是CUDA程序能够跨显卡、跨版本兼容的底层核心原理。 |
2.3 主机代码编译与链接
剥离设备端代码后的纯主机C++代码,会调用Linux系统原生gcc/g++编译器完成编译,生成CPU可识别的目标obj文件。该文件包含两部分核心内容:CPU运行的机器码、嵌入文件段内的FatBinary GPU二进制数据块。
随后链接器会将obj文件与CUDA核心运行时库libcudart.so完成链接整合,我们日常调用的cudaMalloc、cudaMemcpy等所有CUDA Runtime API,均由该动态库提供底层实现。链接完成后,最终生成Linux标准ELF格式可执行文件vectorAdd。
至此,完整编译流程结束。此时磁盘中的可执行文件可直接被CPU加载运行,文件内部封存了全套GPU Kernel指令数据,但GPU硬件尚未感知任何任务与指令,处于空闲待命状态。
三、程序启动运行:从 main 执行到 Kernel 即将下发 GPU
在终端执行./vectorAdd启动程序后,操作系统会将ELF可执行文件加载至进程虚拟地址空间,CPU从main函数入口开始逐行执行代码。整个程序运行过程,会逐级穿透多层软硬件架构,完整调用链路为:应用程序 → CUDA Runtime(libcudart.so 用户态) → CUDA驱动API(libcuda.so 用户态) → Linux内核NVIDIA驱动模块 → PCIe总线 → GPU硬件,我们逐层拆解每一级的运行逻辑。
3.1 进程初始化、CUDA 上下文创建
main 函数执行之后,当第一次调用任意 CUDA Runtime 接口(比如 cudaMalloc),Runtime 会隐式完成几件核心工作:
加载底层驱动动态库libcuda.so,该库封装了底层原生Driver API,CUDA Runtime本质是对原生驱动接口的高层封装与简化适配,降低开发者的调用门槛;
向Linux内核nvidia驱动模块发起系统调用,为当前运行进程创建专属CUDA Context(GPU上下文)。CUDA Context是进程在GPU侧的独立运行沙箱,GPU会为每个进程独立维护专属虚拟地址空间、显存资源、运算模块、流队列资源,进程间GPU资源完全隔离、互不干扰。上下文初始化完成后,系统会建立GPU虚拟地址与物理地址的映射关系,为后续所有显存操作、Kernel调度提供基础支撑。
很多开发者分不清Runtime API与Driver API的区别:Runtime API封装度更高、使用更简洁,可自动管理Context生命周期,适配绝大多数开发场景;Driver API更加底层、灵活度更高,需要开发者手动管理上下文、模块加载与资源释放。libcudart的所有高层接口,最终都会下沉调用libcuda.so底层驱动接口,通过系统调用陷入Linux内核驱动,完成与GPU的交互。
3.2 cudaMalloc 分配显存、cudaMemcpy 数据拷贝发生了什么
代码执行至cudaMalloc显存分配接口时,不会直接操作GPU硬件,而是逐层下沉至libcuda.so驱动库,通过系统调用进入Linux内核nvidia驱动模块。内核驱动负责向GPU硬件申请物理显存资源,建立进程GPU虚拟地址与GPU物理显存的页表映射关系,最终将设备显存虚拟指针返回给上层应用,也就是代码中d_A、d_B、d_C等设备指针。
显存分配完成后,cudaMemcpyHostToDevice接口会启动主机到设备的数据搬运逻辑,将CPU内存中的原始数据拷贝至GPU显存。所有数据拷贝操作会被封装为标准化命令包,投递至GPU默认0号流的环形命令缓冲区(Ring Buffer)。这里是CUDA异步机制的核心:Stream流是GPU的专属命令队列,Kernel启动、内存拷贝、同步等待等所有操作,均以命令形式入队排队。CPU投递命令后无需阻塞等待,可直接执行后续代码,实现CPU与GPU的并行运行,仅显式调用同步接口时才会阻塞等待任务完成。数据拷贝命令入队后,会通过GPU Doorbell门铃机制触发硬件通知,GPU内部DMA控制器通过PCIe总线完成数据搬运,将主机数据同步至GPU显存。
此时 GPU 显存中已经准备好了输入向量 A、B 的数据,接下来就到最关键的 kernel 核函数启动调用。
3.3 执行 Kernel 启动调用,Runtime 解析胖二进制,加载 GPU 二进制到显存
代码执行到改写之后的 kernel 启动接口,也就是原代码vectorAddKernel<<>>(...)对应的底层 Runtime 函数。
Runtime会优先读取当前进程可执行文件中内嵌的FatBinary胖二进制数据,解析内部存储的多架构cubin指令与通用PTX指令,再自动匹配当前运行设备的GPU SM架构,完成指令适配:
如果胖二进制内已经存在对应架构预编译 cubin(包含 SASS 硬件二进制),直接取出这份 SASS 指令流;
如果没有对应 cubin,则取出 PTX 中间代码,交给驱动 JIT 编译器现场编译,生成适配本机 GPU 的 SASS 二进制指令。
适配完成、生成合规的SASS硬件二进制指令后,Runtime调用底层Driver API,将Kernel对应的SASS机器码加载至GPU显存(全局内存或片上指令缓存),同时记录Kernel在GPU虚拟地址空间的入口地址。至此,GPU硬件才真正加载到可直接执行的Kernel指令,具备并行运算的基础条件。
这里纠正一个高频认知误区:GPU不会在程序启动时预加载所有Kernel指令,仅首次调用Launch接口启动对应Kernel时,才会完成胖二进制解析、指令编译与显存加载。后续重复调用同一Kernel时,会直接复用显存中已加载的SASS指令,无需重复编译加载,这也是首次运行Kernel存在轻微卡顿、后续运行极速的核心原因。 |
指令加载完成后,Runtime会整合所有Kernel调度参数,封装为标准化GPU命令包(Command Packet),核心包含Kernel显存入口地址、Grid/Block线程维度、单Block共享内存配额、Kernel参数显存指针、所属Stream流编号等关键信息。该命令包是GPU硬件的唯一任务执行依据,完整定义了GPU需要执行的指令、线程规模与资源配置。
四、用户态下发命令:穿过 Linux 内核驱动,通知 GPU 硬件
命令包封装完成后,Runtime向下调用libcuda.so驱动库,将Kernel Launch任务命令写入主机锁定页内存(Pinned Memory)中的Ring Buffer环形命令缓冲区。该缓冲区是CPU与GPU跨端通信的核心载体,采用标准生产者-消费者模型:CPU作为生产者,向队列尾部写入任务命令;GPU作为消费者,从队列头部读取待执行任务,实现软硬件高效协同。
命令写入队列后,用户态驱动会执行一次MMIO内存映射IO写入操作,向GPU Doorbell门铃寄存器更新Ring Buffer最新写指针。该操作通过系统调用穿透Linux内核nvidia驱动模块,经PCIe总线向GPU硬件发送硬件中断信号,通知GPU:命令队列存在新增待执行任务,可启动读取调度。
核心重点:CPU完成门铃信号写入后,主机端Kernel调用函数会立即异步返回,默认状态下Kernel启动为完全异步操作。CPU线程无需阻塞等待GPU运算完成,可继续执行后续业务代码,CPU与GPU并行工作,最大化利用软硬件资源,这也是CUDA异步高性能编程模型的核心本质。 |
至此,主机侧所有软件层预处理、任务下发工作全部完成,运算任务正式交付GPU硬件处理。完整下发链路层层穿透、逐级调用,无任何越级操作,保障任务调度的稳定性与准确性。
五、GPU 硬件内部:命令解析、任务分发、SM 调度执行 Kernel
GPU硬件收到Doorbell门铃中断信号后,顶层核心调度部件GigaThread Engine(千兆线程引擎)被唤醒。作为GPU硬件的全局总调度中枢,GigaThread Engine全权负责接收主机下发的所有Kernel任务、解析任务参数、拆分线程块、调度分发运算任务,是GPU并行计算的总入口,不参与具体运算,仅负责全局任务调度管理。
5.1 GigaThread Engine 读取、解析命令包
GigaThread Engine触发片上DMA引擎工作,通过PCIe总线从主机Pinned Memory的Ring Buffer中读取完整的Kernel Launch命令包,缓存至GPU片上高速缓存并完成解码解析,精准提取所有调度与运算核心参数:
Kernel SASS 指令在 GPU 显存内的入口虚拟地址;
Grid、Block 的维度信息,也就是总共需要生成多少个线程块 Block,每个 Block 包含多少线程 Thread;
每个 Block 需要分配的共享内存大小;
kernel 参数的 GPU 虚拟地址;
当前任务归属的 CUDA 上下文编号。
参数解析完成后,GigaThread Engine会根据Grid、Block维度,批量生成待调度的线程块(Block)任务列表。以本文vectorAdd示例为例,当数组长度N=1048576、单Block线程数=256时,全局会生成4096个独立Block任务。引擎会持续遍历GPU所有空闲计算单元,源源不断将Block任务分发至空闲SM,实现全域算力负载均衡。
为了让大家清晰看懂GPU硬件内部调度全流程,先放出GPU任务调度与执行完整流程图,再细化各部件工作逻辑:
A[GPU接收Doorbell门铃信号] B[唤醒GigaThread全局调度引擎] C[DMA读取主机RingBuffer命令包] D[解析Grid/Block/指令/内存参数] E[批量生成Block待调度任务] F[负载均衡分发至空闲SM] G[SM分配寄存器+共享内存] H[Block线程打包为32线程Warp] I[Warp进入硬件调度队列] J[Warp调度器派发SASS指令] K[ALU/访存单元并行计算] L[单Block完成,释放硬件资源] M[全部Block跑完,Kernel收尾] N[更新Stream状态,等待回传] A-->B-->C-->D-->E-->F-->G-->H-->I-->J-->K-->L-->M-->N |
GPU的核心运算单元为SM(Streaming Multiprocessor,流多处理器),单块GPU搭载数十至上百个独立SM,所有并行计算任务均由SM完成。每个SM拥有独立专属硬件资源,包括Warp调度器、寄存器堆、片上共享内存、L0指令缓存、ALU运算单元、访存单元,资源完全独立,互不抢占。
当 Block 被分发到某一个 SM 之后:
SM 为这个 Block 分配硬件寄存器、分配片上共享内存;
Block 内部所有线程被打包为 warp,一个 warp 固定 32 个并行线程,这是 GPU 硬件最小调度单位。256 线程的 Block 就会拆分为 8 个 warp;
全部 warp 送入 SM 内部的 warp 调度器队列等待调度;
SM 从 GPU 显存指定入口地址,加载 kernel 的 SASS 二进制机器指令进入 SM 内部 L0 指令缓存,不需要反复从显存读取指令,提升执行效率。
5.3 Warp 调度、指令派发,硬件执行部件完成计算
每个SM内置多个Warp调度器,作为硬件指令派发核心,会循环扫描队列中所有就绪Warp任务。每个硬件时钟周期内,调度器会筛选出无数据依赖、无阻塞的就绪Warp,提取下一条SASS硬件指令,派发至对应的运算单元(FP32/FP64浮点运算单元、整数运算单元、LD/ST访存单元等),实现32个线程单指令同步并行执行,这也是GPU超高并行算力的核心来源。
回到vectorAdd向量加法Kernel逻辑,每个线程独立读取显存中对应位置的A、B数组浮点数据,完成加法运算后,将结果写入C数组对应显存地址。海量Warp在多个SM中持续调度、运算、访存,批量完成大规模向量并行计算。运算过程中的显存访问请求,会优先经过GPU L1、L2多级缓存加速,大幅降低全局显存访问延迟,提升整体运算效率。
当单个SM内所有Warp全部执行完毕,对应Block任务宣告完成,SM会自动释放该Block占用的寄存器、共享内存等硬件资源,回归空闲状态,等待接收新一轮Block任务调度。
当GigaThread Engine检测到全局Grid中4096个Block全部执行完成、无剩余待调度任务时,标记当前Kernel任务整体结束,并在对应Stream流的状态缓存中写入任务完成标识。
关键特性:Kernel内部所有Block相互独立、无数据依赖、无执行顺序约束,硬件调度器遵循“空闲即调度”原则,哪个SM空闲就优先分配任务,因此每次运行的Block执行顺序不固定,属于正常硬件调度现象。 |
六、计算完成:结果回写显存,状态回传主机,cuda 程序拿到结果
Kernel全局任务执行完毕后,GPU硬件会完成两项收尾核心操作,为结果回传做准备:
所有线程计算出来的结果,已经写回到 GPU 全局显存的结果数组 d_C 对应的存储空间;
在 Stream 流的命令队列尾部写入任务完成标记,更新流内部的完成状态,这个状态可以通过 PCIe 总线回传给主机侧。
此时主机CPU线程大概率已执行至Kernel启动后的后续代码,因异步机制,CPU无法主动感知GPU运算状态。当代码执行至cudaMemcpyDeviceToHost结果回传接口时,该拷贝命令会被投递至同一个默认Stream流。CUDA流遵循串行有序执行规则,后入队的拷贝命令会主动阻塞等待前置Kernel任务完成标识,确认运算结束后,才会启动数据回传流程。
随后GPU DMA控制器启动高速数据搬运,通过PCIe总线将GPU全局显存中存储的结果数据d_C,批量传输至主机CPU内存空间。DMA传输为同步阻塞操作,待全部数据搬运完成后,cudaMemcpy接口才会执行返回,此时主机内存h_C中即可读取到GPU并行计算的最终结果。
结果读取完成后,CPU可执行数据校验、结果打印等业务逻辑,最终调用cudaFree释放显存资源。程序进程退出时,Linux内核nvidia驱动会自动销毁当前进程的专属CUDA上下文,回收所有占用的GPU显存、调度、缓存资源,彻底结束本次CUDA程序的完整运行生命周期。
七、全链路复盘总结,厘清常见误区
我们把完整链路再做一遍高度浓缩复盘,方便记忆:
编译阶段(nvcc工具链):拆分Host/Device双端源码,设备代码编译生成PTX中间代码与SASS硬件指令,打包为FatBinary嵌入ELF可执行文件,主机代码链接运行时库完成编译,最终生成带GPU指令的双端可执行程序,此阶段GPU无任何任务感知。
主机运行与任务下发阶段:进程启动初始化CUDA上下文,完成显存分配与数据预加载;首次启动Kernel时解析胖二进制,适配编译生成对应硬件SASS指令并加载至显存;封装标准化任务命令包写入主机环形队列,通过内核驱动与PCIe总线通知GPU,主机异步返回、持续运行。
GPU硬件执行阶段:GPU顶层调度引擎解析任务命令,拆分批量Block任务,均衡分发至各空闲SM;SM完成资源分配、Warp拆分与指令缓存加载,通过Warp调度器流水线派发指令,完成大规模并行运算,全局任务执行完毕后标记Kernel结束。
结果回传与资源释放阶段:流队列有序执行结果拷贝命令,DMA完成GPU显存到主机内存的数据回传;CPU校验处理结果,程序结束后内核自动销毁CUDA上下文,回收全部GPU硬件资源。
几个高频误区澄清
❌误区:nvcc编译完成后,Kernel指令已运行在GPU上。✅真相:编译仅将GPU指令封存于磁盘可执行文件,仅程序运行、首次启动Kernel时,指令才会加载至GPU显存。
❌误区:<<<>>>是C++原生语法。✅真相:该语法为CUDA专属扩展,编译期会被nvcc自动替换为Runtime底层函数调用,标准C++编译器无法直接识别。
❌误区:执行Kernel启动指令后,CPU会阻塞等待GPU运算完成。✅真相:默认异步执行,CPU调用后立即返回继续执行后续代码,需手动调用同步接口才会阻塞等待。
❌误区:PTX中间汇编可直接被GPU硬件执行。✅真相:PTX为跨架构通用中间代码,GPU硬件仅识别SASS机器码,必须通过预编译或运行时JIT编译转化后才能执行。
❌误区:CUDA Runtime可直接操作GPU硬件寄存器。✅真相:libcudart仅为高层封装接口,无法直接操作硬件,所有硬件交互均需下沉至libcuda.so驱动、Linux内核驱动,通过PCIe总线完成。
熟练掌握这套完整的CUDA软硬件运行全链路,对实际开发、问题排查、性能调优至关重要。日常开发中遇到的Kernel启动失败、首次运行JIT编译卡顿、流同步异常、PCIe传输瓶颈、显存泄漏、上下文泄漏、算子算力跑不满等高频问题,均可通过该链路快速定位故障层级。绝大多数开发者遇到的性能瓶颈与报错问题,根源都是对底层调度、编译、交互逻辑理解不透彻,吃透这套原理,才能从API调用者进阶为真正的GPU算力优化工程师。
开源链接
cuda‑samples 项目开源链接: https://github.com/NVIDIA/cuda-samples
免责申明
本文所有内容仅用于技术科普与学习参考,基于NVIDIA公开CUDA开发文档、技术手册等公开资料整理撰写,不构成任何生产环境部署、产品落地、工程调优的专业指导建议。文中所述为通用CUDA架构运行原理,不同CUDA Toolkit版本、GPU硬件架构、Linux内核版本的具体实现细节存在小幅差异。本文内容不代表NVIDIA官方观点,读者引用、实操时请自行核对官方最新原版文档,自行承担相关使用风险。
夜雨聆风