目標很簡單:先量再快。
這篇帶你一步一步用 Nsight Systems(看「整體流程/時間線」)和 Nsight Compute(看「單支 kernel 的瓶頸」),再搭配 程式內部量測、幾個經典優化手法與排錯清單。看完就能從「勉強能跑」,變成「知道為什麼慢、怎麼讓它快」。
你想知道:我的時間花在哪?拷貝多還是算多?kernel 能不能重疊?
nsys
。也有 GUI(Nsight Systems),安裝後可直接開啟 .nsys-rep
報告。nsys profile -t cuda,nvtx --stats=true -o report ./your_app
# 會產生 report.nsys-rep(GUI用)和摘要
cudaMemcpy
、各個 kernel 的開始/結束與是否重疊。cudaDeviceSynchronize()
,改用 events 或 stream 回調,只在必要點同步。範例圖:
你想知道:這支 kernel 到底卡在「記憶體」還是「算力」?warp 有沒有分歧?occupancy 夠不夠?
# 跑所有常用分析段落(第一次用這招最省事)
ncu --set full ./your_app
# 只針對名稱含 foo 的 kernel
ncu --set full --kernels ".*foo.*" ./your_app
也可用 GUI(Nsight Compute)直接打開 .ncu-rep
,圖表更容易理解。
Summary:牆鐘時間、呼叫次數、平均耗時。
Launch Statistics / Occupancy:
Memory Workload Analysis:
Scheduler / Warp State:
Speed of Light / Roofline(GUI):
cudaEvent_t a,b; cudaEventCreate(&a); cudaEventCreate(&b);
cudaEventRecord(a);
myKernel<<<grid,block,shared,stream>>>(...);
cudaEventRecord(b); cudaEventSynchronize(b);
float ms=0; cudaEventElapsedTime(&ms,a,b);
printf("kernel took %.3f ms\n", ms);
優點:準確抓 GPU 執行時間。缺點:看不到細節,搭配 Nsight 才完整。
#include <nvToolsExt.h>
nvtxRangePushA("Stage: HtoD Copy");
// ... do copy ...
nvtxRangePop();
Coalesced access(相鄰 thread 讀相鄰位址):重排資料或索引,避免跳躍。
Shared Memory 做 tiling:重複使用的資料先搬到共享記憶體,少碰 DRAM。
tile[T][T+1]
)。Read-only broadcast 用 constant/texture cache:所有 thread 都讀同一數值時,constant memory 很省。
避免無效搬運:把多次小 cudaMemcpy
合併成一次大拷貝;Host buffer 用 pinned memory。
Unified Memory 若造成大量 page fault:
cudaMemPrefetchAsync()
預取到裝置;或改回顯式 cudaMemcpy
。if
分兩路,就會排隊跑 → 用資料分群、分支轉算術(有時可用 ?:
或 max/min
)、或把差異大的資料拆到不同 kernel。用 cudaOccupancyMaxPotentialBlockSize()
或 Nsight 建議值找 block size sweet spot。
暫存器爆量會限縮 occupancy:
-Xptxas -v
與 Nsight 的 Register Usage;__restrict__
幫編譯器別名分析。Shared memory 用太多也會卡 occupancy:檢討 tile 大小。
float
甚至 FP16/TF32(用對硬體和庫)可大幅提升吞吐。-use_fast_math
或 __frcp_rn
、__fsqrt_rn
等(需衡量精度)。numactl
)。症狀 | 常見原因 | 立即檢查 | 快速解法 |
---|---|---|---|
拷貝時間占比超高 | 太多小 cudaMemcpy 、Unified Memory 頻繁遷移 |
Nsight Systems 的 API Summary | 合併拷貝、pinned host、streams 重疊、cudaMemPrefetchAsync |
Kernel 很慢、DRAM 吞吐高 | 記憶體受限 | NCU 的 Memory Workload / Roofline | Coalesced、tiling 到 shared、提高重用率、壓縮資料 |
Kernel 很慢、算力利用高 | 算力受限 | NCU Roofline/SM Active | fast-math、混合精度、庫函式、演算法改寫 |
Warp stalls: barrier/sync 多 | 過度同步、atomic 爆量 | NCU Warp Stall Reasons | 降低同步頻率、先 local 彙整再全域原子、分塊 |
Occupancy 低 | 暫存器/SMEM 過量、block size 不佳 | NCU Launch Stats / ptxas -v | 調整 block size、減少暫存器/SMEM、分割 kernel |
結果對但時快時慢 | 系統雜訊/時脈/溫度、動態時鐘 | 多次量測 | 取多次平均、暖機、關掉背景負載 |
Release 編譯:-O3 -lineinfo -Xptxas -v
。
Nsight Systems:nsys profile -t cuda,nvtx --stats=true ./app
Nsight Compute(鎖定 1–2 支最花時間的 kernel):ncu --set full --kernels "regex"
小步優化:一次只改一件事(例如:把訪問改成連續、加 shared tile)。
重量測:用相同輸入與環境,取多次平均,寫下 改善百分比。
反覆:回到 2) 3) 再抓下一個瓶頸。
這就是專業團隊的常態工作流程。工具 + 方法論,沒有神奇捷徑。
先用 Nsight Systems 找「最大的慢點」→ 再用 Nsight Compute 拆解「單顆 kernel 的瓶頸」→ 按「記憶體、分歧、occupancy、算力、啟動」五大方向一條條對症下藥 → 量測、記錄、反覆。
當你會這一套,你已經具備把任何 CUDA 專案「從能跑,拉到會飛」的核心能力。