mcpField
C
cuda

cuda

github.com/mohitmishra786开发269332 次安装18 周前更新
代码仓库

关于 cuda

cuda 是面向 NVIDIA CUDA C/C++ 开发的 Agent 技能,涵盖内核设计、内存、异步流、编译、Thrust、occupancy,以及常见性能和正确性问题。

主要功能

  1. 01内核启动配置
  2. 02CUDA 内存层级
  3. 03异步流与内存复制
  4. 04nvcc 编译选项
  5. 05Thrust 并行原语
  6. 06性能与正确性排查

适用场景

  1. 01编写矩阵乘法或归约内核
  2. 02调整 block、grid 与 occupancy
  3. 03构建多流异步处理管线
  4. 04诊断内存访问或竞态问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill cuda

安装后在 Claude Code 中输入/cuda确认已加载。

详细介绍

CUDA

目的

指导 Agent 进行 NVIDIA CUDA C/C++ 开发:内核启动配置、从寄存器到全局内存的存储层次结构、使用流进行异步执行、nvcc 编译标志、Thrust 库的使用,以及诊断常见性能问题,例如 warp 分歧和非合并内存访问。

适用场景

  • 为矩阵乘法、归约或模板运算编写或优化 CUDA 内核
  • 选择 block/grid 维度并估算占用率
  • 调试因内存访问模式或占用率低而运行缓慢的内核
  • 使用异步 cudaMemcpyAsync 设置多流流水线
  • 使用 nvcc 编译并选择架构标志(-gencode)
  • 使用 Thrust 执行并行原语,而不是手写内核

工作流

1. 最小内核与启动

CUDA 将工作组织为线程组(block),多个 block 组成一个 grid。

Thread hierarchy
├── grid (1D/2D/3D)
│   └── block (1D/2D/3D, max 1024 threads)
│       └── thread (threadIdx, blockIdx, blockDim, gridDim)
// vector_add.cu
#include <cuda_runtime.h>
#include <stdio.h>

__global__ void vector_add(const float *a, const float *b, float *c, int n) {
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < n)
        c[i] = a[i] + b[i];
}

int main(void) {
    const int n = 1 << 20;
    size_t bytes = n * sizeof(float);
    float *h_a, *h_b, *h_c, *d_a, *d_b, *d_c;

    cudaMalloc(&d_a, bytes);
    cudaMalloc(&d_b, bytes);
    cudaMalloc(&d_c, bytes);
    // ... host init and cudaMemcpy H2D ...

    int threads = 256;
    int blocks = (n + threads - 1) / threads;
    vector_add<<<blocks, threads>>>(d_a, d_b, d_c, n);
    cudaDeviceSynchronize();

    cudaMemcpy(h_c, d_c, bytes, cudaMemcpyDeviceToHost);
    cudaFree(d_a); cudaFree(d_b); cudaFree(d_c);
    return 0;
}
2. 存储层次结构
存储类型作用范围延迟典型用途
寄存器每个线程~1 个周期局部标量、循环索引
共享内存(__shared__)每个 block~5 个周期分块数据、halo 交换
全局内存所有线程~400+ 个周期大型数组、合并访问
常量内存(__constant__)只读、缓存快速广播内核参数、查找表
纹理内存缓存的二维访问已缓存图像采样、不规则读取

共享内存示例(矩阵分块):

#define TILE 16

__global__ void matmul_tiled(const float *A, const float *B, float *C, int N) {
    __shared__ float As[TILE][TILE];
    __shared__ float Bs[TILE][TILE];

    int row = blockIdx.y * TILE + threadIdx.y;
    int col = blockIdx.x * TILE + threadIdx.x;
    float sum = 0.0f;

    for (int t = 0; t < (N + TILE - 1) / TILE; t++) {
        As[threadIdx.y][threadIdx.x] = (row < N && t * TILE + threadIdx.x < N)
            ? A[row * N + t * TILE + threadIdx.x] : 0.0f;
        Bs[threadIdx.y][threadIdx.x] = (col < N && t * TILE + threadIdx.y < N)
            ? B[(t * TILE + threadIdx.y) * N + col] : 0.0f;
        __syncthreads();

        for (int k = 0; k < TILE; k++)
            sum += As[threadIdx.y][k] * Bs[k][threadIdx.x];
        __syncthreads();
    }
    if (row < N && col < N)
        C[row * N + col] = sum;
}
3. 流与异步拷贝
cudaStream_t stream1, stream2;
cudaStreamCreate(&stream1);
cudaStreamCreate(&stream2);

