You can read the motivation behind clj-async-profiler and the usage example in the blog post.
async-profiler is a low overhead sampling profiler for JVM that does not suffer from the safepoint bias problem. It operates by attaching a native Java agent to a running JVM process and collecting the stack traces samples by using HotSpot-specific APIs. Current version of async-profiler that is used by clj-async-profiler is 1.4.
FlameGraph is a set of scripts to generate flame graphs. Flame graphs are a visualization of profiled software, allowing the most frequent code-paths to be identified quickly and accurately.
clj-async-profiler is only supported on GNU/Linux and MacOS. See https://github.com/jvm-profiling-tools/async-profiler#supported-platforms.
If you run clj-async-profiler on MacOS, no extra steps are required.
If you are running GNU/Linux, you need to do the following:
- Ensure that
perf_event_paranoidis set to 1:
$ cat /proc/sys/kernel/perf_event_paranoid 1
If it prints 2, it means you are running a newer Linux kernel. You have to set it to 1 to allow async-profiler to use kernel profiling data.
$ echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid
- If you see stackframes like
/usr/lib/.../libjvm.so, it means that you have to install JDK debug symbols. E.g., on Ubuntu that would be the package
JDK9+: you must start the JVM with option
otherwise the agent will not be able to dynamically attach to the running
process. For Leiningen, add
:jvm-opts ["-Djdk.attach.allowAttachSelf"] to
project.clj. For Boot, start the process with environment variable
It is highly recommended to use
-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints JVM flags. Without those flags the profiler will still
work correctly but results might be less accurate. Without these options, there
is a high chance that simple inlined methods will not appear in the profile.
When agent is attached at runtime CompiledMethodLoad JVMTI event enables debug
info, but only for methods compiled after the event is turned on.
com.clojure-goes-fast/clj-async-profiler to your dependencies:
clj-async-profiler exposes an all-in-one facade for generating profiling flame graphs. The most common usage scenario looks like this:
(require '[clj-async-profiler.core :as prof]) ;; Profile the following expression: (prof/profile (dotimes [i 10000] (reduce + (range i)))) ;; The resulting flamegraph will be stored in /tmp/clj-async-profiler/results/ ;; You can view the SVG directly from there or start a local webserver: (prof/serve-files 8080) ; Serve on port 8080
You can also start and stop the profiler manually with
Each profiling command accepts a map of options. See docstrings for each command for the list of supported options.
Option map for each profiling command can have a
:pid value. If it is
provided, an external JVM process with this PID will be sampled, otherwise the
current process is targeted.
Running on non-x64 platforms
clj-async-profiler ships with native libraries only for x64 Linux/OSX. To use it on ARM or other supported platform, you should to the following:
Build async-profiler for the desired platform.
Put the resulting
libasyncProfiler.soin a place accessible by your JVM process.
Execute from Clojure:
(reset! clj-async-profiler.core/async-profiler-agent-path "/path/to/libasyncProfiler.so")
async-profiler is distributed under Apache-2.0. See APACHE_PUBLIC_LICENSE file. The location of the original repository is https://github.com/jvm-profiling-tools/async-profiler.
Copyright 2017 Andrei Pangin
flamegraph.pl is distributed under CDDL-1.0. See COMMON_DEVELOPMENT_AND_DISTRIBUTION_LICENSE file. The original file location is https://github.com/brendangregg/FlameGraph/blob/master/flamegraph.pl.
Copyright 2016 Netflix, Inc.
Copyright 2011 Joyent, Inc. All rights reserved.
Copyright 2011 Brendan Gregg. All rights reserved.
Copyright 2013 Fogus and contributors.
clj-async-profiler is distributed under the Eclipse Public License. See ECLIPSE_PUBLIC_LICENSE.
Copyright 2017 Alexander Yakushev