面向 CUDA Custom Operator 的 YAML 驱动自动验证与性能回归平台。输入一张 Task Card 和候选 C++/CUDA 源码,平台完成编译、PyTorch Dispatcher 动态加载、数值与契约验证、 CUDA Event Benchmark、结果归档、排行榜和基线回归判断。
本项目刻意聚焦工程闭环,不负责生成 Kernel。它可以理解为一个更小、更强调可复现构建、 非法输入契约和证据归档的 KernelBench。
- Quick Start:安装依赖并跑通第一张 Task Card;
- 项目架构图:了解输入、Verifier stages 与结果归档之间的关系;
- 性能优化证据:RMSNorm 优化分析 · 机器可读 Profile 对比。
前提:Linux/WSL2、Python 3.12、uv;运行 CUDA 验证还需要可用的 NVIDIA Driver、CUDA
Toolkit 和 nvcc。
git clone https://github.com/Willowkk/mini-kernel-verifier.git
cd mini-kernel-verifier
uv sync --frozen --extra cu128
source .venv/bin/activate
python -m mini_kv doctor
python -m mini_kv validate-task --task tasks/vector_add.yaml
python -m mini_kv verify --task tasks/vector_add.yaml无 NVIDIA GPU 时可安装 CPU extra 并运行与 GitHub Actions 相同的静态/单元测试:
uv sync --frozen --extra cpu
pytest -m "not gpu and not profile"flowchart LR
subgraph Inputs[Inputs]
A[YAML Task Card]
B[Candidate C++ / CUDA]
C[PyTorch Reference]
end
subgraph Verifier[Mini Kernel Verifier]
D[Strict Loader]
E[Content-addressed Compiler]
F[PyTorch Dispatcher Load]
G[Correctness / Contract / opcheck]
H[CUDA Event Benchmark]
I[Baseline Regression Gate]
P[Nsight Compute Capture]
end
subgraph Outputs[Evidence & Derived Views]
J[Attempt + Logs + Source Snapshot]
K[Artifact Index]
L[Environment-scoped Leaderboard]
M[NCU Report + Profile Comparison]
end
A --> D
B --> D
C --> D
D --> E --> F --> G
G -->|pass| H --> I --> J
G -->|fail| J
J --> K --> L
E --> P --> M
核心包使用 src layout:
src/mini_kv/
├── task_card.py # 严格 YAML/路径校验
├── compiler.py # 内容哈希、项目内 build、dispatcher load
├── correctness.py # Reference、边界/非法、opcheck、gradcheck
├── benchmark.py # CUDA Event、P50/P95、稳定性门禁
├── artifacts.py # 原子 JSON、append-only Attempt、Index
├── regression.py # pinned baseline、可比性、双批确认
├── leaderboard.py # latest-valid、环境分组、几何平均 speedup
├── profiler.py # Nsight Compute 单 case capture
└── profile_analysis.py # NCU 指标解析与 CUDA Event 证据绑定
| 算子 | PyTorch Reference | CUDA 候选 | 主要覆盖 |
|---|---|---|---|
| Vector Add | torch.add(a, b) |
v0_naive |
FP32/FP16、warp 边界、空 Tensor |
| Fused Bias + ReLU | torch.relu(x + bias) |
v0_naive |
1D bias broadcast、非对齐 hidden |
| RMSNorm | FP32 accumulate Reference | v0_naive、v1_block_reduce |
reduction、数值稳定性、非对齐 hidden |
四个候选均注册 CPU、CUDA 和 Meta backend;CUDA wrapper 使用当前 PyTorch stream、
CUDAGuard 和 launch-error check,且不会在算子内部做破坏异步语义的全设备同步。
平台能力包括:
- 3 类算子、36 组固定核心 shape × dtype 正确性矩阵;
- 空 Tensor、zero/tiny/large value、非连续、shape/dtype/device 不匹配和非法参数测试;
- 独立记录 PyTorch Reference 数值误差、完整
torch.library.opcheck和 Autogradgradcheck; - 项目内、内容寻址的 JIT build cache,以及源码、stdout/stderr 和编译元数据归档;
- 每个实现每个 case 保存 500 个 CUDA Event 原始样本及 P50/P95/均值/标准差/CV;
- 显式 baseline promotion、环境/套件可比性检查、5% P50 双批确认回归门禁;
- append-only Attempt、Artifact Index、按 suite/GPU 环境分组的 Leaderboard;
- 固定 RMSNorm case 的 Nsight Compute 报告采集、强校验与结构化 A/B 对比;
- CPU GitHub Actions 与本机 GPU gate 分层。
已验收的本机环境:
| 项目 | 版本 |
|---|---|
| OS | WSL2 Ubuntu 22.04 |
| GPU | NVIDIA GeForce RTX 5070 Ti Laptop GPU, compute capability 12.0 |
| PyTorch | 2.11.0+cu128 |
| CUDA Toolkit / nvcc | 12.9 / 12.9.86 |
| Nsight Compute | 2025.2.1.0, build 35987062 |
| Python / C++ | 3.12 / C++17 |
PyTorch wheel 自带的 CUDA runtime 不等于构建 .cu 所需的本地 Toolkit;
torch.utils.cpp_extension.load 的构建参数与 plain dynamic-library 模式见
PyTorch 2.11 cpp_extension 文档。
uv sync --frozen --extra cu128
source .venv/bin/activate
python -m mini_kv doctor项目强制把 Extension build 放在 .build/torch_extensions/,不会使用默认的
~/.cache/torch_extensions。当前 Blackwell 机器建议固定原生目标:
export TORCH_CUDA_ARCH_LIST=12.0Verifier 默认使用内容寻址 JIT build;也提供经真实验证的 CMake AOT 入口,可一次构建并 加载包含四个唯一 dispatcher op 的共享库:
./scripts/build_cmake.sh先只验证 Task Card,不触发编译:
python -m mini_kv validate-task --task tasks/vector_add.yaml执行完整流水线:
python -m mini_kv verify --task tasks/vector_add.yaml
python -m mini_kv verify --task tasks/fused_bias_relu.yaml
python -m mini_kv verify --task tasks/rmsnorm.yaml覆盖默认候选,例如比较 RMSNorm naive 和 block-reduce:
./scripts/compare_rmsnorm.sh只跑编译、正确性、opcheck 和 gradcheck:
python -m mini_kv verify --task tasks/rmsnorm.yaml --skip-benchmark完整本机 gate:
./scripts/run_gpu_suite.shCLI 使用非零退出码区分配置、编译、正确性、Benchmark、回归和内部错误,适合直接作为 CI gate。
Task Card 只描述“测什么”,不嵌入执行代码:
schema_version: "1.0.0"
task_id: vector_add_v1
operator: vector_add
operator_version: "1.0.0"
reference: mini_kv.references.vector_add:reference
input_factory: mini_kv.references.vector_add:make_inputs
candidate: candidates/vector_add/v0_naive
device: cuda
cases:
- id: core_1025_fp16
kind: positive
params: {shape: [1025], dtype: float16}
tolerances:
float16: {rtol: 1.0e-3, atol: 1.0e-3}
benchmark:
case_ids: [bench_1m_fp16]
primary_case_id: bench_1m_fp16
warmup: 20
iterations: 100
repeats: 5Loader 使用 yaml.safe_load、拒绝未知字段与重复 case ID,并限制 candidate、source 和
baseline 路径留在项目目录内;运行时也强制校验 identifier、import path、dispatcher
qualname 和 schema version。Task Card、baseline 与运行结果由 14 份 Draft 2020-12 JSON
Schema 约束。
36 组核心矩阵固定为每个算子 6 个 shape × FP32/FP16。31/32/33 和
127/128/129 用于覆盖 warp/block 边界与非对齐长度;大尺寸性能 case 不混入“36/36”
简历口径。
每个正例都会:
- 以
sha256(task_id, case_id)派生固定 seed; - 给 Candidate 和 Reference 独立 clone 的同一输入;
- 同步 CUDA 后比较 shape/dtype/device 和数值;
- 记录 max absolute/relative error、mismatch count、异常和输入 metadata;
- 检查声明为 functional 的算子没有修改输入。
opcheck 与数值测试分开归档。前者验证 schema、Autograd registration、Meta/FakeTensor
和 AOT dynamic contract,不替代 Reference 数值测试;支持梯度的注册另外执行
gradcheck。这是 PyTorch 官方教程明确区分的两类验证:
Custom C++ and CUDA Operators。
计时不使用 CPU wall clock。每个 case:
- Candidate/Reference 各 warm-up 20 次;
- 5 个 repeat,每个 repeat 100 个独立 CUDA Event 样本;
- repeat 间交替 Candidate/Reference 先后顺序;
- 保存 500 个 raw samples、P50/P95/min/mean/std,以及 repeat 级 P50/P95、MAD 和 robust CV;
- Candidate/Reference P50 robust CV 上限为 3%,Candidate P95 上限为 15%;超限标记
unstable,不进榜、不做 baseline; speedup = reference_p50 / candidate_p50,跨 case 排名使用等权几何平均。
Baseline 永远不会自动更新:
python -m mini_kv promote-baseline \
--attempt artifacts/rmsnorm_v1/<attempt-id> \
--output baselines/rmsnorm_v1.json只有 task/operator semantic version、suite hash 和 environment key 完全相同时才比较;
环境不同返回 INCOMPARABLE,不是伪装成 PASS。当前 P50 阈值为 5%,首次超限会自动跑
独立 confirmation batch,两批都超限才 FAIL;P95 超过 10% 只告警。
仓库已保存三份由真实稳定 Attempt 显式 promotion 的 baseline;2026-07-13 随后的三次完整
运行均得到 regression.status = PASS。Baseline 内嵌原始 Benchmark 数据并通过独立 Schema
校验,在其他 GPU/软件环境会返回 INCOMPARABLE,不会沿用本机数字。
一次运行的最终目录:
artifacts/<task-id>/<attempt-id>/
├── attempt.json
├── task_card.json
├── candidate_manifest.json
├── environment.json
├── compile.json
├── compile_stdout.log
├── compile_stderr.log
├── correctness.json
├── benchmark.json
├── regression.json
└── sources/ # 本次真正编译的源码快照
写入期间目录以 .partial 结尾;JSON 同目录临时写、fsync 后 os.replace,最终再原子
rename。attempt.json 保存所有文件的 SHA-256 与大小。artifact_index.json 可幂等重建,
更新时使用文件锁;Leaderboard 只接受完整正确且稳定的 latest-valid attempt,并按 task、
suite、GPU 环境分榜。
python -m mini_kv rebuild-index
python -m mini_kv leaderboardRMSNorm 提供两份独立候选:
v0_naive:每个 row 一个线程串行 reduction;v1_block_reduce:每个 row 一个 256-thread block,shared-memory reduction,FP32 accumulate。
固定 [1024, 4096] / FP16 case 收集 Speed of Light、Memory Workload、Occupancy 和 Warp
State sections:
./scripts/profile_rmsnorm.sh candidates/rmsnorm/v0_naive
./scripts/profile_rmsnorm.sh candidates/rmsnorm/v1_block_reduce成功的报告和所有命令日志写入 artifacts/profiles/;失败也会保存结构化原因。Profile
产物绑定原始 Task Card/manifest、源码与 .so SHA-256、build/environment key、固定输入
seed,并使用候选专属 kernel-name filter;只有 .ncu-rep 可重新导入、raw CSV 可解析、
必需指标齐全且唯一数据行完整匹配目标 kernel 才标记成功。compare-profiles 还会要求两份
Profile 与 CUDA Event A/B Comparison 的 task/case/environment/build/source hash 全部一致。
可提交的结构化结果见
RMSNorm Profile 对比摘要。Nsight
Compute 支持按 section 选择指标、跳过 launch、导出报告以及 GUI baseline 对比,详见
NVIDIA Nsight Compute CLI
和 报告 Baseline 对比。
ruff check src tests scripts main.py
python scripts/validate_schemas.py
pytest -m "not gpu and not profile"
pytest -m gpuuv.lock 将 cpu 与 cu128 PyTorch 设为互斥 extra;本机使用
uv sync --frozen --extra cu128,Actions 使用 CPU-only wheel,避免在普通 Runner 下载整套
CUDA runtime。CI 还会上传 JUnit 与 coverage XML。
GitHub Actions 只运行 lint、format、Schema/Task Card/baseline 校验和 CPU 单元测试。CUDA 编译、36 组 GPU 正确性、Benchmark、回归和 Nsight 留在本机 GPU gate;项目不会把个人笔记本作为公开 PR 可触发的 self-hosted runner。GitHub 对 self-hosted runner 的部署与权限边界见 官方文档。
2026-07-13 在上表 RTX 5070 Ti Laptop 环境完成真实全量 gate。所有数字均来自保存 500
个原始样本的 Attempt,且质量状态为 valid:
| 主 case | 正确性 | Candidate P50 / P95 | Reference P50 | Speedup |
|---|---|---|---|---|
Vector Add [1M], FP16 |
19/19(core 12/12) | 7.744 / 58.608 μs | 3.680 μs | 0.48× |
Fused Bias+ReLU [1024,4096], FP16 |
20/20(core 12/12) | 28.224 / 34.147 μs | 32.704 μs | 1.16× |
RMSNorm v1 [1024,4096], FP16 |
24/24(core 12/12) | 20.000 / 32.160 μs | 164.368 μs | 8.22× |
三个算子合计 core 36/36,加边界/非法契约为 63/63;CPU 单测 95 passed,GPU
集成测试 14 passed,合计 109 passed。Vector Add 慢于高度优化的 PyTorch Reference,项目如实记录,未只
挑有利数字。
同进程、同输入、交替顺序的 RMSNorm A/B 对比为:naive P50 1956.096 μs,block-reduce
P50 18.016 μs,108.58× speedup,延迟下降 99.08%;两边 repeat-P50 robust CV
分别约 0.086% 和 0%,repeat-P95 robust CV 为 1.23% 和 0.70%,质量状态
valid。Comparison 同时保存两边各 500 个样本、完整 24/24 re-gate、源码快照与哈希。
复现命令:
./scripts/compare_rmsnorm.sh两份 Nsight Compute 2025.2.1 报告已成功采集并重新导入校验,raw CSV 均为唯一目标
Kernel 数据行、587 列。关键变化为:grid 4 → 1024 blocks、waves/SM 0.01 → 3.71、
achieved occupancy 16.66% → 89.44%、DRAM throughput 1.21% → 55.02%、实际 DRAM
bandwidth 4.11 → 186.73 GB/s。v0 的 LG Throttle / Long Scoreboard 为
60.56 / 45.05 cycles per issued instruction;v1 降至 0.15 / 6.25,剩余首要 stall 为
Long Scoreboard。NCU 将 v1 的 Speed-of-Light 状态判为 compute/memory balanced。
NCU 多 section replay 下的 6007.808 / 62.880 μs 只用于诊断,不能替代上面的同进程
CUDA Event A/B 延迟。完整指标、两个 report SHA、源码/build/.so/环境绑定关系均保存在
结构化证据,分析见
RMSNorm 优化闭环。
- ScalingIntelligence/KernelBench
- gpu-mode/reference-kernels
- meta-pytorch/tritonbench
- pytorch/extension-cpp
- 单 GPU、单机、forward-focused;不包含 LLM 生成 Kernel、Web UI 或分布式队列;
- 每个候选使用唯一 dispatcher op name;未把任意不可信源码接入公开 self-hosted runner;
- 当前编译、动态加载和候选执行针对可信本地源码,仍在 verifier 进程内;不可信候选的 crash/timeout 子进程隔离属于下一阶段;
- 采用当前 PyTorch 标准 ATen API,Stable ABI wheel 可作为后续分发增强项;
- Laptop GPU 的功耗和温度会影响结果,因此环境不同或噪声超限时拒绝做确定性回归结论。