The Android community had awesome news this week: Dagger and Hilt KSP processors are now available in the latest release, v2.48:
The benefits of using KSP over kapt, in terms of build performance, are explained in the official doc:
The major advantages of KSP over kapt are improved build performance
...
To run Java annotation processors unmodified, kapt compiles Kotlin code into Java stubs that retain information that Java annotation processors care about. To create these stubs, kapt needs to resolve all symbols in the Kotlin program. The stub generation costs roughly 1/3 of a full kotlinc analysis and the same order of kotlinc code-generation
Regarding Android projects, KSP was already used by different libraries, but Dagger/Hilt, one of the main DI frameworks used in the Android projects, required using kapt. Mixing KSP and kapt didn't bring benefits in terms of build performance. We were waiting anxiously to test a project using KSP exclusively.
This article compares the results of building nowinadroid with KSP, using Dagger/Hilt 2.48, against the current configuration with kapt.
The Project
As usual in these articles, the project under experimentation is nowinandroid. We are based on the main branch on this commit. Build stack components:
- Gradle 8.2
- AGP 8.1.0
- KGP 1.9.0
- Hilt 2.47
The main branch is one of the variants of this experiment, representing the kapt build. Currently, the kapt configuration is used on 21 projects defining the dependency:
com.google.dagger:hilt-android-compiler:2.47
Then, we need a KSP branch acting as another variant in the experiment. We updated the required convention plugin to use KSP instead of kapt. Additionally, we had to apply small changes. The complete list of changes: https://github.com/cdsap/KspVsKapt/commit/5c7bab7b0241142f71caabde1d3558782db0bef4
Methodology
We created two different scenarios:
- Clean builds: 50 builds per variant executed in parallel in GitHub Action runners. Task:
:app:assembleProdDebug
. - Incremental change: 20 builds per variant executed in Github Action runners applying an incremental change on
core/data/src/main/java/com/google/samples/apps/nowinandroid/core/data/repository/NewsRepository.kt
using Gradle Profiler.
We retrieved the build information with Gradle Enterprise API.
Results
Before reviewing the build results, it's important to mention that replacing kapt with KSP affects the nature of the build. When applying the kapt plugin, we are adding two tasks to the project:
org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask
-
org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask
However, KSP adds only:
com.google.devtools.ksp.gradle.KspTaskJvm
We will reduce the number of tasks on the KTS variant:
Tasks executed (kapt variant) | Tasks executed (KSP variant) | |
---|---|---|
Clean Build | 310 | 292 |
Incremental Change | 164 | 154 |
Clean Builds
The build time, in seconds, for both variants was:
We noticed that the configuration time took around 30% of the build time. Because the builds are executed in clean runners, we preferred to exclude the configuration time and reduce the noise from the configuration phase. The results were:
Still, this data included the execution of tasks unrelated to the kapt/KSP. We picked the modules implementing kapt/KSP and measured the task duration:
- For kapt variant, is the sum of
KaptGenerateStubsTask
+KaptWithoutKotlincTask
- For the KSP variant, it represents the duration of
KspTaskJvm
The following view represents the median grouped by module of the projects using the plugins under investigation:
We noticed a general improvement in the build duration on each module, showing the app
module a decrease of 60% in the processor duration.
Incremental Builds
Because an incremental change affects a specific tree of the task graph, we have fewer modules involved compared to the previous scenario.
The configuration time is not a concern because we have incremental builds. The results after removing the warm-up builds:
Analyzing the median duration of the processor execution by module:
All modules decreased the processing time when using KSP. In this case, we didn't observe the same excellent results of clean builds, but we had significant wins.
Final words
We showed that KSP decreases the processing build time in the project nowinandroid. The project is small, and all the task durations in both variants take seconds, far from the expensive kapt executions we are used to in real projects where it takes minutes in large modules. This first version is just the beginning because the release notes mention the following:
Dagger’s KSP processors are still in the alpha stage. So far we’ve focused mainly on trying to ensure correctness rather than optimize performance.
Exciting times and kudos to the Dagger/Hilt team.
Happy Building
Top comments (0)