scalaのコンパイルを3倍速くした話
Post on 08-Sep-2014
41 Views
Preview:
TRANSCRIPT
TBD
自己紹介
•@todesking • ジャバ(バッチ) → Ruby(ソシャゲサーバサイド) → Scala(広告システムサーバサイド)
近況
•ビルドシステムと戦っている http://twitter.com/todesking/status/488675512424734720!
sbt/ivy使えばパッケージ管理の問題を解決してくれるというのは幻覚だったということがわかった、社会は厳しい
何はともあれ•みんな大好きなあの話をします
Scalaのコンパイルが 3倍
速くなった話
問題
https://twitter.com/todesking/status/449393123894906880!Scala、みんなコンパイルの遅さに困ってるが解決手段が無いためコンパイル中に音楽を流すプラグインを作成して慰みを得ているということがわかった。Ruby使ったほうがいいと思う。!
(́・_・`)
• https://twitter.com/todesking/status/449406714123927553
どれくらい遅いか[Info] Compiling 278 Scala sources and 4
Java sources to target/scala-2.10/classes...
.
.
.
.
.
.
.
.[success] Total time: 425 s
?!
• 他のプロジェクト [info] Compiling 234 Scala sources and 5 Java sources to target/scala-2.10/classes... . . [success] Total time: 64 s !
はやい(相対的に)
さすがに死っぽいので 調査しました
• 特定のプロジェクトだけすごく遅い • プロジェクトの設定? • 使用ライブラリ?
hprof: JVM標準 プロファイラ
• jvmオプションつけてsbt compile • 結果はjava.hprof.txtに出力されます
$ sbt -J-agentlib:hprof=cpu=samples,depth=5 \ clean compile
結果見る
• depth=5で荒い解析 • クラスのロードが大量にされている……?
rank self accum count trace method 1 12.04% 12.04% 2158 300093 java.util.zip.ZipFile.getEntry 2 9.90% 21.95% 1775 300065 java.lang.Throwable.fillInStackTrace 3 7.21% 29.16% 1293 303874 java.lang.Class.forName0 4 5.40% 34.56% 967 300200 java.lang.Throwable.fillInStackTrace 5 2.76% 37.32% 495 300061 java.lang.ClassLoader.defineClass1 6 1.66% 38.98% 298 300616 java.lang.ClassLoader.findLoadedClass0 7 1.32% 40.30% 236 303922 scala.collection.IndexedSeqOptimized$class.foreach 8 1.27% 41.57% 228 303902 scala.collection.IndexedSeqOptimized$class.foreach 9 1.27% 42.84% 228 301496 java.net.SocketInputStream.socketRead0 10 1.15% 43.99% 206 300711 java.lang.ClassLoader.findLoadedClass0 11 1.03% 45.02% 184 304106 java.lang.Class.forName 12 0.95% 45.97% 170 300630 java.lang.ClassLoader.loadClass 13 0.86% 46.83% 155 304054 java.lang.Object.hashCode 14 0.84% 47.68% 151 303870 java.io.UnixFileSystem.getBooleanAttributes0 15 0.84% 48.51% 150 303879 java.lang.ClassLoader.loadClass 16 0.81% 49.33% 146 304060 java.security.AccessController.doPrivileged
スタックトレースの詳細
•処理時間上位の処理を見ていく • この処理がどこから呼ばれてるかを知りたい • スタックトレースの深度を増やして再実行
TRACE 300093: java.util.zip.ZipFile.getEntry(ZipFile.java:Unknown line) java.util.zip.ZipFile.getEntry(ZipFile.java:306) java.util.jar.JarFile.getEntry(JarFile.java:226) java.util.jar.JarFile.getJarEntry(JarFile.java:209) sun.misc.URLClassPath$JarLoader.getResource(URLClassPath.java:840)
結果見る
• depth = 50 • トレース深度を増やしてみる
CPU SAMPLES BEGIN (total = 22833) Tue Jul 15 15:02:57 2014 rank self accum count trace method 1 0.58% 0.58% 132 312316 java.util.zip.ZipFile.getEntry 2 0.56% 1.14% 128 313147 java.util.zip.ZipFile.getEntry 3 0.53% 1.67% 121 313118 java.util.zip.ZipFile.getEntry 4 0.45% 2.12% 103 313343 java.lang.Object.hashCode 5 0.44% 2.56% 100 313093 java.util.zip.ZipFile.getEntry 6 0.42% 2.98% 96 306293 java.net.SocketInputStream.socketRead0 7 0.42% 3.39% 95 312675 java.util.zip.ZipFile.getEntry 8 0.38% 3.78% 87 314506 java.util.zip.ZipFile.getEntry 9 0.36% 4.14% 83 313104 java.lang.Class.forName0 10 0.32% 4.45% 72 306826 java.net.SocketInputStream.socketRead0 11 0.29% 4.74% 66 312099 java.util.zip.ZipFile.getEntry 12 0.28% 5.02% 63 313314 java.lang.Class.forName0 13 0.27% 5.29% 61 313184 java.lang.Class.forName0 14 0.25% 5.54% 57 312970 java.lang.Throwable.fillInStackTrace 15 0.25% 5.79% 57 313083 java.util.zip.ZipFile.getEntry 16 0.24% 6.03% 55 312783 java.lang.Class.forName0
結果見る
•怪しいものが
TRACE 313147: java.util.zip.ZipFile.getEntry(ZipFile.java:Unknown line) java.util.zip.ZipFile.getEntry(ZipFile.java:306) java.util.jar.JarFile.getEntry(JarFile.java:226) java.util.jar.JarFile.getJarEntry(JarFile.java:209) : scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:418) scala.reflect.macros.runtime.Evals$class.eval(Evals.scala:16) scala.reflect.macros.runtime.Context.eval(Context.scala:6) scalikejdbc.SQLInterpolationMacro$.selectDynamic(SQLInterpolationMacro.scala:32) sun.reflect.GeneratedMethodAccessor3.invoke(<Unknown Source>:Unknown line) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke(Method.java:606) scala.tools.nsc.typechecker.Macros$$anonfun$scala$tools$nsc$typechecker$Macros$$macroRuntime$2$$anonfun$apply$5.apply(Macros.scala:542)
原因特定
• scalikejdbcのマクロが原因 • context.eval()が遅い
26 object SQLInterpolationMacro {!27 !28 def selectDynamic[E: c.WeakTypeTag](c: Context)(name: c.Expr[String]): c.Expr[SQLSyntax] = {!29 import c.universe._!30 !31 val nameOpt: Option[String] = try {!32 Some(c.eval(c.Expr[String](c.resetAllAttrs(name.tree.duplicate))))!33 } catch {!34 case t: Throwable => None!35 }!36
ツイッター便利
https://twitter.com/todesking/status/461816289086820352
修正しました
• [success] Total time: 122 s • scalikejdbc 1.7.7からは速いよ https://github.com/scalikejdbc/scalikejdbc/pull/241
学び•基本的にコンパイルは遅い(社会は厳しい) • でもユースケースによっては高速化の余地が! • コンパイラがJVM上で動くので既存のプロファイリングノウハウが使えて便利
• Scalaエコシステムはフロンティア • 目が届いてないとこが残ってるのでコントリビュートチャンスだ
• ツイッター便利
top related