140文字 ✕ 2で表すとこんな感じ
sbt 0.13.1[info] Compiling 1 Scala source[info] Compiling 7[info] Compiling 84[info] Compiling 240[success] Total time: 259 s
2014-01-10 12:56:08 via web
sbt 0.13.2-M1[info] Compiling 1 Scala source[success] Total time: 15 sURL URLAwesome!!!
2014-01-10 12:56:52 via web to @xuwei_k
測定方法は
- Scalazの、現状の最新のcoreモジュールを使って実験
- EphemeralStreamにheadOptionとtailOptionという2つのメソッドを追加するコミットを使用 https://github.com/scalaz/scalaz/commit/39e0bf853a8f38
- メソッド追加する前にコンパイル => キャッシュをクリアせずに、メソッド追加して再びコンパイル
- 同じ条件でsbt0.13.1と、sbt0.13.2-M1で比較
- sbt0.13.2-M1のほうは、MLに書いてあったように「
withNameHashing(true)
」というオプションをONにしてコンパイル https://groups.google.com/d/topic/sbt-dev/KmGEhFTMve0/discussion
その結果が最初に貼り付けたtweet。
つまり、sbt 0.13.1では、結局全部のファイルをコンパイルし直していたが、sbt0.13.2-M1では、変更があった1ファイルのみをコンパイルして終了した。(依存関係解析が賢くなって、この場合のメソッド追加は、他のファイルに影響を与えないという判断をsbt0.13.2-M1がしたということ)
単純にこの場合だけでコンパイル時間を比較すれば「1ファイルのコンパイル vs 240ファイル全部コンパイル」の対決になっているので、10倍以上速い。
インクリメンタルコンパイルの新しいアルゴリズムの仕組みは、このあたり
https://github.com/gkossakowski/sbt/wiki/Incremental-compiler-notes
などに書いてあります。*1
アルゴリズム知るのは面白そうだけど、理解できてない、というより難しそうだし長くてそもそもちゃんと読めてない・・・。
1パターン試しただけなので、このようにうまくいくパターンがどのくらいあるのかわかりませんが、とにかく素晴らしいです。あとは、かなり大胆な変更してるので、バグがないか心配ですが。(sbtがバグって変なキャッシュが使われるというミスは、かなりわかりずらいやっかいなバグになりそうなので怖い。だから、現状では明示的にオプションでONにしないと、新しいアルゴリズムは使われない仕組みになっているのだと思う。)
はやくsbt0.13.2 finalがでて実用されるようになるといいですね。*2
*1:関連するコードの変更は、このpull req https://github.com/sbt/sbt/pull/1042 など
*2:べつに、今sbt0.13系を使っている人は、build.propertiesに0.13.2-M1を書いてincOptionの設定加えるだけですぐ使えるので、使いたい人は試してみましょう