News

Introducing Kotlin Build Reports

Read this post in other languages:

Starting with Kotlin 1.7.0, you can create build reports for Kotlin compiler tasks. Reports contain durations of different compilation phases and reasons why incremental compilation could not be used. This functionality is still Experimental, so the list of metrics may change.

TRY BUILD REPORTS

Build reports are useful when you want to investigate issues with compiler tasks. For example, when a Gradle build takes too much time, and it’s quite difficult to understand the root cause of poor performance. Another example is when the compilation time of the same projects differs: sometimes it takes seconds, and sometimes minutes.

Kotlin build reports help examine problems more efficiently than Gradle build scans. Many engineers use them to investigate build performance, but the unit of granularity in Gradle scans is a single Gradle task.

How to enable build reports

To enable build reports, declare the output location in gradle.properties  where to save build reports:

kotlin.build.report.output=file

The following values (and their combinations)  are available:

  • file saves build reports in a local file. By default, it’s ${project_folder}/build/reports/kotlin-build/${project_name}-timestamp.txt.
  • build_scan saves build reports in the custom values section of the build scan. Note that the Gradle Enterprise plugin limits the number of custom values and their length. This can result in some values being lost when dealing with large projects.
  • http posts build reports using an HTTP(S) request. The POST method sends metrics in JSON format. Data may change from version to version; see the current version of the sent data in the Kotlin repository.

If you don’t have an HTTP endpoint, use one of the samples below:

  1. HTTP endpoint based on the ELK stack. Install an instance of Elasticsearch and use the following config for Logstash:
  1. Kotlin-based HTTP endpoint. It saves information about the compilation duration and the reasons for non-incremental compilation if it was recompiled into a CSV file.

 To further set up build reports, use the following options for your gradle.properties:

How to read build reports

The optimization process is quite creative. It’s often difficult to provide a ready cookbook, and you have to investigate each case separately. But sometimes, you can achieve good results with the following pipeline:

1. Understand why builds are not incremental and fix underlying problems.

2. If incremental compilation takes too much time, a good approach is to reorganize source files. For example, don’t pack all classes in one file, don’t declare all top-level functions in one file, and so on.

Let’s take a look at a generated build report. This task took almost 40 seconds to execute:

The Total Gradle task time shows the time from task execution to listeners’ notification. Task action indicates only the task that schedules compilation jobs in Gradle workers. The compilation itself is performed in Gradle workers. You can see its compilation time in the Run compilation section.

We see that this module was built non-incrementally because Gradle couldn’t calculate the difference between the inputs. It usually happens with clean builds or when some changes in build scripts have been performed. Since the incremental compilation wasn’t available, almost all the time was spent on code analysis.

The most common reasons why compilation couldn’t be incremental are:

  • DEP_CHANGE_HISTORY_NO_KNOWN_BUILDS – this means that one of the dependent modules wasn’t previously compiled, or its history file was housekept.
  • DEP_CHANGE_HISTORY_IS_NOT_FOUND – this means that one of the changed dependencies isn’t a source module or a non-Kotlin module.
  • OUT_OF_PROCESS_EXECUTION, IN_PROCESS_EXECUTION – this means that the incremental compilation could be performed in the Kotlin daemon. Any other mode forces a non-incremental build.

More details on the incremental compilation in Kotlin are coming in future posts. Stay tuned!

How we use build reports in JetBrains

Decreasing compilation time

Consider this build report for the project Space. We had a module with large generated source files. While compilation was incremental, the Kotlin compiler still had to reanalyze large source files on every change.

In this case, it’s recommended to reorganize sources – split large files, place separate classes in different files, refactor large classes, and so on.

Tracking performance regression

The Kotlin team uses build reports to track compilation for several projects. We asked developers to enable an HTTP endpoint for build reports to see the overall build performance in one place. For example, you can quickly check for performance regressions after Kotlin or Gradle version updates and find long-running compilations.

Leave your feedback

You are welcome to try build reports in your infrastructure. If you have any feedback, encounter any issues, or want to suggest improvements, please don’t hesitate to report them in our issue tracker. Thank you!

image description