cudaMemcpyAsync(d_a, h_a, bytes, cudaMemcpyHostToDevice, stream1);
cudaMemcpyAsync(d_b, h_b, bytes, cudaMemcpyHostToDevice, stream2);
vector_add<<<blocks, threads, 0, stream1>>>(d_a, d_b, d_c, n);
cudaMemcpyAsync(h_c, d_c, bytes, cudaMemcpyDeviceToHost, stream1);
cudaStreamSynchronize(stream1);

锁页主机内存(cudaMallocHost)可实现真正的异步 DMA 与内核执行重叠。

4. nvcc 编译
# Single architecture (local GPU)
nvcc -O3 -arch=sm_80 -o prog vector_add.cu

# Fat binary for multiple GPUs
nvcc -O3 \
  -gencode arch=compute_80,code=sm_80 \
  -gencode arch=compute_90,code=sm_90 \
  -o prog vector_add.cu

# Debug symbols for cuda-gdb
nvcc -G -g -O0 -arch=sm_80 -o prog_debug vector_add.cu

# Show PTX/SASS
nvcc -arch=sm_80 -ptx vector_add.cu
nvcc -arch=sm_80 -cubin vector_add.cu
cuobjdump -sass prog

常用标志:

标志效果
-O3激进优化
-G调试时禁用优化
-lineinfo在性能分析中关联源代码行
-Xcompiler -fopenmp在 CUDA 中使用主机端 OpenMP
--use_fast_math使用更快、精度较低的数学内建函数
-maxrregcount=N限制寄存器数量以提高占用率
5. 占用率估算
# CUDA Occupancy Calculator (spreadsheet) or programmatic:
./occupancy_tool --kernel vector_add --block-size 256 --regs 16 --smem 0

决策树:

Kernel slow?
├── Low occupancy (< 25%) → reduce registers, shared mem, or block size
├── Memory-bound → check coalescing, use shared memory tiling
└── Compute-bound → increase arithmetic intensity, use tensor cores

使用 cudaOccupancyMaxActiveBlocksPerMultiprocessor API,或 Nsight Compute 的 sm__warps_active.avg.pct_of_peak_sustained_active 指标。

6. Thrust 基础
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/reduce.h>

thrust::device_vector<int> d_vec(1000000);
thrust::sort(d_vec.begin(), d_vec.end());
int sum = thrust::reduce(d_vec.begin(), d_vec.end());

Thrust 会在内部处理临时存储和内核启动。排序、扫描和归约优先使用 Thrust;对于特定领域的融合操作,则编写自定义内核。

7. 常见问题

Warp 分歧:一个 warp 中的线程(32 个)以 SIMT 锁步方式执行。根据 threadIdx 进行分支会导致串行执行。

// Bad: divergent branch
if (threadIdx.x % 2 == 0) { heavy_a(); } else { heavy_b(); }

// Better: separate kernels or predication

非合并访问:相邻线程应访问相邻地址。

// Bad: strided access
float val = data[threadIdx.x * stride];

// Good: coalesced
float val = data[blockIdx.x * blockDim.x + threadIdx.x];

常见问题

现象原因修复方法
cudaErrorIllegalAddress(700)设备指针越界运行 compute-sanitizer --tool memcheck;添加边界检查
cudaErrorLaunchTimeout(702)内核运行时间超过看门狗限制减少工作量;拆分内核;在开发用 GPU 上禁用 TDR
占用率低警告寄存器或共享内存使用过多减少 __shared__ 大小;使用 -maxrregcount;缩小 block
CPU 与 GPU 计算结果不一致共享内存或全局内存上的竞争添加 __syncthreads();在归约中使用原子操作
no kernel image available-arch=sm_XX 不正确与 GPU 计算能力匹配:nvidia-smi --query-gpu=compute_cap
H2D/D2H 拷贝缓慢主机内存可分页使用 cudaMallocHost 分配锁页缓冲区

相关技能

  • skills/gpu/cuda-profiling — 使用 Nsight Systems/Compute 诊断内核性能
  • skills/gpu/cuda-debugging — 使用 cuda-gdb 和 compute-sanitizer 检查正确性
  • skills/gpu/gpu-memory-model — SIMT 执行、合并规则、bank 冲突
  • skills/gpu/hip-rocm — 将 CUDA 内核移植到 AMD HIP
  • skills/gpu/triton-lang — 用于自定义内核的 Python DSL 替代方案
  • skills/hpc/openmp — 与 CUDA 并用的主机端并行处理

评论

支持 Markdown