@borkdude, just curious, did you benchmark the difference between building a classpath with & without JVM. As you well know, SCI is best for quick tasks. Seems there might be crossover point depending on whether it's a simple, one-jar dependency or a complex classpath with multiple (maybe some recursive) dependencies. Nice for some use cases to not need JVM at all, but it would seem most babashka users would also have JVM Clojure handy.
I did do benchmarks and didn't find a point where the invocation of the JVM was worth it. Have you?
SCI has gotten pretty fast over the years and most of the performance stuff is probably XML parsing (native) and I/O-bound (not interpreter-speed bound)
you can easily measure the difference with time bb clojure -Sforce -Spath with or without BABASHKA_DEPS_RESOLVER=jvm in several projects.
For a pretty big closed-source project, I'm getting 500ms on bb and 700ms on clojure
on metabase I'm getting 1.2s on both. metabase is a big project
I'm sure the JVM might be more optimal at some point, but you'd have to have projects bigger than metabase and after the deps are there + classpath caching, there's no difference whatsoever
Cool news! I hadn't run into a countercase, just seemed a logical possibility. Do you ever forsee ditching traditional JVM completely? ๐
depends on your use case? the main JVM use case: long running server processes, is there it still excels?
For one of my closed source projects I get 600ms vs 6000ms on clojure ๐ . It is also big
I find it mildly amusing that one of the selling points for Clojure & some CLs, such as SBCL, was that they always compiled, even in the REPL. And then you have found that there's still a place for an interpreter in a Lispy ecosystem
Ignorance is bliss
FYI if you want a specific test case where bb excels vs Clojure it is with Polylith projects. A lot :local/root of deps I think. I just did a test with Polylith itself:
git clone
cd projects/poly
poly git:(master) โ time bb clojure -Sforce -Spath | wc -m
13197
bb clojure -Sforce -Spath 0,53s user 0,08s system 199% cpu 0,307 total
wc -m 0,00s user 0,00s system 1% cpu 0,304 total
poly git:(master) โ time BABASHKA_DEPS_RESOLVER=jvm bb clojure -Sforce -Spath | wc -m
13197
BABASHKA_DEPS_RESOLVER=jvm bb clojure -Sforce -Spath 2,45s user 0,19s system 45% cpu 5,830 total
wc -m 0,00s user 0,00s system 0% cpu 5,825 total
poly git:(master) โ time clojure -Sforce -Spath | wc -m
13197
clojure -Sforce -Spath 2,60s user 0,18s system 47% cpu 5,804 total
wc -m 0,00s user 0,00s system 0% cpu 5,802 total Metabase takes a lot longer on bb and not factor 10 difference "only" factor 2
git clone
time bb clojure -Sforce -Spath | wc -m
38601
bb clojure -Sforce -Spath 1,83s user 0,18s system 62% cpu 3,198 total
wc -m 0,00s user 0,00s system 0% cpu 3,196 total
time BABASHKA_DEPS_RESOLVER=jvm bb clojure -Sforce -Spath | wc -m
38601
BABASHKA_DEPS_RESOLVER=jvm bb clojure -Sforce -Spath 4,77s user 0,39s system 70% cpu 7,345 total
wc -m 0,00s user 0,00s system 0% cpu 7,343 total
This is on an M2 mac. I guess that matters too
what I'm seeing from your post is that it's faster on bb, not longer?
Yeah I meant a lot longer vs the Polylith projects sorry. BB is much faster in both cases, just smaller difference in Metabase
> BB is much faster in both cases thanks for the confirmation ;)
I'm confused. I thought bb clojure explicitly invoked JVM Clojure. BABASHKA_DEPS_RESOLVER=jvm obviously uses the JVM. Where's the non-JVM. Sorry for what's probably a silly question.
bb clojure runs clojure on bb's deps resolver via deps.clj (built-in)
so dependency fetching/caching goes via bb, and then clojure is invoked with those deps
of course clojure itself does need a JVM
unless you run https://github.com/borkdude/cream but that's another tangent ;)
another way to invoke clojure via bb is babshka.deps/clojure or in tasks (`bb.edn`): (clojure ...)
these all go through https://github.com/borkdude/deps.clj
and deps.clj now has a hook called make-classpath which is overridden in bb to go through its own copy of http://tools.de/maven
Let's see, these examples needed full clojure, the question was simply how the classpath was built?
yes, that's why we used -Spath which just prints the classpath and does not invoke a JVM. we used -Sforce to force classpath calculation
and we used bb clojure since it uses deps.edn which usually has more deps than typical bb.edn projects, so the results would be more interesting
Pretty sure I see now. Thanks! Probably not useful to add -Spath to bb . Not usually enough deps added for a bb run for -Spath to be useful
yeah we could add -Spath to bb but there's already a programmatic way to do it:
(babashka.classpath/get-classpath)Re: Polylith -- I haven't tried but I wouldn't expect the poly tool itself to run on bb and we have build.clj and Polylith intermingled at work, since we normally start a REPL with both on the classpath and invoke various build-related tasks from that REPL (avoiding startup costs). But I'm slowly pulling our build.clj apart and creating a bb-compatible subset for things I can then run as bb tasks directly from the command-line, such as running Splint or antq, where it's faster to do that than run the same task via clojure from within the (Clojure JVM) build.clj part of our world.
@seancorfield It doesn't yet. I've tried a few times and I a made an experimental patch a while ago. But would work only for a subset of tasks. This bb feature does show potential though
When running antq on bb (via your unofficial fork), I occasionally get a concurrent.ExecutionException. Deets in ๐งต
> bb ancient
----- Error --------------------------------------------------------------------
Type: java.util.concurrent.ExecutionException
Message: java.lang.IllegalStateException: Recursive update
Location: /home/sean/.gitlibs/libs/io.github.borkdude/antq/a58106230492cfd970e92e9969ef975283ec58c5/src/antq/core.clj:229:29
----- Context ------------------------------------------------------------------
225: (seq forced-artifacts)
226: (mapv #(mark-forced-version % forced-artifacts)))
227: uniq-deps (distinct-deps org-deps)
228: _ (report/init-progress uniq-deps options)
229: uniq-deps-with-vers (doall (pmap #(assoc-versions % options) uniq-deps))
^--- java.lang.IllegalStateException: Recursive update
230: _ (report/deinit-progress uniq-deps options)
231: assoc-latest-version* #(assoc-latest-version % options)
232: version-checked-deps (->> org-deps
233: (pmap #(complete-versions-by % uniq-deps-with-vers))
234: (map (comp dissoc-no-longer-used-keys
----- Stack trace --------------------------------------------------------------
clojure.core/deref-future - <built-in>
clojure.core/future-call/reify--8574 - <built-in>
clojure.core/deref - <built-in>
sci.addons.future/pmap/step--31882/fn--31886 - <built-in>
clojure.core/next--5470 - <built-in>
... (run with --debug to see elided elements)
antq.core - /home/sean/.gitlibs/libs/io.github.borkdude/antq/a58106230492cfd970e92e9969ef975283ec58c5/src/antq/core.clj:375:7
clojure.core/apply - clojure/core.clj:662:1
ws.scripts.build - /home/sean/workspace/wsmain/scripts/ws/scripts/build.clj:30:11
babashka.tasks/-cli-dispatch - babashka/impl/tasks.clj:384:1
user-5507a596-7de8-4e55-9592-c629d4fbc76d - NO_SOURCE_PATH:37:3(re-running it pretty much always works, so I assume it's some weird edge case race condition)
Using bb 223?
I'll take a look later thanks
I have a fix for this coming (was already in a branch for a few days)
Cool, thanks! Wasn't even sure if it could be repro'd! That was 1.13.222 (sorry, should have added that). I just updated to 223 now.