我编写了一个自定义 CUDA 推理引擎,以在 130 美元的挖矿卡上运行 Qwen3.5-27B
I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source link, formatting, markdown, and any code blocks exactly as they are.
概览
我在二手市场以大约 每张 130 美元 的价格购买了四块 NVIDIA CMP 100‑210 显卡。这些是基于 Volta GV100 芯片(与 V100 使用相同硅片)的旧矿卡,每块配有 16 GB HBM2。理论上,四块卡的总内存为 64 GB HBM2,价格相当于一块二手 RTX 3090。
实际上,NVIDIA 在硬件层面对它们做了限制。
节流
- Tensor‑core 节流: 64 倍减速。
- HMMA 延迟从 8 周期 → 512 周期 拉伸。
cuBLASWMMA 限制在 ≈ 5 TFLOP 每卡。
- PCIe: 锁定为 Gen1 ×1。
- 无 P2P,亦无 NVLink。
- CUPTI: 被阻止 → NVIDIA 的分析器不可用。
节流是通过芯片上的 e‑fuse + PMU 启动 ROM 双重锁 实现的——这是硬件层面的锁定,而非固件开关。没有软件解锁(我尝试过)。
结果: 任何通过 cuBLAS 张量核心的计算都以 1/64 的速度 运行,或直接失败。包括:
- vLLM
llama.cpp的默认cuBLAS路径- FlashAttention
- bitsandbytes
- PyTorch 的默认
matmul
因此,标准的 LLM 推理栈在此硬件上 不可用。
变通方案
Only the tensor cores are throttled. Two other execution paths on the same chip run at full speed:
| 路径 | 描述 | 性能 | 节流 |
|---|---|---|---|
| DP4A | 4‑way packed int8 dot‑product | ≈ 17 TFLOP | 否 |
| HFMA2 | 2‑way packed fp16 fused multiply‑add | ≈ 24 TFLOP | 否 |
Neither matches a healthy V100’s tensor cores, but both are far above the 5 TFLOP cuBLAS WMMA ceiling. By routing all inference through these two paths we can recover ≈ 50 % of an unthrottled V100’s performance – still vastly better than nothing.
Source: …
介绍 qengine
qengine 是一个 从零实现的 CUDA 推理引擎,用于 Qwen 3.5 / Qwen 3.6 混合模型。(注意:Qwen 3.5/3.6 使用 稠密 GDN + Attention 架构,而非纯 Transformer,因此内核不同。)
特性
- 手写的 Q8_0 GEMM tile 路径 用于预填充 – 全 DP4A。
- 融合的 FlashAttention 内核(score + softmax + value)– 单遍计算。
- Split‑K FlashAttention 用于超长上下文。
- 3‑bit Walsh‑Hadamard + Lloyd‑Max KV 缓存 → 27 B 模型可在三块 16 GB 显卡上容纳 256 K 上下文。
- 兼容 OpenAI 的 HTTP API,支持流式输出、工具调用、视觉输入、连续批处理以及每槽前缀缓存。
所有内核均针对 sm_70(CMP 限制)编写,不是现有库的分支。
诚实基准
比较:qengine vs. llama.cpp(构建 8462,-fa 1,相同 Q8_0 GGUFs,相同硬件)。数值越大越好。
预填
| 模型 / 预填长度 | 令牌 / 秒 (qengine) | 令牌 / 秒 (llama.cpp) | 加速 |
|---|---|---|---|
| Qwen 3.5‑9B – 297 tokens | 594 | 199 | 2.99× |
| Qwen 3.5‑9B – 1.16K tokens | 683 | 316 | 2.16× |
| Qwen 3.5‑9B – 4.62K tokens | 584 | 361 | 1.62× |
| Qwen 3.5‑9B – 18K tokens | 393 | 324 | 1.22× |
qengine 在前三个长度上领先,在 18 K 时达到持平。
生成吞吐量
| 模型 | 令牌 / 秒 (qengine) | 令牌 / 秒 (llama.cpp) | 增益 |
|---|---|---|---|
| 9 B | ≈ 70 | 46.6 | +48 % |
| 27 B | 26.3 | 17.7 | +51 % |
薄弱点: 9 B 双 GPU 在 18 K 时仍落后于 llama.cpp(约 0.48×)。原因是 llama.cpp 将激活转移与计算重叠,而 qengine 必须通过固定主机内存顺序传输(无 P2P)。单 GPU 9 B 已经比任一双 GPU 运行更快,因此差距主要是理论上的。
实现挑战
1. 多 GPU(无 P2P)
- CMP 卡不支持点对点(peer‑to‑peer)和 NVLink。
- 隐状态必须在 GPU 之间通过 pinned host memory(固定主机内存)来回传递。
- 方案:为每条跨 GPU 边缘分配一个 pinned‑host 缓冲区,并为每个 GPU 启动一个工作线程。可行,但是顺序执行的。
2. 数值漂移导致韩文输出错误
- Qwen 3.5‑9B 的韩文电路较弱;微小的 fp16 重排噪声会改变 argmax 决策,产生乱码韩文。
- 在一次通过英文测试的 chunked‑prefill 内核优化后,韩文表现崩溃。
- 修复:所有涉及 attention‑reduction 顺序的内核现在在输出前都会执行 Korean argmax‑stability check(韩文 argmax 稳定性检查)。
3. Split‑K FlashAttention 在保持确定性的前提下实现
- 原始的 64‑块 FA 网格在长上下文下 SM 利用率低(仅 64 块分布在 3 × 68 SM = 204 上)。
- 添加了 split‑K 变体,将每个
(kv_head, t_idx)映射到N个独立块,每块处理一段连续的 tile 范围。 - 使用对数求和指数(log‑sum‑exp)恒等式合并部分结果:
m_global = max_s m_s
l_global = Σ_s exp(m_s − m_global) · l_s
o_global = Σ_s exp(m_s − m_global) · acc_o_s
- 第一个版本把部分
o累加器存为 half,导致约 31 个生成 token 后出现漂移(非位精确)。 - 将部分结果存为 fp32 后,漂移降至 fp32 重排噪声(约 1e‑7 每次相加),贪心 argmax 在 32+ token 上保持稳定。
- 效果:18 K 预填充的吞吐量从 270 → 393 t/s(9 B)提升到 104 → 139 t/s(27 B)。
4. 投机解码(仍然损坏)
- 仓库中包含用于未来微调 drafter 的 DFlash + DDTree 代码。
- 预训练的 drafter(
lucebox‑hub/dflash)基于原始 Qwen 3.5 训练;我们的蒸馏输出分布不匹配 → 接受率约为 0 %,链路退化。 - 在 README 中标记为 broken on purpose(故意损坏)。
- MTP K=1 单 token 投机解码能够正常工作。
谁应该使用 qengine?
| 情况 | 推荐 |
|---|---|
| RTX 30/40 系列、A100、H100 | 使用 vLLM 或 SGLang —— 它们的优化程度更高,且拥有广泛的测试覆盖。 |
| 旧的挖矿卡(CMP 100‑210、旧挖矿 V100、P104‑100 等) | qengine 可能有用。 |
| 较老的 Volta 工作站(V100 16/32 GB、Titan V、Quadro GV100) | qengine 可运行(目标 sm_70)。 |
| T4 或 RTX 20 系列在标准堆栈表现不佳时 | qengine 可能有所帮助。 |
没有 DP4A 的 GPU(例如 sm_60) | 不受支持。 |
| AMD / Apple GPU | 不受支持。 |
qengine 专门针对 sm_70。sm_75 应该可以工作,但未进行调优;sm_60 缺少 DP4A,因而无法运行。
Silicon Definitely Won’t Work
Repo
https://github.com/Haru-neo/qengine — Apache 2.0
本文中的基准测试可以通过仓库中的 bench_curl.sh 脚本复现。27 B 3‑GPU 的数据为
- 2026‑05‑03 在我的机器上测得。
- 如果你有相同硬件并尝试运行,欢迎告诉我你的结果。
项目详情
- 单人项目。
- 在 CUDA 上大量使用 AI 辅助——我负责架构、性能分析和调试的多个会话;Claude 完成了大部分内核实现。
- 我是韩国高中生。
- PR(合并请求)处理速度慢。