Eine Anleitung zum Async-Profiler

1. Übersicht

Java Sampling Profiler werden normalerweise mithilfe der JVM Tool Interface (JVMTI) entwickelt und sammeln Stapelspuren an einem sicheren Punkt. Daher können diese Stichprobenprofiler unter dem Problem der Vorspannung der Sicherheitspunkte leiden.

Für eine ganzheitliche Ansicht der Anwendung benötigen wir einen Stichprobenprofiler, für den keine Threads an Sicherheitspunkten vorhanden sein müssen und der die Stapelspuren jederzeit erfassen kann, um das Problem der Sicherheitspunktverzerrung zu vermeiden .

In diesem Tutorial werden wir den Async-Profiler zusammen mit verschiedenen Profiling-Techniken untersuchen, die er bietet.

2. Async-Profiler

async-profiler ist ein Sampling-Profiler für jedes JDK, das auf der HotSpot-JVM basiert. Es hat einen geringen Overhead und ist nicht auf JVMTI angewiesen.

Es vermeidet das Safepoint-Bias-Problem, indem die von HotSpot JVM bereitgestellte AsyncGetCallTrace- API zum Profilieren der Java-Codepfade und die perf_events von Linux zum Profilieren der nativen Codepfade verwendet werden.

Mit anderen Worten, der Profiler vergleicht Aufrufstapel von Java-Code und nativen Codepfaden, um genaue Ergebnisse zu erzielen.

3. Setup

3.1. Installation

Zuerst laden wir die neueste Version von async-profiler herunter, die auf unserer Plattform basiert. Derzeit werden nur Linux- und MacOS-Plattformen unterstützt.

Nach dem Herunterladen können wir überprüfen, ob es auf unserer Plattform funktioniert:

$ ./profiler.sh --version
Async-profiler 1.7.1 built on May 14 2020 Copyright 2016-2020 Andrei Pangin

Es ist immer eine gute Idee, vorher alle mit async-profiler verfügbaren Optionen zu überprüfen :

$ ./profiler.sh
Usage: ./profiler.sh [action] [options] Actions: start start profiling and return immediately resume resume profiling without resetting collected data stop stop profiling check check if the specified profiling event is available status print profiling status list list profiling events supported by the target JVM collect collect profile for the specified period of time and then stop (default action) Options: -e event profiling event: cpu|alloc|lock|cache-misses etc. -d duration run profiling for seconds -f filename dump output to -i interval sampling interval in nanoseconds -j jstackdepth maximum Java stack depth -b bufsize frame buffer size -t profile different threads separately -s simple class names instead of FQN -g print method signatures -a annotate Java method names -o fmt output format: summary|traces|flat|collapsed|svg|tree|jfr -I include output only stack traces containing the specified pattern -X exclude exclude stack traces with the specified pattern -v, --version display version string --title string SVG title --width px SVG width --height px SVG frame height --minwidth px skip frames smaller than px --reverse generate stack-reversed FlameGraph / Call tree --all-kernel only include kernel-mode events --all-user only include user-mode events --cstack mode how to traverse C stack: fp|lbr|no is a numeric process ID of the target JVM or 'jps' keyword to find running JVM automatically

Viele der gezeigten Optionen werden in den späteren Abschnitten nützlich sein.

3.2. Kernel-Konfiguration

Wenn Sie den Async-Profiler auf der Linux-Plattform verwenden, sollten Sie sicherstellen, dass unser Kernel so konfiguriert ist, dass Anrufstapel von allen Benutzern mithilfe der perf_events erfasst werden:

Zuerst setzen wir perf_event_paranoid auf 1, damit der Profiler Leistungsinformationen sammeln kann:

$ sudo sh -c 'echo 1 >/proc/sys/kernel/perf_event_paranoid'

Dann setzen wir kptr_restrict auf 0, um die Einschränkungen für die Offenlegung von Kerneladressen aufzuheben :

$ sudo sh -c 'echo 0 >/proc/sys/kernel/kptr_restrict'

Der Async-Profiler funktioniert jedoch auf der macOS-Plattform von selbst.

Nachdem unsere Plattform bereit ist, können wir unsere Profiling-Anwendung erstellen und mit dem Java-Befehl ausführen:

$ java -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -jar path-to-jar-file

Hier haben wir unsere Profiling-App mit den JVM-Flags -XX: + UnlockDiagnosticVMOptions -XX: + DebugNonSafepoints gestartet , die für genaue Ergebnisse dringend empfohlen werden .

