SIMD 秒算 CRC:64 字节并行,CPU 周期省 90%

Photos provided by Unsplash OR Pexels

SIMD 加速 CRC 计算的完整原理

—— 深入解读 crc-fast v1.8.0 是如何做到 100GiB/s+ 的

一、传统 CRC 计算为什么慢?

经典位级/字节级 CRC(Sarwate 算法)每处理 1 字节需要:

  • 8 次移位 + 8 次条件异或(反射时更复杂)
  • 大量分支和内存访问 → 每字节 > 30 个时钟周期

即使是“表驱动”字节算法(1 次查表 + 1 次异或),在现代 CPU 上也只能达到 ~8–15 GiB/s,因为:

  • 查表有缓存延迟
  • 每 1 字节只能启动 1 次运算,流水线利用率低

二、SIMD 加速 CRC 的核心思想(Intel 2010 白皮书)

论文标题:
《Fast CRC Computation for Generic Polynomials Using PCLMULQDQ Instruction》
核心突破:把“多项式模运算”变成“矩阵乘法 + 模运算”,而矩阵乘法可以用 Carry-less Multiplication(无进位乘法) 完美加速!

关键数学等价变换

设当前 CRC 寄存器为 R,多项式为 P,待处理数据块为 M(长度固定,如 64 字节)

传统:
R’ = (R << 8×n ⊕ M) mod P

SIMD 加速公式(折叠 Fold):

R' = R × X^(8×n)  ⊕  M_low × X^(8×m)  ⊕  M_high   (mod P)

其中所有 × 都是 GF(2) 上的无进位乘法 → 刚好对应 CPU 的 PCLMULQDQ 指令!

三、crc-fast 实际采用的 8-at-a-time 折叠策略(最快实现)

crc-fast 不是论文里的 4-at-a-time,而是更激进的 8 倍折叠(一次处理 64 字节):

输入数据分成 8 个 8 字节块: D0 D1 D2 D3 D4 D5 D6 D7
当前寄存器:R

最终结果 =
    Fold8(R  ⊕ D7) ⊕
    Fold7(D6)      ⊕
    Fold6(D5)      ⊕
    Fold5(D4)      ⊕
    Fold4(D3)      ⊕
    Fold3(D2)      ⊕
    Fold2(D1)      ⊕
    Fold1(D0)

每一步 FoldN 只需要 2–3 条 PCLMULQDQ + 几条 XOR!

四、各平台具体指令对照表(crc-fast 实际使用)

平台关键指令说明crc-fast 实现位置
x86_64PCLMULQDQ64-bit 无进位乘法src/arch/x86_64/pclmulqdq.rs
x86_64 (AVX512)VPCLMULQDQ512-bit 向量无进位乘法,一次折叠更多src/arch/x86_64/avx512.rs
aarch64PMULL / PMULL2 (ARMv8 Crypto)64-bit 多项式乘法src/arch/aarch64/pmull.rs
x86 (32-bit)SSE + PCLMULQDQ降级使用 128-bit 向量src/arch/x86/sse.rs

五、完整 8× 折叠算法伪代码(精华)

// 伪代码,实际在汇编/intrinsic 中实现
fn fold_8x(crc: u64, block64: &[u8; 64]) -> u64 {
    let mut x = _mm512_loadu_si512(block64);        // 加载 64 字节
    let mut r = crc.to_le_bytes();                  // 当前寄存器

    // 预计算常数:X^(512), X^(1024), X^(1536)...(编译期生成)
    let k1 = X_512;   let k2 = X_1024;  let k3 = X_1536;  ...

    // 8 次无进位乘 + Barrett Reduction(模 P(x))
    r = clmul_fold(r, x.lo(), k1);
    r = clmul_fold(r, x.hi(), k2);
    // ... 继续 6 次

    barrett_reduction(r, poly)   // 最后一次模多项式(64→32 位)
}

Barrett Reduction:把 128-bit 中间结果快速折回到 32/64 bit,比传统移位快 10 倍。

六、crc-fast 的分层加速策略(自动选择最快路径)

输入数据长度 > 16KB

CPU 支持 AVX-512 + VPCLMULQDQ → 512-bit 8× 折叠(最快,>100GiB/s)
     ↓ 否
CPU 支持 AVX2 + PCLMULQDQ    → 256-bit 4× 折叠(~60GiB/s)
     ↓ 否
CPU 支持 SSE4.1 + PCLMULQDQ   → 128-bit 2× 折叠
     ↓ 否
ARM64 PMULL                  → 128-bit NEON 折叠
     ↓ 否
回退到 64-bit 纯软件 3-way 展开(仍然比传统表驱动快 5–10 倍)

运行 crc-fast 自带的 arch-check 二进制即可看到你的 CPU 实际使用的路径:

$ cargo run --bin arch-check --release
Detected best implementation: x86_64_avx512_vpclmulqdq
Theoretical max throughput: 128 GiB/s (estimated)

七、实测性能对比(2025 年主流 CPU)

CPU实现方式CRC-32 吞吐量CRC-64 吞吐量
Intel i9-13900KAVX-512 VPCLMULQDQ115–130 GiB/s58–65 GiB/s
AMD Ryzen 9 7950XAVX-512 VPCLMULQDQ120+ GiB/s60+ GiB/s
Apple M2 MaxARMv8 PMULL (NEON)45–55 GiB/s35–45 GiB/s
Intel Xeon (无 AVX512)AVX2 PCLMULQDQ45–60 GiB/s28–35 GiB/s
传统 crc32fast硬件 CRC32 指令(单核)20–30 GiB/s不支持

结论:crc-fast 在支持 VPCLMULQDQ 的机器上,比硬件 CRC32 指令快 4–6 倍!

八、总结:为什么 crc-fast 能做到“世界最快”

  1. 使用无进位乘法(PCLMULQDQ/PMULL)把除法变乘法
  2. 激进的 8× 折叠(一次处理 64 字节)
  3. Barrett Reduction 替代慢速移位
  4. 编译期生成所有常数 + 运行时完美分支预测
  5. 自动选择 CPU 最强指令集(AVX-512 > AVX2 > SSE > ARM)

这就是 crc-fast v1.8.0 能在现代 CPU 上突破 100GiB/s 的全部秘密。
如果你在写高性能存储、网络、备份、校验工具,crc-fast 几乎是无可替代的选择。

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)