kaptからkspに変わるとどれくらい早くなるのか〜Room編〜

# kaptとは

```
Annotation processors (see JSR 269) are supported in Kotlin with the kapt compiler plugin.
```
Javaのannotation processingをkotlinで使えるようにするcompiler pluginのことです。

# kspとは
```
Kotlin Symbol Processing (KSP) is an API that you can use to develop lightweight compiler plugins. KSP provides a simplified compiler plugin API that leverages the power of Kotlin while keeping the learning curve at a minimum. Compared to KAPT, annotation processors that use KSP can run up to 2x faster.
```

kspは軽量なcompiler pluginの開発が行えるAPIです。kspは最小限のKotlinの学習コストを最小限に抑えて開発する方法を提供します。kaptに比較して最大2倍速い。

https://android-developers.googleblog.com/2021/02/announcing-kotlin-symbol-processing-ksp.html

kspのREADMEで説明されていた2倍がどういう2倍なのかわからん、実際どれくらい早くなるんやってことで検証しました(上にもroomで最大2倍の高速化が図れた旨が記載されてます)。

# KSPの簡単な使い方(2021年8月時点)

- setting.gradle(.kts)にpluginMangementを追加してgradlePluginPortalのdependenciesを追加する
- 使いたいmoduleのbuild.gradle(.kts)のplugin部分でバージョン指定をして`com.google.devtools.ksp`を追加する、もしくはsetting.gradleにバージョン指定をして使いたいmoduleのbuild.gradle(.kts)のplugin部分に`com.google.devtools.ksp`を追加する
- 今まで`kapt`としてしていたところを`ksp`に変える

👉https://github.com/RyuNen344/annotation-perf/blob/master/settings.gradle.kts#L1

# 比較方法

2021年8月執筆時点ではいくつかのライブラリですでにksp対応が実験的対応完了しているようです。

https://github.com/google/ksp/blob/e854ce3c9c97f72a292b81f25477bdfa0cc208f8/README.md

