CUDA 生产落地案例
CUDA 生产落地案例
案例一:用自定义融合 kernel 替换一串小算子。背景是推理链路里存在归一化 + 缩放 + 旋转位置编码的连续小算子,每个都单独启动 kernel,中间结果反复往返显存,剖析显示 kernel 启动开销与显存往返占了相当比例的时间。做法是先用 nsys 定位热点区间,再把这几步合成一个 kernel:一个 block 处理一行数据,读入后直接在寄存器里算,块内归约用 warp shuffle 做,减少 shared memory 往返;用一次加载、向量化 float4 访问,让访存合并。关键配置是 block 取 256、每个线程用网格跨步循环处理多组数据、限制寄存器使用以保证占用率。效果是与原实现相比端到端时间明显下降,具体数值随模型和卡型差异较大,以本地压测为准。踩的坑有三个:一是归约时漏了 __syncthreads(),结果偶发错误,换了几个 batch 才复现,最后靠 compute-sanitizer 定位;二是 shared memory 申请过大,占用率掉到很低,反而比原版慢;三是把 __syncthreads() 写进了 if 分支,导致线程永久等待,程序直接挂死。
案例二:推理服务里的流与并发改造。背景是单 stream 串行执行,H2D 拷贝与计算无法重叠,小 batch 场景下拷贝时间占比很高。做法是改成多条 stream 交替处理不同请求,host 侧内存全部换成页锁定内存,拷贝统一走 cudaMemcpyAsync,用 event 串联依赖,并用 CUDA Graph 把固定的启动序列打包以降低启动开销。踩的坑:默认 stream(stream 0)与自定义 stream 之间存在隐式同步语义,混用时会出现意料之外的等待,后来统一显式指定 stream;另外在热路径里调用 cudaMalloc 会同步整个设备,改成启动时预分配显存池。做完之后小 batch 的端到端延迟与整机吞吐都有改善,CPU 侧等待时间明显减少。

