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

Optimising Scala 3 Build Times - Scala Matsuri

Optimising Scala 3 Build Times - Scala Matsuri

Build tools for Scala help you to compile projects as fast as possible. Let's understand the architecture underlying Scala builds, take an in-depth look at new improvements in 2023/2024 to improve build times, from pipelined compilation, progress tracking, more efficient scheduling, to even fine-grained parallel compilation.

Jamie Thompson

June 10, 2024
Tweet

More Decks by Jamie Thompson

Other Decks in Technology

Transcript

  1. Optimising Scala 3 Build times 2024 edition • Twitter: @bishabosha

    • Email: [email protected] Jamie Thompson Scala 3 ビルド時間を最適化 1
  2. Agenda Scala はどのようにコードをビルドするか、去年から 何が変わったか、また今後の展望について 2 Scala build 101 Changes 2023-2024

    Future Speculation What happens when you build code? Concrete steps we made to improve performance What can we do next?
  3. Research Open Source 8000+ Github repos 1,200,000+ artifacts Industry 非営利団体として、OSSコミュニティと業界と

    学会の橋渡しをしています 3 Scala Native Scala.js Dotty (Scala 3) Caprese (new effect system)
  4. たくさんのプロジェクトに関わりましたが、私たちの焦点は開発 者の作業をより楽にする開発ツールにあります 4 2 Debug Adapter LSP server for Scala

    Compile Scala to JS Index of Scala libraries Online playground for Scala Porting to Scala 3 expression evaluator, smart stack trace, hot code swapping Scala.js
  5. Explaining the Scala Build “Premature optimisation is the root of

    all evil” - Donald Knuth Scalaビルドについて話しましょう。ツールの相互作用と性能最 適化のボトルネックについて話します 6
  6. ビルドツールはプロジェクトの基本情報と Mavenアーティファクトの管理 13 Layer 1 common server client name =

    “common” libs = [“com.lihaoyi::os-lib:0.1.0”] srcs = “common/**/*.scala” gens = “gen-protobuf” name = “server” deps = [“common”] srcs = “server/**/*.scala” name = “client” deps = [“common”] srcs = “client/**/*.scala” Build Tools - Layer 1
  7. 実際のファイルを用意して(ダウンロードか生成)、 次の層に渡します 14 C.scala E.scala F.scala A.scala B.scala os-lib.jar fetch

    “com.lihaoyi::os-lib:0.1.0” require “common” to build first require “common” to build first Layer 1 generate sources from protobuf schema Build Tools - Layer 1
  8. Layer 1 API common APIはcommonが生成する JAR が必要で、clientはcommon とAPIが生成する JAR が必要だからです。

    18 client Inputs: [“common/**/*.scala”] Outputs: [common.jar] Inputs: [“api/**/*.scala”,common.jar] Outputs: [api.jar] Inputs: [“client/**/*.scala”,common.jar,api.jar] Outputs: [client.jar] Build Tools - Layer 1
  9. コンパイラを抽象化して、仮想ファイルに対する 差分コンパイル・サービスを提供します 21 Layer 2 Zinc • Virtual file system

    • Tracks changes in sources • Compiles only necessary files A.scala B.scala machine-independent paths Build Tools - Layer 2 • Cached compiler • Cancellation
  10. 前のコンパイルと比べて、 変更があったソースを無効化します 22 Layer 2 Zinc Build Tools - Layer

    2 A.scala B.scala C.scala D.scala E.scala F.scala G.scala H.scala New compilation request, invalidate sources.
  11. A.scala に変更があったことを検知したとします 23 Layer 2 Zinc Build Tools - Layer

    2 A.scala B.scala C.scala D.scala E.scala F.scala G.scala H.scala Detect A.scala has changed, compile it.
  12. A.scalaと依存関係あるファイルもチェック 24 Layer 2 Zinc Build Tools - Layer 2

    A.scala B.scala C.scala E.scala G.scala H.scala D.scala F.scala invalidate any dependencies affected by changes, e.g. F.scala and D.scala.
  13. 必要なファイルだけコンパイルして、時間を節約します 25 Layer 2 Zinc Build Tools - Layer 2

    A.scala B.scala C.scala E.scala G.scala H.scala D.scala F.scala No more changes. We are done!
  14. 詳しい説明はScala Days Seattle 2023の トークをご覧ください。 26 Layer 2 Zinc Build

    Tools - Layer 2 A.scala B.scala C.scala E.scala G.scala H.scala D.scala F.scala watch my previous talk for more info! Scala Days Seattle 2023: How Does Incremental compilation work with Scala 3? (YouTube)
  15. Build Tools - Layer 3 ソースファイルを読み込んで、クラス、tasty、 およびjarファイルなどを生成します。 28 Layer 3

    Zinc scalac api.jar A.class B.class C.tasty A.scala B.scala C.scala common.jar -classpath \ scala3-library_3.jar API
  16. Build Tools - Advice Tip No. 1 Use small files!

    A more granular dependency graph avoids unnecessary recompilation 小さいファイルを使えば、 コンパイルのスピードが速くなります 36
  17. Tip No. 2 With a more granular project graph, you

    can introduce parallelism. Split apps into smaller projects! 複数のサブプロジェクトに分割すると、 並行コンパイルの可能性が増えます 37 Build Tools - Advice
  18. Tip No. 3 Thread starvation, duplicate work Don’t make projects

    too small! 非常に小さなモジュールは競合の増加や作業の重複などに よってパフォーマンスを低下させる可能性があります。 38 Build Tools - Advice
  19. Performance updates 2023 - 2024 the road to pipelined builds

    and beyond. 過去1年間のコンパイラの変更点で パフォーマンス関連のものを総括しましょう 39
  20. Progress Tracking and Cancel ソースファイルの数とフェーズの積で総進捗を計算します 44 total = |files| ×

    |phases| current = |files| × |seen_phases| + |seen_in_phase| progress = current / total refreshed after every compilation unit and phase genBCode pickler parser deps api typer
  21. Project B Project A Project D off pipelining Pipelined Builds

    パイプライニングを導入してない場合、依存関係あるプロジェク トは前のプロジェクトを待たないといけません 48
  22. Project B Project D saved time! on pipelining Project A

    Pipelined Builds パイプライニングを導入した場合、依存関係があっても 次のプロジェクトを早く開始することが可能です 49 *projects and dependencies should not define macros ThisBuild / usePipelining := true
  23. data server infra template webclient coreJS coreJVM Scaladex project layout

    Pipelined Builds - example プロジェクトのレイアウトは、パイプライン化の程度に 影響します。Scaladexはいいレイアウトの手本です。 52
  24. -- Error: /example/src/main/scala/example.scala:15:52 15 | val span: Binding.Stable[HTMLSpanElement] = 16

    | html"<span>foo</span>" | ^^^^^^^^^^^^^^^^^^^^^^ |Macro code depends on missing object Definitions found on the classpath, but could not be | loaded while evaluating the macro. This is likely because class files could not be | found in the classpath entry for the symbol. | | A possible cause is if the origin of this symbol was built with pipelined compilation; | in which case, this problem may go away by disabling pipelining for that origin. | |object Definitions is defined in file | /definitions/target/early/definitions-early.jar(Definitions.tasty) |--------------------------------------------------------------------------- |Inline stack trace |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |This location contains code that was inlined from package.scala:712 712| ${ Macros.html('stringContext, 'args) } --------------------------------------------------------------------------- Pipelined Builds macrosとパイプライニングが衝突する場合、 エラーメッセージでヒントを与えます 55
  25. TASTyファイルのみのクラスパスがサポートできました 57 timeline 2023 - 2024 Jun 06 2023 Jul

    03 2023 Demo pipeline and outline builds at Scala Days (???) Support TASTy only classpaths (Scala 3.4.0)
  26. ビルドキャッシュがサポートできました 58 timeline 2023 - 2024 Jun 06 2023 Jul

    03 2023 Jul 23 2023 Demo pipeline and outline builds at Scala Days (???) Support TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3)
  27. 進捗状況の追跡がサポートできました 59 timeline 2023 - 2024 Jun 06 2023 Jul

    03 2023 Jul 23 2023 Oct 31 2023 Demo pipeline and outline builds at Scala Days (???) Support TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3) Compile progress tracking (Scala 3.4.0)
  28. JavaファイルのTASTyファイルもサポートできました。 これは一番時間をかけたマイルストーンです。 60 timeline 2023 - 2024 Jun 06 2023

    Jul 03 2023 Jul 23 2023 Oct 31 2023 Nov 28 2023 Demo pipeline and outline builds at Scala Days (???) Support TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3) Compile progress tracking (Scala 3.4.0) Write Java Definitions to TASTy (Scala 3.4.0)
  29. Jun 06 2023 Jul 03 2023 Jul 23 2023 Oct

    31 2023 Nov 28 2023 Demo pipeline and outline builds at Scala Days (???) Support TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3) Compile progress tracking (Scala 3.4.0) Write Java Definitions to TASTy (Scala 3.4.0) timeline 2023 - 2024 // A.tasty Trees (70 bytes, starting from 153): 44: TYPEDEF(24) 2 [A] 47: TEMPLATE(21) 49: SHAREDtype 23 51: SPLITCLAUSE 52: ... 61: DEFDEF(7) 12 [foo] 64: EMPTYCLAUSE 65: SHAREDtype 38 67: ELIDED 68: SHAREDtype 38 Attributes (4 bytes, starting from 287): JAVAattr OUTLINEattr SOURCEFILEattr 14 [A.java] JavaファイルのTASTyファイルもサポートできました。 これは一番時間をかけたマイルストーンです。 61 // A.java public class A { public void foo() { System.out.println("Hello"); } }
  30. Scala 2の「-Ytasty-reader」がサポートできました 62 timeline 2023 - 2024 Jun 06 2023

    Jul 03 2023 Jul 23 2023 Oct 31 2023 Nov 28 2023 Feb 20 2024 Demo pipeline and outline builds at Scala Days (???) Support TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3) Compile progress tracking (Scala 3.4.0) Write Java Definitions to TASTy (Scala 3.4.0) support pipeline TASTy with -Ytasty-reader (Scala 2.13.13)
  31. Demo pipeline and outline builds at Scala Days (???) Support

    TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3) Compile progress tracking (Scala 3.4.0) Write Java Definitions to TASTy (Scala 3.4.0) support pipeline TASTy with -Ytasty-reader (Scala 2.13.13) Java TASTy feature complete (Scala 3.4.0) Scala 3.4でJavaのTASTyモードを一緒に リリースしました 63 timeline 2023 - 2024 Jun 06 2023 Jul 03 2023 Jul 23 2023 Oct 31 2023 Nov 28 2023 Feb 20 2024 Feb 22 2024
  32. Demo pipeline and outline builds at Scala Days (???) Support

    TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3) Compile progress tracking (Scala 3.4.0) Write Java Definitions to TASTy (Scala 3.4.0) support pipeline TASTy with -Ytasty-reader (Scala 2.13.13) Java TASTy feature complete (Scala 3.4.0) Pipelining complete (Scala 3.5.0) Scala 3.5でパイプライニング機能が完成しました 64 timeline 2023 - 2024 Jun 06 2023 Jul 03 2023 Jul 23 2023 Oct 31 2023 Nov 28 2023 Feb 20 2024 Feb 22 2024 Apr 04 2024
  33. Demo pipeline and outline builds at Scala Days (???) Support

    TASTy only classpaths (Scala 3.4.0) Support Zinc 1.4+ (sbt Remote Build Cache) (Scala 3.3.3) Compile progress tracking (Scala 3.4.0) Write Java Definitions to TASTy (Scala 3.4.0) support pipeline TASTy with -Ytasty-reader (Scala 2.13.13) Java TASTy feature complete (Scala 3.4.0) Pipelining complete (Scala 3.5.0) Write TASTy in parallel (Scala 3.5.0) 追加機能として、TASTyを書き込んでる時、 メインスレッドをブロックしないようになりました 65 timeline 2023 - 2024 Jun 06 2023 Jul 03 2023 Jul 23 2023 Oct 31 2023 Nov 28 2023 Feb 20 2024 Feb 22 2024 Apr 04 2024 Apr 16 2024
  34. ファイルをバッチに分割し、複数のスレッドで コンパイル時間を短くすることもできます 70 pass 2 pass 1 lowering, erasure backend

    on Multi-pass compilation outline type checking api, pickler outline typer pipelining start (full compile) saved time!
  35. Batch Compilation 単一のパスの場合、他のファイルのアウトラインタイプを利用 し、加速することもできます 71 outline typer D.scala B.scala E.scala

    B.scala A.scala D.scala E.scala batch A. batch B. on off outline typer pass full batch A. pass full batch B. saved time maybe? A.scala
  36. Testing on MacBook Pro 14” 2021 (M1 Pro, 32GB RAM)

    From cold sbt start: - clean; compile 2x to warm up - then take mean time of next 7 cycles. Benchmarks - pipelining M1 Pro CPU、32ギガバイトのRAMを搭載した MacBook Pro 14インチで記録されました 73
  37. “clean compile” time & memory 308,829 LOC lichess-org/lila The key

    takeaway seems to be that you trade time overall for peak memory. 72s 6GB 55s 8.3GB 3.3.0 (standard) 3.3.2-SNAPSHOT (pipelined) 5600 lines/s Benchmarks - pipelining パイプライニングのベンチマーク 74
  38. Benchmarks - pipelining Scaladex 31% improved 3.3.2-SNAPSHOT (pipelined) Time to

    finish “clean compile” time Your mileage may vary Other projects パイプライニングのベンチマーク 75
  39. Benchmarks - outlining 158,000 LOC 30s 1.54x faster! we could

    still do better… 19.5s 3.3.2-SNAPSHOT (2-pass, 3 workers) 3.3.1 (single pass) 8119 lines/s 5277 lines/s lampepfl/dotty アウトラインコンパイルのベンチマーク 76