Ever wanted to share an example benchmark and be able to easily generate async profiler flamegraphs ?
This blog explains how that is trivial with JBang.
The other day Francesco Nigro aka. Mr. Performance Guru posted a message pointing to a gist he made.
This gist has some code that uses Java Microbenchmark Harness(JMH) to make some measurements related to Java 19 virtual threads (aka Loom) + some async profiler generated flamegraphs.
All good and great - but how do you run this ?
You could try:
copy the code to your local disk
setup a maven project
add the dependencies
add the async profiler agent
Or you (or Francesco) could just made a one-liner to run it with JBang.
jbang --java 19 --deps org.openjdk.jmh:jmh-generator-annprocess:1.36 -m org.openjdk.jmh.Main -R=--enable-preview -R=--add-opens -R=java.base/java.lang=ALL-UNNAMED --javaagent=ap-loader@maxandersen=start,event=cpu,file=profile.html https://gist.github.com/franz1981/4234195ca0168f3833023b610d91ddff
If you run that, you will get the JMH benchmark numbers…
…and a nice flamegraph generated for you in
How does it work ?
The command line is a bit of a mouthful, so let’s break it down.
This says it must use Java 19. You can use 19+ to use 19 or later.
This is the JMH dependency.
This is the main class to run; as the snippet is a JMH benchmark, we need to run the JMH main class.
-R=--enable-preview -R=--add-opens -R=java.base/java.lang=ALL-UNNAMED
These are the Java 19 preview flags needed to run the code.
This is the gist to run.
Those are fairly simple to understand, but what about this part:
This loads the async profiler agent and configures it - without you having to download a
async-profiler.jar file and add it to your classpath.
It works because I made a jbang-catalog that defines
ap-loader alias that uses the async profile loader published to Github releases.
I’ve submitted a PR to the ap-loader project to add this to the project itself, but until that is merged you can use my alias.
Making your own (simple) reproducers
Francesco did not know about this feature of JBang, but if he had known he could have made his gist even simpler to use. By adding a few comments JBang can configure itself to run the code.
//JAVA 19 //DEPS org.openjdk.jmh:jmh-generator-annprocess:1.36 //JAVA_OPTIONS --enable-preview --add-opens java.base/java.lang=ALL-UNNAMED
With that the gist would be directly runnable.
I’ve made b1a6dd2019b359ec32b07f0599ee2d9e301a73e2[my own fork of the gist] to show it:
and to run it with async profiler you would just add the
jbang --javaagent=ap-loader@maxandersen=start,event=cpu,file=profile.html https://gist.github.com/franz1981/4234195ca0168f3833023b610d91ddff
Not only does the above make it possible run the gist, but if you have any of the JBang IDE plugins installed it will also just work with content assist, debugging etc. without further setup. All without having to setup a maven project or anything.
This uses a gist, but could also been any .java or .jar file locally or on the web, a maven artifact or another jbang alias.
For example if you wanted to generate flamegraph for Quarkus CLI you would do:
jbang --javaagent=ap-loader@maxandersen=start,event=cpu,file=profile.html quarkus@quarkusio
This is loading the agent on the
quarkus@quarkusio alias which behind the scene points to a jar in maven central.
Furthermore, you can even make a command line that will install JBang and even a Java Development Kit (JDK) for you if you don’t have it installed.
curl -Ls https://sh.jbang.dev | bash -s - --javaagent=ap-loader@maxandersen=start,event=cpu,file=profile.html quarkus@quarkusio
The combinations and possibilities are endless.
See JBang for more details and if you have any questions or feedback, please reach out to me on Twitter or on JBang discussions.