帧指针的回归
帧指针的性能权衡
- 讨论的主要成本:少一个通用寄存器(在 32 位 x86 上影响显著,在 x86_64 和其他 ISA 上影响较小)以及额外的函数序言/尾声指令,这会让那些小而高频调用的函数膨胀,并增加 I-cache 压力。
- 报告的性能下降差异很大:有人在真实应用中看到约 1–3%;Phoronix 的测试报告称几何平均惩罚约 14%;内核测量中某些工作负载被引用为 5–10%;也有人声称在现代工具链下,发行版范围内“低于 1%”。
- 对基准质量存在分歧:有人把数据库基准称为“微基准”,另一些人则认为它们是现实的端到端测试。普遍共识是,影响取决于工作负载,不能一概而论。
- 32 位 x86 仍被认为特别缺寄存器;而对许多其他架构来说,损失一个寄存器被视为微不足道。
性能分析、调试,以及为什么 FP 很重要
- 许多人认为,可靠、低开销的堆栈回溯对于 CPU、内存,尤其是 off-CPU 性能分析和执行跟踪至关重要。
- 没有帧指针时,内核 perf 必须复制大量堆栈块并在之后再回溯,这会带来 CPU、内存和磁盘开销,并且需要调试包。
- 开发者认为,对整个系统和第三方库而言,“只要重新编译并开启 FP”并不现实,这也让向最终用户索要 trace 变得不切实际。
- 也有人指出,更好的性能分析已经在真实软件中带来超过 10–20% 的加速,这完全足以抵消全局 FP 的小幅开销。
DWARF 与替代回溯方案
- DWARF/.eh_frame 回溯被描述为灵活但复杂,并且在高频采样或 off-CPU 性能分析中较慢。perf 当前的 DWARF 路径尤其昂贵,因为需要复制堆栈。
- 另一些人声称,通过预加载和缓存 unwind 信息,DWARF 可以做得很快,并指出基于 eBPF 的 profiler 会把表转换成高效的内核内格式。
- JVM/JIT 和其他高级运行时仍然很难处理:自定义回溯、混合的原生/托管堆栈,以及大量 JIT 活动,使得仅靠 DWARF 的方案在大规模场景下要么脆弱,要么成本过高。
默认设置、发行版策略,以及谁来承担成本
- 争论的焦点是内核、libc 和发行版构建的默认值应该是什么。
- 一方认为:全局启用 FP,让系统级性能分析“开箱即用”,从而支持持续优化和对生产版本进行事后分析。
- 另一方认为:大多数用户从不做性能分析;在数百万设备和服务器上损失几个百分点,能源和成本都不容忽视;对性能敏感的代码可以只在开发构建中启用 FP。
- 还有建议包括:按函数属性设置(但有注意事项)、分别构建“dev”和“end-user”版 libc,以及使用基于源码或 Nix/Guix 的系统在全系统范围内切换策略。
安全性与架构设想
- 讨论了用于返回地址的独立栈或影子栈,认为这是更简洁、更安全的设计,但当前硬件和 ABI 兼容性限制了实际部署。
- 有人建议与其承担 FP 成本,不如禁止
alloca();也有人反驳说,FP 至少现在就能部署,而更激进的改动并不能。