Boot-clj Startup
After having a great conversation with Mike Kaplisky at ClojureWest 2017 about how to optimize a Clojure build chain to be as fast as possible (they use Buck at Ladder), I was inspired to look at Boot-clj, my preferred build tool, with some fresh and curious eyes. I'd like to understand better how Boot works under the hood, so I figure a good way to start is to time some various pieces of it in comparison with lein, clojure, and the JVM.
To start with, let's create a hello world boot-built app:
boot -d boot/new new -t app -n hello
By default, after loading deps with an initial run, it takes about 16 sec to build a jar.
time boot build
Compiling 1/1 hello.core...
Writing pom.xml and pom.properties...
Adding uberjar entries...
Writing hello-0.1.0-SNAPSHOT-standalone.jar...
Writing target dir(s)...
36.62s user 5.61s system 267% cpu 15.780 total
Let's add a super basic boot task to build.boot
that does nothing:
(deftask noop
"the simplest boot task"
[]
identity)
time boot noop
17.88s user 0.83s system 380% cpu 4.920 total
It takes 18 sec cpu time, 5 sec real time, just to do nothing! At least it's using all my 4 cores.
Let's compare this with a hello world java app:
// Hello.java
public class Hello {
public static void main(String[] args){
System.out.println("Hello world");
}
}
javac Hello.java
time java Hello
0.12s user 0.04s system 103% cpu 0.149 total
0.15 secs! That's amazing! Now let's compare that with running our Clojure hello world:
time java -jar target/hello-0.1.0-SNAPSHOT-standalone.jar
2.57s user 0.16s system 196% cpu 1.395 total
1.4 secs ... There's a big time difference there from the java hello world, but it's still much less than running an empty boot task. What causes a bare boot strap to take so long?