|Library|Status|Tracking issue for KSP|
|---|---|---|
|Room|[Experimentally supported](https://developer.android.com/jetpack/androidx/releases/room#2.3.0-beta02)|   |
|Moshi|[Experimentally supported](https://github.com/ZacSweers/MoshiX/tree/main/moshi-ksp)|   |
|Kotshi|[Experimentally supported](https://github.com/ansman/kotshi)|   |
|Lyricist|[Experimentally supported](https://github.com/adrielcafe/lyricist)|   |
|Auto Factory|Not yet supported|[Link](https://github.com/google/auto/issues/982)|
|Dagger|Not yet supported|[Link](https://github.com/google/dagger/issues/2349)|
|Hilt|Not yet supported|[Link](https://issuetracker.google.com/179057202)|
|Glide|Not yet supported|[Link](https://github.com/bumptech/glide/issues/4492)|
|DeeplinkDispatch|Not yet supported|[Link](https://github.com/airbnb/DeepLinkDispatch/issues/307)|

Roomは`2.3.0-beta02`からkspにexperimental対応しています。
露骨にコード生成するのはRoomかなと思ったのでRoomで~~検証します~~検証しようとしました。


👉https://developer.android.com/jetpack/androidx/releases/room#2.3.0-beta02

## 起きた問題たち

### kotlin 1.4.30でroomの```@delegate:Ignore```が正常に動作しない

kotlin1.5.20で解決された様子(issue trackerまだ見つけられてません)

### kotlin 1.5.21でkspがコード生成してくれない

room2.3.0がksp1.4.30でビルドされているため動きませんでした。kspのalpha releaseではcompatibilityはないとのこと(他部分でビルドコケてた説もあるので検証はしないとですが)。
そのためkotlin 1.5.21でkspを動かすためにはroom 2.4.0-alphaを使う必要がありました。

```
BTW, room 2.3.0 does not work with ksp 1.5.21-1.0.0-beta06, because it was built with ksp 1.4.30-1.0.0-alpha04 and there had been some API changes that made them incompatible.
```

👉https://github.com/google/ksp/issues/471#issuecomment-895620658



### kspの高速化が動かない

roomはkspとkaptが同居するとコード生成高速化が動かないらしいのでkaptとkspを同時使用する際は別モジュールにするのが現状おすすめとのこと。

```
The reduction of build times is only applicable if there are no other processors that use KAPT.
```

👉https://developer.android.com/jetpack/androidx/releases/room#2.3.0-beta02

## 最終的に使用したバージョン

| name | version |
| --- | --- |
| kotlin | 1.5.21 |
| gradle | 7.0.2 |
| room | 2.4.0-alpha04 |
| ksp | 1.5.21-1.0.0-beta06 |

## 環境
下記2つの環境で試す。Ryzen7 3700のみで検証を始めたのですが、追加でintel cpuでも検証しました。

|OS|CPU|
|---|---|
|Windows 11|AMD Ryzen7 3700|
|macOS Big Sur|Intel Core i5-8257U|

テーブル定義は以下のRepositoryのものを拝借させていただきました。
FTS, comibine, releationがあるものかつテーブル定義数をかさ増しして負荷がかかるはずの状態にしました。

| Repository | Link |
| --- | --- |
| Dagashi | https://github.com/RyuNen344/Dagashi |
| Sunflower | https://github.com/android/sunflower |
| tivi | https://github.com/chrisbanes/tivi |

# 実験結果(1回目) こちら計測不備

## 使用コマンド

gradle daemonが速度を高速化しようとするため結果にばらつきが発生し過ぎていました。そのため```--no-daemon```を付与しています。
profileでkapt, kspそれぞれの実行時間を表示させて計測しました。

### ksp
```bash
./gradlew clean
./gradlew --profile --no-daemon :db:kspDebugKotlin
```

### kapt
```bash
./gradlew clean
./gradlew --profile --no-daemon :db:kaptDebugKotlin
```

---

|CPU|ksp(s)|kapt(s)|
|---|---|---|
|Ryzen|1.964|2.643|
|intel|3.257|3.525|

Ryzenで思ったより差が出ていますがintelでの差があまりでていないです。最大2倍速いとのことですが、通常使用で考えられるDB定義を用いて差を感じられるのは多くて500msぐらいなのかなという結果になりました(500msの差が塵積という話はありますが)

# 実験結果(2回目)

https://twitter.com/swiz_ard/status/1425670034316095488?s=20


どうにも結果がパッとしない(Googleのannounceと乖離が激しい)ので悩んでいたところ`--no-daemon`だけでなく`--no-build-cache`をつけてみたら、とアドバイスいただいたので再度計測しました。
また、どうにもkaptのほうが実行時間の早い結果が出てしまい悩んでいたのですが、比較する際にはコード生成するタスクを比較しなければならないことに気が付きました。なのでkaptのほうに表示されている時間は下記の表に表示されているタスクの経過時間になります。

|before|after|
|---|---|
|`:db:kspDebugKotlin`|`:db:kspDebugKotlin`|
|`:db:kaptDebugKotlin`|`:db:kaptDebugKotlin`\ `:db:kaptGenerateStubsDebug`|

## 使用コマンド

### ksp
```bash
./gradlew clean
./gradlew --profile --no-daemon --no-build-cache :db:kspDebugKotlin
```

### kapt
```bash
./gradlew clean
./gradlew --profile --no-daemon --no-build-cache :db:kaptDebugKotlin
```

---

| |ksp|kapt|
|---|---|---|
|1回目|2.996|3.068|
|2回目|2.875|2.777|
|3回目|2.707|3.058|
|4回目|2.895|2.860|
|5回目|2.759|2.808|
|avg|2.8464|2.9142|

# 早くksp対応進んでほしい
ことコード生成部分に関しては若干kspのほうが早いという結果になりました。ただkaptからkspに移行することよりも`強いマシンを使うこと`、`cacheを効かせること`のほうが圧倒的に効果がでるようです(roomに関しては)。個人的にはroomのビルドがあまりに遅いと感じる場面は少なく、DataBindingやDaggerが遅く感じる要因なのかなと思っています。なのでそれぞれが対応されたタイミングで再度実験できたらと思ってます。

# 使用したサンプル
https://github.com/RyuNen344/annotation-perf