Go 1.28 小 key 哈希从 AES 换成 wyhash:swissmap 转正后,旧 map 基准不再可比
文档:golang.design/history/runtime-compiler/go1.28.html
Go 1.28 概要行:mapsplitgroup 默认开启;SSA 包拆成 ssacompile 等;ARM64 SVE;移除 size-specialized-malloc flag;小 key 用 wyhash;recover 的调用者可内联;复合字面量类型省略进行中;string(int) 受限;PGO 接受 Linux perf profile。
swissmap 成为唯一实现
GOEXPERIMENT=swissmap 从实验开关变成唯一实现(only implementation)。构建脚本里继续带这个 GOEXPERIMENT 已经没有选择作用。
mapaccess2 被内联进 mapaccess1,做法是提高 inline budget(defa1f0155)。驱动因素是 wrapper 成本在合成基准里可见。把 mapaccess1 在调用点内联被判定为困难,因为该调用是在 walk 阶段引入的,晚于内联发生的时机。
map 哈希:MinAeshashSize 取代 UseAeshash
UseAeshash 被可调的 MinAeshashSize 替换。很小的 key 改走 wyhash,原因是 AES SIMD “does not like being used for one-offs”。cutoff 按微架构取值:
| 微架构 | cutoff | CL | 记录的变化 |
|---|---|---|---|
| Zen 4 | 8 字节 | c9e4a2aa07 | MapGroupBy、HashInt64Speed -10%;MapAccessMiss/int64/len=65536 -10.9% |
| Apple M1 Max | 16 字节 | b751a977cb | Hash5 -41%;MapGroupBy/int64 -65% |
interface key 的哈希现在折入动态类型的 compiler typehash(40e7643c46),因此 interface 里的 int64(0) 与 uint64(0) 不再碰撞。
未完成的部分:其他微架构(Intel steppings)的 cutoff 被列为 easy follow-ups;arm64 的 latency cutoff 192 尚未探索(issue 80970)。
对现有代码的实际影响
GOEXPERIMENT=swissmap失效。 它不再是可切换的实验项,带上它不会切回旧实现,也不会改变构建产物。- 别拿旧基准直接比。 小 key 的哈希路径从 AES 换成 wyhash,
mapaccess2的调用形态也因内联改变;1.28 之前的 map 基准数字与 1.28 的结果不是同一套路径下的对比。 - base 基准会抖。 cutoff 依赖微架构:Zen 4 是 8 字节、Apple M1 Max 是 16 字节,同一份代码在不同机器上走不同的哈希分支。跨机器或换机器复用 baseline 时,波动来自 cutoff 差异而不一定是代码改动。
- interface key 的碰撞分布变了。
int64(0)和uint64(0)作为 interface key 不再碰撞,构造大量 interface key 的基准或依赖碰撞分布的测量结果会跟着变。
同期其它条目
- reflect。 method Value 现在 eager 创建 func Value,receiver + index 存在
methodValue闭包里,Call保持快路径(3ebc191975);MethodByName不再通过FuncOf构造完整 Method(1a1b710b4c)。 - recover。 调用 recover 的函数现在可内联(0977a589b4)。
- PGO。
FromPProf接受 Linux perf 经perf_to_profile产生的 CPU profile(3bd19c1c39,issue #64489)。 string(x)。 对整数只允许byte、rune或无类型 rune 常量(自 1.28 起,#3939)。- 复合字面量。 按目标类型省略(#12854),多项进行中或已完成。
说明
以上为运行时/编译器仓库的历史整理页,属开发分支记录;文中基准数字为该 CL 当时的对比结果,方向和幅度依赖 CPU 与负载,本站未实测。GOEXPERIMENT swissmap 相关提案见 go.dev/issue。