每周性能技巧 #74:不要把路灯扫到地毯下面

本节阅读量:

本文翻译自 Abseil 官网的 Performance Tip of the Week #74: Sweeping the streetlight under the rug

原文发布于 2024 年 1 月 16 日,作者 Chris Kennelly,更新于 2025 年 8 月 23 日。

“路灯效应”描述的是:我们倾向于在容易观察的地方找答案,而不是在真正可能藏有答案的地方。本篇讨论性能分析中类似陷阱:可见成本不一定是真实成本,隐藏成本不一定可以忽略。

可见不等于重要

Profile 中显眼的函数很容易吸引注意。优化这些函数有时是正确选择,但也可能只是因为工具更容易把成本归因到它们身上。

例如,某个库函数可能承担了等待成本,真正的问题却来自之前的内存访问、锁竞争或 I/O。简单地让这个函数看起来更便宜,不一定改善端到端结果。

相反,有些优化会让某个组件自己的 profile 看起来更差,却改善系统整体。例如,预取指令可能把成本记到发出 prefetch 的库上,但它减少了后续等待,让调用方变快。

隐藏成本

隐藏成本常见于共享资源:

  • 内存带宽和缓存压力。
  • 分配器碎片。
  • 后端服务请求量。
  • 调度器和负载均衡行为。
  • 代码大小带来的指令缓存和 iTLB 压力。

这些成本可能不会出现在被修改函数的局部 profile 中,但会影响整体生产效率。只看局部指标,可能会把成本转移误判为优化。

使用代理指标

代理指标可以帮助我们看到不易直接测量的成本。例如 PMU counter 可以显示 cache miss、TLB miss 或 stalled cycles。内存分配 profile 可以显示分配频率和大小分布。端到端 A/B 测试可以显示跨组件影响。

代理指标不是目标本身。我们使用它们,是为了解释为什么主指标变化,或为什么主指标没有变化。代理指标与主结果冲突时,应该重新检查假设。

避免只优化工具能看到的东西

一个实用策略是同时看多种视角:

  • 函数级 CPU profile。
  • 分配和 heap profile。
  • 硬件计数器。
  • 业务或系统级吞吐量指标。
  • 代表性负载测试和生产实验。

不同工具的盲点不同。多个工具交叉验证,可以减少我们只在路灯下找钥匙的风险。

结语

性能优化不是让 profile 中某个数字变好,而是让系统以更少资源完成更多有用工作。可见成本是调查起点,不是结论。

上一篇:每周性能技巧 #83:减少内存间接访问

上一节

下一篇:每周性能技巧 #75:如何做微基准测试

下一节