高性能Go语言编译器优化与落地实践|青训营笔记

298 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。

主要内容

主要能学习到Go的编译器优化方案介绍:

  • 编译器优化

背景

  • 编译器优化的基本问题和思路

性能优化是为了什么呢

  • 提升软件系统处理能力,减少消耗,充分发挥计算机的算力
  • 用户体验
  • 资源高效利用

编译器的结构

  • 重要的系统软件
    • 识别符合语法和非法的程序
    • 生成正确且高效的代码
  • 分析部分(前端)
    • 词法分析,生成词素
    • 语法分析,生成语法树
    • 语义分析,收集类型信息,进行语义检查
    • 中间代码生成,IR
  • 综合部份
    • 代码优化,机器无关优化,生成优化后的IR
    • 代码生成,生成目标代码

image.png

相关概念

  • 静态分析 :不执行程序代码,推导程序的行为,分析程序的性质
  • 控制流:程序执行的流程
  • 数据流: 数据在控制流上的传递

通过上述概念,我们来优化代码

过程内分析和过程间分析

  • 过程内分析
    • 仅在过程内部进行分析
  • 过程间分析
    • 考虑过程调用时参数传递和返回值的数据流和控制流
  • 为什么过程分析会成为问题
    • 过程间分析需要同时分析数据流和控制流,联合求解,较复杂

GO编译器的优化

  • 目的:
    • 现在的优化太少了
    • 编译时间太少了,没有进行复杂的代码分析和优化
  • 思路
    • 面向后端长期执行任务
    • 用编译时间换取搞笑的机器码
  • 字节的方案
    • Beast mode

函数内联

大多数情况下都是正向优化

  • 内联 将函数的函数体做副本替换到调用位置上去
  • 优点 消除调用开销,将过程内分析变为过程间分析,例如逃逸分析 使用micro-benchmark验证一下
  • 缺点 函数体变大,编译生成的Go镜像变大 image.png

Beast Mode

  • 调整函数内敛的策略,使更多的函数被内联,增加逃逸分析,使更多对象不逃逸,降低开销
  • 代价:镜像文件增加10%,编译时间增加
  • 优化:未逃逸的对象可以在栈上分配(分配和回收快,降低GC)

逃逸分析

分析代码中指针的动态作用域:指针在何处可以被访问

  • 逃逸的几种情况:
    • 作为参数传递给其他参数
    • 传递给全局变量
    • 传递给协程
    • 传递给已经逃逸指针指向的对象