
In my previous post, I showed you how tricky it is to compare objects from the JFR Java API. You probably wondered why I wrote about this topic. Here is the reason: In this blog post, I’ll cover how to load JFR files into a DuckDB database to allow querying profiling data with simple SQL queries, all JFR views included.
This blog post will start a small series on making JFR quack.
TL;DR
You can now use a query tool (via GitHub) to transform JFR files into similarly sized DuckDB files:
> java -jar target/query.jar duckdb import jfr_files/recording.jfr duckdb.db > duckdb duckdb.db "SELECT * FROM Events"; ┌───────────────────────────────┬───────┐ │ name │ count │ │ varchar │ int32 │ ├───────────────────────────────┼───────┤ │ GCPhaseParallel │ 69426 │ │ ObjectAllocationSample │ 6273 │
Or run the queries directly, with the database file being cached (if you don’t pass --no-cache), directly supporting all built-in JFR views:
> java -jar target/query.jar query jfr_files/metal.jfr "hot-methods" Method Samples Percent -------------------------------------------------------------------------------------------------------- ------- ------- java.util.concurrent.ForkJoinPool.deactivate(ForkJoinPool.WorkQueue, int) 1066 8.09% scala.collection.immutable.RedBlackTree$.lookup(RedBlackTree.Tree, Object, Ordering) 695 5.27% akka.actor.dungeon.Children.initChild(ActorRef) 678 5.14%
This view is implemented as:
CREATE VIEW "hot-methods" AS SELECT (c.javaName || '.' || m.name || m.descriptor) AS "Method", COUNT(*) AS "Samples", format_percentage(COUNT(*) / (SELECT COUNT(*) FROM ExecutionSample)) AS "Percent" FROM ExecutionSample es JOIN Method m ON es.stackTrace$topMethod = m._id JOIN Class c ON m.type = c._id GROUP BY es.stackTrace$topApplicationMethod, c.javaName, m.name, m.descriptor ORDER BY COUNT(*) DESC LIMIT 25Continue reading