Nachdem wir nun bereit sind, unsere Anwendung zu profilieren, wollen wir verschiedene Arten von Profilen untersuchen, die vom Async-Profiler unterstützt werden .

4. CPU-Profilerstellung

Der Async-Profiler sammelt bei der Profilerstellung der CPU Beispiel-Stack-Traces von Java-Methoden, einschließlich JVM-Code, nativer Klasse und Kernelfunktionen.

Lassen Sie uns unsere Anwendung anhand ihrer PID profilieren:

$ ./profiler.sh -e cpu -d 30 -o summary 66959 Started [cpu] profiling --- Execution profile --- Total samples : 28 Frame buffer usage : 0.069%

Hier haben wir das CPU- Profilierungsereignis mithilfe der Option -e definiert . Dann haben wir das -d verwendet Option, um die Probe für 30 Sekunden zu sammeln.

Last, the -o option is useful to define the output format like summary, HTML, traces, SVG, and tree.

Let's create the HTML output while CPU profiling our application:

$ ./profiler.sh -e cpu -d 30 -f cpu_profile.html 66959

Here, we can see the HTML output allows us to expand, collapse, and search the samples.

Additionally, async-profiler supports flame graphs out-of-the-box.

Let's generate a flame graph by using the .svg file extension for the CPU profile of our application:

$ ./profiler.sh -e cpu -d 30 -f cpu_profile.svg 66959

Here, the resulting flame graph shows Java code paths in green, C++ in yellow, and system code paths in red.

5. Allocation Profiling

Similarly, we can collect samples of memory allocation without using an intrusive technique like bytecode instrumentation.

async-profiler uses the TLAB (Thread Local Allocation Buffer) based sampling technique to collect the samples of the heap allocation above the average size of TLAB.

By using the alloc event, we can enable the profiler to collect heap allocations of our profiling application:

$ ./profiler.sh -e alloc -d 30 -f alloc_profile.svg 66255

Here, we can see the object cloning has allocated a large part of memory, which is otherwise hard to perceive when looking at the code.

6. Wall-Clock Profiling

Also, async-profiler can sample all threads irrespective of their status – like running, sleeping, or blocked – by using the wall-clock profile.

This can prove handy when troubleshooting issues in the application start-up time.

By defining the wall event, we can configure the profiler to collect samples of all threads:

$ ./profiler.sh -e wall -t -d 30 -f wall_clock_profile.svg 66959

Here, we've used the wall-clock profiler in per-thread mode by using the -t option, which is highly recommended when profiling all threads.

Additionally, we can check all profiling events supported by our JVM by using the list option:

$ ./profiler.sh list 66959
Basic events: cpu alloc lock wall itimer Java method calls: ClassName.methodName

7. async-profiler With IntelliJ IDEA

IntelliJ IDEA features integration with async-profiler as a profiling tool for Java.

7.1. Profiler Configurations

We can configure async-profiler in IntelliJ IDEA by selecting the Java Profiler menu option at Settings/Preferences > Build, Execution, Deployment:

Also, for quick usage, we can choose any predefined configuration, like the CPU Profiler and the Allocation Profiler that IntelliJ IDEA offers.

Similarly, we can copy a profiler template and edit the Agent options for specific use cases.

7.2. Profile Application Using IntelliJ IDEA

There are a few ways to analyze our application with a profiler.

For instance, we can select the application and choose Run with option:

Or, we can click on the toolbar and choose the Run with option:

Or, by choosing the Run with Profiler option under the Run menu, then selecting the <profiler configuration name>:

Additionally, we can see the option to Attach Profiler to Process under the Run menu. It opens a dialog that lets us choose the process to attach:

Once our application is profiled, we can analyze the profiling result using the Profiler tool window bar at the bottom of the IDE.

The profiling result of our application will look like:

It shows the thread wise results in different output formats like flame graphs, call trees, and method list.

Alternativ können Sie die Option Profiler im Menü Ansicht> Werkzeugfenster auswählen , um die Ergebnisse anzuzeigen:

8. Fazit

In diesem Artikel haben wir den Async-Profiler zusammen mit einigen Profiling-Techniken untersucht.

Zuerst haben wir gesehen, wie der Kernel unter Verwendung der Linux-Plattform konfiguriert wird, und einige empfohlene JVM-Flags, mit denen Sie die Profilerstellung für unsere Anwendung starten können, um genaue Ergebnisse zu erhalten.

Anschließend untersuchten wir verschiedene Arten von Profiling-Techniken wie CPU, Zuordnung und Wanduhr.

Zuletzt haben wir eine Anwendung mit Async-Profiler unter Verwendung von IntelliJ IDEA profiliert .