Skip to content

Commit 385d9f8

Browse files
committed
Tech review of java azure LP
1 parent c8e251f commit 385d9f8

File tree

5 files changed

+101
-69
lines changed

5 files changed

+101
-69
lines changed

content/learning-paths/servers-and-cloud-computing/java-on-azure/_index.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,21 @@ cascade:
77

88
minutes_to_complete: 30
99

10-
who_is_this_for: This Learning Path introduces Java deployment on Microsoft Azure Cobalt 100 (Arm-based) virtual machines. It is designed for developers migrating Java applications from x86_64 to Arm with minimal or no changes.
10+
who_is_this_for: This is an introductory topic about Java deployment and benchmarking on Microsoft Azure Cobalt 100 (Arm-based) virtual machines. It is designed for developers migrating Java applications from x86_64 to Arm.
1111

1212
learning_objectives:
13-
- Provision an Azure Arm64 virtual machine using Azure console, with Ubuntu Pro 24.04 LTS as the base image.
14-
- Deploy Java on the Ubuntu Pro virtual machine.
15-
- Perform Java baseline testing and benchmarking on both x86_64 and Arm64 virtual machines.
13+
- Provision an Azure Arm-based Cobalt 100 virtual machine using Azure console, with Ubuntu Pro 24.04 LTS as the base image.
14+
- Deploy Java on the Azure Arm64 virtual machine.
15+
- Perform Java baseline testing and benchmarking on the Arm64 virtual machines.
1616

