从 Kotlin 1.7.0 开始,您可以为 Kotlin 编译器任务创建构建报告(Build Reports)。 报告包含不同编译阶段的持续时间以及无法使用增量编译的原因。 此功能目前仍为实验性功能,因此指标列表未来可能会发生变化。
想要调查编译器任务的问题时,构建报告就可以派上用场。 例如,当 Gradle 构建花费过多时间时,难以理解性能不佳的根本原因。 或者,相同项目的编译时间不同:有时需要几秒钟,有时需要几分钟。
Kotlin 构建报告能够比 Gradle 构建扫描更有效地展示问题。 许多工程师使用它们来调查构建性能,但 Gradle 扫描中的粒度单位是单个 Gradle 任务。
如何启用构建报告
要启用构建报告,首先在gradle.properties
中声明保存构建报告的输出位置:
kotlin.build.report.output=file
以下值(及其组合)可用:
-
file
,将构建报告保存到本地文件中。 默认文件为${project_folder}/build/reports/kotlin-build/${project_name}-timestamp.txt
。 -
build_scan
,将构建报告保存到构建扫描的自定义值部分中。 请注意,Gradle Enterprise 插件会限制自定义值的数量及其长度。 这可能导致处理大型项目时丢失某些值。 -
http
,使用 HTTP(S) 请求发布构建报告。POST 方法以 JSON 格式发送指标。 数据可能因版本而异,请在 Kotlin 仓库中查看已发送数据的当前版本。
如果您没有 HTTP 端点,请使用以下示例之一:
1. 基于 ELK 堆栈的 HTTP 端点。 安装 Elasticsearch 实例并为 Logstash 使用以下配置:
input {
http {}
}
filter {
date {
match => [ "timestamp", "yyyy-MM-dd'T'HH:mm:ss" ]
timezone => "UTC"
target => "@timestamp"
}
mutate { remove_field => [ "http", "url" ] }
}
output {
elasticsearch {
index => "kotlin_reports"
}
}
2. 基于 Kotlin 的 HTTP 端点。 如果重新编译为 CSV 文件,它将保存编译时长和非增量编译原因的相关信息。
要进一步设置构建报告,请为gradle.properties
使用以下选项:
# Required outputs. Any combinations are allowed
kotlin.build.report.output=file,http,build_scan
# Optional. Output directory for file-based reports. Default: build/reports/kotlin-build/
kotlin.build.report.file.output_dir=kotlin-reports
# Mandatory if http output is used. Where to post HTTP(S)-based reports
kotlin.build.report.http.url=http://127.0.0.1:8080
# Optional. User and password if the HTTP endpoint requires authentication
kotlin.build.report.http.user=someUser
kotlin.build.report.http.password=somePassword
# Optional. Label for marking your build report (e.g. debug parameters)
kotlin.build.report.label=some_label
如何阅读构建报告
这里的优化过程很有创意。 现成指南经常很难提供,您需要具体情况具体分析。 但有时,您可以使用以下管道获得良好结果:
了解构建并非增量的原因并修正底层问题。
如果增量编译需要过多时间,可以重新组织源代码文件。 例如,不将所有类打包在一个文件中,不将所有顶级函数声明在一个文件中,等等。
我们来看一看生成的构建报告。 执行这个任务花费了将近 40 秒:
Task ':kotlin-gradle-plugin:compileCommonKotlin' finished in 39,73 s
Compilation log for task ':kotlin-gradle-plugin:compileCommonKotlin':
Non-incremental compilation will be performed: UNKNOWN_CHANGES_IN_GRADLE_INPUTS
Time metrics:
Total Gradle task time: 39,73 s
Task action: 0,09 s
Calculate output size: 0,01 s
Run compilation: 39,32 s
Incremental compilation in daemon: 39,27 s
Update caches: 0,40 s
Sources compilation round: 38,57 s
Compiler initialization time: 1,02 s
Compiler code analysis: 26,36 s
Compiler code generation: 10,87 s
Size metrics:
Total size of the cache directory: 6,2 MB
ABI snapshot size: 49 B
Total compiler iteration: 1
Build attributes:
REBUILD_REASON: Unknown Gradle changes
Total Gradle 任务时间显示了从任务执行到侦听器通知的时间。 任务操作仅指示在 Gradle 工作进程中安排编译作业的任务。 编译本身在 Gradle 工作进程中执行。 您可以在运行编译部分查看其编译时间。
我们看到这个模块是以非增量方式构建的,因为 Gradle 无法计算输入之间的差异。 这通常发生在干净构建中或在构建脚本中执行了更改时。 由于增量编译不可用,几乎所有时间都花在了代码分析上。
编译无法增量的最常见原因:
-
DEP_CHANGE_HISTORY_NO_KNOWN_BUILDS
– 这表示先前没有编译某个依赖模块,或者其历史记录文件已被保管起来。 -
DEP_CHANGE_HISTORY_IS_NOT_FOUND
– 这表示某个更改的依赖项不是源模块或非 Kotlin 模块。 -
OUT_OF_PROCESS_EXECUTION, IN_PROCESS_EXECUTION
– 这表示增量编译可在 Kotlin 守护进程中执行。 其他模式都会强制进行非增量构建。
后续文章将发布关于 Kotlin 增量编译的更多详细信息。 敬请关注!
我们如何在 JetBrains 中
使用构建报告
减少编译时间
以 Space 项目的这个构建报告为例。 我们有一个包含大量生成的源代码文件的模块。 虽然编译是增量的,但 Kotlin 编译器仍然必须在每次更改时重新分析大型源代码文件。
Compile iteration:
<a large="" generated="" source="" file="">
Time metrics:
Total Gradle task time: 108,98 s
Task action: 0,20 s
Backup output: 0,18 s
Connect to Kotlin daemon: 0,01 s
Calculate output size: 0,01 s
Run compilation: 108,23 s
Incremental compilation in daemon: 108,19 s
Calculate initial dirty sources set: 0,23 s
Analyze dependency changes: 0,03 s
Detect removed classes: 0,19 s
Update caches: 0,28 s
Sources compilation round: 107,49 s
Compiler initialization time: 0,12 s
Compiler code analysis: 80,26 s
Compiler code generation: 25,04 s
Size metrics:
Total size of the cache directory: 3,2 MB
ABI snapshot size: 643 B
Total compiler iteration: 1
在这种情况下,建议的做法是重新组织源代码:例如拆分大型文件、将不同的类置于不同的文件中、重构大型类等。
跟踪性能回归
Kotlin 团队使用构建报告跟踪多个项目的编译。 我们让开发者为构建报告启用 HTTP 端点,以在一个位置查看总体构建性能。 例如,您可以在 Kotlin 或 Gradle 版本更新后快速检查性能回归并找到运行时间长的编译。
分享反馈
欢迎在您的基础架构中试用构建报告。 如果您有任何反馈、遇到问题或想提出改进建议,请随时在我们的问题跟踪器中报告。 谢谢!
本博文英文原作者:Andrey Uskov
⏬ 戳「阅读原文」了解更多
本文分享自微信公众号 - JetBrains(JetBrainsChina)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。