Skip to content

Commit ceb80bf

Browse files
committed
Add SBT command to collect profiles
`prof hot ....` is the same as ``` hot ... -prof sbt.extras.JFR ... hot ... -prof sbt.extras.Async ... hot ... -prof perfnorm ... hot ... -prof sbt.extras.JFR ... hot ... -jvmArgs -Xprof -prof hs_comp -prof hs_gc -prof stack -prof hs_rt ``` Output (logs, stack counts, flame graphs) are collected in target/profile-* Assumes that `ASYNC_PROFILER_DIR`, `FLAME_GRAPH_DIR` and `JFR_FLAME_GRAPH_DIR` are configured as env variables.
1 parent aaabc83 commit ceb80bf

File tree

1 file changed

+37
-0
lines changed

1 file changed

+37
-0
lines changed

build.sbt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import sbt.complete.DefaultParsers.OptSpace
2+
import sbt.complete.Parser
3+
14
name := "compiler-benchmark"
25

36
version := "1.0-SNAPSHOT"
@@ -93,6 +96,40 @@ addCommandAlias("hot", "compilation/jmh:run HotScalacBenchmark -foe true")
9396

9497
addCommandAlias("cold", "compilation/jmh:run ColdScalacBenchmark -foe true")
9598

99+
100+
def profParser(s: State): Parser[String] = {
101+
import Parser._
102+
token("prof" ~> OptSpace) flatMap { _ => matched(s.combinedParser)} map (_.trim)
103+
}
104+
105+
commands += Command.custom((s: State) => Command.applyEffect(profParser(s))((line: String) => {
106+
abstract class Profiler(val name: String) {
107+
def command(outDir: File): String
108+
}
109+
110+
object basic extends Profiler("basic") {
111+
def command(outDir: File): String = "-jvmArgs -Xprof -prof hs_comp -prof hs_gc -prof stack -prof hs_rt"
112+
}
113+
object jfr extends Profiler("jfr") {
114+
def command(outDir: File): String = s"-prof jmh.extras.JFR:dir=${outDir.getAbsolutePath};flameGraphOpts=--hash,--minwidth,1;verbose=true'"
115+
}
116+
object async extends Profiler("async") {
117+
def command(outDir: File): String = s"-prof jmh.extras.Async:dir=${outDir.getAbsolutePath};flameGraphOpts=--hash,--minwidth,1;verbose=true;event=cpu"
118+
}
119+
object perfNorm extends Profiler("perfNorm") {
120+
def command(outDir: File): String = "-prof perfnorm"
121+
}
122+
123+
val profs = List(perfNorm, basic, async, jfr)
124+
val commands: List[String] = profs.flatMap { (prof: Profiler) =>
125+
val outDir = file(s"target/profile-${prof.name}")
126+
IO.createDirectory(outDir)
127+
List(line + " " + prof.command(outDir) + s" -o ${(outDir / "jmh.log").getAbsolutePath} -rf json -rff ${(outDir / "result.json").getAbsolutePath}", BasicCommandStrings.FailureWall)
128+
}
129+
s.copy(remainingCommands = BasicCommandStrings.ClearOnFailure :: commands ++ s.remainingCommands)
130+
}))
131+
132+
96133
def addJmh(project: Project): Project = {
97134
// IntelliJ SBT project import doesn't like sbt-jmh's default setup, which results the prod and test
98135
// output paths overlapping. This is because sbt-jmh declares the `jmh` config as extending `test`, but

0 commit comments

Comments
 (0)