Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ABEMAのビルド速度改善のために取り組んだこと

Avatar for Ryutaro Yagi Ryutaro Yagi
March 16, 2023
790

 ABEMAのビルド速度改善のために取り組んだこと

Avatar for Ryutaro Yagi

Ryutaro Yagi

March 16, 2023
Tweet

Transcript

  1. AbemaTV, Inc. All Rights Reserved
 AbemaTV, Inc. All Rights Reserved


    1 ABEMAのビルド速度改善 のために取り組んだこと 2023 March 16t 株式会社サイバーエージェント Ryutaro Yagi (@yagiryuuu)
  2. AbemaTV, Inc. All Rights Reserved
 自己紹介 2 八木 利生太郎 (やぎ

    りゅうたろう) 日本大学3年 2024年新卒入社予定 現在は、ABEMAでAndroidエンジニアとして 内定者バイトをしています。
  3. INDEX 1. Gradle Profilerで計測 3. JVM Parallel GCを使う 2. Configuration

    cache有効化 4. buildSrcからinclude buildへ 6. まとめ 5. 実際どのくらい早くなった?
  4. AbemaTV, Inc. All Rights Reserved
 公式のビルド速度最適化 Android Developersのビルド速度改善Tips 5 Android

    Developersの、ビルド速度最 適化のセクションに載っているTipsを全 てではないですが、実際にいくつか ABEMAに導入していきました。 Optimize your build speed https://developer.android.com/studio/build/optimize-your-build
  5. AbemaTV, Inc. All Rights Reserved
 ビルド速度を可視化 Gradle Profiler 7 •

    Gradleプラグインバージョンやクリーンビルドのプロファイ リングなど、自分達で計測したい特定のシナリオを設定 し、速度を計測することができる。 • 元々、Gradle Profilerのような計測ツールを使って、実際 にどのくらいの速度なのかを計測していなかったので、ま ずは計測し改善を目に見える形にするようにしました。 Profile your build https://developer.android.com/studio/build/profile-your-build
  6. AbemaTV, Inc. All Rights Reserved
 例:シナリオの設定 Gradle Profilerの導入 8 clean_build

    { tasks = [“:root:assembleDebug”] show-build-cache-size = true warm-ups = 4 gradle-args = [“--no-build-cache”] } clean_no_cache_build { tasks = [“:root:assembleDebug”] show-build-cache-size = true warm-ups = 4 gradle-args = [“--no-build-cache”, “--no-configuration cache”] } ビルドキャッシュがある場合とない場合の2パターンで計 測しています。
  7. AbemaTV, Inc. All Rights Reserved
 Configuration cache Configuration cache有効化 10

    • Configuration cacheを有効化することで、 Configuration phaseをスキップすることがで き、ビルドパフォーマンスの改善が期待できま す。 • デフォルトでは、Configuration cacheが無効に なっており、gradle.propertiesにオプションを追加 することで有効化することができます。 Use the configuration cache https://developer.android.com/studio/build/optimize-your-build#use-the-confi guration-cache-experimental
  8. AbemaTV, Inc. All Rights Reserved
 Configuration cacheを有効にする Configuration cacheの有効化 11

    org.gradle.unsafe.configuration-cache=true org.gradle.unsafe.configuration-cache-problems=fail gradle.propertiesに以下の2つのオプションを追加する プラグインの互換性が完璧でない場合に備え て、warnではなくfailを設定して、厳しく設定し ています。 Configuration cacheに対応していないライブラリがプ ロジェクトの中に存在している場合は、それらのアップ デート・削除も同時に行う必要があります。
  9. AbemaTV, Inc. All Rights Reserved
 特定のケースで無効にしたい場合 Configuration cache有効化 12 •

    一部のタスクだけ、Configuration cacheを無効にしたいような場合では、 no-configuration-cacheを使用することで、そのタスクだけ無効にすることができます。 • ABEMAでは、普段のDebugビルドでは有効にしていますが、 Releaseビルドでは、一 部のプラグインが対応していなかったため、 CI上ではno-configuration-cacheを使用 しています。(開発するときは有効なので開発者体験の向上はできる。 )
  10. AbemaTV, Inc. All Rights Reserved
 Android Studio Electric Eel JVM

    Parallel GC 14 • Android Studio Electric Eelから対象JDKが11以 上となり、JDKのバージョンを上げる必要がありま した。 • JDK8までは、Parallel GCがデフォルトで使用され ていましたが、 JDK9以降では、G1 GCがデフォル トで使用されるようになっており、ビルド速度に多 少影響が出ていました。 Android Studio Electric Eel | 2022.1.1 https://developer.android.com/studio/releases
  11. AbemaTV, Inc. All Rights Reserved
 Parallel GCを有効にする JVM Parallel GC

    15 • そこで、G1GCではなくParallel GCを使用 することでビルド速度の改善を試みまし た。 • ちなみに、Android Studio Electric Eelに するだけでも、ビルド速度が改善するよう です。 https://developer.squareup.com/blog/celebrating-the-release-of-android-studio-electric-eel/ Experiment with the JVM parallel garbage collection https://developer.android.com/studio/build/optimize-your-build#experiment- with-the-jvm-parallel-garbage-collector
  12. AbemaTV, Inc. All Rights Reserved
 Parallel GCを有効にする JVM Parallel GC

    16 org.gradle.jvmargs=-Xmx1536m -XX:+UseParallelGC gradle.propertiesにこのオプションを追加する Parallel GCを使用することで、複数スレッドで GCを行うので、ビルドパフォーマンスの改善が 期待できます。
  13. AbemaTV, Inc. All Rights Reserved
 buildSrcの問題点 buildSrcからinclude buildへ 18 •

    buildSrc内部の変更をすると、プロジェクト全体に影響を与えてしまうため、ビルドキャッ シュが無効になってしまう。 • リモートビルドキャッシュを使用している場合、リモートビルドキャッシュも無効化されて しまう。
  14. AbemaTV, Inc. All Rights Reserved
 buildSrcからinclude buildへ 19 • include

    buildだと、ビルドロジックを一つのモジュールに独立させることができる ので、buildSrcのように変更するとビルドキャッシュが無効になるといった問題が 発生しない。 • Square社では、buildSrcからinclude buildに移行したことで、ビルド速度が30% 向上したらしい。 (https://developer.squareup.com/blog/measure-measure-measure/) include Buildはどうなのか?
  15. AbemaTV, Inc. All Rights Reserved
 include buildへの移行 buildSrcからinclude buildへ 20

    • ABEMAでは、元々buildSrcでライブラリのバージョン管理をしていたので、 Version Catalogでライブラリ管理するようにしました。 ◦ buildSrc削除ため • どうやってPluginを作っていくのか、決める必要がありました。 ◦ Pluginを切り出す単位・命名規則など。
  16. AbemaTV, Inc. All Rights Reserved
 Version catalogを使ってライブラリバージョンを管理 buildSrcからinclude buildへ 21

    gradle / libs.versions.tomlでライブラリを 定義して、Version catalogでライブラリの バージョン管理をするように統一しました。 Central declaration of dependencies https://docs.gradle.org/current/userguide/platforms.html#sub:central-declaration-of-d ependencies
  17. AbemaTV, Inc. All Rights Reserved
 Version catalogでの定義のルール buildSrcからinclude buildへ 22

    • ケバブケース。 • バージョンの値を直接参照しないか つ、librariesやplugins内で共通で使 われないものは、versionsに定義しな い。 [versions] kotlin-coroutines = “1.6.4” androidx-fragment = “1.5.5” [libraries] coroutines-core = { module = “org.jetbrains…..”, version.ref = “kotlin-coroutines” } coroutines-test = { module = “org.jetbrains…..”, version.ref = “kotlin-coroutines” } fragment = { module = “androidx….”, version.ref = “androidx-fragment” } fragment-test = { module = “androidx….”, version.ref = “androidx-fragment” } kotlin-datetime = { module = “org.jetbrains….”, version = “0.4.0” } 共通で使われるバージョン kotlin-datetimeだけでしか使われないバージョンなので直接定義
  18. AbemaTV, Inc. All Rights Reserved
 nowinandroidのPluginの分け方 buildSrcからinclude buildへ 23 nowinandroidのように、

    build-logic/convention以下にそれぞ れのPluginを定義していくやり方だと、 Plugin同士の依存関係が分かりにくい 問題がありました。 plugins { id(“com.example.library”) id(“com.example.hilt”) id(“com.example.compose”) } com.android.libraryを適用させたPlugin 下の2つのPluginは、一番上のPlugin に依存している
  19. AbemaTV, Inc. All Rights Reserved
 どう解決したか? buildSrcからinclude buildへ 24 •

    特定の技術ごとに細かくPluginを切り分けるPrimitie Pluginと、それらを集合 体として管理するConvention Pluginを作るようにしました。 • Primitive PluginとConvention Pluginのような分け方をすることで、セットで使う ようなPrimitive Pluginを一つのConvention Pluginとしてまとめることができ、 Plugin間の依存関係をより分かりやすくしました。
  20. AbemaTV, Inc. All Rights Reserved
 buildSrcからinclude buildへ 25 • Pluginを構成する最小の単位。

    • Primitive Pluginはビルドロジックを管理し、Primitive Plugin同士が依存しないようにして います。 • 特定の技術ごとにPluginを切り分けて、Pluginを作成するようにしました。 ◦ Robolectric, Dagger Hilt, Coroutineなど • Primitive Pluginの命名規則 Primitive Plugin tv.abema.primitive.xxxx
  21. AbemaTV, Inc. All Rights Reserved
 例:Primitive Plugin buildSrcからinclude buildへ 26

    class AndroidHiltPlugin : Plugin<Project> { override fun apply(target: Project) { with(target) { with(pluginManager) { apply(“dagger.hilt.android.plugin”) } hilt { enableAggregatingTask = true } dependencies { implementation(libs.findLibrary(“hilt”)) } } } } ビルドロジックを定義していく ライブラリの依存関係の追加 DSLを定義して Plugin内で簡単に使える ようにしています
  22. AbemaTV, Inc. All Rights Reserved
 buildSrcからinclude buildへ 27 • Primitive

    Pluginを集合体として管理する。 • Convention Pluginはビルドロジックを持たないようにする。 • Convention Pluginで、Primitive Pluginをまとめることで、Primitive Plugin間の依存関係 がわかりやすくなり、本来Primitive Pluginを複数適用させなければいけない設定を Convention Pluginを一つ適用させるだけで設定完了できるようにしました。 • Convention Pluginの命名規則 Convention Plugin tv.abema.convention.xxxx
  23. AbemaTV, Inc. All Rights Reserved
 例:Convention Plugin buildSrcからinclude buildへ 28

    class AndroidHiltConventionPlugin : Plugin<Project> { override fun apply(target: Project) { with(target) { with(pluginManager) { apply(“com.example.primitive.kotlin.kapt”) apply(“com.example.primitive.kotlin.kapt.hilt”) apply(“com.example.primitive.android.hilt”) } } } } Primitive Pluginをまとめていくだけ で、ビルドロジックは含めない
  24. AbemaTV, Inc. All Rights Reserved
 Plugin同士の依存関係のルール buildSrcからinclude buildへ 29 依存していい関係

    • Gradleモジュール -> Convention, Primitive • Gradleモジュール -> Convention, Convention • Gradleモジュール -> Primitive, Primitive • Convention -> Primitive • Convention -> Convention 依存してはいけない関係 • Primitive -> Primitive • Primitive -> Convention Primitive Plugin間で依存関係が必要な場合は、お互いを Pluginのなかで呼び出すのではなく、命名によって依存関 係を解決するようにしました。 com.example.primitive.android com.example.primitive.android.compose com.example.primitive.android.hilt ライブラリの基本設定 Composeやhiltの設定
  25. AbemaTV, Inc. All Rights Reserved
 測定してみる 実際どのくらい早くなった? 31 今日紹介した手法を実際にABEMAに 導入した結果、どのくらいビルド速度が

    改善したのかを計測して比べてみまし た。 右のシナリオで計測してみました。 clean_build { tasks = [“:root:assembleDevelopDebug”] cleanup-tasks = [“clean”] warm-ups = 3 } clean_build_no_cache { tasks = [“:root:assembleDevelopDebug”] gradle-args = [“--no-build-cache”] cleanup-tasks = [“clean”] warm-ups = 3 } build cache有り build cache無し
  26. AbemaTV, Inc. All Rights Reserved
 実際どのくらい早くなった? 32 ◦ build cache有り

    ▪ Before : Min = 52s, Median = 58s, Max = 69s, Mean = 59s ▪ After : Min = 38s, Median = 43s, Max = 56s, Mean = 45s ◦ build cache無し ▪ Before : Min = 508s, Median = 588s, Max = 627s, Mean = 577s ▪ After : Min = 492s, Median = 507s, Max = 609s, Mean = 526s 速度計測は、登壇者のローカル PCで測定しています。 平均値で約25%の改善👏 平均値で約10%の改善👏 結果
  27. AbemaTV, Inc. All Rights Reserved
 まとめ 33 • Android Developersのビルド最適化セクションに載っているTipsを実践していき

    ました。 ◦ Gradle Profilerでビルド速度計測 ◦ Configuration cache有効化 ◦ JVM Parallel GCを使う • buildSrcからinclude buildへビルドロジックを移行。 • Android Developersに載っている方法を実際に導入するのと、nowinandroidで 実践されていたComposite buildを導入してみました。まだ他にもビルド速度を向 上させるための方法はあると思うので、何か他にいい方法等あればフィードバッ クいただけると嬉しいです。