Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: Setup Tomcat Benchmark Environment
title: Set up Tomcat benchmark environment
weight: 2

### FIXED, DO NOT MODIFY
Expand All @@ -8,43 +8,57 @@ layout: learningpathall


## Overview
There are numerous performance analysis methods and tools for Java applications, among which the call stack flame graph method is regarded as a conventional entry-level approach. Therefore, generating flame graphs is considered a basic operation.
Various methods and tools are available for generating Java flame graphs, including `async-profiler`, `Java Agent`, `jstack`, `JFR` (Java Flight Recorder), etc.
This Learning Path focuses on introducing two simple and easy-to-use methods: `async-profiler` and `Java Agent`.

Flame graphs are a widely used entry point for analyzing Java application performance. Tools for generating flame graphs include `async-profiler`, Java agents, `jstack`, and Java Flight Recorder (JFR). This Learning Path focuses on two practical approaches: using `async-profiler` and a Java agent.

## Setup Benchmark Server - Tomcat
- [Apache Tomcat](https://tomcat.apache.org/) is an open-source Java Servlet container that enables running Java web applications, handling HTTP requests and serving dynamic content.
- As a core component in Java web development, Apache Tomcat supports Servlet, JSP, and WebSocket technologies, providing a lightweight runtime environment for web apps.
In this section, you'll set up a benchmark environment using Apache Tomcat and `wrk2` to simulate HTTP load and evaluate performance on an Arm-based server.

## Set up the Tomcat benchmark server
[Apache Tomcat](https://tomcat.apache.org/) is an open-source Java Servlet container that runs Java web applications, handles HTTP requests, and serves dynamic content. It supports technologies such as Servlet, JSP, and WebSocket.

## Install the Java Development Kit (JDK)

Install OpenJDK 21 on your Arm-based Ubuntu server:

1. Start by installing Java Development Kit (JDK) on your Arm-based server running Ubuntu:
```bash
sudo apt update
sudo apt install -y openjdk-21-jdk
```

2. Next, you can install Tomcat by either [building it from source](https://github.com/apache/tomcat) or downloading the pre-built package simply from [the official website](https://tomcat.apache.org/whichversion.html)
## Install Tomcat

Download and extract Tomcat:

```bash
wget -c https://dlcdn.apache.org/tomcat/tomcat-11/v11.0.9/bin/apache-tomcat-11.0.9.tar.gz
tar xzf apache-tomcat-11.0.9.tar.gz
```
Alternatively, you can build Tomcat [from source](https://github.com/apache/tomcat).

## Enable access to Tomcat examples

To access the built-in examples from your local network or external IP, modify the `context.xml` file:

3. If you intend to access the built-in examples of Tomcat via an intranet IP or even an external IP, you need to modify a configuration file as shown:
```bash
vi apache-tomcat-11.0.9/webapps/examples/META-INF/context.xml
```
Then change the allow value as shown and save the changes:
```output
# change <Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />
# to
Update the `RemoteAddrValve` configuration to allow all IPs:

<!-- Before -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow="127\.\d+\.\d+\.\d+|::1|0:0:0:0:0:0:0:1" />

<!-- After -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve" allow=".*" />
```
Now you can start Tomcat Server:

## Start the Tomcat server

Start the server:

```bash
./apache-tomcat-11.0.9/bin/startup.sh
```

The output from starting the server should look like:
You should see output like:

```output
Using CATALINA_BASE: /home/ubuntu/apache-tomcat-11.0.9
Expand All @@ -56,42 +70,58 @@ Using CATALINA_OPTS:
Tomcat started.
```

4. If you can access the page at "http://${tomcat_ip}:8080/examples" via a browser, you can proceed to the next benchmarking step.
## Confirm server access

In your browser, open: `http://${tomcat_ip}:8080/examples`.

You should see the Tomcat welcome page and examples, as shown below:

![Screenshot of the Tomcat homepage showing version and welcome panel alt-text#center](./_images/lp-tomcat-homepage.png "Apache Tomcat homepage")

![example image alt-text#center](./_images/lp-tomcat-homepage.png "Tomcat-HomePage")
![Screenshot of the Tomcat examples page showing servlet and JSP demo links alt-text#center](./_images/lp-tomcat-examples.png "Apache Tomcat examples")

![example image alt-text#center](./_images/lp-tomcat-examples.png "Tomcat-Examples")
{{% notice Note %}}Make sure port 8080 is open in the security group of the IP address for your Arm-based Linux machine.{{% /notice%}}

Make sure port 8080 is open in the security group of the IP address for your Arm-based Linux machine.
## Set up the benchmarking client using wrk2
[Wrk2](https://github.com/giltene/wrk2) is a high-performance HTTP benchmarking tool specialized in generating constant throughput loads and measuring latency percentiles for web services. `wrk2` is an enhanced version of `wrk` that provides accurate latency statistics under controlled request rates, ideal for performance testing of HTTP servers.

## Setup Benchmark Client - [wrk2](https://github.com/giltene/wrk2)
`wrk2` is a high-performance HTTP benchmarking tool specialized in generating constant throughput loads and measuring latency percentiles for web services. `wrk2` is an enhanced version of `wrk` that provides accurate latency statistics under controlled request rates, ideal for performance testing of HTTP servers.
{{% notice Note %}}
Currently `wrk2` is only supported on x86 machines. Run the benchmark client steps below on an `x86_64` server running Ubuntu.
{{%/notice%}}

Currently `wrk2` is only supported on x86 machines. You will run the Benchmark Client steps shown below on an x86_64 server running Ubuntu.
## Install dependencies

Install the required packages:

1. To use `wrk2`, you will need to install some essential tools before you can build it:
```bash
sudo apt-get update
sudo apt-get install -y build-essential libssl-dev git zlib1g-dev
```

2. Now you can clone and build it from source:
## Clone and build wrk2

Clone the repository and compile the tool:

```bash
sudo git clone https://github.com/giltene/wrk2.git
cd wrk2
sudo make
```
Move the executable to somewhere in your PATH:

Move the binary to a directory in your system’s PATH:

```bash
sudo cp wrk /usr/local/bin
```

3. Finally, you can run the benchmark of Tomcat through wrk2.
## Run the benchmark

Use the following command to benchmark the HelloWorld servlet running on Tomcat:

```bash
wrk -c32 -t16 -R50000 -d60 http://${tomcat_ip}:8080/examples/servlets/servlet/HelloWorldExample
```
Shown below is the output of wrk2:
You should see output similar to:

```console
Running 1m test @ http://172.26.203.139:8080/examples/servlets/servlet/HelloWorldExample
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,54 @@
---
title: Java FlameGraph - Async-profiler
title: Generate Java flame graphs using async-profiler
weight: 3

### FIXED, DO NOT MODIFY
layout: learningpathall
---

## Java Flame Graph Generation using [async-profiler](https://github.com/async-profiler/async-profiler)
`async-profiler` is a low-overhead sampling profiler for JVM applications, capable of capturing CPU, allocation, and lock events to generate actionable performance insights.
A lightweight tool for Java performance analysis, `async-profiler` produces flame graphs and detailed stack traces with minimal runtime impact, suitable for production environments. In this section, you will learn how to install and use it to profile your Tomcat instance being benchmarked.
## Overview

[Async-profiler](https://github.com/async-profiler/async-profiler) is a low-overhead sampling profiler for JVM applications. It can capture CPU usage, memory allocations, and lock events to generate flame graphs and detailed stack traces.


This tool is well-suited for production environments due to its minimal runtime impact. In this section, you'll install and run `async-profiler` to analyze performance on your Tomcat instance under benchmark load.

{{%notice Note%}}
Install and run `async-profiler` on the same Arm-based Linux machine where Tomcat is running to ensure accurate profiling.
{{%/notice%}}

## Install async-profiler

Download and extract the latest release:

You should deploy `async-profiler` on the same Arm Linux machine where Tomcat is running to ensure accurate performance profiling.
1. Download async-profiler-4.0 and uncompress
```bash
wget -c https://github.com/async-profiler/async-profiler/releases/download/v4.0/async-profiler-4.0-linux-arm64.tar.gz
tar xzf async-profiler-4.0-linux-arm64.tar.gz
```

2. Run async-profiler to profile the Tomcat instance under benchmarking
## Run the profiler

Navigate to the profiler binary directory:

```bash
cd async-profiler-4.0-linux-arm64/bin
./asprof -d 10 -f profile.html $(jps | awk /Bootstrap/'{print $1}')
```
You can also run:
Run async-profiler against the Tomcat process:

```bash
./asprof -d 10 -f profile.html $(jps | awk /Bootstrap/'{print $1}')
```
Alternatively, if you already know the process ID (PID):

```bash
./asprof -d 10 -f profile.html ${tomcat_process_id}
```
* `-d 10` sets the profiling duration to 10 seconds

* `-f profile.html` specifies the output file

## View the flame graph

3. Now launch `profile.html` in a browser to analyse your profiling result
Open the generated `profile.html` file in a browser to view your Java flame graph:

![example image alt-text#center](_images/lp-flamegraph-async.png "Java Flame Graph via async-profiler")
![Flame graph visualization showing Java method stack traces captured using async-profile alt-text#center](_images/lp-flamegraph-async.png "Java flame graph built using async-profiler")
Original file line number Diff line number Diff line change
@@ -1,48 +1,72 @@
---
title: Java FlameGraph - Java Agent
title: Generate Java flame graphs using a Java agent
weight: 4


### FIXED, DO NOT MODIFY
layout: learningpathall
---

## Java Flame Graph Generation using Java agent and perf
To profile a Java application with perf and ensure proper symbol resolution, you must include `libperf-jvmti.so` when launching the Java application.
- `libperf-jvmti.so` is a JVM TI agent library enabling perf to resolve Java symbols, facilitating accurate profiling of Java applications.
- A specialized shared library, `libperf-jvmti.so` bridges perf and the JVM, enabling proper translation of memory addresses to Java method names during profiling.
## Overview

You can profile a Java application using `perf` by including a Java agent that enables symbol resolution. This allows `perf` to capture meaningful method names instead of raw memory addresses.

The required library is `libperf-jvmti.so`, a JVM Tool Interface (JVMTI) agent that bridges `perf` and the JVM. It ensures that stack traces collected during profiling can be accurately resolved to Java methods.

In this section, you'll configure Tomcat to use this Java agent and generate a flame graph using the FlameGraph toolkit.

## Locate the Java agent

Locate the `libperf-jvmti.so` library:

1. Find where `libperf-jvmti.so` is installed on your Arm-based Linux server:
```bash
pushd /usr/lib
find . -name libperf-jvmti.so`
```
The output will show the path of the library that you will then include in your Tomcat setup file:
The output will show the path to the shared object file:

## Modify Tomcat configuration

Open the Tomcat launch script:

```bash
vi apache-tomcat-11.0.9/bin/catalina.sh
```
Add JAVA_OPTS="$JAVA_OPTS -agentpath:/usr/lib/linux-tools-6.8.0-63/libperf-jvmti.so -XX:+PreserveFramePointer" to `catalina.sh`. Make sure the path matches the location on your machine from the previous step.
Add the following line (replace the path if different on your system):

```bash
JAVA_OPTS="$JAVA_OPTS -agentpath:/usr/lib/linux-tools-6.8.0-63/libperf-jvmti.so -XX:+PreserveFramePointer"
```
Now shutdown and restart Tomcat:

```bash
cd apache-tomcat-11.0.9/bin
./shutdown.sh
./startup.sh
```

2. Use perf to profile Tomcat, and restart wrk that running on your x86 instance if necessary:
## Run perf to record profiling data

Run the following command to record a 10-second profile of the Tomcat process:

```bash
sudo perf record -g -k1 -p $(jps | awk /Bootstrap/'{print $1}') -- sleep 10
```
This command will record the collected data in a file named `perf.data`
This generates a file named `perf.data`.

If needed, restart `wrk` on your x86 client to generate load during profiling.

## Generate a flame graph

Clone the FlameGraph repository and add it to your PATH:

3. Convert the collected `perf.data` into a Java flame graph using FlameGraph
```bash
git clone https://github.com/brendangregg/FlameGraph.git
export PATH=$PATH:`pwd`/FlameGraph
sudo perf inject -j -i perf.data | perf script | stackcollapse-perf.pl | flamegraph.pl &> profile.svg
```
## View the result

4. You can now successfully launch `profile.svg` in a browser to analyse the profiling result
You can now launch `profile.svg` in a browser to analyse the profiling result:

![example image alt-text#center](_images/lp-flamegraph-agent.png "Java Flame Graph via Java agent and perf")
![Flame graph visualization of Java method calls collected using perf and a Java agent on a Tomcat server alt-text#center](_images/lp-flamegraph-agent.png "Java flame graph built through Java agent and perf")
Original file line number Diff line number Diff line change
@@ -1,57 +1,49 @@
---
title: Analyze Java Performance on Arm servers using FlameGraphs

draft: true
cascade:
draft: true

title: Analyze Java performance on Arm servers using flame graphs
minutes_to_complete: 30

who_is_this_for: This is an introductory topic for software developers looking to analyze the performance of their Java applications on the Arm Neoverse based servers using flame graphs.
who_is_this_for: This is an introductory topic for developers who want to analyze the performance of Java applications on Arm Neoverse-based servers using flame graphs.

learning_objectives:
- How to set up tomcat benchmark environment
- How to generate flame graphs for Java applications using async-profiler
- How to generate flame graphs for Java applications using Java agent
- Set up a benchmarking environment using Tomcat and wrk2
- Generate flame graphs using async-profiler
- Generate flame graphs using a Java agent

prerequisites:
- An Arm-based and x86 computer running Ubuntu. You can use a server instance from a cloud service provider of your choice.
- Basic familiarity with Java applications and flame graphs
- Access to both Arm-based and x86-based computers running Ubuntu (you can use cloud-based server instances)
- Basic familiarity with Java applications and performance profiling using flame graphs

author: Ying Yu, Martin Ma
author:
- Ying Yu
- Martin Ma

### Tags
# Tags
skilllevels: Introductory
subjects: Performance and Architecture
armips:
- Neoverse
- Neoverse

tools_software_languages:
- OpenJDK-21
- Tomcat
- Async-profiler
- FlameGraph
- wrk2
operatingsystems:
- Linux
- OpenJDK-21
- Tomcat
- async-profiler
- FlameGraph
- wrk2

operatingsystems:
- Linux

further_reading:
- resource:
title: OpenJDK Wiki
link: https://wiki.openjdk.org/
type: documentation
- resource:
title: Java FlameGraphs
link: https://www.brendangregg.com/flamegraphs.html
type: website




### FIXED, DO NOT MODIFY
# ================================================================================
weight: 1 # _index.md always has weight of 1 to order correctly
layout: "learningpathall" # All files under learning paths have this same wrapper
learning_path_main_page: "yes" # This should be surfaced when looking for related content. Only set for _index.md of learning path content.
- resource:
title: OpenJDK Wiki
link: https://wiki.openjdk.org/
type: documentation
- resource:
title: Java FlameGraphs
link: https://www.brendangregg.com/flamegraphs.html
type: website

weight: 1
layout: "learningpathall"
learning_path_main_page: "yes"
---