Skip to content

Instantly share code, notes, and snippets.

@markrmiller
Created October 16, 2021 00:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markrmiller/b089efa4f9c85c5213169e88b7a2fe39 to your computer and use it in GitHub Desktop.
Save markrmiller/b089efa4f9c85c5213169e88b7a2fe39 to your computer and use it in GitHub Desktop.

JMH Profiler Setup

JMH ships with a number of built-in profiler options that have grown in number over time. The profiler system is also pluggable, allowing for "after-market" profiler implementations to be added on the fly.

Many of these profilers, most often the ones that stay in the realm of Java, will work across platforms and architectures and do so right out of the box. Others may be targeted at a specific OS, though there is a good chance a similar profiler for other OS's may exist where possible. A couple of very valuable profilers also require additional setup and environment to either work fully or at all.

Async-Profiler and Perfasm

This guide will cover setting up both the async-profiler and the Perfasm profiler. Currently, we roughtly cover two Linux family trees, but much of the information can be extrapalated or help piont in the right direction for other systems.


Path 1: Arch, Manjaro, etc

Archlinux Manjaro

Path 2: Debian, Ubuntu, etc

debian ubuntu


You JMH with the lprof argument, it will make an attempt to only list the profilers that it detects will work in your particular environment. You should do this first to see where you stand. In our case, we will start with very minimal Arch and Ubuntu clean installations, and so we already know there is no chance that async-profiler or Perfasm are going to run.

In fact, first we have to install a few project build requirements before thinking too much about JMH profiler support.


 sudo pacman -Syu wget jdk-openjdk11

Try async-profiler

Here we give async-profiler a try on Arch anyway and observe the failure indicating that we need to obtain the async-profiler library and put it in the correct location at a minimum.


 cd /lucene/jmh/
./jmh.sh FuzzyQuery -prof async:output=flamegraph

iconmonstr-keyboard-13-240

 Running JMH with args: FuzzyQuery -prof async:output=flamegraph
     Profilers failed to initialize, exiting.

   Unable to load async-profiler. Ensure asyncProfiler library is on LD_LIBRARY_PATH (Linux)
   DYLD_LIBRARY_PATH (Mac OS), or -Djava.library.path.

   Alternatively, point to explicit library location with: '-prof async:libPath={path}'

   no asyncProfiler in java.library.path: [/usr/java/packages/lib, /usr/lib64, /lib64, /lib, /usr/lib]

iconmonstr-server-10-240

Install async-profiler


 wget -c https://github.com/jvm-profiling-tools/async-profiler/releases/download/v2.5/async-profiler-2.5-linux-x64.tar.gz -O - | tar -xz
sudo mkdir -p /usr/java/packages/lib
sudo cp async-profiler-2.5-linux-x64/build/* /usr/java/packages/lib

That should work out better, but there is still an issue that will prevent a successful profiling run. async-profiler relies on Linux's perf, and in any recent Linux kernel, perf is restricted from doing its job without some configuration loosening.

The following changes will persist across restsarts, and that is likely how you should leave things.

sudo sysctl -w kernel.kptr_restrict=0
sudo sysctl -w kernel.perf_event_paranoid=1

No we should see a bit of success.

iconmonstr-keyboard-13-240


 cd /lucene/jmh/
./jmh.sh FuzzyQuery -prof async:output=flamegraph

But you will also find the following if you look closely at the logs. We do not want the debug symbols stripped from Java for the best experience. And it also turns out that if we want to use async-profilers alloc option to sample and create flamegraphs for heap usage, the debug symbols are required.

[WARN] Install JVM debug symbols to improve profile accuracy

iconmonstr-server-10-240

Install Java Debug symbols




  sudo apt update
sudo apt install openjdk-11-dbg

Archlinux-sm

On the Arch side we will rebuild the Java 11 package, but turn off the option that strips debug symbols. Often, large OS package and Java repositories originated in SVN and can be a bit a of a bear to wrestle with git about for just a fraction of the repository, we do so GitHub API workaround efficiency.


 sudo pacman -Syu dkms base-devel linux-headers dkms git vi jq --needed --noconfirm
curl -sL "https://api.github.com/repos/archlinux/svntogit-packages/contents/java11-openjdk/repos/extra-x86_64" | jq -r '.[] | .download_url' | xargs -n1 wget

Now we need to change that option in PKGBUILD. Choose your favorite editor. (nano, vim, emacs, ne, nvim, tilde etc)

vi PKGBUILD

We insert a single option line:

arch=('x86_64')
url='https://openjdk.java.net/'
license=('custom')
+   options=('debug' '!strip')
makedepends=('java-environment>=10' 'java-environment<12' 'cpio' 'unzip' 'zip' 'libelf' 'libcups' 'libx11' 'libxrender' 'libxtst' 'libxt' 'libxext' 'libxrandr' 'alsa-lib' 'pandoc'

And then we build. (-s: --syncdeps -i: --install -f: --force)


 makepkg -sif

When that is done, if everything went well, we should be able to succesfully run asyncprofiler in alloc mode to generate a flamegreaph based on memory rather than cpu.


  sudo apt update
sudo apt install openjdk-11-dbg

HDIS ROUGHER DUMP STIL

Perfasm hsdis for output assembly

Archlinux-sm

https://aur.archlinux.org/packages/java11-openjdk-hsdis/

wget -c https://aur.archlinux.org/cgit/aur.git/snapshot/java11-openjdk-hsdis.tar.gz -O - | tar -xz

[root@2c99f04f894a jmh]# cd java11-openjdk-hsdis/
[root@2c99f04f894a java11-openjdk-hsdis]# ls
binutils-compat.patch  binutils.patch  PKGBUILD



 export JAVA_HOME=/usr/lib/jvm/java-11-openjdk/
sudo apt update
sudo apt -y upgrade
sudo apt -y install openjdk-11-jdk git wget jq

 curl -sL "https://api.github.com/repos/openjdk/jdk11/contents/src/utils/hsdis" | jq -r '.[] | .download_url' | xargs -n1 wget

# Newer versions of binutils don't appear to compile, must use 2.28 for JDK 11 wget http://ftp.heanet.ie/mirrors/ftp.gnu.org/gnu/binutils/binutils-2.28.tar.gz tar xzvf binutils-2.28.tar.gz make BINUTILS=binutils-2.28 ARCH=amd64

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment