幸福里 C 端 iOS 编译优化实践-优化 40% 耗时

动手点关注干货不迷路 👆

背景

经过长期的业务迭代,C 端工程增量编译已经严重劣化,2021 年 12 月前,C 端平均增量编译长达 3 分钟以上,严重影响研发效率,急需优化!经过优化之后,增量编译时长降低到 2 分钟左右。

7b48a5d91ffa9d291a3c19b3fe29a347.png

分析

幸福里 app 编译过程

986106b6c31b2351776c1bd6b292e12a.png

主要耗时分析

  • 全量编译:pod 编译占用大部分时间,多达数百秒,CI 打包需要 20 到 30 分钟。

  • 增量编译:link、资源处理占用大部分耗时(C 端工程优化前该部分占用 130s 耗时)。

53bbc59dc749e2bf3071ecadac493122.png f654f90ae4dc244f491256e79b06913c.png 44d52b70f6649710565826e81e8c12da.png

方案

LLVM 编译优化

LLVM 编译过程

.m 文件编译从点.o 文件依次经历以下阶段:

9e4195bd72edd745ac68758700a83f63.png
  • 预处理:去掉注释、替换宏定义、添加行号和文件标识

  • 词法分析:将代码切成一个个 token

  • 语法分析:验证语法是否正确,生成语义节点

  • 生成 AST:将所有节点组合生成抽象语法树

  • 静态分析:通过语法树进行静态代码检测

  • 生成 LLVM IR:CodeGen 将语法树从顶至下遍历翻译成 IR 代码

  • 生成汇编:将 IR 代码转变成汇编代码

  • 生成目标文件:汇编器将汇编代码转变成机器代码

可以看到,从源文件到目标文件的编译过程中做了大量工作,如果一个源文件新增了一行代码,那么所有研发同学 build 时都要按照这些步骤重新走一遍,增加了大量重复耗时。

dolphin 分布式编译缓存

字节 app infra 团队通过 hook LLVM Clang,对于基本编译命令(比如 oc 文件),可以根据内容、依赖将其哈希成一个唯一的 key,我们编译完新的.m 后,将对应的.o 和 key 存储在本地硬盘和远程服务器上,其他研发同学编译时,就只需要下载.o 文件即可,可以极大提高编译的效率。幸福里 CI 接入 dolphin 后,打包编译部分耗时从 600s 降低到 240s。

f0829d6434939fa7e73592ee34c5d61a.png

资源优化

  • 主工程 asset 编译

主工程资源在每次编译都会被编译成 Assets.car,项目里有不少图片存放在主工程的资源下,每次编译都会在这一步耗费 30+s,于是将大部分主工程图片资源迁移至 pod 库中去,可以降低主工程资源编译耗时到 5s 内。

  • copy pods resource

我们工程是用 resources 引用资源,这一步是复制所有 pod 库的资源并编译合并到主工程的 Assets.car,耗时大概在 40s 左右。优化有两个方向:

  1. 如果改成 resource_bundles,那么每个 pod 都享有自己的 bundle 有自己的 Assets.car,不需要每次都编译一遍,增量编译这一步耗时会降低成 0,但是项目改造成本巨大,可当成一个长期目标去做。

  2. 如果我们不需要 care UI 界面,比如做埋点时,就可以写脚本在编译时选择跳过这一步骤,短期可实现。

link 优化

ld64

ld64 工作原理参考:https://mp.weixin.qq.com/s/tSj6JVEg7plJQm7aDHLyMw

静态链接器 ld64 负责分析 compiler 等模块输出的 .o.a.dylib、经过对 symbol 的解析、重定向、聚合,组装出 executable。ld64 主要工作流程如下:

0ee3b415962a7dc3928f79c44d00aa86.png

zld

zld 是基于 ld64 开发的优化版链接器,增加并发数、使用效率更快的数据结构去优化 link 过程,当然我们也可以参与优化 zld,如飞书一位大佬就通过 map 查找优化线性查找,降低算法时间复杂度优化了符号决议的耗时。

线性查找

880a059f46d6293dc81f7f751ae28d8a.png

map 查找