1717
prerequisites:
1818
- A [Microsoft Azure](https://azure.microsoft.com/) account with access to Cobalt 100 based instances (Dpsv6).
19-
- Basic understanding of Linux command line.
20-
- Familiarity with the [Java platform](https://openjdk.org/) and deployment practices on Arm64 platforms.
2119

2220

23-
author: Jason Andrews
21+
author: Pareena Verma
2422

2523
### Tags
26-
skilllevels: Advanced
24+
skilllevels: Introductory
2725
subjects: Performance and Architecture
2826
cloud_service_providers: Microsoft Azure
2927

content/learning-paths/servers-and-cloud-computing/java-on-azure/baseline.md

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ layout: learningpathall
77
---
88

99

10-
### Deploy a Java application with Tomcat-like operation
11-
Apache Tomcat is a Java-based web application server (technically, a Servlet container) that executes Java web applications. It's widely used to host Java servlets, JSP (JavaServer Pages),
12-
and RESTful APIs written in Java.
10+
### Deploy a Java application with a Tomcat-like operation
11+
Apache Tomcat is a widely used Java web application server. Technically, it is a Servlet container, responsible for executing Java servlets and supporting technologies like:
1312

14-
The below Java class simulates the generation of a basic HTTP response and measures the time taken to construct it, mimicking a lightweight Tomcat-like operation. It measures how long it
15-
takes to build the response string, helping evaluate raw Java execution efficiency before deploying heavier frameworks like Tomcat.
13+
* JSP (JavaServer Pages): Java-based templates for dynamic web content.
14+
* RESTful APIs: Lightweight endpoints for modern microservices.
1615

17-
Create a file named `HttpSingleRequestTest.java`, and add the below content to it:
16+
In production, frameworks like Tomcat introduce additional complexity (request parsing, thread management, I/O handling). Before layering those components, it's useful to measure how efficiently raw Java executes simple request/response logic on Azure Cobalt 100 Arm-based instances.
17+
18+
In this section, you will run a minimal Tomcat-like simulation. It won't launch a real server, but instead it:
19+
* Constructs a basic HTTP response string in memory.
20+
* Measures the time taken to build that response, acting as a microbenchmark.
21+
* Provides a baseline for raw string and I/O handling performance in Java.
22+
23+
Using a file editor of your choice create a file named `HttpSingleRequestTest.java`, and add the content below to it:
1824

1925
```java
2026
public class HttpSingleRequestTest {
@@ -45,7 +51,7 @@ java -Xms128m -Xmx256m -XX:+UseG1GC HttpSingleRequestTest
4551
- -Xmx256m sets the maximum heap size for the JVM to 256 MB.
4652
- -XX:+UseG1GC enables the G1 Garbage Collector (Garbage First GC), designed for low pause times and better performance in large heaps.
4753

48-
You should see an output similar to:
54+
You should output similar to:
4955
```output
5056
java -Xms128m -Xmx256m -XX:+UseG1GC HttpSingleRequestTest
5157
Response Generated:
@@ -56,8 +62,11 @@ Content-Length: 29
5662
Tomcat baseline test on Arm64
5763
Response generation took 12901.53 microseconds.
5864
```
59-
Output summary:
65+
Output breakdown:
66+
67+
Generated Response: The program generates a fake HTTP 200 OK response with headers and a custom body string.
68+
Timing Result: The program prints how long it took (in microseconds) to build that response.
69+
In this example, it took ~12,901 µs (~12.9 ms). Your result will vary depending on CPU load, JVM warm-up, and environment.
6070

61-
- The program generated a fake HTTP 200 OK response with a custom message.
62-
- It then measured and printed the time taken to generate that response (22125.79 microseconds).
63-
- This serves as a basic baseline performance test of string formatting and memory handling on the JVM running on an Azure Arm64 instance.
71+
This provides you with a baseline measurement of how Java handles simple string operations and memory allocation on Cobalt 100 (Arm64) instances.
72+
It serves as a lightweight proxy for Tomcat-style request handling before adding the full complexity of a servlet container.

content/learning-paths/servers-and-cloud-computing/java-on-azure/benchmarking.md

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@ weight: 6
66
layout: learningpathall
77
---
88

9-
Now that you’ve built and run the Tomcat-like response, you can use it to test the JVM performance using JMH. You can also use it to test the performance difference between Cobalt 100 instances and other similar D series x86_64 based instances.
10-
## Run the performance tests using JMH
9+
Now that you have built and run a Tomcat-like response in Java, the next step is to benchmark it using a reliable, JVM-aware framework.
1110

12-
JMH (Java Microbenchmark Harness) is a Java benchmarking framework developed by the JVM team at Oracle to measure the performance of small code snippets with high precision. It accounts for JVM optimizations like JIT and warm-up to ensure accurate and reproducible results. It measures the throughput, average latency, or execution time. Below steps help benchmark the Tomcat-like operation:
11+
## Run performance tests using JMH
12+
13+
JMH (Java Microbenchmark Harness) is a Java benchmarking framework developed by the JVM team at Oracle to measure the performance of small code snippets with high precision. It accounts for JVM optimizations like JIT and warm-up to ensure accurate and reproducible results. You can measure throughput (ops/sec), average execution time, or percentiles for latency.
14+
15+
Follow the steps to help benchmark the Tomcat-like operation with JMH:
1316

1417

1518
Install Maven:
1619

1720
```console
1821
sudo apt install maven -y
1922
```
20-
Create Benchmark Project:
23+
Once Maven is installed, create a JMH benchmark project using the official archetype provided by OpenJDK:
2124

2225
```console
2326
mvn archetype:generate \
@@ -30,8 +33,31 @@ mvn archetype:generate \
3033
-Dversion=1.0
3134
cd jmh-benchmark
3235
```
36+
The output should look like:
37+
38+
```output
39+
[INFO] ----------------------------------------------------------------------------
40+
[INFO] Using following parameters for creating project from Archetype: jmh-java-benchmark-archetype:1.37
41+
[INFO] ----------------------------------------------------------------------------
42+
[INFO] Parameter: groupId, Value: com.example
43+
[INFO] Parameter: artifactId, Value: jmh-benchmark
44+
[INFO] Parameter: version, Value: 1.0
45+
[INFO] Parameter: package, Value: com.example
46+
[INFO] Parameter: packageInPathFormat, Value: com/example
47+
[INFO] Parameter: package, Value: com.example
48+
[INFO] Parameter: groupId, Value: com.example
49+
[INFO] Parameter: artifactId, Value: jmh-benchmark
50+
[INFO] Parameter: version, Value: 1.0
51+
[INFO] Project created from Archetype in dir: /home/azureuser/jmh-benchmark
52+
[INFO] ------------------------------------------------------------------------
53+
[INFO] BUILD SUCCESS
54+
[INFO] ------------------------------------------------------------------------
55+
[INFO] Total time: 3.474 s
56+
[INFO] Finished at: 2025-09-15T18:28:15Z
57+
[INFO] ------------------------------------------------------------------------
58+
```
3359

34-
Edit the `src/main/java/com/example/MyBenchmark.java` file and add the below code on it:
60+
Now edit the `src/main/java/com/example/MyBenchmark.java` file in the generated project. Replace the placeholder `TestMethod()` function with the following code:
3561

3662
```java
3763
package com.example;
@@ -56,23 +82,36 @@ public class MyBenchmark {
5682
}
5783
}
5884
```
59-
This simulates HTTP response generation similar to Tomcat.
85+
This mirrors the Tomcat-like simulation you created earlier but now runs under JMH.
6086

61-
Build the Benchmark:
87+
Build the Benchmark JAR:
6288

6389
```console
6490
mvn clean install
6591
```
6692

67-
After the build is complete, the JMH benchmark jar will be in the target/ directory.
93+
The output from this command should look like:
94+
95+
```output
96+
[INFO] Installing /home/azureuser/jmh-benchmark/target/jmh-benchmark-1.0.jar to /home/azureuser/.m2/repository/com/example/jmh-benchmark/1.0/jmh-benchmark-1.0.jar
97+
[INFO] Installing /home/azureuser/jmh-benchmark/pom.xml to /home/azureuser/.m2/repository/com/example/jmh-benchmark/1.0/jmh-benchmark-1.0.pom
98+
[INFO] ------------------------------------------------------------------------
99+
[INFO] BUILD SUCCESS
100+
[INFO] ------------------------------------------------------------------------
101+
[INFO] Total time: 5.420 s
102+
[INFO] Finished at: 2025-09-15T18:31:32Z
103+
```
104+
105+
After the build is complete, the JMH benchmark JAR will be located in the target directory.
68106

69107
Run the Benchmark:
70108

71109
```console
72110
java -jar target/benchmarks.jar
73111
```
112+
This will execute the benchmarkHttpResponse() method under JMH, showing average time per operation.
74113

75-
You should see an output similar to:
114+
You should see output similar to:
76115
```output
77116
# JMH version: 1.37
78117
# VM version: JDK 21.0.8, OpenJDK 64-Bit Server VM, 21.0.8+9-Ubuntu-0ubuntu124.04.1
@@ -160,6 +199,9 @@ Result "com.example.MyBenchmark.benchmarkHttpResponse":
160199
161200
# Run complete. Total time: 00:08:21
162201
202+
JMH runs warmup iterations so the JVM has a chance to JIT-compile and optimize the code before the real measurement begins.
203+
Each iteration shows how many times per second your `benchmarkHttpResponse()` method ran. You get an aggregate summary of the result at the end. In this example, on average the JVM executed ~35.6 million response constructions per second.
204+
163205
REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
164206
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
165207
experiments, perform baseline and negative tests that provide experimental control, make sure
@@ -178,12 +220,12 @@ MyBenchmark.benchmarkHttpResponse thrpt 25 35659618.044 ± 686946.011 ops/s
178220

179221
### Benchmark Metrics Explained
180222

181-
- **Run Count**: The total number of benchmark iterations executed. A higher run count increases statistical reliability and reduces the effect of outliers.
182-
- **Average Throughput**: The mean number of operations executed per second across all iterations. This metric represents the overall sustained performance of the benchmarked workload.
223+
- **Run Count**: The total number of benchmark iterations that JMH executed. More runs improve statistical reliability and help smooth out anomalies caused by the JVM or OS.
224+
- **Average Throughput**: The mean number of operations completed per second across all measured iterations. This is the primary indicator of sustained performance for the benchmarked code.
183225
- **Standard Deviation**: Indicates the amount of variation or dispersion from the average throughput. A smaller standard deviation means more consistent performance.
184-
- **Confidence Interval (99.9%)**: The statistical range within which the true average throughput is expected to fall, with 99.9% certainty. Narrow intervals imply more reliable results.
185-
- **Min Throughput**: The lowest throughput observed across all iterations, reflecting the worst-case performance scenario.
186-
- **Max Throughput**: The highest throughput observed across all iterations, reflecting the best-case performance scenario.
226+
- **Confidence Interval (99.9%)**: The statistical range in which the true average throughput is expected to fall with 99.9% certainty. Narrow confidence intervals suggest more reliable and repeatable measurements.
227+
- **Min Throughput**: The lowest observed throughput across all iterations, representing a worst-case scenario under the current test conditions.
228+
- **Max Throughput**: The highest observed throughput across all iterations, representing the best-case performance under the current test conditions.
187229

188230
### Benchmark summary on Arm64
189231

@@ -198,26 +240,12 @@ Here is a summary of benchmark results collected on an Arm64 **D4ps_v6 Ubuntu Pr
198240
| **Min Throughput** | 33.53M ops/sec |
199241
| **Max Throughput** | 36.99M ops/sec |
200242

201-
### Benchmark summary on x86
202-
203-
Here is a summary of benchmark results collected on x86 **D4s_v6 Ubuntu Pro 24.04 LTS virtual machine**.
204-
205-
| Metric | Value |
206-
|--------------------------------|---------------------------|
207-
| **Java Version** | OpenJDK 21.0.8 |
208-
| **Run Count** | 25 iterations |
209-
| **Average Throughput** | 16.78M ops/sec |
210-
| **Standard Deviation** | ±0.06M ops/sec |
211-
| **Confidence Interval (99.9%)**| [16.74M, 16.83M] ops/sec |
212-
| **Min Throughput** | 16.64M ops/sec |
213-
| **Max Throughput** | 16.88M ops/sec |
214-
215243

216-
### Benchmark comparison insights
217-
When comparing the results on Arm64 vs x86_64 virtual machines:
244+
### Key insights from the results
218245

219-
- **High Throughput:** Achieved an average of **35.66M ops/sec**, with peak performance reaching **36.99M ops/sec**.
220-
- **Stable Performance:** Standard deviation of **±0.92M ops/sec**, with results tightly bounded within the 99.9% confidence interval **[34.97M, 36.34M]**.
221-
- **Consistent Efficiency:** Demonstrates the reliability of Arm64 architecture for sustaining high-throughput Java workloads on Azure Ubuntu Pro environments.
246+
- **Strong throughput performance** The benchmark sustained around 35.6 million operations per second, demonstrating efficient string construction and memory handling on the Arm64 JVM.
247+
- **Consistency across runs** With a standard deviation under 1 million ops/sec, results were tightly clustered. This suggests stable system performance without significant noise from background processes.
248+
- **High statistical confidence** The narrow 99.9% confidence interval ([34.97M, 36.34M]) indicates reliable, repeatable results.
249+
- **Predictable performance envelope** The difference between min (33.5M) and max (37.0M) throughput is modest (~10%), suggests the workload performed consistently without extreme slowdowns or spikes.
222250

223-
You have now benchmarked Java on an Azure Cobalt 100 Arm64 virtual machine and compared results with x86_64.
251+
The Arm-based Azure `D4ps_v6` VM provides stable and efficient performance for Java workloads, even in microbenchmark scenarios. These results establish a baseline you can now compare directly against x86_64 instances to evaluate relative performance.

content/learning-paths/servers-and-cloud-computing/java-on-azure/create-instance.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@ weight: 3
66
layout: learningpathall
77
---
88

9-
## Introduction
9+
## Create an Azure Cobalt 100 Arm64 VM using the Azure portal
1010

11-
There are several ways to create an Arm-based Cobalt 100 virtual machine : the Microsoft Azure console, the Azure CLI tool, or using your choice of IaC (Infrastructure as Code). This guide will use the Azure console to create a virtual machine with Arm-based Cobalt 100 Processor.
11+
You can create an Azure Cobalt 100 Arm64 virtual machine in several ways, including the Azure portal, the Azure CLI, or an Infrastructure as Code (IaC) tool.
1212

13-
This learning path focuses on the general-purpose virtual machine of the D series. Please read the guide on [Dpsv6 size series](https://learn.microsoft.com/en-us/azure/virtual-machines/sizes/general-purpose/dpsv6-series) offered by Microsoft Azure.
13+
In this Learning Path, you’ll use the Azure portal to create a VM with the Cobalt 100 processor, following a process similar to creating any other virtual machine in Azure.
1414

15-
If you have never used the Microsoft Cloud Platform before, please review the microsoft [guide to Create a Linux virtual machine in the Azure portal](https://learn.microsoft.com/en-us/azure/virtual-machines/linux/quick-create-portal?tabs=ubuntu).
16-
17-
#### Create an Arm-based Azure Virtual Machine
15+
## Step-by-step: create the virtual machine
1816

1917
Creating a virtual machine based on Azure Cobalt 100 is no different from creating any other virtual machine in Azure. To create an Azure virtual machine, launch the Azure portal and navigate to "Virtual Machines".
2018
1. Select "Create", and click on "Virtual Machine" from the drop-down list.
@@ -35,7 +33,7 @@ Creating a virtual machine based on Azure Cobalt 100 is no different from creati
3533

3634
![Azure portal VM creation — Azure Cobalt 100 Arm64 virtual machine (D4ps_v6) alt-text#center](images/ubuntu-pro.png "Figure 3: Review and Create an Azure Cobalt 100 Arm64 VM")
3735

38-
10. Finally, when you are confident about your selection, click on the "Create" button, and click on the "Download Private key and Create Resources" button.
36+
10. Finally, click on the "Create" button, and click on the "Download Private key and Create Resources" button.
3937

4038
![Azure portal VM creation — Azure Cobalt 100 Arm64 virtual machine (D4ps_v6) alt-text#center](images/instance4.png "Figure 4: Download Private key and Create Resources")
4139

content/learning-paths/servers-and-cloud-computing/java-on-azure/deploy.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,24 @@ layout: learningpathall
99

1010

1111
## Java Installation on Azure Ubuntu Pro virtual machine
12-
Install Java on Ubuntu Pro virtual machine by updating the system and installing `default-jdk`, which includes both JRE and JDK. Verify the installation using `java -version` and `javac -version`, then set the `JAVA_HOME` environment variable for Arm-based systems.
12+
In this section, you will install Java on your Arm-based Ubuntu Pro virtual machine. The goal is to ensure you have both the Java Runtime Environment (JRE) for running Java applications and the Java Development Kit (JDK) for compiling code and running benchmarks.
1313

1414

1515
### Install Java
1616

17+
You will install Java using the Ubuntu package manager. `default-jdk` installs both the default JRE and JDK provided by Azure Ubuntu Pro machine.
1718
```console
1819
sudo apt update
1920
sudo apt install -y default-jdk
2021
```
2122

22-
`default-jdk` installs both the default JRE and JDK provided by Azure Ubuntu Pro machine.
23-
24-
Check to ensure that the JRE is properly installed:
23+
Verify your JRE installation:
2524

2625
```console
2726
java -version
2827
```
2928

30-
You should see an output similar to:
29+
You should the JRE version printed:
3130

3231
```output
3332
openjdk version "21.0.8" 2025-07-15
@@ -40,13 +39,13 @@ Check to ensure that the JDK is properly installed:
4039
```console
4140
javac -version
4241
```
43-
You should see an output similar to:
42+
The output should look similar to:
4443

4544
```output
4645
javac 21.0.8
4746
```
4847

49-
Set Java Environment Variable for Arm:
48+
Set the Java Environment Variables to point to the root directory of your JDK installation:
5049

5150
```console
5251
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-arm64
@@ -58,7 +57,7 @@ source ~/.bashrc
5857
Ubuntu Pro 24.04 LTS offers the default JDK version 21.0.8. It’s important to ensure that your version of OpenJDK for Arm is at least 11.0.9, or above. There is a large performance gap between OpenJDK-11.0.8 and OpenJDK 11.0.9. A patch added in 11.0.9 reduces false-sharing cache contention.
5958
For more information, you can view this [Arm community blog](https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/java-performance-on-neoverse-n1).
6059

61-
The [Arm Ecosystem Dashboard](https://developer.arm.com/ecosystem-dashboard/) also recommends Java/OpenJDK version 11.0.9 as minimum recommended on the Arm platforms.
60+
You can also refer to the [Arm Ecosystem Dashboard](https://developer.arm.com/ecosystem-dashboard/) for software package version recommendations on Arm Neoverse Linux machines.
6261
{{% /notice %}}
6362

64-
Java installation is complete. You can now proceed with the baseline testing.
63+
Your Java environment has been successfully configured. You may now proceed with baseline testing.

0 commit comments

Comments
 (0)