60%+性能提升:持续性能分析与库匹配的结合 - 第一部分/二
为什么需要结合静态和动态分析?
几年前我共同创立了optimyze.cloud,并构建了Prodfiler(现为Elastic Universal Profiler)——一个全舰队范围、持续、全系统的性能分析器。这种分析器足够高效,可以始终开启,在您舰队中的每台机器上分析整个系统。
当面对舰队中最昂贵的10个或100个函数时,问题出现了:这些函数如此昂贵是"正常"的吗?如果不正常,为什么它们如此昂贵,以及如何解决?
结合动态和静态分析的模式
在性能优化和分析方面,我认为有三种模式可以让多种分析相互受益:
上下文排序
动态分析提供了系统中最昂贵部分的基本事实,静态分析的结果可以据此进行排序。排序很重要,因为开发人员时间有限,而且静态分析发现的有效性可能取决于相关代码是否处于热路径上。
分析排序
轻量级动态分析提供系统中最昂贵部分的信息,以便重量级分析可以聚焦在那里。
操作上下文
一个分析提供另一个分析运行所需的数据。这方面的例子包括配置文件引导优化/AutoFDO或Facebook的BOLT等链接后优化器。
低垂的美味果实
结合静态和动态分析进行性能优化的最低 hanging fruit 是模式匹配性能分析中最显著的库和函数,并替换为功能等效的优化版本。
我们遇到的具体例子:
- 如果在内存分配相关函数(如malloc、free、realloc等)上花费了大量时间,并且应用程序使用标准系统分配器,那么切换到更优化的分配器(如mimalloc或jemalloc)可能会获得性能改进
- 如果在zlib上花费了大量时间,切换到zlib-ng可以带来改进。我们的一个客户使用此更改使应用程序性能提高了30%
- 如果在处理JSON或序列化和反序列化上花费了大量时间,那么执行此操作的第三方库的性能存在巨大差异。我们的一位客户通过将他们使用的JSON编码器替换为orjson,使其最繁重的工作负载减少了60%
结论
上述内容为思考如何结合分析提供了一个有用的框架。如果您是SRE/SWE并在环境中集成了持续性能分析/grep-to-win方法,我很想听听结果如何。