Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

跨过程分析(进阶)

复习

  • 函数内联:把调用与被调函数拉到同一上下文
  • 静态单赋值形式:简化分析
  • 优化为什么必须保留行为:等价是前提

本章为进阶内容,零基础读者可以跳过,不影响后续阅读。

TL;DR

  • 跨过程分析跨越函数边界来观察程序
  • 它能发现“只盯一个函数”看不到的优化机会
  • 但分析范围越大,代价越高
  • 它常与内联配合使用

正文

  前面讲的优化,大多是在一个函数内部做的。可有些问题,只有跨过函数边界才能看清。这类分析叫跨过程分析(interprocedural analysis)。

越过边界,看得更全

  举个典型的例子:

函数 计算(x): 返回 x * x
主程序: 计算(10)

  如果只分析“计算”这个函数本身,你不知道 x 会是什么;但如果跨过程看,发现它总是被传 10,就可能为这个调用点做特化——直接算出结果 100。

  这类“某个参数在很多调用处总是同一个常量”“某个函数从不返回错误”“某个变量跨函数也不变”等结论,只有把多个函数连起来看,才能得出。内联把代码合到一起,跨过程分析则让优化能看到更大的图景。

代价:范围越大越贵

  但跨过程分析不是没有代价的:

  • 分析范围爆炸:函数相互调用,可能的组合非常多,分析成本急剧上升
  • 编译更慢、内存更多:为了全局信息,编译器要保存和处理更多数据
  • 重新编译的连锁:一个函数改了,依赖它的分析结论可能都要重做

  所以,实际的编译器往往在“看多远”上做折中:有的只做过程内的优化,有的在模块内做,有的则在链接时做(常称为链接时优化,LTO)——把整个程序合起来再分析一遍,代价更大,收益也可能更大。

同一个主题

  你会发现,跨过程分析又一次落入那个熟悉的结构:看得越全,能优化的越多,但代价也越大。

  这和处理器的乱序执行、缓存的大小、线程的数量……都是同一种味道:没有免费的全局视野。 关键在于,找到收益与代价最匹配的那个范围。

思考题 1

  跨过程分析相比过程内分析,多看到了什么?

思考题 2

  跨过程分析的代价是什么?

小结

知识点

  • 跨过程分析跨越函数边界观察程序
  • 它能发现过程内看不到的优化机会
  • 代价是分析成本高、编译更慢
  • 常与内联、链接时优化配合

参考资料

  1. Wikipedia(zh):过程间优化:跨越函数边界的分析与优化
  2. Wikipedia(zh):链接时优化:在链接阶段进行的全局优化

思考题答案(仅供参考)

思考题 1

  它能看到函数之间的相互关系,例如某个参数在调用处总是同一个常量、某函数从不返回错误、某值跨函数保持不变等。这些结论在只分析单个函数时是看不到的,因此能带来额外的优化机会。

思考题 2

  代价是分析成本高:函数互相调用使可能的组合急剧增多,编译器需保存更多全局信息、编译更慢,某个函数改动还可能使相关分析结论失效而要重做。因此只能在“看多远”上做折中。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