NVCC:NVIDIA CUDA 編譯器 (The NVIDIA CUDA Compiler)
重點總覽
| 項目 | 重點 |
|---|---|
| nvcc 定位 | CUDA Toolkit 內的 toolchain,驅動 offline 編譯;含 compiler、linker、PTX/Cubin assembler,由頂層 nvcc 協調各階段 |
| nvcc vs nvrtc | nvcc 是離線編譯;nvrtc 是執行期 online / JIT runtime compiler |
| Source files | .cu=CUDA 原始檔(含 device code),.cuh=CUDA header;.c/.cpp/.cc/.cxx=host-only |
| 編譯流程 | nvcc 把 device code 與 host code 分流:device → PTX → ptxas → Cubin;host → host compiler |
| Fatbin | 單一 binary 可內嵌多個 PTX + Cubin target,支援多虛擬/實體 ISA |
| PTX/Cubin 生成 | -arch、-gencode、-arch=native/all/all-major 控制目標架構 |
| Host code 編譯 | -ccbin 指定 host compiler、-Xcompiler 透傳參數、--cudart 選靜/動態 runtime |
| Separate compilation | -rdc=true / -dc 啟用跨 compilation unit 的 device code linking |
| LTO | -dlto / lto_<SM> 在 link 時跨檔最佳化,挽回 separate compilation 的效能 |
| 常用選項 | language(-std)、debug(-g/-G/-lineinfo)、optimization、profiling、fatbin 壓縮、compiler 效能控制 |
nvcc 是什麼
nvcc(NVIDIA CUDA Compiler)是 NVIDIA 提供、用來編譯 CUDA C/C++ 與 PTX 程式碼的 toolchain,屬於 CUDA Toolkit 的一部分。它本身是一個頂層工具,會協調整個編譯流程,依各階段呼叫合適的子工具(compiler、linker、PTX assembler、Cubin assembler)。
- nvcc 驅動的是 offline 編譯(編譯時就產生目標碼)。
- 相對地,CUDA runtime compiler
nvrtc驅動的是 online / Just-in-Time (JIT) 編譯(執行期才編譯)。
這份指南只涵蓋建置應用程式最常用的 nvcc 用法;完整選項請查官方 nvcc documentation。
2.7.1 CUDA Source Files and Headers
用 nvcc 編譯的原始檔可同時含 host code(在 CPU 執行)與 device code(在 GPU 執行)。nvcc 依副檔名判斷內容類型。
| 副檔名 | 說明 | 內容 |
|---|---|---|
.c |
C source file | Host-only code |
.cpp, .cc, .cxx |
C++ source file | Host-only code |
.h, .hpp, .hh, .hxx |
C/C++ header | device / host / 混合皆可 |
.cu |
CUDA source file | device / host / 混合皆可 |
.cuh |
CUDA header file | device / host / 混合皆可 |
- 含 device code 的原始檔慣例用
.cu;含 device code 的 header 慣例用.cuh,以與 host-only header(.h等)區分。
副檔名只是慣例:原文指出一般 header(.h/.hpp/...)其實也可容納 device、host 或混合程式碼。.cuh 主要是用來「標示」這是含 device code 的 header,方便人類區分。
2.7.2 NVCC Compilation Workflow
初始階段,nvcc 會把 device code 與 host code 分離,分別交給 GPU compiler 與 host compiler。
example.cu
│ nvcc 分流
┌─────────────┴──────────────┐
host code device code
│ │
host compiler GPU compiler (每個 virtual ISA 各跑一次)
(gcc/clang/...) │ 例如 compute_90
│ PTX assembly
│ │ ptxas
host object Cubin (對應 SM 版本的 hardware ISA)
│ │
└──────────► link ◄──────────┘
│
可內嵌多個 PTX + Cubin
的 Fatbin 容器
▼
executable
關鍵事實:
- nvcc 編譯 host code 需要相容的 host compiler;CUDA Toolkit 對 Linux/Windows 各定義了 host compiler 支援政策。
- 只含 host code 的檔案,可用 nvcc 或 直接用 host compiler 編譯;產生的 object file 可在 link 階段與含 GPU code 的 nvcc object file 合併。
- GPU compiler 把 C/C++ device code 編成 PTX assembly,並為命令列上每個指定的 virtual ISA(如
compute_90)各跑一次。 - 個別 PTX 再交給
ptxas,產生對應 target hardware ISA 的 Cubin;hardware ISA 以其 SM version 識別。 - 可把多個 PTX 與 Cubin target 內嵌進單一 Fatbin 容器,讓一個 binary 同時支援多個 virtual 與 target hardware ISA。
上述工具的呼叫與協調都由 nvcc 自動完成。-v 可顯示完整編譯流程與工具呼叫;-keep 可保留中間檔(搭配 --keep-dir 指定輸出目錄)。
範例 example.cu:
// ----- example.cu -----
#include <stdio.h>
__global__ void kernel() {
printf("Hello from kernel\n");
}
void kernel_launcher() {
kernel<<<1, 1>>>();
cudaDeviceSynchronize();
}
int main() {
kernel_launcher();
return 0;
}
此檔同時含 device(__global__ kernel)與 host(main/kernel_launcher)程式碼,正是 nvcc 分流編譯的典型輸入。
2.7.3 NVCC Basic Usage
基本編譯指令:
nvcc <source_file>.cu -o <output_file>
nvcc 接受常見 compiler flag:
| Flag | 用途 |
|---|---|
-I <path> |
指定 include 目錄 |
-L <path> |
指定 library 路徑 |
-l<library> |
連結某個 library(如 -lcublas) |
-D<macro>=<value> |
定義巨集 |
nvcc example.cu -I path_to_include/ -L path_to_library/ -lcublas -o <output_file>
2.7.3.1 PTX 與 Cubin 生成
預設下,nvcc 會為 CUDA Toolkit 支援的最早(最低 compute_XY / sm_XY)GPU 架構產生 PTX 與 Cubin,以最大化相容性。
-arch:為特定 GPU 架構產生 PTX 與 Cubin。-gencode:為多個 GPU 架構產生 PTX 與 Cubin。--list-gpu-code:列出所有支援的 real GPU 架構;--list-gpu-arch:列出所有支援的 virtual GPU 架構。
nvcc example.cu -arch=compute_<XY> # 例 compute_80:PTX-only,GPU 向前相容
nvcc example.cu -arch=sm_<XY> # 例 sm_80:PTX + Cubin,GPU 向前相容
nvcc example.cu -arch=native # 自動偵測並為當前 GPU 產生 Cubin(無 PTX,無向前相容)
nvcc example.cu -arch=all # 為所有支援架構產生 Cubin,另含最新 PTX 供向前相容
nvcc example.cu -arch=all-major # 為所有主要架構產生 Cubin(如 sm_80, sm_90),另含最新 PTX
-arch 值 |
PTX | Cubin | GPU 向前相容 |
|---|---|---|---|
compute_XY |
是 | 否 | 是(靠 JIT PTX) |
sm_XY |
是 | 是 | 是 |
native |
否 | 僅當前 GPU | 否 |
all / all-major |
含最新 PTX | 多架構 | 是 |
進階:可個別指定 PTX 與 Cubin target。
# 為 virtual arch compute_80 產生 PTX,並編成 sm_86 的 Cubin,且保留 compute_80 PTX
nvcc example.cu -arch=compute_80 -gpu-code=sm_86,compute_80 # PTX + Cubin
# 編成 sm_86、sm_89 的 Cubin(不保留 PTX)
nvcc example.cu -arch=compute_80 -gpu-code=sm_86,sm_89
nvcc example.cu -gencode=arch=compute_80,code=sm_86,sm_89 # 同上
# 多個 gencode:compute_80→sm_86,sm_89 與 compute_90→sm_90
nvcc example.cu -gencode=arch=compute_80,code=sm_86,sm_89 \
-gencode=arch=compute_90,code=sm_90
compute_XY 是 virtual architecture(產生可 JIT 的 PTX,向前相容);sm_XY 是 real hardware architecture(直接產生 Cubin)。sm_XY 同時也內嵌 PTX 以保留向前相容性,但 native 不含 PTX 因而無向前相容。
2.7.3.2 Host Code Compilation Notes
不含 device code 或 symbol 的 compilation unit(原始檔 + 其 header)可直接用 host compiler 編譯。
- 若任一 compilation unit 使用 CUDA runtime API,最終必須連結 CUDA runtime library。
- runtime 同時提供靜態與動態版:
libcudart_static(靜態)與libcudart(動態)。 - 預設連結靜態 runtime;要改用動態版,在 compile 或 link 指令加
--cudart=shared。 -ccbin <compiler>:指定 host function 使用的 host compiler;環境變數NVCC_CCBIN亦可。-Xcompiler:把參數透傳給 host compiler。
nvcc example.cu -ccbin=clang++
export NVCC_CCBIN='gcc'
nvcc example.cu -Xcompiler=-O3 # -O3 被透傳給 host compiler
2.7.3.3 Separate Compilation of GPU Code
nvcc 預設為 whole-program compilation:要求用到的所有 GPU code 與 symbol 都在同一 compilation unit 內。
要讓 device function 呼叫其他 compilation unit 定義的 device function 或存取其 device variable,必須加 -rdc=true(或別名 -dc),啟用跨單元的 device code linking,這稱為 separate compilation。
| 比較 | Whole-program(預設) | Separate compilation |
|---|---|---|
| 跨檔 device 連結 | 不允許 | 允許(需 -dc/-rdc=true) |
| 程式碼組織 | 較受限 | 較彈性 |
| 編譯時間 | — | 可改善 |
| 二進位大小 | — | 可更小 |
| 效能 | 較佳 | 可能因 device link 受影響(可用 LTO 緩解) |
| 建置複雜度 | 較低 | 較高 |
separate compilation 的條件:
- 在某單元定義的 non-const
__device__變數,於其他單元須以extern引用。 - 所有 const
__device__變數都必須以extern定義並引用。 - 所有
.cu原始檔都須用-dc或-rdc=true編譯。 - host 與 device function 預設即為 external linkage,不需
extern。
自 CUDA 13 起,__global__ 函式與 __managed__ / __device__ / __constant__ 變數預設為 internal linkage。這會影響跨單元引用,需特別注意。
// ----- definition.cu -----
extern __device__ int device_variable = 5;
__device__
int device_function() { return 10; }
// ----- example.cu -----
extern __device__ int device_variable; // 以 extern 引用
__device__
int device_function(); // 宣告,定義在另一單元
__global__ void kernel(int* ptr) {
device_variable = 0;
*ptr = device_function();
}
nvcc -dc definition.cu -o definition.o
nvcc -dc example.cu -o example.o
nvcc definition.o example.o -o program # device link + 最終連結
每個 .cu 都以 -dc 各自編成 object,最後再由 nvcc 連結;這就是 separate compilation 的標準流程。
2.7.4 Common Compiler Options
2.7.4.1 Language Features
nvcc 支援從 C++03 到 C++23 的核心語言特性。
-std={c++03|c++11|c++14|c++17|c++20|c++23}:指定語言標準。-restrict:斷言所有 kernel pointer 參數皆為 restrict pointer。-extended-lambda:允許在 lambda 宣告中加__host__、__device__標註。-expt-relaxed-constexpr(實驗性):允許 host code 呼叫__device__constexpr 函式、device code 呼叫__host__constexpr 函式。
2.7.4.2 Debugging Options
| Flag | 作用 |
|---|---|
-g |
產生 host code 的 debug 資訊(gdb/lldb 用) |
-G |
產生 device code 的 debug 資訊(cuda-gdb 用),並定義 __CUDACC_DEBUG__ 巨集 |
-lineinfo |
產生 device code 的行號資訊,不影響執行效能,搭配 compute-sanitizer 追蹤 kernel 執行 |
nvcc 對 GPU code 預設用最高最佳化等級 -O3。-G 會阻止部分編譯器最佳化,因此 debug code 效能預期較低。可用 -DNDEBUG 關閉 runtime assertion 以免拖慢執行。
2.7.4.3 Optimization Options
-Xptxas:把參數傳給 PTX assemblerptxas。例如-Xptxas=-maxrregcount=N設定每 thread 最大 register 數。-extra-device-vectorization:啟用更積極的 device code 向量化。--apply-controls=/path/to/file:傳入 advanced controls file (ACF) 給 nvcc 與 ptxas,針對特定 workload 改變預設編譯行為。
使用 advanced controls file(ACF)可能造成編譯失敗或執行結果錯誤,原文明言「Use at your own risk」。
可從編譯器取得、利於進階最佳化的輸出旗標:
| Flag | 輸出 |
|---|---|
-res-usage |
列出資源使用:每個 kernel 的 register、shared memory、constant memory、local memory |
-opt-info=inline |
列出被 inline 的函式資訊 |
-Xptxas=-warn-lmem-usage |
使用到 local memory 時警告 |
-Xptxas=-warn-spills |
register 被 spill 到 local memory 時警告 |
更細緻的浮點行為控制請見 Floating-Point Computation 章節與 nvcc 文件。
2.7.4.4 Link-Time Optimization (LTO)
separate compilation 因跨檔最佳化機會有限,效能可能低於 whole-program。LTO 在 link 時跨各別編譯的檔案做最佳化,代價是編譯時間增加,但可挽回大部分 whole-program 的效能,同時保留 separate compilation 的彈性。
啟用 LTO 需 -dlto 旗標或 lto_<SM version> link-time 最佳化 target:
# 方式一:-dlto
nvcc -dc -dlto -arch=sm_100 definition.cu -o definition.o
nvcc -dc -dlto -arch=sm_100 example.cu -o example.o
nvcc -dlto definition.o example.o -o program
# 方式二:lto_<SM> target
nvcc -dc -arch=lto_100 definition.cu -o definition.o
nvcc -dc -arch=lto_100 example.cu -o example.o
nvcc -dlto definition.o example.o -o program
注意:device 編譯(-dc)與最終 link 兩步驟都要帶上 LTO 旗標。
2.7.4.5 Profiling Options
用 Nsight Compute 與 Nsight Systems 可直接 profile,編譯時不必加額外旗標。但下列旗標能讓 profiling 工具把原始碼與生成碼對應起來:
-lineinfo:產生 device code 行號資訊,讓 profiling 工具顯示原始碼(工具需原始碼仍在編譯時的相同位置)。-src-in-ptx:把原始碼保留在 PTX 中,避開上述-lineinfo對檔案位置的限制;需搭配-lineinfo。
2.7.4.6 Fatbin Compression
nvcc 預設會壓縮 binary 內的 fatbin。
-no-compress:停用 fatbin 壓縮。--compress-mode={default|size|speed|balance|none}:設定壓縮模式。
| 模式 | 取向 |
|---|---|
speed(預設) |
著重快速解壓縮時間 |
size |
著重縮小 fatbin 大小 |
balance |
在 speed 與 size 間取折衷 |
none |
停用壓縮 |
2.7.4.7 Compiler Performance Controls
加速與分析「編譯過程本身」的選項:
| Flag | 作用 |
|---|---|
-t <N> |
用 N 個 CPU thread 平行化單一 compilation unit、多 GPU 架構的編譯 |
-split-compile <N> |
用 N 個 CPU thread 平行化最佳化階段 |
-split-compile-extended <N> |
更積極的 split compilation;需 LTO |
-Ofc <N> |
device code 編譯速度等級 |
-time <filename> |
產生 CSV 表,記錄各編譯階段耗時 |
-fdevice-time-trace |
產生 device code 編譯的 time trace |
考試/測驗重點
| 情境/關鍵字 | 答案 |
|---|---|
| nvcc vs nvrtc | nvcc=offline 編譯;nvrtc=online/JIT runtime compiler |
.cu vs .cuh |
.cu=CUDA 原始檔;.cuh=含 device code 的 header(慣例) |
| device code 編譯鏈順序 | C/C++ device code → PTX → ptxas → Cubin |
compute_XY vs sm_XY |
compute_XY=virtual ISA(產生 PTX,可 JIT);sm_XY=real hardware ISA(產生 Cubin),以 SM version 識別 |
-arch=native 的代價 |
只為當前 GPU 產 Cubin、無 PTX、無向前相容 |
| 預設為哪個架構生成 | 支援的最早/最低架構,為了最大相容性 |
| 顯示完整編譯流程 | -v;保留中間檔 -keep(搭 --keep-dir) |
| 跨檔呼叫 device function 需要 | -rdc=true 或別名 -dc(separate compilation) |
| 為何 separate compilation 非預設 | 效能可能因 device code linking 受影響 |
| CUDA 13 linkage 陷阱 | __global__ 與 __managed__/__device__/__constant__ 變數預設 internal linkage |
const __device__ 變數 |
必須以 extern 定義並引用 |
| 預設連哪種 runtime | 靜態 libcudart_static;改動態用 --cudart=shared |
| 指定 host compiler | -ccbin 或環境變數 NVCC_CCBIN;透傳參數用 -Xcompiler |
-g vs -G vs -lineinfo |
-g=host debug;-G=device debug(定義 __CUDACC_DEBUG__、抑制最佳化);-lineinfo=行號、不影響效能 |
| GPU code 預設最佳化等級 | -O3(最高) |
| 限制每 thread register 數 | -Xptxas=-maxrregcount=N |
| register spill / local memory 警告 | -Xptxas=-warn-spills / -Xptxas=-warn-lmem-usage |
| 列印 kernel 資源使用 | -res-usage(register/shared/constant/local memory) |
| LTO 啟用方式 | -dlto 或 lto_<SM> target;compile 與 link 都要帶 |
-src-in-ptx 前提 |
需搭配 -lineinfo |
| fatbin 預設壓縮模式 | speed(--compress-mode 另有 size/balance/none;-no-compress 全關) |
| 平行編譯 vs 平行最佳化 | -t <N>=多架構編譯平行;-split-compile <N>=最佳化階段平行 |
--apply-controls 風險 |
ACF 可能造成編譯失敗或執行錯誤(自負風險) |
Related Notes
- 02-Programming-GPUs/01-CUDA-Cpp-Kernels-and-Launch
- 02-Programming-GPUs/04-CUDA-Cpp-Errors-and-Specifiers
- 02-Programming-GPUs/07-SIMT-Device-Memory-Spaces
- 02-Programming-GPUs/08-SIMT-Memory-Performance
- 02-Programming-GPUs/09-SIMT-Atomics-Cooperative-Occupancy
- 01-Introduction-to-CUDA/05-CUDA-Platform
- 02-Programming-GPUs/Practice-Programming-GPUs
- 00-Dashboard/Exam-Traps