Skip to content

Commit 8dce8a5

Browse files
dfa1claude
andcommitted
build: add JMH benchmark module
Compare zstd-java (byte[] and zero-copy MemorySegment) against zstd-jni (JNI) and aircompressor (pure Java), for compress and decompress across 1K/64K/1M payloads at level 3. Self-contained shaded benchmarks.jar; host libzstd pulled via platform profile. See benchmark/README.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 0fcb9b3 commit 8dce8a5

7 files changed

Lines changed: 631 additions & 0 deletions

File tree

benchmark/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# zstd-java benchmarks
2+
3+
JMH microbenchmarks comparing **zstd-java** against the two common JVM zstd
4+
options:
5+
6+
| Contestant | Binding | Modes benchmarked |
7+
|------------|---------|-------------------|
8+
| **zstd-java** (this project) | FFM (no JNI) | `byte[]` and zero-copy `MemorySegment` |
9+
| **zstd-jni** (`com.github.luben`) | JNI | `byte[]` |
10+
| **aircompressor** (`io.airlift:aircompressor-v3`) | pure Java | `byte[]` |
11+
12+
The `MemorySegment` path is the one we expect to win: input and output are
13+
already off-heap, so there is no `byte[]` copy in or out of native code.
14+
15+
Two suites, each across payload sizes 1 KiB / 64 KiB / 1 MiB at level 3:
16+
17+
- `CompressBenchmark`
18+
- `DecompressBenchmark`
19+
20+
Payloads (`BenchData`) are deterministic, ~3x-compressible text so the ratios
21+
are realistic rather than all-zeros or random noise.
22+
23+
## Build
24+
25+
```bash
26+
./mvnw -q -pl benchmark -am package -DskipTests
27+
```
28+
29+
Produces a self-contained `benchmark/target/benchmarks.jar`. The host's native
30+
`libzstd` JAR is pulled in automatically by the platform profile.
31+
32+
## Run
33+
34+
```bash
35+
# everything (full warmup/measurement — takes a few minutes)
36+
java -jar benchmark/target/benchmarks.jar
37+
38+
# one suite, one size
39+
java -jar benchmark/target/benchmarks.jar CompressBenchmark -p size=1048576
40+
41+
# quick smoke run
42+
java -jar benchmark/target/benchmarks.jar -f 1 -wi 1 -i 3 -p size=65536
43+
```
44+
45+
`--enable-native-access=ALL-UNNAMED` is applied to forked JVMs via `@Fork`, so
46+
no extra flags are needed.
47+
48+
## Reading results
49+
50+
Throughput is `ops/ms` (higher is better). Compare rows at the same `(size)`:
51+
52+
```
53+
Benchmark (size) Mode Cnt Score Units
54+
CompressBenchmark.zstdJavaSegment 65536 thrpt 5 ... ops/ms
55+
CompressBenchmark.zstdJavaBytes 65536 thrpt 5 ... ops/ms
56+
CompressBenchmark.zstdJni 65536 thrpt 5 ... ops/ms
57+
CompressBenchmark.aircompressor 65536 thrpt 5 ... ops/ms
58+
```
59+
60+
Microbenchmark numbers are machine-specific; rebuild and run on the target host.
61+
Heed JMH's own caveat printed after each run.
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3+
<parent>
4+
<artifactId>parent</artifactId>
5+
<groupId>io.github.dfa1</groupId>
6+
<version>0.1-SNAPSHOT</version>
7+
</parent>
8+
<modelVersion>4.0.0</modelVersion>
9+
<artifactId>zstd-java-benchmark</artifactId>
10+
<name>zstd FFM Benchmark</name>
11+
<description>JMH microbenchmarks: zstd-java (byte[] vs MemorySegment) against zstd-jni
12+
(JNI) and aircompressor (pure Java). Not published; not part of a release.</description>
13+
<build>
14+
<finalName>benchmarks</finalName>
15+
<plugins>
16+
<plugin>
17+
<artifactId>maven-compiler-plugin</artifactId>
18+
<configuration>
19+
<annotationProcessorPaths>
20+
<path>
21+
<groupId>org.openjdk.jmh</groupId>
22+
<artifactId>jmh-generator-annprocess</artifactId>
23+
<version>${jmh.version}</version>
24+
</path>
25+
</annotationProcessorPaths>
26+
</configuration>
27+
</plugin>
28+
<plugin>
29+
<artifactId>maven-shade-plugin</artifactId>
30+
<version>3.6.0</version>
31+
<executions>
32+
<execution>
33+
<phase>package</phase>
34+
<goals>
35+
<goal>shade</goal>
36+
</goals>
37+
<configuration>
38+
<transformers>
39+
<transformer>
40+
<mainClass>org.openjdk.jmh.Main</mainClass>
41+
</transformer>
42+
<transformer />
43+
</transformers>
44+
<filters>
45+
<filter>
46+
<artifact>*:*</artifact>
47+
<excludes>
48+
<exclude>META-INF/*.SF</exclude>
49+
<exclude>META-INF/*.DSA</exclude>
50+
<exclude>META-INF/*.RSA</exclude>
51+
</excludes>
52+
</filter>
53+
</filters>
54+
</configuration>
55+
</execution>
56+
</executions>
57+
</plugin>
58+
</plugins>
59+
</build>
60+
<profiles>
61+
<profile>
62+
<id>native-osx-aarch64</id>
63+
<dependencies>
64+
<dependency>
65+
<groupId>io.github.dfa1</groupId>
66+
<artifactId>zstd-java-native-osx-aarch64</artifactId>
67+
<version>${project.version}</version>
68+
<scope>runtime</scope>
69+
</dependency>
70+
</dependencies>
71+
</profile>
72+
<profile>
73+
<id>native-osx-x86_64</id>
74+
<dependencies>
75+
<dependency>
76+
<groupId>io.github.dfa1</groupId>
77+
<artifactId>zstd-java-native-osx-x86_64</artifactId>
78+
<version>${project.version}</version>
79+
<scope>runtime</scope>
80+
</dependency>
81+
</dependencies>
82+
</profile>
83+
<profile>
84+
<id>native-linux-x86_64</id>
85+
<dependencies>
86+
<dependency>
87+
<groupId>io.github.dfa1</groupId>
88+
<artifactId>zstd-java-native-linux-x86_64</artifactId>
89+
<version>${project.version}</version>
90+
<scope>runtime</scope>
91+
</dependency>
92+
</dependencies>
93+
</profile>
94+
<profile>
95+
<id>native-linux-aarch64</id>
96+
<dependencies>
97+
<dependency>
98+
<groupId>io.github.dfa1</groupId>
99+
<artifactId>zstd-java-native-linux-aarch64</artifactId>
100+
<version>${project.version}</version>
101+
<scope>runtime</scope>
102+
</dependency>
103+
</dependencies>
104+
</profile>
105+
<profile>
106+
<id>native-windows-x86_64</id>
107+
<dependencies>
108+
<dependency>
109+
<groupId>io.github.dfa1</groupId>
110+
<artifactId>zstd-java-native-windows-x86_64</artifactId>
111+
<version>${project.version}</version>
112+
<scope>runtime</scope>
113+
</dependency>
114+
</dependencies>
115+
</profile>
116+
<profile>
117+
<id>native-windows-aarch64</id>
118+
<dependencies>
119+
<dependency>
120+
<groupId>io.github.dfa1</groupId>
121+
<artifactId>zstd-java-native-windows-aarch64</artifactId>
122+
<version>${project.version}</version>
123+
<scope>runtime</scope>
124+
</dependency>
125+
</dependencies>
126+
</profile>
127+
</profiles>
128+
<dependencies>
129+
<dependency>
130+
<groupId>org.openjdk.jmh</groupId>
131+
<artifactId>jmh-generator-annprocess</artifactId>
132+
<version>1.37</version>
133+
<scope>provided</scope>
134+
</dependency>
135+
</dependencies>
136+
<properties>
137+
<jmh.version>1.37</jmh.version>
138+
<zstd-jni.version>1.5.7-11</zstd-jni.version>
139+
<maven.deploy.skip>true</maven.deploy.skip>
140+
<aircompressor.version>3.6</aircompressor.version>
141+
</properties>
142+
</project>

0 commit comments

Comments
 (0)