DEV Community

Cover image for KSP in Android projects
Iñaki Villar
Iñaki Villar

Posted on

KSP in Android projects

The Android community had awesome news this week: Dagger and Hilt KSP processors are now available in the latest release, v2.48:

Image description

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:
Image description
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:

Image description

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:

Image description

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:
Image description

Analyzing the median duration of the processor execution by module:
Image description

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)