<<<CUDA C++ 学习路线grid · block · warp · lane
Cheat Sheet

速查表

写 kernel 时最常回头查的东西,集中放在一页。想理解背后的原因,回到对应的课程。

内置变量与限定符

写法含义
threadIdx.x/y/zblock 内的线程坐标
blockIdx.x/y/zgrid 内的 block 坐标
blockDim.x/y/z每个 block 的线程数
gridDim.x/y/zgrid 的 block 数
warpSize恒为 32
__global__kernel 入口,GPU 执行、host 调用,返回 void
__device__GPU 执行、GPU 调用
__host__ __device__两边各编译一份
__shared__block 内共享的片上内存
__constant__只读常量内存,64 KB,广播优化
__restrict__无别名保证,配合 const 可走只读缓存
__launch_bounds__(T, B)约束编译器的寄存器预算

索引推导

CUDA C++
// 一维int i = blockIdx.x * blockDim.x + threadIdx.x;if (i < n) { ... } // 二维(x 对应列,即内存连续方向)int col = blockIdx.x * blockDim.x + threadIdx.x;int row = blockIdx.y * blockDim.y + threadIdx.y;if (row < rows && col < cols) m[row * cols + col] = ...; // grid-stride loop:grid 尺寸与数据规模解耦for (int i = blockIdx.x * blockDim.x + threadIdx.x;     i < n; i += gridDim.x * blockDim.x) { ... } // block 内线性 tid(warp 就是按它每 32 个切一组)int tid = threadIdx.x        + threadIdx.y * blockDim.x        + threadIdx.z * blockDim.x * blockDim.y; // 向上取整的 grid 尺寸int blocks = (n + threads - 1) / threads;

Runtime API

CUDA C++
cudaMalloc(&d_p, bytes);                 // 注意是 &d_pcudaMallocManaged(&p, bytes);            // 统一内存cudaHostAlloc(&h_p, bytes, cudaHostAllocDefault);   // pinned,异步拷贝的前提cudaMemcpy(dst, src, bytes, cudaMemcpyHostToDevice);cudaMemcpyAsync(dst, src, bytes, kind, stream);cudaMemset(d_p, 0, bytes);cudaFree(d_p);  cudaFreeHost(h_p); cudaStreamCreate(&s);cudaStreamSynchronize(s);                // 只等这条流cudaStreamWaitEvent(s2, evt, 0);         // 跨流依赖,CPU 不阻塞cudaDeviceSynchronize();                 // 等一切,仅用于调试和退出前 cudaEventCreate(&e);  cudaEventRecord(e, s);cudaEventSynchronize(e);cudaEventElapsedTime(&ms, start, stop);  // 唯一正确的 kernel 计时方式 cudaGetLastError();                      // launch 时的同步错误cudaGetErrorString(err);cudaOccupancyMaxPotentialBlockSize(&minGrid, &block, kernel, 0, 0);cudaFuncSetAttribute(kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, 96*1024);

同步与 warp 原语

原语作用域说明
__syncthreads()block屏障,绝不能放在分叉的分支里
__syncwarp(mask)warpVolta 之后 warp 内交换数据必须显式同步
__threadfence()device内存序,不是屏障
__shfl_sync(m, v, src)warp广播
__shfl_down_sync(m, v, d)warp归约,结果落在 lane 0
__shfl_xor_sync(m, v, k)warp蝶形,所有 lane 都拿到结果
__ballot_sync(m, pred)warp投票位图,配合 __popc 做流压缩
__activemask()warp分叉路径内构造掩码
warp 归约模板
__inline__ __device__ float warpReduceSum(float v) {    for (int off = 16; off > 0; off >>= 1)        v += __shfl_down_sync(0xffffffff, v, off);    return v;}

编译选项

选项作用
-arch=sm_80同时指定虚拟架构与真实架构
-gencode arch=compute_80,code=sm_80精确控制单个目标
-gencode arch=compute_90,code=compute_90保留 PTX,新卡可 JIT,发布时务必带上
-Xptxas -v打印寄存器用量与溢出情况
-lineinfo加行号供 profiler 与 sanitizer 定位,不影响优化
-Gdevice 端调试,会关闭所有优化,慎用
--use_fast_math快速数学,牺牲精度换速度
-maxrregcount=N全局限制寄存器,粒度太粗,优先用 __launch_bounds__
--default-stream per-thread让默认流不再与其他流隐式同步
架构代号代表型号
sm_70VoltaV100
sm_75TuringT4、RTX 20 系
sm_80AmpereA100
sm_86AmpereRTX 30 系、A10
sm_89AdaRTX 40 系、L4
sm_90HopperH100

Profiling 命令

shell
# 第一步:看整体时间线,找出真正的瓶颈 kernelnsys profile -o report --stats=true ./app # 第二步:深挖单个 kernelncu --set full -o profile ./appncu --kernel-name myKernel --launch-count 3 ./app # 只看关键指标(快很多)ncu --metrics \  sm__throughput.avg.pct_of_peak_sustained_elapsed,\  gpu__dram_throughput.avg.pct_of_peak_sustained_elapsed,\  sm__warps_active.avg.pct_of_peak_sustained_active \  ./app # 检查访存合并:sectors/requests 理想为 4,接近 32 说明完全没合并ncu --metrics \  l1tex__t_sectors_pipe_lsu_mem_global_op_ld.sum,\  l1tex__t_requests_pipe_lsu_mem_global_op_ld.sum ./app # 检查 bank conflictncu --metrics l1tex__data_bank_conflicts_pipe_lsu_mem_shared.sum ./app # 正确性compute-sanitizer --tool memcheck ./appcompute-sanitizer --tool racecheck ./app # 看编译产物cuobjdump -sass ./app | lessnvcc -ptx -arch=sm_80 -o k.ptx k.cu

经验数值

这些量级值得记住,能帮你快速判断一个想法值不值得试

项目量级
寄存器延迟~1 周期
共享内存延迟~20-30 周期
L2 延迟~200 周期
全局内存延迟~400-800 周期
sector 粒度32 字节
共享内存 bank32 个,每个 4 字节宽
A100 峰值带宽1.55 TB/s
A100 FP32 算力19.5 TFLOPS
A100 BF16 Tensor Core312 TFLOPS(约 16 倍)
A100 计算强度拐点≈ 12.5 FLOP/Byte
kernel launch 开销3-10 微秒
一个 block 最大线程数1024

排错对照

症状最可能的原因
kernel 里的 printf 没输出缺少同步点,进程已退出
结果全是 0忘了 cudaMemcpy 回来,或 launch 失败但没检查错误
结果偶发错误__syncthreads();或在 PyTorch 扩展里用了默认流
invalid configuration argumentblockDim 超过 1024,或共享内存超限
no kernel image is available编译的 -arch 与实际 GPU 不匹配,且没保留 PTX
拷贝与计算不重叠host 内存不是 pinned,或用了默认流
改了一行代码性能暴跌寄存器数跨过台阶导致占用率下降,查 -Xptxas -v
性能远低于带宽上限访存没合并,查 sectors/requests 比值
共享内存 kernel 很慢bank conflict,试试行宽 +1

还没开始学?从 第一个 kernel 开始,或者直接去 occupancy 计算器 看看是什么在卡你的 kernel。