构建时间优化-第1部分

几乎每个开发人员至少一次遇到了相当长的项目构建时间。这会导致生产率降低,并减慢整个团队的开发过程。如您所见,增加项目的构建时间至关重要,因为这直接影响到将应用程序发布到AppStore的时间以及更快地发布应用程序的新功能。

在本文中,我们将学习如何在Xcode中描述程序集并获取度量。在下一篇文章中,我将讨论消除瓶颈并加快项目组装速度的方法。还应该提到的是,我们将使用可以在Github上找到的Kickstarter iOS项目因此,让我们开始吧!

我们在测量什么?


我们必须做的第一件事就是确定我们要衡量和优化的内容。可以考虑两个选项:

  • 清理构建 -清理并构建项目。通常,会在CI中完成干净的构建,以检查是否有新的请求并运行单元测试。
  • 增量构建 -在对源代码进行重大更改后构建项目。该程序集由开发人员在使用新功能时创建。

在大多数情况下,减少“ 清除”构建期间的时间也应加快“ 增量”构建。最好的选择是为这两种类型的程序集创建指标并进行跟踪。我们将使用Debug配置来测量构建时间,因为大多数时间都使用它,并且对开发有更大的影响。

我们计算组装时间


缩短构建时间的最有效方法应该是基于特定指标实施和验证更改的方法。考虑它们,以及我们可以用来获取有关项目构建时间信息的工具。

Xcode构建时间报告


我们可以使用Xcode轻松获取构建时间数据。默认情况下,它跟踪所有构建,并允许您在报告导航器中查看项目的构建时间。

图片

您还可以选择在活动查看器面板的Xcode中显示类似信息可以通过运行以下命令来使用命令行启用该功能: 在装配后显示项目生成时间,并显示消息“成功”。 这些只是两个基本选项,应该使您大致了解“ 干净”和“ 增量”构建时间。

defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES



图片



Xcode中的项目构建时间摘要


Xcode构建时间摘要-您的第一个获得构建时间统计信息和瓶颈的朋友。您可以通过Product-> Perform Action-> Build with Timing Summary运行它。现在,您将看到花在各种任务上的时间的大量细目:

图片

该方法应该是在组装过程中查找最耗时的任务的良好起点。上面的屏幕截图显示,CompileStoryboardCompileXIBCompileSwiftSourcesPhaseScriptExecution阶段花费了大部分构建时间。 Xcode能够并行完成部分任务,因此,比完成每个命令的任务所需的时间要快得多。

我们可以使用带有选项-buildWithTimingSummary的xcodebuild来获得Clean构建的构建时间摘要 现在,让我们获得Incremental构建的类似指标。应该注意的是,增量构建时间完全取决于项目中正在修改的文件。为了获得一致的结果,您可以修改一个文件并编译项目。与Buck或Bazel系统不同,Xcode使用时间戳来确定已更改的内容和需要重建的内容。我们可以使用touch更新时间戳:

xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
-showBuildTimingSummary \
clean build | sed -n -e '/Build Timing Summary/,$p'

Build Timing Summary
CompileStoryboard (29 tasks) | 87.128 seconds
CompileSwiftSources (4 tasks) | 54.144 seconds
PhaseScriptExecution (14 tasks) | 18.167 seconds
CompileAssetCatalog (2 tasks) | 6.532 seconds
CompileXIB (21 tasks) | 6.293 seconds
CodeSign (7 tasks) | 3.069 seconds
Ld (4 tasks) | 2.342 seconds
LinkStoryboards (2 tasks) | 0.172 seconds
CompileC (3 tasks) | 0.122 seconds
Ditto (20 tasks) | 0.076 seconds
Touch (4 tasks) | 0.007 seconds
** BUILD SUCCEEDED ** [92.620 sec]



touch KsApi/mutations/CancelBackingMutation.swift && \
xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
-showBuildTimingSummary \
build | sed -n -e '/Build Timing Summary/,$p'

Build Timing Summary
PhaseScriptExecution (14 tasks) | 18.089 seconds
CodeSign (7 tasks) | 2.990 seconds
CompileSwiftSources (1 task) | 1.245 seconds
Ld (1 task) | 0.361 seconds
** BUILD SUCCEEDED ** [23.927 sec]

类型验证警告


当编译时间成为瓶颈时,我们可以通过在Xcode中将其他Swift Flags设置为项目构建选项来获得更多信息。启用该标志后,Xcode会为花费超过100ms来确定变量类型的任何函数或表达式生成警告:

  • -Xfrontend-警告长功能体= 100
  • -Xfrontend -warn-long-expression-type-checking = 100

图片

现在您知道了Swift编译器遇到的代码,现在您可以尝试对其进行改进。

编译器诊断选项


Swift编译器具有许多内置的诊断选项,可用于配置程序集。

  • -driver-time-compilation-驱动程序执行的任务的高度同步。
  • -Xfrontend -debug-time-compilation — .
  • -Xfrontend -debug-time-function-bodies – .
  • -Xfrontend -debug-time-expression-type-checking – .

让我们使用-debug-time-compilation标志在编译时获取有关最慢文件的信息: 如您所见,编译SettingsNewslettersCellViewModel.swift花了25秒。从汇编日志中,您可以获得有关文件编译时间的其他信息: 现在很明显,类型检查语义分析是最耗时的工作。让我们继续并在类型检查步骤中列出最慢的函数和表达式

xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
clean build \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-compilation" |
awk '/CompileSwift normal/,/Swift compilation/{print; getline; print; getline; print}' |
grep -Eo "^CompileSwift.+\.swift|\d+\.\d+ seconds" |
sed -e 'N;s/\(.*\)\n\(.*\)/\2 \1/' |
sed -e "s|CompileSwift normal x86_64 $(pwd)/||" |
sort -rn |
head -3

25.6026 seconds Library/ViewModels/SettingsNewslettersCellViewModel.swift
24.4429 seconds Library/ViewModels/PledgeSummaryViewModel.swift
24.4312 seconds Library/ViewModels/PaymentMethodsViewModel.swift



===-------------------------------------------------------------------------===
Swift compilation
===-------------------------------------------------------------------------===
Total Execution Time: 25.6026 seconds (26.6593 wall clock)

---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
24.4632 ( 98.3%) 0.5406 ( 76.5%) 25.0037 ( 97.7%) 26.0001 ( 97.5%) Type checking and Semantic analysis
0.0981 ( 0.4%) 0.1383 ( 19.6%) 0.2364 ( 0.9%) 0.2872 ( 1.1%) Name binding
0.1788 ( 0.7%) 0.0043 ( 0.6%) 0.1831 ( 0.7%) 0.1839 ( 0.7%) IRGen
0.0508 ( 0.2%) 0.0049 ( 0.7%) 0.0557 ( 0.2%) 0.0641 ( 0.2%) Parsing
0.0599 ( 0.2%) 0.0020 ( 0.3%) 0.0619 ( 0.2%) 0.0620 ( 0.2%) SILGen
0.0285 ( 0.1%) 0.0148 ( 2.1%) 0.0433 ( 0.2%) 0.0435 ( 0.2%) SIL optimization
0.0146 ( 0.1%) 0.0015 ( 0.2%) 0.0161 ( 0.1%) 0.0162 ( 0.1%) Serialization, swiftmodule
0.0016 ( 0.0%) 0.0006 ( 0.1%) 0.0022 ( 0.0%) 0.0022 ( 0.0%) Serialization, swiftdoc
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0001 ( 0.0%) SIL verification, pre-optimization
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) AST verification
0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) 0.0000 ( 0.0%) SIL verification, post-optimization
24.8956 (100.0%) 0.7069 (100.0%) 25.6026 (100.0%) 26.6593 (100.0%) Total



xcodebuild -project 'Kickstarter.xcodeproj' \
-scheme 'Kickstarter-iOS' \
-configuration 'Debug' \
-sdk 'iphonesimulator' \
clean build \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-expression-type-checking \
-Xfrontend -debug-time-function-bodies" |
grep -o "^\d*.\d*ms\t[^$]*$" |
awk '!visited[$0]++' |
sed -e "s|$(pwd)/||" |
sort -rn |
head -5

16226.04ms Library/Styles/UpdateDraftStyles.swift:31:3
10551.24ms Kickstarter-iOS/Views/RewardCardContainerView.swift:171:16 instance method configureBaseGradientView()
10547.41ms Kickstarter-iOS/Views/RewardCardContainerView.swift:172:7
8639.30ms Kickstarter-iOS/Views/Controllers/AddNewCardViewController.swift:396:67
8233.27ms KsApi/models/templates/ProjectTemplates.swift:94:5

同样,我们对装配进行了概要分析,发现在类型检查阶段存在相当大的瓶颈。下一步,您可以看一下上面列出的函数和表达式,并尝试优化类型推断

目标构建时间


建议单独测量目标的组装时间,并将其显示在图形上。您可以帮助了解正在收集或可以并行收集的目标。为此,您可以使用xcode-build-time-rendering工具。让我们将其设置为RubyGem: 安装完成后,运行以下命令以在目标的“运行脚本构建”阶段中输入时间戳日志: 然后编译项目并使用以下命令进行报告: 结果,您应该通过构建时间得到一个漂亮的甘特图,其中显示了时间所有目标的组合:

gem install xcode-build-times



xcode-build-times install



xcode-build-times generate



图片

汇总指标


汇总上面提到的各种指标将是很棒的。XCLogParser是一个很好的工具,可以为您提供帮助。它是Xcode生成的xcactivitylog的日志分析器,并提供有关项目中每个模块和文件的构建时间,警告,错误和单元测试结果的大量信息。您可以通过克隆存储库并通过命令行启动来安装它: 这是为Kickstarter iOS项目创建的报告:

git clone https://github.com/spotify/XCLogParser
rake build
xclogparser parse --project Kickstarter --reporter html



图片

自动化


应该注意的是,组装时间度量取决于硬件及其使用。您可以将设备用于实验。最好的选择是尽可能地自动化该过程,并使用专用的CI设备进行每日度量。最终,可以在仪表板上对其进行监视,并使用Slack通知构建时间的延长。

结论


减少项目的构建时间对于提高开发人员的生产率至关重要。今天,我们学习了如何衡量项目的构建时间并获得一些分析指标……

在下一个出版物中,我们将考虑可用于减少构建时间的方法。

谢谢阅读!

All Articles