Add compact-strings module: Compact Strings (JEP 254) measured with JOL on JDK 25, with and without -XX:-CompactStrings, and compact object headers on 25 vs 27

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01KqJyCidz3ZgRyHABv2GVJh
This commit is contained in:
2026-10-01 04:23:27 +00:00
co-authored by Claude Sonnet 5.5
parent fadfd05670
commit fc05eed4b5
26 changed files with 943 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
lib/
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Downloads JMH 1.37 and its two runtime dependencies from Maven Central into ./lib, checking each against the published .sha1
set -euo pipefail
cd "$(dirname "$0")"; mkdir -p lib
M=https://repo1.maven.org/maven2
for a in org/openjdk/jmh/jmh-core/1.37/jmh-core-1.37 \
org/openjdk/jmh/jmh-generator-annprocess/1.37/jmh-generator-annprocess-1.37 \
net/sf/jopt-simple/jopt-simple/5.0.4/jopt-simple-5.0.4 \
org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1; do
f="lib/$(basename "$a").jar"
for try in 1 2 3 4 5; do [ -s "$f" ] && break; curl -sfL -o "$f" "$M/$a.jar" || { rm -f "$f"; sleep 5; }; done
want=""; for try in 1 2 3 4 5; do want="$(curl -sfL "$M/$a.jar.sha1" | cut -d' ' -f1)" && [ -n "$want" ] && break; sleep 5; done
got="$(sha1sum "$f" | cut -d' ' -f1)"
[ "$want" = "$got" ] && echo "ok $f $got" || { echo "SHA1 MISMATCH $f"; exit 1; }
done
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Builds and runs StringBench on JDK 25 with the default and with -XX:-CompactStrings; writes ../output/30-jmh.txt (about 6 minutes).
# JDK25=/path ./run-jmh.sh (run ./fetch.sh once first)
set -uo pipefail
unset JAVA_TOOL_OPTIONS
HERE="$(cd "$(dirname "$0")" && pwd)"; cd "$HERE"
JDK25="${JDK25:-/opt/jdks/jdk-25.0.4.1+1}"
CP="$(ls lib/*.jar | tr '\n' ':')"; B="$(mktemp -d)"; trap 'rm -rf "$B"' EXIT
"$JDK25/bin/javac" -cp "$CP" -processorpath "$CP" -d "$B" src/bench/StringBench.java 2>&1 | grep -v '^Note:'
{
echo "machine: $(nproc) CPUs, $(grep -m1 'model name' /proc/cpuinfo | sed 's/.*: //')"
for fl in "" "-XX:-CompactStrings"; do
echo; echo "\$ java $fl org.openjdk.jmh.Main -f 2 -wi 3 -w 1 -i 5 -r 1 ($("$JDK25/bin/java" -version 2>&1 | sed -n 2p | sed 's/.*(build \(.*\))/\1/'), JMH 1.37)"
"$JDK25/bin/java" -cp "$B:$CP" org.openjdk.jmh.Main -f 2 -wi 3 -w 1 -i 5 -r 1 -jvmArgs "$fl" 2>&1 | sed -n '/^Benchmark /,$p'
done
} > "$HERE/../output/30-jmh.txt"
cat "$HERE/../output/30-jmh.txt"
@@ -0,0 +1,34 @@
package bench;
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
/**
* Read-only String operations on 256-character strings. Every string is built from a char[] so no two share a byte[].
* Run twice by run-jmh.sh: with the default and with -XX:-CompactStrings. hashCode is deliberately absent: String caches it,
* so a loop would measure the cache, not the hashing.
*/
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class StringBench {
String a, b, c;
int hit;
@Setup
public void setup() {
char[] x = new char[256];
for (int i = 0; i < x.length; i++) x[i] = (char) ('a' + (i % 26));
a = new String(x);
b = new String(x); // equal content, different object
x[255] = 'Z';
c = new String(x); // differs in the last character
}
@Benchmark public boolean equalsSameContent() { return a.equals(b); }
@Benchmark public int compareToLastCharDiffers() { return a.compareTo(c); }
@Benchmark public int indexOfLastChar() { return a.indexOf('z', 200); }
@Benchmark public int indexOfAbsentString() { return a.indexOf("zyx"); }
@Benchmark public String concatTwo() { return a.concat(b); }
@Benchmark public String toUpper() { return a.toUpperCase(); }
}