FLINK-35534]Enable async profiler (#90)
diff --git a/README.md b/README.md
index 246f71a..75c9ae8 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,20 @@
java -jar target/benchmarks.jar "org.apache.flink.state.benchmark.*" -p "backendType=ROCKSDB"
```
+## Generating Flame graphs
+
+JMH has support for enabling profilers when running benchmarks, in particular [async profiler](https://github.com/async-profiler/async-profiler) which can generate flame graphs of the call stack. However, async profiler requires linking with native code which needs downloaded manually which means its location is user and architecture specific. To enable async profiler support run the benchmarks as follows:
+
+with maven
+```
+java -jar target/benchmarks.jar -rf csv "<benchmark_class>" -DasyncProfilerLib=<PATH_TO_libasyncProfiler.*>
+```
+
+or directly
+```
+java -jar target/benchmarks.jar -prof async:libPath=<PATH_TO_libasyncProfiler.*>;output=flamegraph "<benchmark_class>"
+```
+
## Configuration
Besides the parameters, there is also a benchmark config file `benchmark-conf.yaml` to tune some basic parameters.
diff --git a/benchmark.sh b/benchmark.sh
new file mode 100755
index 0000000..28722f0
--- /dev/null
+++ b/benchmark.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+################################################################################
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+################################################################################
+
+JAVA_ARGS=()
+JMH_ARGS=()
+BINARY="java"
+BENCHMARK_PATTERN=
+
+while getopts ":j:c:b:e:p:a:m:h" opt; do
+ case $opt in
+ j) JAVA_ARGS+=("${OPTARG}")
+ ;;
+ c) CLASSPATH_ARG="${OPTARG}"
+ ;;
+ b) BINARY="${OPTARG}"
+ ;;
+ p) PROFILER_ARG="${OPTARG:+-prof ${OPTARG}}"
+ # conditional prefixing inspired by https://stackoverflow.com/a/40771884/1389220
+ ;;
+ a) JMH_ARGS+=("${OPTARG}")
+ ;;
+ e) BENCHMARK_EXCLUDES="${OPTARG:+-e ${OPTARG}}"
+ ;;
+ m) BENCHMARK_PATTERN="${OPTARG}"
+ ;;
+ h)
+ 1>&2 cat << EOF
+usage: $0 -c ${CLASSPATH} [-j JVM_ARG] [-b /path/to/java] [-a JMH_ARG] [-p <profiler>:<opt1=X;opt2=Y] [-e benchmark exclusions]
+-j JVM argument. Can be used 0 - n times
+-c the classpath to use for JMH
+-b path to the java binary to use for the benchmark run
+-p Profiler argument. Accepts the value to be passed to jmh -prof option
+-a additional JMH command line argument. Can be used 0 - N times
+-e the regex for JMH to exclude benchmarks.
+-h this help message
+EOF
+ exit 1
+ ;;
+ \?) echo "Invalid option -$opt ${OPTARG}" >&2
+ exit 1
+ ;;
+ esac
+done
+shift "$(($OPTIND -1))"
+
+# shellcheck disable=SC2086
+${BINARY} "${JAVA_ARGS[@]}" \
+ -classpath "${CLASSPATH_ARG}" \
+ org.openjdk.jmh.Main \
+ -foe true \
+ -rf csv \
+ "${JMH_ARGS[@]}" \
+ ${PROFILER_ARG:-} \
+ ${BENCHMARK_EXCLUDES:-} \
+ "${BENCHMARK_PATTERN:-.*}"
diff --git a/pom.xml b/pom.xml
index 3b8a8e1..4be1a4a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,11 +54,11 @@
<maven.compiler.target>${java.version}</maven.compiler.target>
<slf4j.version>1.7.36</slf4j.version>
<log4j.version>1.2.17</log4j.version>
- <jmh.version>1.19</jmh.version>
+ <jmh.version>1.37</jmh.version>
<junit.version>4.13.2</junit.version>
<avro.version>1.11.1</avro.version>
<mockito.version>3.4.6</mockito.version>
- <maven.exec.version>1.6.0</maven.exec.version>
+ <maven.exec.version>3.3.0</maven.exec.version>
<maven.compiler.version>3.8.0</maven.compiler.version>
<chill.version>0.7.6</chill.version>
<thrift.version>0.13.0</thrift.version>
@@ -67,6 +67,8 @@
<benchmarkExcludes>org.apache.flink.benchmark.full.*,org.apache.flink.state.benchmark.*,org.apache.flink.scheduler.benchmark.*</benchmarkExcludes>
<benchmarks>.*</benchmarks>
<executableJava>java</executableJava>
+ <jmhProfArgument> </jmhProfArgument>
+ <profilerOutputDir>${build.directory}/profile-results</profilerOutputDir>
</properties>
<repositories>
@@ -290,25 +292,31 @@
<configuration>
<skip>${skipTests}</skip>
<classpathScope>test</classpathScope>
- <executable>${executableJava}</executable>
+ <executable>${basedir}/benchmark.sh</executable>
<arguments>
- <argument>-Xmx6g</argument>
- <argument>-classpath</argument>
+ <argument>-c</argument>
<classpath/>
- <argument>org.openjdk.jmh.Main</argument>
- <!--shouldFailOnError-->
- <argument>-foe</argument>
- <argument>true</argument>
+ <argument>-b</argument>
+ <argument>${executableJava}</argument>
+ <argument>-j</argument>
+ <argument>-Xmx6g</argument>
<!--speed up tests-->
+ <argument>-a</argument>
<argument>-f</argument>
+ <argument>-a</argument>
<argument>1</argument>
+ <argument>-a</argument>
<argument>-i</argument>
+ <argument>-a</argument>
<argument>1</argument>
+ <argument>-a</argument>
<argument>-wi</argument>
+ <argument>-a</argument>
<argument>0</argument>
- <argument>-rf</argument>
- <argument>csv</argument>
- <argument>.*</argument>
+ <argument>-e</argument>
+ <argument>${benchmarkExcludes}</argument>
+ <argument>-m</argument>
+ <argument>${benchmarks}</argument>
</arguments>
</configuration>
</plugin>
@@ -340,18 +348,25 @@
</executions>
<configuration>
<classpathScope>test</classpathScope>
- <executable>${executableJava}</executable>
+ <executable>${basedir}/benchmark.sh</executable>
<arguments>
- <argument>-classpath</argument>
+ <argument>-c</argument>
<classpath/>
- <argument>org.openjdk.jmh.Main</argument>
- <!--shouldFailOnError-->
- <argument>-foe</argument>
- <argument>true</argument>
+ <argument>-b</argument>
+ <argument>${executableJava}</argument>
+ <argument>-a</argument>
+ <argument>-r</argument>
+ <argument>-a</argument>
+ <argument>1</argument>
+ <argument>-a</argument>
+ <argument>-w</argument>
+ <argument>-a</argument>
+ <argument>1</argument>
+ <argument>-p</argument>
+ <argument>${jmhProfArgument}</argument>
<argument>-e</argument>
<argument>${benchmarkExcludes}</argument>
- <argument>-rf</argument>
- <argument>csv</argument>
+ <argument>-m</argument>
<argument>${benchmarks}</argument>
</arguments>
</configuration>
@@ -424,20 +439,29 @@
</executions>
<configuration>
<classpathScope>test</classpathScope>
- <executable>${executableJava}</executable>
+ <executable>${basedir}/benchmark.sh</executable>
<arguments>
+ <argument>-j</argument>
<argument>--add-opens</argument>
+ <argument>-j</argument>
<argument>java.base/java.util=ALL-UNNAMED</argument>
- <argument>-classpath</argument>
+ <argument>-c</argument>
<classpath/>
- <argument>org.openjdk.jmh.Main</argument>
- <!--shouldFailOnError-->
- <argument>-foe</argument>
- <argument>true</argument>
+ <argument>-b</argument>
+ <argument>${executableJava}</argument>
+ <argument>-a</argument>
+ <argument>-r</argument>
+ <argument>-a</argument>
+ <argument>1</argument>
+ <argument>-a</argument>
+ <argument>-w</argument>
+ <argument>-a</argument>
+ <argument>1</argument>
+ <argument>-p</argument>
+ <argument>${jmhProfArgument}</argument>
<argument>-e</argument>
<argument>${benchmarkExcludes}</argument>
- <argument>-rf</argument>
- <argument>csv</argument>
+ <argument>-m</argument>
<argument>${benchmarks}</argument>
</arguments>
</configuration>
@@ -536,6 +560,19 @@
</plugins>
</build>
</profile>
+
+ <profile>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ <property>
+ <name>asyncProfilerLib</name>
+ </property>
+ </activation>
+ <id>enable-async-profiler</id>
+ <properties>
+ <jmhProfArgument>async:libPath=${asyncProfilerLib};output=flamegraph;dir=${profilerOutputDir}</jmhProfArgument>
+ </properties>
+ </profile>
</profiles>
<build>