随着项目工程的迭代,代码量不断的增加,扩展功能不断的被引入,项目的整体编译时间开始变长。

前言

随着项目工程的迭代,代码量不断的增加,扩展功能不断的被引入,项目的整体编译时间开始变长。

研发在开发/调试过程中容易被过长的编译时间打断思路,所以需要定期对项目的编译时间做个体检。

采样编译阶段耗时的多种方法

显示Xcode编译耗时

在命令行中输入,可以开启编译耗时显示。在Xcode在每次编译完成后,在运行窗口中显示编译时间。

$ defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES

使用Xcode自带的编译耗时分析

在Xcode的菜单中选择 Product > Perform Action > Build With Timing Summary来获得编译耗时信息

Showing Recent Messages

Build Timing Summary

CompileC (2770 tasks) 													| 649.139 seconds
SwiftCompile (209 tasks) 												| 75.789 seconds
Ld (57 tasks) 																	| 9.891 seconds
SwiftEmitModule (27 tasks) 											| 9.002 seconds
SwiftDriver (27 tasks) 													| 4.057 seconds
Copy (2022 tasks) 															| 1.863 seconds
CompileMetalFile (8 tasks) 											| 1.290 seconds
WriteAuxiliaryFile (708 tasks) 									| 1.287 seconds
CpHeader (941 tasks) 														| 1.276 seconds
PhaseScriptExecution (8 tasks) 									| 0.536 seconds
MetalLink (1 task) 															| 0.332 seconds
RegisterExecutionPolicyException (61 tasks)			| 0.243 seconds
SwiftDriver Compilation Requirements (27 tasks) | 0.237 seconds
Touch (61 tasks) 																| 0.209 seconds
ProcessInfoPlistFile (62 tasks) 								| 0.110 seconds
SwiftDriver Compilation (27 tasks) 							| 0.085 seconds
CodeSign (1 task) 															| 0.066 seconds
CpResource (6 tasks)														| 0.056 seconds
ExtractAppIntentsMetadata (23 tasks) 						| 0.049 seconds
SwiftMergeGeneratedHeaders (27 tasks) 					| 0.038 seconds
Libtool (3 tasks) 															| 0.037 seconds
ProcessProductPackagingDER (1 task) 						| 0.003 seconds
CopyPlistFile (1 task) 													| 0.002 seconds
ProcessProductPackaging (2 tasks) 							| 0.001 seconds

查看Xcode的Build Reprot

在Xcode菜单中选择View > Navigators > Report,查看编译报告

Swift代码编译耗时警告

在 Xcode 项目的 Other Swift Flags中添加这两个提示,当函数/表达式编译时长超过 100毫秒 显示警告

-Xfrontend -warn-long-function-bodies=100
-Xfrontend -warn-long-expression-type-checking=100

Swift 编译器性能[2]中,Apple 官方提到了几个诊断选项:

  • -driver-time-compilation
  • -Xfrontend -debug-time-function-bodies,开启Swift文件中函数体编译耗时警告
  • -Xfrontend -debug-time-expression-type-checking,开启Swift文件中表达式编译耗时警告
  • -Xfrontend -print-stats
  • -Xfrontend -print-clang-stats
  • -Xfrontend -print-stats -Xfrontend -print-inst-counts

使用XCLogParser进行日志分析

XCLogParser可以将xcactivitylog转换为JSON文档,也可以生成分析报告(json, flatJson, summaryJson, chromeTracer, issueshtml

可用于

# 在当前目录生成报告,使用 --project 可以自动定位xcactivitylog位置
$ xclogparser parse --project AAA --reporter html

image-20221011161259162

image-20221011161310736

image-20221011161319712

image-20221011161328241

分析日志

  1. 首次编译,157秒(会生成缓存,多发生在切换分支后)

  2. 无变动编译,11.8秒
    1. SwiftLint(3.2秒)
    2. [CP] Embed Pods Frameworks(5.0秒)
  3. 修改文件后编译,38.84秒(开发/调试场景)
    1. Planning target AAA(4.3秒)
    2. Emitting module for AAA (6.9秒)
    3. Complie AAA (12秒)
    4. Link AAA(1.2秒)
    5. SwiftLint(3.4秒)
    6. [CP] Embed Pods Frameworks(5.0秒)
    7. Sign(2.4秒),受文件数量影响

image-20221011174744869

优化方案

Swift代码优化

解决编译时间过长的代码,多数为类型推断耗时过长,可以手动指定变量类型。

SwiftLint脚本优化

当前项目中,Lint+Correct耗时在3.4秒,单独开启Lint只需要耗时0.7秒

Lint 从3.4秒 减少到 0.7

优化Debug环境下编译参数

  1. Xcode默认使用SHA-256签名,本地调试阶段可以改成更快的SHA-1,不会有安全性问题,在Other Code Signing Flags添加--digest-algorithm=sha1
  2. iOS校验签名只对二进制签名,其他文件不签名也不会报错,可以过滤文件减少签名文件数量,在Other Code Signing Flags添加--resource-rules=/path/to/rule.plistrule.plist文件如下
--resource-rules=CodeSigningFileRule.plist
--resource-rules=$(SDKROOT)/CodeSigningFileRule.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>rules</key>
    <dict>
            <key>.*</key>
            <false/>
    </dict>
</dict>
</plist>

Sign时间从2.7秒减少到0.2

优化结果

测试环境:M1 Max + 32G,同时只编译一个项目

  优化前 优化后
首次编译(分支切换后) 157 秒 152.27秒
代码修改后编译(主要开发场景) 38.8 秒 31.3 秒
无修改编译 11.8 秒 6.7 秒

进一步优化

从日志上可以看出,代码发生修改后,AAA项目整体发生了重新编译,而Pod库的编译产物被复用。

可以得出结论模块Pod化也可以提升编译速度。

本次未针对首次编译进行优化,主要是目前交叉开发的情况较少。后续可以从固定资源文件,将动态库转为静态库的方向来优化首次编译的速度。

参考资料

xcode-build-optimization-a-definitive-guide

how-to-reduce-xcode-build-time