作者|许彬彬背景经过长期的业务迭代,C端项目增量编译严重退化。2021年12月之前,C端平均增量编译时间超过3分钟,严重影响研发效率,亟待优化!优化后,增量编译时间减少到2分钟左右。分析Happiness中app的编译过程主要是分析全量编译耗时:pod编译耗时最多,达数百秒,CI打包耗时20~30分钟。增量编译:链接和资源处理占用了大部分时间(这部分在C端项目优化前耗时130s)。解决方案LLVM编译优化LLVM编译流程从点.o文件编译.m文件依次经历以下阶段:预处理:去除注释,替换宏定义,添加行号和文件标识符词法分析:将代码切割成tokens语法分析:验证语法是否正确,生成语义节点生成AST:组合所有节点生成抽象语法树静态分析:通过语法树进行静态代码检测生成LLVMIR:CodeGen将语法树从上到下翻译成IR代码生成汇编:将IR代码转换成汇编代码生成目标文件:汇编器将汇编代码转换成机器码。可以看出,从源文件到目标文件的编译过程,做了很多工作。如果在一个源文件中加入了一行新的代码,那么所有的研发同学在构建的时候,都得重新经历这些步骤,增加了很多重复和耗时。dolphin分布式编译缓存字节应用程序基础设施团队挂钩LLVMClang。对于基本的编译命令(比如oc文件),可以根据内容和依赖关系hash成一个唯一的key。我们编译新的.m后,将对应的.o和key保存到本地硬盘和远程服务器上。其他研发同学编译时,只需要下载.o文件即可,可以大大提高编译效率。Happiness中的CI接入dolphin后,打包编译耗时从600s减少到240s。资源优化主项目资源编译主项目资源每次编译都会编译到Assets.car中。项目中有很多图片存放在主项目的资源下。这一步每次编译会耗时30+s,所以将大部分主工程图片资源迁移到pod库中,可以将主工程资源的编译时间缩短到5s以内。copypodsresource我们的项目使用resources来引用资源。这一步是复制所有pod库的资源,编译合并到主工程的Assets.car中,耗时40s左右。优化方向有两个:如果改成resource_bundles,那么每个pod都有自己的bundle,有自己的Assets.car,不需要每次都编译。增量编译的耗时步骤会降为0,但项目改造成本巨大,可以作为一个长期目标。如果我们不需要关心UI界面,比如做埋点的时候,我们可以写脚本在编译的时候选择跳过这一步,短期内是可以实现的。link优化ld64ld64工作原理参考:https://mp.weixin.qq.com/s/tSj6JVEg7plJQm7aDHLyMw静态链接器ld64负责解析编译器等模块输出的.o、.a、.dylib,经过符号解析和重定向后,聚合,组装可执行文件。ld64的主要工作流程如下:zldzld是基于ld64开发的优化版链接器。它增加并发数并使用更快的数据结构来优化链接过程。当然我们也可以参与zld的优化。比如飞书的一位大佬通过地图搜索优化了线性搜索,降低了算法的时间复杂度,优化了符号解析的时间消耗。线性搜索图搜索访问zld数据对比ld64数据:zld数据:结论数据对比:优化前:3.79m优化后:1.91m实用技巧资源拷贝项目podinstall会在pods-target-resources中生成资源拷贝脚本代码,这个脚本编译时会运行。如果想跳过资源复制,只需要在资源的第一行加上exit0即可。zld调试zld源码:https://github.com/michaeleisel/zld使用zld编译工程,查看编译日志,获取链接命令代码:去掉括号和里面的内容,在-v后面加一个-vclang命令,可以显示链接参数,然后执行脚本,生成链接参数,复制删除-demangle前的东西,保存到juzi.txt:-demangle-lto_library/Applications/Xcode.app/Content。..打开zld工程,将编译模式调整为release(debug跑的太慢,release跑的快但不能断点调试),将juzi.txt的参数复制到arguments中,可以直接调试工程的链接过程。zld耗时分析将release可执行文件从zld工程复制到桌面。打开xcode工具的时间分析器并选择桌面上的zld可执行文件。将juzi.txt参数中的\s-替换为\\n-,复制到上图中的arguments中,然后运行分析。-demangle\-lto_library/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib\-dynamic\...如图getUserVisibleName()耗时较多,我们查看一下zld源码:断点测试或加日志后,发现该方法始终找不到“.llvm”的子串。(仅作为demo测试),所以尝试改成如下代码:重新编译生成新的可执行文件,再次通过instruments测试,得到如下数据:Todo将resources改为resource_bundles,减少resourcecopying时间归零。Swift在项目中使用的越来越多,可以为swift连接dolphin的编译缓存。探索LLD行业动态,进一步优化链接速度。