59888aee20e021eddc26c8693d43692e.png

接入 zld 数据对比

ld64 数据:

67b0e53ab7e6fb6b25cb43fbdd9aa573.png

zld 数据:

b13fa9da32a31212cfd65bb5da2900e1.png

结论

数据对比:

优化前:3.79m

10c36feb642fd1c8f923d68dce76fa05.png

优化后:1.91m

92efb9318e8a2d2c39b8789a9d8b40d2.png

实用技巧

资源拷贝

项目 pod install 时会在 pods-target-resources 生成资源拷贝脚本代码, 编译的时候都会运行这个脚本,如果想跳过资源拷贝,直接在 resources 第一行加上 exit 0 即可。

aba7edf8f28b9ac09a8f2da4f0230725.png

zld 调试

zld 源码:https://github.com/michaeleisel/zld

使用 zld 编译工程,查看编译日志,获取 link 命令代码:

739a66b672cc78a88b6b4eb37cbb0cfd.png

删掉括号和里面的东西,clang 命令后加一个-v,可以显示 link 参数,然后执行脚本,生成 link 参数,复制并删除-demangle 之前的东西,存到 juzi.txt:

-demangle -lto_library /Applications/Xcode.app/Content......

打开 zld 工程,编译模式调整为 release(debug 运行太慢,release 运行快但是不能断点调试),并将 juzi.txt 的参数复制到 arguments,就可以直接调试项目的 link 过程了。

827520800b5a6597caa08a0be28ec22d.png 3c991be0b306d5027603bc6f6361e5c3.png 189577a4ccaf63655fa38c50274fcd4a.png

分析 zld 耗时

将 zld 工程跑出来的 release 版可执行文件复制到桌面。

f0cb3e9164ca4c9b29d8b2fe6a4a5014.png

打开 xcode 的 instruments 的 time profiler,选择桌面上的 zld 可执行文件。

672d666c5dcbc1e9a40e0541cb53f2ab.png

将 juzi.txt 参数中的\s-换成 \\n-,并复制到上图的 arguments,然后运行并分析。

-demangle \
-lto_library /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib \
-dynamic \
...
96822a0880ab53f69fab69a517fc1069.png

如图,getUserVisibleName()耗时较多,我们查看 zld 源码:

354c617d3cff265a328b0a3b2ed3f608.png

经过断点或加日志测试发现,这个方法永远找不到".llvm."的子串(仅作为 demo 测试),于是尝试改成以下代码:

8fd575a1dcea841ae97bc69ea4802ca3.png

再次编译产生新的可执行文件,经过 instruments 再次测试得到如下数据:

3342ee2ad6bcb8efda5990cf7fedb183.png

Todo

  1. 将 resources 改成 resource_bundles,将资源拷贝耗时真正的降为 0。

  2. 项目中 swift 用的越来越多,可以接 dolphin 对 swift 的编译缓存。

  3. 探索 lld 的行业动态,进一步优化 link 速度。

参考资料

https://mp.weixin.qq.com/s/tSj6JVEg7plJQm7aDHLyMw

https://github.com/michaeleisel/zld

https://github.com/ming1016/study/wiki/%E6%B7%B1%E5%85%A5%E5%89%96%E6%9E%90-iOS-%E7%BC%96%E8%AF%91-Clang---LLVM

加入我们

字节房产部门客户端岗位面向2023届校园招聘啦!感兴趣的同学联系:xubinbin.19971226@bytedance.com

幸福里是集内容、社区、工具于一体的房产信息与服务平台。产品基于个性化推荐引擎向用户推荐优质的房产内容和全面、真实的房源信息,致力于为用户提供全面、专业、可靠的购房决策支持。

北京:

52661321413f5a50ce1200468e4789c3.jpeg

上海:

7264ed708bf804e8ca90870a802fbf98.jpeg

住小帮是真实可靠的一站式家装服务平台。整合海量真实家装案例,实用易懂的家装知识,严选把关的家装服务,陪伴装修全流程,让你轻松实现理想的家。  

杭州:

a388ad298599faf6036d7b3ce3c32769.jpeg

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值