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

Triplequote Hydra Compiler: a bigger hammer

Triplequote Hydra Compiler: a bigger hammer

We all love Scala, but the one aspect we have a hard time accepting are long compile times. It’s not uncommon for a project to experience compilation times of a handful of minutes, if not worse. On top of that, compilation times are unpredictable, depending on a combination of language features, external libraries, and type annotations. A single line change may increase compilation times ten fold.

What can we do? It’s paramount we gain greater insight into the tools and libraries we use. There are also established (anti-)patterns that you should know about, if you fancy to keep compilation times to a minimum. And why not utilizing all cores when compiling? The stock Scala compiler can’t do it, but Triplequote Hydra is here to change that. Sit tight and let’s cut down on compilation time!

Triplequote

March 02, 2017
Tweet

More Decks by Triplequote

Other Decks in Technology

Transcript

  1. Who are we? Iulian Dragos • Triplequote co-founder • 12

    years of Scala experience • Scala committer (#5) • Eclipse Scala IDE committer (#1) • SIP committee member • Part of the founding Lightbend/Typesafe team Mirco Dotta • Triplequote co-founder • Have been using Scala since 2005 • Eclipse Scala IDE committer (#3) • Contributed to Scala, Lagom, Play • Author of MiMa
  2. Agenda • State of Scala releases • How to investigate

    long compile times • Parallelize compilation with Triplequote Hydra Compiler
  3. Scala releases & compilation speed • Scala 2.12 released in

    November 2016 • Drastically reduced binary footprint ◦ Runtime benefits! • Seems to have comparable performance wrt Scala 2.11 ◦ Shapeless tests take 20% more time compile (2.11.8 vs 2.12.1) ◦ Scala team noticed moderate speedup on their benchmarks ◦ ⇒ Hard to assess compilation speed of Scala releases • Good news: The Scala team is working on automated benchmarking! ◦ So we are good? Problem solved?
  4. What can we do? Take advantage of the existing tooling!

    … and let’s create new, better, tooling!
  5. Scala compiler flags • The Scala compiler already gives you

    lots of useful flags! • No brainers ◦ -Ywarn-unused & -Ywarn-unused-import & -Ywarn-dead-code • Be ready to explore the rabbit hole ◦ -verbose ◦ -Xprint:<phase> (-Xshow-phases) ◦ -Xlog-implicits ◦ -Ymacro-debug-lite & -Ymacro-debug-verbose ◦ and others… • Get a feeling of how much time each compiler phase consumes ◦ Use -verbose
  6. Compile time breakdown Does the typer phase take 50%+ of

    the whole compile time? • Yes? Investigate!
  7. Investigate long compile times • test:compile takes more than compile?

    Is that expected? • Usual suspects for long compile times ◦ Implicits ◦ Macros ◦ Type Inference • Identify sources that take the most to compile: ◦ Hard without tooling help, but if you have a guess go for it ◦ Compile a single source (add the target folder in the classpath) ◦ If a source takes more time than expected to compile, inspect its AST: -Xprint:typer ▪ Scary amount of macro expansions? ▪ Complex/Long inferred types? ◦ Also use -Xlog-implicits ▪ Are there many implicits that are not applicable?
  8. Implicit Resolution imports package definitions local definitions orElse everything available

    without a prefix Map[String, Employee] class Map[K, V] extends Seq[(K, V)] with Iterable[(K, V])... Implicit Scope of target type T
  9. Implicit Resolution imports package definitions local definitions orElse Implicit Scope

    of target type T Map[String, Employee] class Map[K, V] extends Seq[(K, V)] with Iterable[(K, V])... everything available without a prefix
  10. Implicit resolution - take away • Implicit resolution can be

    costly • Tip: Limit implicits in the scope ◦ Avoid import clauses bringing implicits in the scope ▪ Wildcard imports are bad ◦ Avoid defining implicits in the package object • Where should I place implicits? ◦ In the implicit scope! • Real world experience: ◦ A simple refactoring that consisted in moving implicits defined in a package object into the implicit scope yield a 40% compile time speedup!
  11. Macro bittersweet • Macros can reduce boilerplate • Macros can

    be responsible for 80-90% of typechecking time ⇒ WOOOT! ◦ Macros can trigger expensive typechecking ◦ Watch out for implicit definitions that are implemented with a macro • Are you ok to trade productivity for code elegance? ◦ Be pragmatic: you may be better off maintaining some boilerplate code.
  12. Distribute Scala compiler • Distribute files to workers in the

    cloud (and gather results) ◦ Cost: network ◦ Network costs are small compared to compilation costs • Hard problem: ◦ Inter-file dependencies ◦ It’s a distributed system
  13. Amdahl’s law How much speedup should we expect? p =

    percentage of parallelizable work s = speedup for parallelizable work (~ nr. of cores)
  14. Amdahl’s law Non-parallel covers everything that can’t be perfectly parallelized

    (JVM startup time, JIT compilation, memory bus contention, penalty for dependencies) Non-parallel Max Speedup 30% 3.33 40% 2.50 50% 2.00
  15. Stage 1: parallelize (MVP) • What about the many cores

    we have? • Granularity? ◦ Parallelize at the CompilationUnit level ◦ Parallelize the whole phase pipeline (including typer!) • Hard problems ◦ Inter-file dependencies between workers ◦ Laziness and mutable state • Approach ◦ Share-nothing (use different compiler instances) ◦ ..but add back sharing when it’s safe
  16. How well does it work? Project Speedup specs2-core/test 2.5x specs2-common/main

    2.2x shapeless-core/js 1.58x shapeless-core/jvm 1.62x
  17. Constant factor • Can we get that factor down? •

    Dmitry’s talk about Dotty performance ◦ Know your hardware and great things may happen! ▪ ~30x speedup potential by utilizing the CPU pipeline to the fullest If p goes down, speedup goes up!
  18. Triplequote Hydra Compiler • Based on Scalac ◦ We’re hoping

    this won’t be a fork forever • Drop-in replacement ◦ Not tied to Sbt, command line available • Supporting Scala 2.12.1 ◦ May support older versions based on demand ◦ Other forks™ should work too • Run the community build ◦ Compare binary output ..standing on the shoulders of giants
  19. Insights • Monitor the build ◦ Build times across builds,

    commits or files ◦ Other metrics coming ▪ implicit uses, type inference steps, etc ▪ GC load on workers, time spent blocking, etc.
  20. Hydrate. Build. • Using Hydra equates to adding one line

    to your Sbt build! addSbtPlugin("com.triplequote" % "sbt-hydra" % "1.0") • Run sbt tasks as usual • Hydra takes care of parallel compilation • Sbt support ready • Support for other build tools (e.g., Gradle, Maven) based on demand
  21. Giving back to the community • Push patches upstream to

    Scala and Sbt • Work well with Scala and Typelevel Scala • Triplequote will implement Scala SIP-25 ◦ @static fields and methods in Scala objects ◦ https://github.com/scala/scala-dev/issues/305
  22. Q2 2017 Q3 2017 Q4 2017 Support 2.11 Start Private

    Roll-out General Availability Insights & Metrics Distributed Build Cloud Service
  23. What now? • We are looking for a few reference

    customers who want Hydra asap • We will make using Hydra in your projects our priority • Interested? Grab us after the talk or [email protected] https://twitter.com/etorreborre/status/830105082465103872