Hello wonderful people! Can anyone share some pointers on how to properly profile and debug bb scripts? I am talking here more babashka specific approaches or pointers. I can run basic profiling on OS side, but interested if maybe people already spent some time and have something to share. For context, I am doing some yak-shaving and migrating some personal tooling scripts from the java -> clojure -> babashka. There is some expected marginal increase in execution time, but also some quite unexpected (and not so marginal) increases. My current "rule of assesment" is that I expect bb to be slower for big data wrangling tasks. So for example: I have a "sameish" script run across 3 "envs" java is ~100ms, clojure is 1 second, and babashka is 1.5 second. This is working timings for me no complaints so far ๐. Script itself is quite simple read file from disk compute sha256 digest and output it back. But for the same script when I increase the input size of file from 2MB to 200MB babashka script runtime is in multiple of minutes. And I see two possible solutions here I need to update my "rule" or I need to profile the babashka script executions or something else is happening that I missing. So will be happy for any feedback here. bb script in question is this:
(ns scripts
(:require [ :as io]))
(defn file-to-a-digest
[file]
(let [md (java.security.MessageDigest/getInstance "SHA-256")
digest-arr (with-open [s (io/input-stream file :buffer-size 8192)
dis (new java.security.DigestInputStream s md)]
(while (not= (.read dis) -1))
(.digest (.getMessageDigest dis)))]
digest-arr))
(.read ...) on every character is very expensive in babashka since it's java interop. if you could come up with a clojure stdlib function that did the same, then it would be in the same ballpark
I can probably optimize .read though
Try this instead:
(ns scripts
(:require [ :as io]))
(defn file-to-a-digest
[file]
(let [md (java.security.MessageDigest/getInstance "SHA-256")]
(with-open [s (io/input-stream file :buffer-size 8192)
dis (java.security.DigestInputStream. s md)
out (java.io.OutputStream/nullOutputStream)]
(io/copy dis out :buffer-size 8192)
(.digest md)))) Yep. The copy buffer approach is significantly faster in bb. Thank you. Will add it to the heap of stuff to be aware for the bb interop scripts.
interop in a hot loop is just much slower than in a JVM, that's the rule of thumb
And just like that you singlehandedly reduced my yak-shaving time ๐ . Thank you.
https://gist.github.com/borkdude/a19d6f12a0292deaf489d1eeb6374597 https://gist.github.com/borkdude/a19d6f12a0292deaf489d1eeb6374597 Feedback welcome. Text isn't intended for publication, so it's not about that, just the technical side of it.
I often use bb just as a launcher for (clojure -X:build ...) I wonder if a cool feature of bb tasks would be you can tell it to auto-map all build.clj public functions to a build task of the same name. For example I have:
{:tasks
{test (clojure "-X:build test")
test-vars {:doc "Run specific tests by passing their fully qualified names"
:task (do (println "Testing with core.async 1.8+")
(apply clojure "-M:test" "-v" *command-line-args*)
(println "Now testing with core.async 1.7")
(apply clojure "-M:test:test-1.7" "-v"
*command-line-args*))}
gen (clojure "-X:build gen")
lint (clojure "-X:build lint")
deploy (clojure "-X:build deploy")
install (clojure "-X:build install")
update-documents (clojure "-X:build update-documents")
bump-major-version (clojure "-X:build bump-major-version")
bump-minor-version (clojure "-X:build bump-minor-version")
bump-patch-version (clojure "-X:build bump-patch-version")
release (clojure "-X:build release")
publish (clojure "-X:build publish")
publish-patch (clojure "-X:build publish-patch")
publish-minor (clojure "-X:build publish-minor")
publish-major (clojure "-X:build publish-major")}}
Maybe if I could do:
{:tasks
:all-from-build-clj true
{test-vars {:doc "Run specific tests by passing their fully qualified names"
:task (do (println "Testing with core.async 1.8+")
(apply clojure "-M:test" "-v" *command-line-args*)
(println "Now testing with core.async 1.7")
(apply clojure "-M:test:test-1.7" "-v"
*command-line-args*))}}}Though it might break shell completion, and I wouldn't want to lose that
You may be able to write a rewrite clj script that adds them or using rewrite-edn
Perhaps in combination with clj kondo analysis
โ ๏ธ ๐ Testers wanted for a feature that will hopefully soon land in bb. It's auto-completions for bb tasks powered by #C03KJHCNZ99
It auto-completes options / arguments and offers automatic --help.
Reactions in ๐งต
This now landed. When you use this, you'll get auto-completions for exec-fns and subcommands. You can try this with the dev build:
bash <(curl ) --dev-build --dir /tmp
;; bb.edn
{:tasks
{:cli script.cli/defaults ; parser options for every CLI task
build {:doc "Build it" ; a plain task: untouched by any of this
:task (println "building")}
dev {:exec-fn dev/run} ; a handler: options and help come from its metadata
deploy {:doc "Manage deployments"
:cli {:epilog "See "} ; parser options for this task
:cmd {"lock" {:exec-fn deploy/lock} ; a command tree
"unlock" {:exec-fn deploy/unlock
:spec {:force {:coerce :boolean}} ; leaves are plain
:epilog "Releases the lock."}}}}} ; babashka.cli nodes For folks on Windows, the bash script to get the dev build also works in git bash
Gonna try it now btw, not sure if this is a good idea and if it works in all settings, but it seems like a handy trick to try out existing bb wrapper scripts with the tmp version:
PATH=/tmp/bb-snapshot-dir:$PATH bb -version
babashka v1.12.219-SNAPSHOTyeah sure
I can easily verify this way the :repl option works again before and after
(otherwise I have to reinstall the wrapper script with bbin)
wrapper script?
yeah so the script that is using the repl is a babashka script installed with bbin. So it uses the bb binary on the path. Changing the PATH env allows me to test this script with the new bb binary without touching the script itself. I dont know maybe it is obvious but i didn't think of this before
right
fyi I can't find the test text anymore from https://github.com/babashka/babashka/tree/cli-tree-tasks/test-cli Do you still want feedback on that?
I removed that prose since that was just a working document. What counts is the implementation. When I'll release I'll write a blog post. But some testing would be nice
Maybe my bad, but I remember the working document had some instructions on how to setup the completions. I have trouble finding these instructions (or similar) now
ah sorry: source <(bb org.babashka.cli/completions snippet --shell zsh)
deploy + space + TAB should complete, if not, it's a bug
Yeah that does not seem to complete
borkdude@MBP25-3 /tmp/bb-cli-test $ source <(bb org.babashka.cli/completions snippet --shell zsh)
borkdude@MBP25-3 /tmp/bb-cli-test $ bb deploy
lock -- Take the deploy lock
unlock -- Release the deploy lock which bb
/Users/borkdude/dev/babashka/bbSeems to work fine here
which shell are you using? zsh?
The deploy<TAB> just adds a space (so no completion)
โ babashka-test which bb
/tmp/bb-snapshot-dir/bb
โ babashka-test bb -version
babashka v1.12.219-SNAPSHOT
Yeah zsh
what does your bb.edn look like exactly?
{:tasks
{:cli script.cli/defaults ; parser options for every CLI task
build {:doc "Build it" ; a plain task: untouched by any of this
:task (println "building")}
; dev {:exec-fn dev/run} ; a handler: options and help come from its metadata
deploy {:doc "Manage deployments"
:cli {:epilog "See "} ; parser options for this task
:cmd {"lock" {:exec-fn deploy/lock} ; a command tree
"unlock" {:exec-fn deploy/unlock
:spec {:force {:coerce :boolean}} ; leaves are plain
:epilog "Releases the lock."}}}}} is it possible to put your project in a github repo so I can test locally?
I disabled dev because I don't have the ns configured
maybe something else in my zsh is breaking things. Should i have a specific version?
borkdude@MBP25-3 /tmp $ git clone
Cloning into 'bb-cli-test-case'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (3/3), done.
borkdude@MBP25-3 /tmp $ cd bb-cli-test
borkdude@MBP25-3 /tmp/bb-cli-test $ bb deploy
lock -- Take the deploy lock
unlock -- Release the deploy lock do you get autocompletions for a normal exec-fn with bb.cli specs?
if not, then maybe your old bb tasks completions are still active
?
i didn't clean up anything. Let me check if have something old lingering around
> do you get autocompletions for a normal exec-fn with bb.cli specs? Not sure. Do you have an example i can test?
just :tasks {lock {:exec-fn deploy/lock}}
it should list the --env option when doing bb lock<TAB>
No, that doesn't work either
what actually does work?
the completion of the task and the display of tasks (the menu)
that is new, right?
the completion of the tasks already existed if you had the snippet from the book installed
Ok i didn't have installed
what version of zsh do you have? I'm not sure why everything this new feature is about doesn't work :)
zsh --version
zsh 5.9 (arm64-apple-darwin25.0)same here but on darwin 24
what terminal are you using
same
can we try once more? open a fresh iterm2. then
add your tmp bb to the PATH.
then which bb
then eval "$(bb org.babashka.cli/completions snippet --shell zsh)"
and then bb <TAB>
and then bb lock <TAB>
@lee also tested zsh on linux, it all worked for him
also make sure you are using the latest dev build
and check the SHA in bb describe
ok
that looks good
bb describe
{:babashka/version "1.12.219-SNAPSHOT"
:git/sha "42d4fd0f151ec2c0a78bc60fcd6d04312578e6e4"
:feature/csv true
:feature/java-nio true
:feature/java-time true
:feature/xml true
:feature/yaml true
:feature/jdbc false
:feature/postgresql false
:feature/sqlite false
:feature/hsqldb false
:feature/oracledb false
:feature/httpkit-client true
:feature/lanterna false
:feature/core-match true
:feature/hiccup true
:feature/test-check true
:feature/spec-alpha false
:feature/selmer true
:feature/logging true
:feature/priority-map true}Is there a way to find other potential interference of completions? I've checked the zshrc files and I don't see something suspicious, but I did mess with these things in the past. So maybe i'm missing some directory
hmm I don't get option auto-completes anymore for bb dev.. darnit. I'll debug
this still works though:
$ bb deploy
lock -- Take the deploy lock
unlock -- Release the deploy lockdoes this work?
$ bb dev --help
Usage: bb dev [options]
Run the dev system
Options:
--port HTTP port (default: 8080)
-h, --help Show this help
Reads config from dev.edn.bb dev --help
----- Error --------------------------------------------------------------------
Type: java.lang.Exception
Message: File does not exist: devwait i disabled that task
bb dev --help
Task dev: cannot resolve :exec-fn dev/run: Could not locate , dev.clj or dev.cljc on classpath.
dude, this is the git repo I just cloned right?
unchanged?
haha well, i changed the dev now, but it was disabled: https://github.com/jeroenvandijk/bb-cli-test-case/blob/main/bb.edn#L7
oooh I was in /tmp/bb-test-cli instead of /tmp/bb-cli-test-case facepalm
dude ๐
:)
and no completions for bb deploy TAB
but of course that is because there is no deploy.clj file
just chiming in from a Linux 7.1.4 fedora machine, all seems to work. at least the subcommands. yet to test out the spec
> but of course that is because there is no deploy.clj file
Should it give an error on completion when there is an unexisting reference (like deploy) in bb.edn ?
@jeroenvandijk add this to your bb.edn:
:paths ["bb"]
and this file to bb/deploy.clj
(ns deploy)
(defn lock
"Lock env"
[_])
(defn unlock
"Unlock env"
[_])I don't think completions should give error messages
no completion after bb deploy
I've pushed to the repo
This is not good I think
bb deploy lock
:tasks :cli script.cli/defaults cannot be resolved: Could not locate script/cli.bb, script/cli.clj or script/cli.cljc on classpath.remove that line
ah! Success
nice!
cool
and --help?
Maybe for debugging it would be handy to have some error output during completion ๐
and bb deploy lock --help?
(`--help` was also completing on - )
great!
yeah some debug info would be nice, but completions don't work with debug info I think... I'll take a look
Or maybe something like bb simulate-completions and then give error output or something I don't know. You have probably better ideas about this haha
But the feature looks great! Can imagine it being very useful
based off what I see in the nushell completer, could you do something like:
๎
../bb org.babashka.cli/completions complete --shell nushell -- "deploy" "lock" ""
dev
prod
staging
(switching out the shell name) to get part of the way to 'simulate-completions', in order to isolate some variablesthat's a great way to debug
I now published the blog post here: https://blog.michielborkent.nl/babashka-tasks-cli.html and the new release is building If you see anything weird in the blog post, lemme know
Looks good! I see you added a debug option nice.
one error at end The task integration is available in babashka 1.13.219. > should be 1.12.219 i guess?
no, 1.13 is coming up
Oh ok cool!
it has the new 1.13 keys! stuff so I thought I'd call it that ;)
makes sense!
thanks for the testing!
and proof-reading