commit e189da79ba8048f3cc1dba12447999acc2c86aa0 Author: Ankur Date: Fri Jul 31 08:47:16 2026 +0530 Generational ZGC vs G1 on JDK 25: benchmarks, internals and captured results Complete companion suite for the ankurm.com guide. Everything was compiled and executed on java 25.0.3+9-LTS-195 (AMD Ryzen 5 5600U, Windows 11); every file under results/ is unedited program output. Code latency/ open-loop latency harness that measures from intended arrival, so coordinated omission is accounted for rather than hidden. Reports response time and service time side by side; the gap reached 2910x on G1. jmh/ four microbenchmarks isolating one mechanism each: TLAB allocation, the ZGC load barrier (with a primitive-load control), the write barrier (with null / old-to-old / primitive controls), and promotion pressure. tuning/ provokes ZGC allocation stalls and reads its own JFR recording back, grouped by page class. jdk.ZAllocationStall is enabled without a threshold, because the 10 ms default hides most stalls. internals/ ZGC page classes vs G1 humongous, read from the live VM via HotSpotDiagnosticMXBean and jdk.ZPageAllocation events. analysis/ unified GC log parser that keeps stop-the-world pauses and concurrent phases in separate buckets. env/ environment capture; proves generational mode from JMX bean names. Docs Eight chapters covering the JEP 439/474/490 timeline, colored pointers and both barriers, allocation stalls, a full flag reference, logging and JFR, benchmark methodology, corner cases, and a decision procedure. Headline result (60 s, 20k req/s, 2 GB heap, ~585 MB live) p50 ZGC 0.006 ms G1 0.005 ms p99.9 ZGC 1.437 ms G1 95.169 ms total STW time ZGC 1.503 ms G1 1,139.624 ms diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b9abbe1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# build output +out/ +target/ +*.class +jmh/dependency-reduced-pom.xml + +# JFR recordings produced by the demos (they are regenerated on every run) +*.jfr + +# raw unified GC logs -- large, machine-specific, regenerated by scripts/run-all +logs/ + +# local run bookkeeping +run-all-transcript.txt +run-all-errors.txt + +# the blog post draft lives on ankurm.com, not here +BLOGPOST.html + +# editors +.idea/ +*.iml +.vscode/ +.DS_Store + +# results/ IS committed on purpose -- it is the evidence for the blog post diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..aa5473f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Ankur Mhatre + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b9a48f9 --- /dev/null +++ b/README.md @@ -0,0 +1,137 @@ +# Generational ZGC vs G1 on JDK 25 — runnable benchmarks and internals + +Companion repository for **[Generational ZGC on JDK 25: Benchmarks vs G1](https://ankurm.com/generational-zgc-jdk-25-vs-g1/)** +on [ankurm.com](https://ankurm.com). + +The blog post covers the concepts most people need. **This repository covers everything** — every +flag, every failure mode, every measurement pitfall, with runnable code, real captured output, and +the reasoning behind each choice. + +Everything here was compiled and executed on `java 25.0.3+9-LTS-195`. Raw, unedited output for every +run is in [`results/`](results). + +--- + +## Quick start + +```console +git clone https://ankurm.com/git.app/asmhatre/zgc-jdk25-benchmarks.git +cd zgc-jdk25-benchmarks + +# Windows +pwsh scripts/run-all.ps1 -JavaHome 'C:\Program Files\Java\jdk-25.0.3' + +# Linux / macOS +./scripts/run-all.sh /path/to/jdk-25 +``` + +Or run a single piece — nothing but a JDK 25 is required for anything outside `jmh/`: + +```console +javac -d out $(find latency tuning internals analysis -name '*.java') + +java -XX:+UseZGC -Xms2g -Xmx2g -cp out com.ankurm.zgc.latency.LatencyHarness +java -XX:+UseG1GC -Xms2g -Xmx2g -cp out com.ankurm.zgc.latency.LatencyHarness +``` + +--- + +## Headline result + +60 seconds, 20,000 req/s open loop, 2 GB heap, ~585 MB live set, ~328 MB/s allocation rate. +Full output: [`results/03-latency-zgc.txt`](results/03-latency-zgc.txt), +[`results/03-latency-g1.txt`](results/03-latency-g1.txt). + +| Metric | Generational ZGC | G1 | +|---|---|---| +| p50 response time | 0.006 ms | **0.005 ms** | +| p90 | 0.009 ms | 0.009 ms | +| p99 | **0.029 ms** | 8.042 ms | +| p99.9 | **1.437 ms** | 95.169 ms | +| p99.99 | **23.675 ms** | 126.949 ms | +| max | **32.178 ms** | 133.018 ms | +| total stop-the-world time | **1.503 ms** | 1,139.624 ms | +| longest single pause | **0.054 ms** | 104.449 ms | +| Full GCs / evacuation failures | **0 / 0** | 4 / 16 | + +G1 wins the median. ZGC wins everything past p99. The two are indistinguishable up to p90 — which is +the part most "ZGC is faster" posts leave out. + +--- + +## What is in here + +### Code + +| Module | What it demonstrates | Deps | +|---|---|---| +| [`env/Env.java`](env/Env.java) | Environment capture; proves generational mode from JMX bean names | none | +| [`latency/`](latency/src/com/ankurm/zgc/latency) | **Open-loop** latency harness with coordinated-omission accounting | none | +| [`tuning/AllocationStallDemo.java`](tuning/src/com/ankurm/zgc/tuning/AllocationStallDemo.java) | Provokes and measures ZGC allocation stalls via JFR | none | +| [`internals/PageSizeDemo.java`](internals/src/com/ankurm/zgc/internals/PageSizeDemo.java) | ZGC page classes vs G1 humongous, read from the live VM | none | +| [`analysis/GcLogParser.java`](analysis/src/com/ankurm/zgc/analysis/GcLogParser.java) | Unified-log parser that keeps pauses and concurrent phases apart | none | +| [`jmh/`](jmh/src/main/java/com/ankurm/zgc/jmh) | Throughput and barrier microbenchmarks | JMH 1.37 | + +### JMH benchmarks + +| Class | Isolates | +|---|---| +| [`AllocationBench`](jmh/src/main/java/com/ankurm/zgc/jmh/AllocationBench.java) | TLAB allocation path at 64 B / 1 KB / 32 KB | +| [`LoadBarrierBench`](jmh/src/main/java/com/ankurm/zgc/jmh/LoadBarrierBench.java) | **ZGC's load barrier** — pointer chase vs primitive sum control | +| [`StoreBarrierBench`](jmh/src/main/java/com/ankurm/zgc/jmh/StoreBarrierBench.java) | **Write barriers** — old→young vs null vs old→old vs primitive control | +| [`PromotionBench`](jmh/src/main/java/com/ankurm/zgc/jmh/PromotionBench.java) | Medium-lived objects; the case where "most objects die young" fails | + +### Documentation + +| Chapter | Covers | +|---|---| +| [1. The generational model](docs/01-generational-model.md) | JEP 439 → 474 → 490 timeline, what `ZGenerational` does now, why there is no `-Xmn` | +| [2. Barriers](docs/02-barriers.md) | Colored pointers, load barrier, store barrier, remembered sets, `ZBufferStoreBarriers` | +| [3. Allocation stalls](docs/03-allocation-stalls.md) | **The ZGC failure mode pause charts cannot see**, and the 10 ms JFR threshold that hides it | +| [4. Tuning reference](docs/04-tuning-reference.md) | Every ZGC product + diagnostic flag, and the G1 flags that still matter | +| [5. Logging and JFR](docs/05-logging-and-jfr.md) | Reading `-Xlog:gc*`, the JMX bean trap, the JFR events worth enabling | +| [6. Methodology](docs/06-methodology.md) | Coordinated omission, timer granularity, the JMH `-jvmArgs` fork trap | +| [7. Corner cases](docs/07-corner-cases.md) | Compressed oops, large-page fragmentation, virtual thread stacks, containers, `System.gc()` | +| [8. Choosing a collector](docs/08-choosing.md) | A decision procedure, sizing guidance, when the answer is neither | + +--- + +## Five findings you will not read elsewhere + +1. **G1's coordinated-omission gap on this workload is 2910x.** A closed-loop harness reports G1's + p99.9 as 0.033 ms. It is really 95.169 ms. + → [docs/06-methodology.md §6.1](docs/06-methodology.md) +2. **ZGC disables compressed oops.** Every reference is 8 bytes instead of 4, so a reference-dense + heap can grow 30–40% on switching collector, before any latency benefit. + → [docs/07-corner-cases.md §7.1](docs/07-corner-cases.md) +3. **`jdk.ZAllocationStall` has a 10 ms default JFR threshold.** In a run whose mean stall was + 3.98 ms, a default profile discards most of them. + → [docs/03-allocation-stalls.md §3.3](docs/03-allocation-stalls.md) +4. **`new byte[4*1024*1024]` gets a ZGC Large page, not a Medium one.** The 16-byte array header + pushes it over the medium-object limit, and it consumes an 8 MB page. + → [docs/07-corner-cases.md §7.2](docs/07-corner-cases.md) +5. **`SoftMaxHeapSize` and `ZAllocationSpikeTolerance` did nothing under sustained overload.** + Measured: 32,200 / 31,967 / 32,442 stalls across baseline and both mitigations. They buy headroom + for *spikes*; they cannot conjure heap that does not exist. + → [results/04-stalls-zgc-softmax.txt](results/04-stalls-zgc-softmax.txt) + +--- + +## Reference machine + +| | | +|---|---| +| CPU | AMD Ryzen 5 5600U, 6 cores / 12 threads | +| RAM | 15.3 GB | +| OS | Windows 11 Home | +| JDK | `java 25.0.3+9-LTS-195` (Oracle) | +| Heap | `-Xms2g -Xmx2g` for all latency runs; `-Xms512m -Xmx512m` for stall runs | + +A laptop, not a server. The absolute numbers are illustrative; the *relationships* are what +generalise. Run it on your own hardware — that is what it is for. + +--- + +## Licence + +MIT. See [LICENSE](LICENSE). diff --git a/analysis/src/com/ankurm/zgc/analysis/GcLogParser.java b/analysis/src/com/ankurm/zgc/analysis/GcLogParser.java new file mode 100644 index 0000000..8314481 --- /dev/null +++ b/analysis/src/com/ankurm/zgc/analysis/GcLogParser.java @@ -0,0 +1,184 @@ +package com.ankurm.zgc.analysis; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Turns a JDK unified GC log into a pause distribution, for either ZGC or G1. + * + *

Why not just use a hosted log analyser? Because the interesting question here is + * cross-collector, and the two logs mean different things by the word "pause": + * + *

+ * + *

It also counts the lines that matter and are easy to miss: ZGC {@code Allocation Stall} + * entries, and G1 {@code To-space exhausted} / {@code Evacuation Failure} / {@code Pause Full} + * entries. Those are each collector's "we lost the race" signal. + * + *

Producing a log this can read

+ *
+ * java -XX:+UseZGC -Xlog:gc*:file=zgc.log:time,uptime,level,tags MyApp
+ * java -cp out com.ankurm.zgc.analysis.GcLogParser zgc.log
+ * 
+ */ +public final class GcLogParser { + + /** Any "... 12.345ms" or "... 0.850s" trailing duration. */ + private static final Pattern DURATION = + Pattern.compile("(\\d+[.,]\\d+)\\s*(ms|s|us)\\s*$"); + + /** + * Matches the {@code GC(n)} prefix, an optional ZGC generation marker ({@code y:} / {@code o:}), + * and then the phase name. + * + *

The phase name is deliberately not matched with a single greedy pattern. G1's + * lines put heap occupancy between the phase name and the duration: + * + *

GC(12) Pause Young (Normal) (G1 Evacuation Pause) 1180M->402M(2048M) 16.784ms
+ * + * while ZGC's do not: + * + *
GC(41) y: Concurrent Mark 32.109ms
+ * + * An earlier version of this parser required the phase name to be followed directly by the + * duration, which silently matched every ZGC line and no G1 line at all -- and then reported + * "no pauses found" for G1, which is the most flattering possible bug for G1. The phase name is + * therefore taken as the leading run of letters, spaces and parenthesised qualifiers, and the + * duration is taken separately from the end of the line. + */ + private static final Pattern PHASE_PREFIX = + Pattern.compile("GC\\((\\d+)\\)\\s+(?:[YyOo]:\\s*)?(Pause|Concurrent|Garbage Collection)\\b([A-Za-z ]*(?:\\([^)0-9]*\\)\\s*)*)"); + + public static void main(String[] args) throws IOException { + if (args.length < 1) { + System.err.println("usage: GcLogParser [...]"); + System.exit(2); + } + for (String arg : args) { + analyse(Path.of(arg)); + System.out.println(); + } + } + + private static void analyse(Path log) throws IOException { + if (!Files.exists(log)) { + System.out.println("missing log: " + log); + return; + } + List lines = Files.readAllLines(log); + + List pauseMillis = new ArrayList<>(); + Map> pausesByPhase = new LinkedHashMap<>(); + Map> concurrentByPhase = new LinkedHashMap<>(); + + int allocationStalls = 0; + int evacuationFailures = 0; + int fullGcs = 0; + int youngCollections = 0; + int oldCollections = 0; + + for (String line : lines) { + if (line.contains("Allocation Stall")) allocationStalls++; + if (line.contains("To-space exhausted") || line.contains("Evacuation Failure")) evacuationFailures++; + if (line.contains("Pause Full")) fullGcs++; + if (line.contains("Minor Collection") || line.contains("Pause Young")) youngCollections++; + if (line.contains("Major Collection") || line.contains("Pause Old")) oldCollections++; + + Matcher phase = PHASE_PREFIX.matcher(line); + if (!phase.find()) continue; + + double ms = parseTrailingMillis(line); + if (ms < 0) continue; // a line with no trailing duration -- skip + + String kind = phase.group(2); // "Pause" | "Concurrent" | "Garbage Collection" + String name = (kind + " " + phase.group(3)).replaceAll("\\s+", " ").trim(); + + if (kind.equals("Pause")) { + pauseMillis.add(ms); + pausesByPhase.computeIfAbsent(name, k -> new ArrayList<>()).add(ms); + } else if (kind.equals("Concurrent")) { + concurrentByPhase.computeIfAbsent(name, k -> new ArrayList<>()).add(ms); + } + } + + System.out.println("=".repeat(78)); + System.out.println("GC log analysis: " + log.getFileName()); + System.out.println("=".repeat(78)); + System.out.printf("lines parsed : %,d%n", lines.size()); + System.out.printf("young / minor cycles : %,d%n", youngCollections); + System.out.printf("old / major cycles : %,d%n", oldCollections); + System.out.printf("ZGC allocation stalls : %,d%n", allocationStalls); + System.out.printf("G1 evacuation failures : %,d%n", evacuationFailures); + System.out.printf("full GCs : %,d%n", fullGcs); + System.out.println(); + + if (pauseMillis.isEmpty()) { + System.out.println("No stop-the-world pause lines found. Was the log written with -Xlog:gc* ?"); + } else { + Collections.sort(pauseMillis); + double total = pauseMillis.stream().mapToDouble(Double::doubleValue).sum(); + System.out.println("STOP-THE-WORLD PAUSES (this is application freeze time)"); + System.out.printf(" count : %,d%n", pauseMillis.size()); + System.out.printf(" total : %,.3f ms%n", total); + System.out.printf(" mean : %,.3f ms%n", total / pauseMillis.size()); + System.out.printf(" p50 : %,.3f ms%n", percentile(pauseMillis, 50)); + System.out.printf(" p99 : %,.3f ms%n", percentile(pauseMillis, 99)); + System.out.printf(" max : %,.3f ms%n", pauseMillis.getLast()); + System.out.println(); + System.out.println(" by phase"); + pausesByPhase.forEach((phase, values) -> { + double sum = values.stream().mapToDouble(Double::doubleValue).sum(); + System.out.printf(" %-28s n=%-6d total=%8.3f ms max=%7.3f ms%n", + phase, values.size(), sum, Collections.max(values)); + }); + } + + if (!concurrentByPhase.isEmpty()) { + System.out.println(); + System.out.println("CONCURRENT PHASES (application keeps running -- NOT freeze time)"); + concurrentByPhase.forEach((phase, values) -> { + double sum = values.stream().mapToDouble(Double::doubleValue).sum(); + System.out.printf(" %-28s n=%-6d total=%8.3f ms max=%7.3f ms%n", + phase, values.size(), sum, Collections.max(values)); + }); + System.out.println(); + System.out.println(" Adding the block above to the pause block would be a category error:"); + System.out.println(" concurrent time overlaps application execution by design."); + } + } + + /** Normalises a trailing "12.345ms" / "0.850s" / "812us" to milliseconds. */ + private static double parseTrailingMillis(String line) { + Matcher m = DURATION.matcher(line.strip()); + if (!m.find()) return -1; + double value = Double.parseDouble(m.group(1).replace(',', '.')); + return switch (m.group(2)) { + case "s" -> value * 1000.0; + case "us" -> value / 1000.0; + default -> value; + }; + } + + private static double percentile(List sorted, double p) { + if (sorted.isEmpty()) return 0; + int idx = (int) Math.ceil(p / 100.0 * sorted.size()) - 1; + return sorted.get(Math.clamp(idx, 0, sorted.size() - 1)); + } +} diff --git a/docs/01-generational-model.md b/docs/01-generational-model.md new file mode 100644 index 0000000..9ae2be3 --- /dev/null +++ b/docs/01-generational-model.md @@ -0,0 +1,115 @@ +# 1. The generational model, and what JDK 25 actually changed + +> Companion notes for [Generational ZGC on JDK 25: Benchmarks vs G1](https://ankurm.com/generational-zgc-jdk-25-vs-g1/). +> Everything here is verified against `java 25.0.3+9-LTS-195`. + +## 1.1 The one-paragraph history + +| Release | What happened | +|---|---| +| JDK 11 | ZGC arrives as an experimental, **non-generational** collector (JEP 333). One generation, whole-heap marking every cycle. | +| JDK 15 | ZGC becomes a production feature (JEP 377). | +| JDK 21 | **Generational ZGC** ships as an opt-in mode behind `-XX:+ZGenerational` (JEP 439). | +| JDK 23 | Generational becomes the **default** (JEP 474). `-XX:-ZGenerational` still gets you the old one. | +| JDK 24 | The non-generational mode is **removed** (JEP 490). `ZGenerational` becomes an obsolete flag. | +| JDK 25 | First **LTS** where ZGC is generational-only. This is the release most teams will actually adopt. | + +Verify the removal yourself — the JVM says so out loud: + +```console +$ java -XX:+UseZGC -XX:+ZGenerational -version +Java HotSpot(TM) 64-Bit Server VM warning: Ignoring option ZGenerational; support was removed in 24.0 +java version "25.0.3" 2026-04-21 LTS +``` + +That warning matters operationally: if your start-up scripts still carry `-XX:+ZGenerational` from a +JDK 21 experiment, JDK 25 will *not* fail fast. It warns and continues. Grep your deployment +manifests. + +## 1.2 What "generational" buys, concretely + +The weak generational hypothesis: most objects die young. A collector that exploits it can reclaim +the young generation without looking at the old one. + +Non-generational ZGC could not do that. Every cycle marked the **entire** heap. With a 600 MB live +set and a 300 MB/s allocation rate, that means repeatedly tracing 600 MB of objects that you +already know are alive, in order to reclaim garbage that lives in a few megabytes of recently +allocated pages. + +Generational ZGC splits this into: + +- a **minor (young) collection** that marks and relocates only young pages, and +- a **major (old) collection** that additionally handles the old generation, run far less often. + +You can see the split in the JMX bean names, which is the cheapest possible proof of what you are +running: + +```console +collector : ZGC Minor Cycles + ZGC Minor Pauses + ZGC Major Cycles + ZGC Major Pauses +``` + +Four beans, not two. Under non-generational ZGC there was one cycle bean and one pause bean. +`env/Env.java` in this repository prints exactly this and derives `generational? yes`. + +## 1.3 The cost of the split: you now need a write barrier + +There is no free lunch. To collect young without scanning old, the collector must know about every +**old-to-young reference**. Those are created by ordinary application code: + +```java +oldCache[i] = new Payload(); // an old object now points at a brand-new young object +``` + +If a young collection ignored `oldCache`, it would conclude `new Payload()` is unreachable and free +a live object. + +So generational ZGC added a **store barrier** — code the JIT injects around reference stores, which +records the cross-generational edge. Non-generational ZGC had *no* store barrier at all; it only +had a load barrier. This is the single biggest structural change in JEP 439, and it is why +generational ZGC has slightly different throughput characteristics from the old one on +store-heavy code. See [02-barriers.md](02-barriers.md). + +You can see the mechanism named in the VM's own diagnostic flags: + +```console +$ java -XX:+UseZGC -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | findstr Z + bool ZBufferStoreBarriers = true {diagnostic} {default} + int ZTenuringThreshold = -1 {diagnostic} {default} + bool ZUseMediumPageSizeRange = true {diagnostic} {default} +``` + +- `ZBufferStoreBarriers` — the store barrier does not update a remembered set inline; it appends to + a per-thread buffer that is drained later. That is what keeps the barrier cheap. +- `ZTenuringThreshold = -1` — **adaptive**. ZGC ages objects like any generational collector, but + unlike G1's `MaxTenuringThreshold` (default 15, a documented product flag), ZGC's is a diagnostic + flag that defaults to "let the collector decide". Pinning it is almost always a mistake; knowing + it exists is occasionally the answer to "why did my promotion rate change after an upgrade". + +## 1.4 Where the generations physically live + +ZGC does not have a contiguous eden / survivor / old layout the way Parallel or (loosely) G1 does. +Generation membership is a property of a **page**, and pages are 2 MB / medium / large units +scattered across the reserved address space. A young page whose objects survive enough cycles is +*promoted* by relocating its live objects into an old page. + +This has a practical consequence people trip over: **there is no `-Xmn` for ZGC**. You cannot size +the young generation. ZGC decides how much of the heap is young dynamically, based on allocation +rate and how much headroom `SoftMaxHeapSize` leaves it. If you are used to tuning G1 with +`-XX:NewRatio` or `-XX:G1NewSizePercent`, that entire toolbox is gone. The ZGC equivalent of "give +the young generation more room" is "give the heap more room, or lower `SoftMaxHeapSize` so +collection starts earlier". + +## 1.5 What this means for a migration + +| If you relied on… | On generational ZGC you get… | +|---|---| +| `-Xmn`, `-XX:NewRatio`, `-XX:SurvivorRatio` | Nothing. Ignored or unavailable. Size the whole heap instead. | +| `-XX:MaxTenuringThreshold` | `ZTenuringThreshold`, diagnostic, adaptive by default. | +| `-XX:+ZGenerational` | An obsolete-flag warning. Remove it. | +| GC pause charts as your latency SLI | A misleading green dashboard. See [03-allocation-stalls.md](03-allocation-stalls.md). | +| `-XX:+UseStringDeduplication` | Still supported on ZGC (since JDK 18), not G1-only any more. | + +--- + +Next: [02-barriers.md](02-barriers.md) — colored pointers, load barriers, store barriers and +remembered sets, with the microbenchmark that prices each one. diff --git a/docs/02-barriers.md b/docs/02-barriers.md new file mode 100644 index 0000000..caf9674 --- /dev/null +++ b/docs/02-barriers.md @@ -0,0 +1,106 @@ +# 2. Colored pointers, load barriers, store barriers, remembered sets + +> Runnable companions: [`jmh/.../LoadBarrierBench.java`](../jmh/src/main/java/com/ankurm/zgc/jmh/LoadBarrierBench.java), +> [`jmh/.../StoreBarrierBench.java`](../jmh/src/main/java/com/ankurm/zgc/jmh/StoreBarrierBench.java) + +This is the chapter that explains *why* the numbers look the way they do. Every throughput +difference between ZGC and G1 traces back to one of the mechanisms below. + +## 2.1 Colored pointers + +A 64-bit JVM does not need 64 bits to address the heap. ZGC uses the spare high bits of every heap +reference as metadata — the "color". The colors encode facts like *has this pointer been marked in +the current young cycle?* and *has the object it points at been relocated?* + +The consequence is that **the pointer, not a side table, carries the collector's state**. Two +objects can hold references to the same object with different colors, and each will be fixed up +independently the first time it is read. + +This is the trick that lets ZGC relocate objects concurrently. Traditional compacting collectors +must stop the world to fix up every reference to a moved object. ZGC does not: it moves the object, +records a forwarding entry, and lets each stale reference repair itself on next read. + +> **Multi-mapping vs. multi-mapping-free.** Older ZGC mapped the same physical heap at several +> virtual addresses so that colored pointers could be dereferenced directly. Modern ZGC (from JDK +> 22's "colored roots"/load-barrier rework onward) masks the color in the barrier instead. Practical +> effect: on Linux, `RSS` no longer looks like 3x the heap in tooling that misreads multi-mapped +> regions. If you have old runbooks explaining that "ZGC reports 3x memory, ignore it", they are +> obsolete. + +## 2.2 The load barrier + +Every time your code reads a **reference field**, the JIT emits a short sequence: test the color +bits, and on the slow path fix the pointer. Primitive loads (`int`, `long`, elements of `int[]`) are +untouched — a common misconception is that ZGC taxes all memory access. It does not. It taxes +reference loads. + +`LoadBarrierBench` prices this by comparing two walks over the same number of elements: + +| Benchmark | What it does | Barrier? | +|---|---|---| +| `chaseReferences` | walks a shuffled 1M-node linked structure, one reference load per step | yes, one per step | +| `sumPrimitives` | sums an `int[]` of the same length | none | +| `readSameReferenceRepeatedly` | reads one already-good reference 1024 times | yes, but always fast path | + +The third one is the interesting control: it measures the **floor** of the barrier — what you pay +when there is nothing to fix. If `readSameReferenceRepeatedly` is close between ZGC and G1, the +fast path is nearly free and any gap in `chaseReferences` is the slow path plus cache effects. + +Two things move these numbers a lot, and both are worth measuring on your own workload: + +- **Whether a GC cycle is in progress.** The barrier does strictly more work during marking and + relocation. Force cycles with `-XX:ZCollectionInterval=1` to see the sustained-load case rather + than the idle-heap case. +- **Whether the walk is cache-resident.** A sequential walk over a small structure is dominated by + the prefetcher and hides the barrier entirely. That is why the benchmark shuffles the node order — + a "random" pointer chase that is secretly sequential measures the memory subsystem, not the GC. + +## 2.3 The store barrier and remembered sets + +Generational collection requires knowing about old-to-young references (see +[01-generational-model.md](01-generational-model.md) §1.3). The two collectors solve it differently +and the difference is measurable. + +**G1: card table + concurrent refinement.** +The heap is divided into 512-byte *cards*. A reference store dirties the card containing the +modified field. Concurrent refinement threads later scan dirty cards and update per-region +*remembered sets* (which regions point into me?). G1's barrier is a two-part affair — a pre-write +barrier for SATB marking and a post-write barrier for card marking — and has historically been the +more expensive of the two collectors' barriers. JDK 24 landed *late barrier expansion* for G1 +(JDK-8342382), which defers expanding the barrier into IR until late in C2 so the optimiser can see +through more of the surrounding code; JDK 25 continued reducing remembered-set memory. + +**ZGC: store barrier + per-page remembered sets.** +Generational ZGC's store barrier appends to a thread-local buffer (`ZBufferStoreBarriers=true`), +which is drained into per-page remembered-set bitmaps. The bitmaps are **double-buffered**: one is +being written by the application while the other is consumed by the collector, which is how ZGC +avoids a stop-the-world handoff. + +`StoreBarrierBench` separates "the barrier code ran" from "the barrier had work to do": + +| Benchmark | Store | Creates old→young edge? | +|---|---|---| +| `storeOldToYoung` | `oldArray[i] = new Object()` | yes | +| `storeNullIntoOld` | `oldArray[i] = null` | no — barrier runs, records nothing | +| `storeOldToOld` | `oldArray[i] = oldArray` | no | +| `storePrimitiveIntoOld` | `oldIntArray[i] = i` | not a reference store; no barrier at all | + +The benchmark walks slots with a stride of 4099 rather than sequentially. Sequential stores hit the +same card / same page repeatedly, and both collectors have an "already dirty" fast path that would +hide most of the cost. This is the single most common way a store-barrier microbenchmark +accidentally measures nothing. + +## 2.4 Why this shows up as a throughput gap, not a latency gap + +Barriers cost throughput: a few extra instructions on a very hot path. They do **not** cost latency, +because they are spread evenly across execution rather than concentrated into a pause. + +That is the whole trade in one sentence: **ZGC converts a rare, large, correlated cost (a +stop-the-world pause) into a constant, small, uncorrelated cost (barrier work on every reference +access).** Whether that is a good deal depends entirely on whether your SLO is expressed as a mean +or as a tail percentile. + +--- + +Next: [03-allocation-stalls.md](03-allocation-stalls.md) — the ZGC failure mode that pause charts +cannot see. diff --git a/docs/03-allocation-stalls.md b/docs/03-allocation-stalls.md new file mode 100644 index 0000000..a2b0274 --- /dev/null +++ b/docs/03-allocation-stalls.md @@ -0,0 +1,161 @@ +# 3. Allocation stalls — the ZGC failure mode your dashboard cannot see + +> Runnable companion: [`tuning/.../AllocationStallDemo.java`](../tuning/src/com/ankurm/zgc/tuning/AllocationStallDemo.java) + +## 3.1 The claim, and why it is misleading + +Every ZGC article ends with the same chart: pause times, flat, under a millisecond, at any heap +size. The chart is accurate. The implied conclusion — *therefore ZGC has no latency problem* — is +not, because **on ZGC, pauses are not where latency comes from.** + +ZGC's stop-the-world pauses are O(number of GC roots). They do not scale with heap size or live-set +size, and they stay in the tens of microseconds. There are three of them per cycle: `Pause Mark +Start`, `Pause Mark End`, `Pause Relocate Start`. + +What actually hurts is different. When the application allocates faster than the collector can +reclaim, a thread that requests memory and cannot be given a page is **stalled** until the collector +frees one. That stall: + +- can last **tens or hundreds of milliseconds**, +- blocks only the allocating thread, not the whole JVM, +- and therefore **never appears in a pause-time metric.** + +A ZGC service can report a p99.99 pause of 0.2 ms and a p99.99 request latency of 400 ms +simultaneously. Both numbers are correct. If your only GC SLI is pause time, you will never find the +second one. + +## 3.2 Seeing it + +`AllocationStallDemo` starts a JFR recording, deliberately drives a small heap into the ground, then +reads its own recording back. Measured on this repository's reference machine (Ryzen 5 5600U, +Windows 11, JDK 25.0.3), 512 MB heap, 15 seconds of allocation: + +```console +$ java -XX:+UseZGC -Xms512m -Xmx512m -Dseconds=15 \ + -cp out com.ankurm.zgc.tuning.AllocationStallDemo + +young collections : 1,319 +old collections : 164 +page allocations : 30,768 +ALLOCATION STALLS : 25,343 + +total time threads spent stalled : 100,989 ms +mean stall : 3.98 ms +longest stall : 49.01 ms +``` + +Read that again: **101 seconds of cumulative stalled thread time inside a 15-second run.** Twelve +allocator threads, each spending a large fraction of the run waiting for memory. The pause chart for +this run is a flat line near zero. + +## 3.3 The threshold that hides them + +`jdk.ZAllocationStall` has a **default JFR threshold of 10 ms**. Anything shorter is not recorded. +In the run above the *mean* stall was 3.98 ms — meaning a default JFR profile would have discarded +the majority of them and reported a much healthier picture. + +If you take one operational thing from this repository, take this: + +```java +recording.enable("jdk.ZAllocationStall").withoutThreshold(); +``` + +or in a `.jfc` settings file: + +```xml + + true + 0 ms + true + +``` + +With stack traces on, you get the exact allocation site that stalled — which is usually far more +actionable than any GC log line. + +The same events are visible in the unified log without JFR: + +```console +-Xlog:gc+alloc=debug +``` + +produces `Allocation Stall` lines. The `GcLogParser` in this repository counts them. + +## 3.4 The stalls have a *shape* + +The demo groups stalls by ZGC page class, which turns "we are out of memory" into a diagnosis: + +- **Small** page stalls — ordinary allocation pressure. The fix is more heap, an earlier collection + trigger, or allocating less. +- **Medium** page stalls — objects in the 256 KB–4 MB band. Often a buffer-pool or serialization + layer. Frequently fixable in application code. +- **Large** page stalls — one page per object. ZGC does not relocate large pages, so a heap with + many long-lived large objects fragments in a way ZGC cannot compact away. + +A run dominated by Large-page stalls has a completely different remedy from one dominated by Small, +and no pause-time chart distinguishes them. + +## 3.5 Mitigations, in the order you should try them + +### `SoftMaxHeapSize` — start collecting earlier + +``` +-XX:SoftMaxHeapSize=400m # with -Xmx512m +``` + +ZGC's heuristic aims to keep the heap under `SoftMaxHeapSize` but is *allowed* to exceed it, up to +`-Xmx`, rather than stall the application. Setting it below `-Xmx` therefore creates a deliberate +reserve: normal operation targets the soft limit, and a spike can eat into the gap instead of +hitting a wall. On JDK 25 it defaults to `-Xmx`, i.e. no reserve at all. + +It is a `manageable` flag, so you can change it on a running JVM — genuinely useful during an +incident: + +```console +$ jcmd VM.set_flag SoftMaxHeapSize 400m +``` + +### `ZAllocationSpikeTolerance` — assume bigger spikes + +``` +-XX:ZAllocationSpikeTolerance=5 # default 2.0 +``` + +ZGC predicts when to start a cycle from the observed allocation rate multiplied by this tolerance +factor. The default of 2.0 assumes allocation can double. A bursty service — one that goes from idle +to full throttle in a second — routinely violates that, and the collector starts a cycle too late. +Raising the tolerance makes ZGC start earlier and more often: you pay CPU to buy headroom. + +### `-XX:ZCollectionIntervalMinor` / `Major` — collect on a clock + +Both default to `-1.0` (disabled). Setting `ZCollectionIntervalMinor=1` forces a young collection +every second regardless of allocation rate. This is a blunt instrument, but it is the right one for +a service with a very spiky duty cycle where the rate-based heuristic keeps being surprised. + +### More heap + +The honest answer, when you can afford it. ZGC trades memory for latency by design; a ZGC heap sized +like a G1 heap is a ZGC heap that stalls. + +## 3.6 What the same pressure looks like on G1 + +Run the identical demo under `-XX:+UseG1GC` and there are no allocation stalls, because G1 does not +have that mechanism. Instead you get **to-space exhaustion** (an evacuation failure) followed by a +**Full GC** — a genuine, whole-application, stop-the-world compaction that will show up in your +pause chart as a multi-hundred-millisecond spike. + +So the failure modes are mirror images: + +| | ZGC | G1 | +|---|---|---| +| Symptom under memory pressure | allocation stalls | evacuation failure → Full GC | +| Affects | the allocating thread(s) | every thread | +| Visible in pause metrics | **no** | yes | +| Typical magnitude here | 4 ms mean, 49 ms max, thousands of them | hundreds of ms, few of them | + +G1's failure is louder and easier to find. ZGC's is quieter and easier to live with — provided you +are actually measuring it. + +--- + +Next: [04-tuning-reference.md](04-tuning-reference.md). diff --git a/docs/04-tuning-reference.md b/docs/04-tuning-reference.md new file mode 100644 index 0000000..092f239 --- /dev/null +++ b/docs/04-tuning-reference.md @@ -0,0 +1,101 @@ +# 4. Tuning reference (JDK 25) + +Everything below was read out of a live `java 25.0.3+9-LTS-195` with +`-XX:+PrintFlagsFinal` and `HotSpotDiagnosticMXBean`. Raw dumps: +[`results/02-flags-zgc.txt`](../results/02-flags-zgc.txt), +[`results/02-flags-g1.txt`](../results/02-flags-g1.txt). + +The general rule for ZGC is unusual and worth stating plainly: **there is almost nothing to tune.** +The design goal was to remove knobs, not add them. If you find yourself reaching for a fourth flag, +the answer is usually heap size or application allocation behaviour. + +## 4.1 ZGC — product flags (supported, safe to use) + +| Flag | Default (2 GB heap) | What it does | When to touch it | +|---|---|---|---| +| `-XX:+UseZGC` | off | Selects ZGC. Always generational on JDK 24+. | — | +| `-XX:SoftMaxHeapSize` | = `-Xmx` | Soft target the GC heuristic aims for; may be exceeded up to `-Xmx` rather than stall. **`manageable`** — changeable at runtime via `jcmd VM.set_flag`. | Set below `-Xmx` to create spike headroom. The single highest-value ZGC flag. | +| `-XX:ZAllocationSpikeTolerance` | `2.0` | Multiplier on observed allocation rate when predicting when to start a cycle. | Raise (3–5) for bursty services that stall on ramp-up. | +| `-XX:ZCollectionIntervalMinor` | `-1.0` (off) | Force a young cycle every N seconds. | Very spiky duty cycles where rate prediction keeps failing. | +| `-XX:ZCollectionIntervalMajor` | `-1.0` (off) | Force an old cycle every N seconds. | Slow, steady old-gen growth you want amortised. | +| `-XX:ZCollectionInterval` | `0.0` (off) | Legacy combined interval. | Prefer the Minor/Major pair. | +| `-XX:ZCollectionIntervalOnly` | `false` | Collect *only* on the interval, ignoring the allocation-rate heuristic. | Benchmarks and reproducible experiments. Not production. | +| `-XX:ZFragmentationLimit` | `5.0` (%) | A page is added to the relocation set when this much of it is garbage. | Lower = more aggressive compaction, more CPU. Rarely worth changing. | +| `-XX:ZYoungCompactionLimit` | `25.0` (%) | Equivalent threshold for young pages. | Rarely. | +| `-XX:+ZUncommit` | `true`, **but `false` when `-Xms == -Xmx`** | Return unused heap to the OS. | Leave on. Note the automatic disable — see §4.4. | +| `-XX:ZUncommitDelay` | `300` (s) | How long a page must stay unused before being uncommitted. | Lower it in bursty container workloads to give memory back sooner. | + +## 4.2 ZGC — diagnostic flags (need `-XX:+UnlockDiagnosticVMOptions`) + +These appear in no tuning guide. You should almost never set them. You should know they exist, +because they name the mechanisms. + +| Flag | Default | Meaning | +|---|---|---| +| `ZBufferStoreBarriers` | `true` | The generational store barrier appends to a per-thread buffer that is drained later, rather than updating remembered sets inline. | +| `ZTenuringThreshold` | `-1` | Age at which young objects are promoted. `-1` = adaptive. ZGC's answer to `MaxTenuringThreshold`. | +| `ZUseMediumPageSizeRange` | `true` | JDK 25: the medium page size is a **range** chosen at runtime, not a constant. This is why there is no `ZPageSizeMedium` product flag to read. | +| `ZStressFastMediumPageAllocation` | `false` | Test hook. | +| `ZIndexDistributorStrategy` | `0` | Internal work-distribution strategy for parallel phases. | +| `ZStatisticsInterval` | `10` (s) | Interval for `-Xlog:gc+stats`. | + +## 4.3 G1 — the flags that still matter on JDK 25 + +| Flag | Default (2 GB heap) | Notes | +|---|---|---| +| `-XX:+UseG1GC` | default collector on server-class machines | | +| `-XX:MaxGCPauseMillis` | `200` | A *goal*, not a guarantee. G1 sizes the young generation to try to hit it. Setting it very low (e.g. 5) makes G1 shrink young until it collects constantly — a classic self-inflicted throughput cliff. | +| `-XX:G1HeapRegionSize` | ergonomic, `1 MB` at 2 GB heap | Power of two, 1–32 MB, roughly heap/2048. **Determines the humongous threshold** (half a region). | +| `-XX:G1NewSizePercent` / `G1MaxNewSizePercent` | `5` / `60` | Bounds on young generation size. | +| `-XX:InitiatingHeapOccupancyPercent` | `45` | When to start a concurrent cycle. G1 adapts this by default (`-XX:-G1UseAdaptiveIHOP` to pin it). | +| `-XX:G1MixedGCLiveThresholdPercent` | `85` | Old regions above this liveness are not collected in mixed GCs. | +| `-XX:MaxTenuringThreshold` | `15` | Real, documented, product flag — unlike ZGC's. | + +**The humongous threshold is the G1 flag most people should check and don't.** At a 2 GB heap the +region size is 1 MB, so anything over 512 KB is humongous: allocated straight into the old +generation, spanning whole regions, never given the cheap young-collection path. A service that +allocates 1 MB buffers is generating humongous objects on every request. Confirmed on this machine: + +```console +G1HeapRegionSize : 1,048,576 bytes (1 MB) +=> G1 humongous threshold: objects larger than 524,288 bytes (512 KB) go straight to old gen +``` + +Raising `-XX:G1HeapRegionSize=8m` moves the threshold to 4 MB and can transform such a workload. + +## 4.4 Two ergonomic surprises worth knowing + +**`ZUncommit` silently turns itself off when `-Xms == -Xmx`.** Verified: + +```console +$ java -XX:+UseZGC -Xms2g -Xmx2g ... PageSizeDemo + ZUncommit = false +``` + +but with a range (`-Xms512m -Xmx2g`) it is `true`. This is logical — you asked for a fixed heap, so +there is nothing to give back — but it surprises people who set a fixed heap *and* expect memory to +be returned to a container. + +**`SoftMaxHeapSize` defaults to `-Xmx`, which means "no reserve".** Its default is ergonomic and +equal to max heap, so out of the box it does nothing. It only becomes useful when you set it. + +## 4.5 A starting configuration + +For a latency-sensitive JVM service on JDK 25, this is a defensible starting point — not because +these values are optimal, but because each one is there for a stated reason: + +``` +-XX:+UseZGC +-Xms8g -Xmx8g # fixed heap: no resize noise +-XX:SoftMaxHeapSize=6g # 25% reserve for allocation spikes +-XX:ZAllocationSpikeTolerance=3 # this service ramps fast +-Xlog:gc*,gc+alloc=debug:file=gc.log:time,uptime,level,tags:filecount=5,filesize=50m +-XX:StartFlightRecording=settings=profile,filename=app.jfr,maxsize=500m +``` + +plus a `.jfc` override setting `jdk.ZAllocationStall` threshold to `0 ms` +(see [03-allocation-stalls.md](03-allocation-stalls.md) §3.3). + +--- + +Next: [05-logging-and-jfr.md](05-logging-and-jfr.md). diff --git a/docs/05-logging-and-jfr.md b/docs/05-logging-and-jfr.md new file mode 100644 index 0000000..a4c4ebc --- /dev/null +++ b/docs/05-logging-and-jfr.md @@ -0,0 +1,137 @@ +# 5. Reading the logs and the flight recording + +> Runnable companion: [`analysis/.../GcLogParser.java`](../analysis/src/com/ankurm/zgc/analysis/GcLogParser.java) + +## 5.1 The unified log lines you need + +``` +-Xlog:gc*,gc+alloc=debug:file=gc.log:time,uptime,level,tags:filecount=5,filesize=50m +``` + +| Selector | Gives you | +|---|---| +| `gc` | one line per collection | +| `gc+phases` | every sub-phase, including the three ZGC pauses | +| `gc+heap` | before/after occupancy | +| `gc+alloc=debug` | **`Allocation Stall` lines** — off by default, and the reason most people never see stalls | +| `gc+start`, `gc+task`, `gc+ref` | cycle triggers, worker counts, reference processing | + +## 5.2 The category error that makes ZGC look terrible + +A ZGC cycle produces lines like this: + +``` +GC(41) Minor Collection (Allocation Rate) 1180M(58%)->402M(20%) 0.051s +GC(41) y: Pause Mark Start 0.014ms +GC(41) y: Concurrent Mark 32.109ms +GC(41) y: Pause Mark End 0.011ms +GC(41) y: Concurrent Relocate 14.802ms +GC(41) y: Pause Relocate Start 0.009ms +``` + +A naive script that sums every duration on every line reports "51 ms of GC" for this cycle. The real +stop-the-world time is **0.034 ms** — the three `Pause` lines. The `Concurrent` phases ran alongside +the application. + +G1's log has no such trap: its lines are pauses. + +``` +GC(12) Pause Young (Normal) (G1 Evacuation Pause) 1180M->402M(2048M) 16.784ms +``` + +`GcLogParser` in this repository keeps the two categories in separate buckets and prints them +separately, precisely so the comparison cannot be made accidentally. It also prints the sentence +that should accompany every such table: + +``` + Adding the block above to the pause block would be a category error: + concurrent time overlaps application execution by design. +``` + +## 5.3 The same trap exists in JMX + +`GarbageCollectorMXBean.getCollectionTime()` means different things per collector: + +| Bean | Reports | +|---|---| +| `ZGC Minor Cycles` / `ZGC Major Cycles` | **concurrent cycle** duration — not freeze time | +| `ZGC Minor Pauses` / `ZGC Major Pauses` | real stop-the-world time | +| `G1 Young Generation` / `G1 Old Generation` | real stop-the-world time | +| `G1 Concurrent GC` | concurrent cycle — despite sitting in the same bean list | + +A dashboard that sums `getCollectionTime()` over all beans will report ZGC as spending ~1.6 seconds +"in GC" during a 60-second run where its actual freeze time rounded to **0 ms**. That is how ZGC +acquires a reputation for being slow on teams that never changed their dashboard query. + +`GcObserver` in this repository classifies each bean and labels it in the output: + +``` +GC activity during the measured window + ZGC Minor Cycles collections=18 time= 919 ms [cycle (mostly concurrent)] + ZGC Minor Pauses collections=54 time= 0 ms [stop-the-world] + ZGC Major Cycles collections=3 time= 667 ms [cycle (mostly concurrent)] + ZGC Major Pauses collections=15 time= 0 ms [stop-the-world] +``` + +Note also the **3 pauses per cycle** arithmetic: 18 minor cycles → 54 minor pauses. + +## 5.4 JFR events worth enabling + +| Event | Default threshold | Why | +|---|---|---| +| `jdk.ZAllocationStall` | **10 ms** | The real ZGC latency source. Set to `0 ms` and enable stack traces. | +| `jdk.ZPageAllocation` | — | Shows the Small / Medium / Large split; diagnoses *which kind* of pressure. | +| `jdk.ZYoungGarbageCollection` / `jdk.ZOldGarbageCollection` | — | Cycle counts with cause. | +| `jdk.ZRelocationSet`, `jdk.ZRelocationSetGroup` | — | What is being compacted each cycle. | +| `jdk.ZUncommit`, `jdk.ZUnmap` | — | Heap being handed back to the OS. | +| `jdk.GCPhasePause` | — | Works for both collectors; the honest cross-collector pause metric. | + +Starting a recording programmatically, which is what both demos in this repository do: + +```java +try (Recording recording = new Recording()) { + recording.enable("jdk.ZAllocationStall").withoutThreshold().withStackTrace(); + recording.setToDisk(true); + recording.setDestination(Path.of("stalls.jfr")); + recording.start(); + // ... workload ... + recording.stop(); +} +``` + +Reading it back without any external tool: + +```java +try (RecordingFile file = new RecordingFile(Path.of("stalls.jfr"))) { + while (file.hasMoreEvents()) { + RecordedEvent e = file.readEvent(); + if (e.getEventType().getName().equals("jdk.ZAllocationStall")) { ... } + } +} +``` + +> **A `RecordedEvent` gotcha that costs an hour.** `getValue` is declared ` T getValue(String)`. +> Writing `String.valueOf(e.getValue("type"))` lets javac infer `T = char[]`, because +> `String.valueOf(char[])` is an applicable overload — and you get +> `ClassCastException: class java.lang.String cannot be cast to class [C` at runtime. Bind to an +> `Object` local first. Similarly `RecordedEvent::getDuration` is overloaded, so a method reference +> to it will not compile inside a `Comparator.comparing(...)`; use an explicit lambda. + +And from the command line, with the stack that was stalled: + +```console +$ jfr summary stalls.jfr +$ jfr print --events ZAllocationStall --stack-depth 10 stalls.jfr +jdk.ZAllocationStall { + startTime = 22:44:24.809 (2026-07-30) + duration = 2.20 ms + type = "Small" + size = 2.0 MB + eventThread = "allocator-3" (javaThreadId = 43) + stackTrace = [ ... ] +} +``` + +--- + +Next: [06-g1-in-jdk25.md](06-g1-in-jdk25.md). diff --git a/docs/06-methodology.md b/docs/06-methodology.md new file mode 100644 index 0000000..04a2119 --- /dev/null +++ b/docs/06-methodology.md @@ -0,0 +1,136 @@ +# 6. Methodology — how to not publish a meaningless GC benchmark + +Most GC comparisons on the internet are wrong in one of a small number of specific, fixable ways. +This chapter lists them, because a benchmark's credibility is entirely a function of which of these +it avoided. + +## 6.1 Coordinated omission + +**The mistake.** A closed-loop harness — `while (true) { doRequest(); }` — stops issuing load exactly +when the system is least able to serve it. If a 100 ms pause freezes the application, the load +generator does not send requests during those 100 ms. It records one slow request per thread and +moves on. The pause was real; your users experienced it as 100 ms of queueing across ~2000 requests; +the benchmark reports it as a handful of samples. + +**The fix.** Fix the arrival schedule up front and measure from *intended* arrival, not from when +the thread actually got around to the request. + +```java +long intended = start + i * interArrivalNanos; +parkUntil(intended); +long actualStart = System.nanoTime(); +handleRequest(); +long done = System.nanoTime(); + +responseTime.record(done - intended); // honest +serviceTime.record(done - actualStart); // what a closed-loop harness reports +``` + +**How much it matters.** This repository records both and prints the ratio. From the 60-second run +on the reference machine: + +| Collector | p99.9 response time | p99.9 service time | ratio | +|---|---|---|---| +| ZGC | 1.437 ms | 0.143 ms | 10x | +| G1 | 95.169 ms | 0.033 ms | **2910x** | + +A closed-loop benchmark of this exact workload would have concluded that G1's p99.9 is 0.033 ms — +*better* than ZGC's 0.143 ms — and published a chart showing G1 winning on tail latency. The honest +numbers say G1's p99.9 is 66x worse. + +Note that the distortion is not uniform: it is far larger for the collector with larger pauses. So +coordinated omission does not merely add noise, it **systematically favours the collector you are +trying to evaluate against**. + +## 6.2 Benchmarking the sleep instead of the system + +The first version of this harness used `LockSupport.parkNanos(remaining)` between requests. On +Windows a park rounds up to roughly 1 ms, and the inter-arrival interval was 200 µs. Every park +overshot by several intervals; the thread then blasted through the backlog and parked again. The +harness reported a p50 of 0.590 ms for a request that takes 3 µs, and the shape of the distribution +looked plausibly like a GC effect. + +The fix is to park only when the deadline is far away (3 ms here, comfortably beyond the timer +slack) and busy-spin the rest. It costs a core per worker thread, which is why the worker count +defaults to a *third* of the logical CPUs — see §6.4. + +If your latency harness's p50 is much larger than the work it does, suspect your sleep before you +suspect the collector. + +## 6.3 Comparing pause time against cycle time + +Covered in detail in [05-logging-and-jfr.md](05-logging-and-jfr.md). In one line: ZGC's +`GarbageCollectorMXBean` "Cycles" beans and its `Concurrent ...` log lines are **not** freeze time, +and summing them against G1's pause numbers produces a comparison that is off by two orders of +magnitude in G1's favour. + +## 6.4 Starving the collector of CPU + +ZGC does concurrent work on its own threads. If the benchmark's load generator occupies every core — +which a busy-spinning open-loop harness will happily do — those threads cannot run, the collector +falls behind, and you measure a scheduling problem while believing you measured a GC. + +This repository's harness therefore defaults to `availableProcessors() / 3` worker threads and states +so in its output. On the 12-thread reference machine that is 4 spinning workers, leaving 8 logical +CPUs for the JVM's own threads. + +## 6.5 Letting the heap resize during measurement + +`-Xms` ≠ `-Xmx` means the heap grows and shrinks during the run, and you are partly measuring the +resize policy. Every run in this repository uses `-Xms2g -Xmx2g`. + +A side effect worth knowing: **`ZUncommit` automatically becomes `false` when `-Xms == -Xmx`** +(verified in [`results/05-pages-zgc.txt`](../results/05-pages-zgc.txt)). Fixing the heap therefore +also removes uncommit behaviour from the comparison. That is the right call for a benchmark and the +wrong call if uncommit is the thing you wanted to study. + +## 6.6 Forgetting that JMH forks a fresh JVM + +This one silently invalidates a large fraction of published GC microbenchmarks: + +```console +# WRONG -- the fork does not inherit the outer JVM's GC flags +java -XX:+UseZGC -jar benchmarks.jar + +# RIGHT +java -jar benchmarks.jar -jvmArgs "-XX:+UseZGC -Xms2g -Xmx2g" +``` + +JMH starts a separate JVM for each trial. Flags on the outer `java` command configure the *harness*, +not the forked JVM under measurement. Run it the wrong way twice and you get two runs of the default +collector, a pleasingly small difference between them, and a blog post. + +Verify with `-XX:+PrintFlagsFinal` inside the fork, or simply read JMH's own `# VM options:` banner — +it prints the fork's arguments. + +## 6.7 Measuring an empty heap + +A collector with nothing to trace is fast. A benchmark that only allocates immediately-dead garbage +measures the TLAB allocation path and nothing else — and every collector has essentially the same +TLAB path. + +The interesting variable is the **live set**: how much genuinely reachable data must be marked, and +how often it is mutated. This repository's harness holds ~585 MB live in a 2 GB heap and rewrites a +random slot on 20% of requests. `PromotionBench` parameterises the same idea directly through +`survivorDepth`. + +## 6.8 Dead-code elimination + +If the JIT can prove your allocation is unused, it deletes it, and you benchmark an empty loop. Use +JMH's `Blackhole` or return values, and — critically — **check `gc.alloc.rate.norm`** from +`-prof gc`. It reports bytes allocated per operation. If that number is not what the source code +implies, escape analysis removed something and the benchmark is measuring nothing. + +## 6.9 One run is not a measurement + +Everything in [`results/`](../results) is a single run on a single laptop, and is presented as an +illustration of *shape*, not as a benchmark result you should plan capacity from. Ryzen 5 5600U, +Windows 11, 15.3 GB RAM, JDK 25.0.3 — with browser tabs, an OS, and thermal limits. Server hardware, +Linux, and a quiet machine will produce different absolute numbers. + +What generalises is the relationship: **G1 wins the median, ZGC wins the tail, and the gap widens as +the live set grows.** What does not generalise is any specific millisecond figure. + +--- + +Next: [07-corner-cases.md](07-corner-cases.md). diff --git a/docs/07-corner-cases.md b/docs/07-corner-cases.md new file mode 100644 index 0000000..6adff4a --- /dev/null +++ b/docs/07-corner-cases.md @@ -0,0 +1,163 @@ +# 7. Corner cases and things that bite + +The blog post covers the headline concepts. This chapter is the long tail — the behaviours that do +not fit a narrative but do show up in production. Every claim here was verified on +`java 25.0.3+9-LTS-195`; raw dumps in [`results/`](../results). + +## 7.1 ZGC turns off compressed oops. This is the biggest hidden cost. + +On a heap under ~32 GB, HotSpot normally stores references as 32-bit offsets rather than 64-bit +pointers ("compressed oops"), roughly halving the space taken by reference fields. **ZGC cannot do +this**, because it needs the high bits of every pointer for the color. Verified: + +```console +# ZGC, 2 GB heap +bool UseCompressedOops = false {product lp64_product} {ergonomic} + +# G1, same 2 GB heap +bool UseCompressedOops = true {product lp64_product} {ergonomic} +``` + +Consequences, in rough order of how often they surprise people: + +- **Every reference field costs 8 bytes instead of 4.** A `HashMap.Node` (hash, key, value, next) goes + from 32 bytes to 48. A reference-dense heap — many small objects, many pointers, think a large + in-memory graph, an ORM session cache, a JSON DOM — can grow **30–40%** just by switching + collector, with no application change. +- **Object header layout differs**, so heap-size estimates from a G1 heap dump do not transfer. +- **`-Xmx` is not comparable across collectors.** "We gave both 8 GB" is not a fair test if one of + them needs 11 GB to hold the same object graph. This repository uses a byte-array-heavy live set + partly for this reason: `byte[]` payloads are dominated by data, not references, which keeps the + comparison honest. A pointer-heavy live set would have handed ZGC a footprint penalty that has + nothing to do with pause behaviour. +- `UseCompressedClassPointers` stays `true` on both, so class pointers are unaffected. + +If you are evaluating ZGC and your heap is full of small objects, measure footprint before you +measure latency. + +## 7.2 ZGC large pages are never relocated + +ZGC's Large pages hold exactly one object each and are **freed, not compacted**. A heap with many +long-lived multi-megabyte objects therefore fragments in a way ZGC structurally cannot fix. G1 has +the mirror problem with humongous regions, but G1 has a Full GC that *can* compact them (at +enormous cost). + +Verified placement on a 2 GB heap — note the last line, which is the one that catches people: + +```console +ZGC pages actually allocated while creating the objects above + page type count total bytes + Large 2 25,165,824 + Medium 1 33,554,432 +``` + +Two Large pages for the 4 MB and 16 MB allocations. **The 4 MB one is the surprise:** the documented +medium-object limit is 4 MB, but `new byte[4 * 1024 * 1024]` is 4 MB *plus a 16-byte array header*, +which is over the limit. It gets an 8 MB Large page to itself — a 2x footprint amplification caused +by sixteen bytes. If you pool buffers, pool them at `4 MB - 64` rather than exactly 4 MB. + +## 7.3 G1's humongous threshold is lower than people think + +At a 2 GB heap, `G1HeapRegionSize` is ergonomically 1 MB, so **anything over 512 KB is humongous**: +allocated straight into the old generation, spanning whole regions, never eligible for the cheap +young-collection path. + +```console +G1HeapRegionSize : 1,048,576 bytes (1 MB) +=> G1 humongous threshold: objects larger than 524,288 bytes (512 KB) go straight to old gen +``` + +A service that reads 1 MB request bodies into a single `byte[]` is producing humongous garbage on +every request. `-XX:G1HeapRegionSize=8m` moves the threshold to 4 MB and can be transformative. +This is one of the few G1 flags that regularly delivers a large win, and it is invisible unless you +go looking. + +## 7.4 Virtual thread stacks live on the heap + +A mounted virtual thread runs on a carrier's stack, but an **unmounted** one has its stack copied +into the heap as `StackChunk` objects. So a service with 200,000 parked virtual threads is holding +200,000 medium-sized, medium-lived objects that the collector must trace. + +This interacts badly with a naive reading of "virtual threads are cheap": they are cheap in +*scheduler* terms and not free in *GC* terms. Applications that move from a 200-thread pool to +200,000 virtual threads often see their live set and promotion rate change shape entirely, which is +exactly the regime where the ZGC-vs-G1 answer flips. If you have made that migration, re-run your GC +choice; the decision you made before it is stale. + +## 7.5 `System.gc()` behaves differently + +`ExplicitGCInvokesConcurrent` is `false` by default on **both** collectors here. Under G1 that means +an explicit `System.gc()` triggers a **Full GC** — a stop-the-world compaction. Under ZGC it +triggers a major cycle, most of which is still concurrent, so the blast radius is much smaller. + +Libraries that call `System.gc()` (some direct-`ByteBuffer` cleanup paths, some test harnesses, some +profilers) are therefore far more damaging on G1. `-XX:+ExplicitGCInvokesConcurrent` is a cheap +mitigation on G1; `-XX:+DisableExplicitGC` is the blunt one. + +Note that `StoreBarrierBench` in this repository calls `System.gc()` twice in `@Setup` — deliberately, +to force the array into the old generation before measurement, and outside the measured window. + +## 7.6 Reference processing still stops the world briefly + +Weak, soft, phantom references and finalizers are processed during specific phases. On ZGC this +happens under `Concurrent Process Non-Strong`, visible in the log: + +``` +Concurrent Process Non-Strong n=8 total= 5.635 ms max= 0.984 ms +``` + +Concurrent, therefore not freeze time — but a heap with millions of weak references still costs +real CPU and can extend cycle duration enough to trigger allocation stalls indirectly. `WeakHashMap` +at scale, and caches built on `SoftReference`, are the usual suspects. Soft references in particular +interact with `SoftRefLRUPolicyMSPerMB` and are cleared based on *free heap*, which behaves very +differently when `SoftMaxHeapSize` is set. + +## 7.7 `ZUncommit` disables itself on a fixed heap + +```console +# -Xms2g -Xmx2g +ZUncommit = false +``` + +Logical — there is nothing to give back — but it surprises teams who set a fixed heap for +predictability *and* expect memory returned to the container. If you want uncommit, you must give +`-Xms` and `-Xmx` different values, and tune `ZUncommitDelay` (default 300 s) down if you want it to +happen promptly. + +## 7.8 GC thread counts differ by default + +```console +ZGC : ParallelGCThreads = 8, ConcGCThreads = 3 +G1 : ParallelGCThreads = 10, ConcGCThreads = 3 +``` + +On the same 12-thread machine. If you pin GC threads for consistency across a fleet, you are +overriding two different ergonomic decisions with one number, and one of the collectors will be +mis-sized. Prefer leaving them ergonomic unless you are running in a CPU-limited container, where +you should set them explicitly because the JVM's view of `availableProcessors()` may not match the +cgroup quota. + +## 7.9 Container limits + +Both collectors respect cgroup limits, but the failure modes differ: + +- ZGC's higher footprint (see §7.1) plus its need for headroom means a container sized for G1 will + push ZGC into allocation stalls. Budget more memory, not the same memory. +- `-XX:MaxRAMPercentage` is the right knob in containers; `-Xmx` hard-codes a number that will be + wrong after the next resize. +- ZGC reserves a large *virtual* address range. Tools that alarm on virtual size rather than RSS + will report frightening numbers. Alarm on RSS. + +## 7.10 Things that are the same and often assumed not to be + +- **String deduplication** works on ZGC (since JDK 18), not just G1. `-XX:+UseStringDeduplication` + is off by default on both. +- **Class unloading** happens on both, during major/concurrent cycles. +- **TLABs** work identically; the fast allocation path is a pointer bump on both. +- **Heap dumps** (`jcmd GC.heap_dump`) work the same and are stop-the-world on both. +- **`-XX:+AlwaysPreTouch`** is `false` by default on both, and is worth turning on for both if you + care about first-minute latency. + +--- + +Next: [08-choosing.md](08-choosing.md). diff --git a/docs/08-choosing.md b/docs/08-choosing.md new file mode 100644 index 0000000..74bc84f --- /dev/null +++ b/docs/08-choosing.md @@ -0,0 +1,97 @@ +# 8. Choosing a collector on JDK 25 + +## 8.1 The short version + +**G1 is still the right default.** It is the default for a reason: it is balanced, it needs no +tuning to be adequate, and it wins the median. Switch to ZGC when you have a *stated* tail-latency +requirement that G1 is measurably missing — not because ZGC is newer. + +## 8.2 What the measurements actually say + +From the 60-second run in this repository (Ryzen 5 5600U, Windows 11, JDK 25.0.3, 2 GB heap, +~585 MB live, 20,000 req/s, ~328 MB/s allocation rate): + +| Metric | ZGC | G1 | Winner | +|---|---|---|---| +| p50 response time | 0.006 ms | 0.005 ms | G1, barely | +| p90 | 0.009 ms | 0.009 ms | tie | +| p99 | 0.029 ms | 8.042 ms | **ZGC, 277x** | +| p99.9 | 1.437 ms | 95.169 ms | **ZGC, 66x** | +| p99.99 | 23.675 ms | 126.949 ms | **ZGC, 5.4x** | +| max | 32.178 ms | 133.018 ms | ZGC | +| mean | 0.016 ms | 0.388 ms | ZGC | +| total stop-the-world time | **1.503 ms** | **1,139.6 ms** | **ZGC, 758x** | +| longest single pause | 0.054 ms | 104.449 ms | ZGC | +| Full GCs / evacuation failures | 0 / 0 | 4 / 16 | ZGC | + +Note the shape: the two collectors are **indistinguishable up to p90**. Everything ZGC buys you is +in the tail. If your SLO is a mean or a p95, this entire table is telling you to stay on G1 and +spend the effort elsewhere. + +Note also that ZGC is not magic: its own p99.99 is 23.7 ms. Those are allocation stalls (the GC log +for that run contains 40 of them), not pauses. ZGC moved the latency source, it did not delete it. + +## 8.3 A decision procedure + +Work through it in order. Stop at the first "yes". + +1. **Is GC actually your problem?** Get a JFR recording and look at `jdk.GCPhasePause` and + `jdk.ZAllocationStall` against your request latency. Most "GC problems" are lock contention, + downstream calls, or connection-pool starvation. Changing collector will not fix those and will + cost you a week. +2. **Is your heap small (< 4 GB) and your SLO a mean or p95?** Stay on G1. ZGC's advantages need a + tail requirement and a heap large enough that marking cost matters. +3. **Do you have a hard tail-latency SLO — p99 or p99.9 in single-digit or low-double-digit + milliseconds — that G1 is missing?** This is the case ZGC was built for. Go to step 5. +4. **Is your heap very large (> 32 GB) with a large live set?** G1's pause time scales with live + data in the collection set; ZGC's does not. ZGC becomes increasingly favourable as the heap + grows. Go to step 5. +5. **Can you afford the footprint?** ZGC needs headroom (§8.4) *and* loses compressed oops + ([07-corner-cases.md](07-corner-cases.md) §7.1). Budget 30–50% more memory than the equivalent + G1 deployment, more if your heap is reference-dense. If you cannot, ZGC will stall and you will + conclude — wrongly — that ZGC is bad. +6. **Is your workload throughput-bound with a hot pointer-chasing inner loop?** ZGC's load barrier + is a real, permanent tax on reference loads. Batch jobs, analytics, and anything that walks large + object graphs should measure before switching. Consider Parallel GC instead — for a batch job + with no latency requirement, Parallel still beats both on raw throughput. + +## 8.4 Sizing ZGC + +The single most common ZGC failure is a heap sized as if it were a G1 heap. + +- Start at **1.5x** the `-Xmx` you used for G1, then measure. +- Set `SoftMaxHeapSize` to roughly **75%** of `-Xmx` so there is a reserve for allocation spikes. +- Watch `jdk.ZAllocationStall` (threshold `0 ms`), not pause time. If stalls are non-zero under + normal load, you are under-provisioned. +- If stalls are concentrated on Large pages, the fix is in your application's allocation sizes, not + in the heap size. + +## 8.5 When the answer is neither + +- **Parallel GC** (`-XX:+UseParallelGC`) — batch jobs, ETL, anything where wall-clock throughput is + the only metric and a multi-second pause is irrelevant. Still the throughput champion. +- **Serial GC** (`-XX:+UseSerialGC`) — small containers, single-core, short-lived processes. Lowest + overhead, smallest footprint, fastest start-up. +- **Shenandoah** (`-XX:+UseShenandoahGC`) — the other concurrent-compacting collector. Broadly + similar goals to ZGC with a different barrier design (Brooks-style forwarding rather than colored + pointers); it keeps compressed oops, which makes it interesting precisely where §7.1 hurts. + Worth benchmarking as a third option if footprint is your constraint. + +## 8.6 The honest summary + +ZGC does not make garbage collection free. It converts a **rare, large, correlated** cost — a +stop-the-world pause that hits every thread at once — into a **constant, small, uncorrelated** cost: +barrier work on every reference access, plus a memory footprint premium. + +For a request-serving system with a tail-latency SLO, that trade is close to unambiguously good, and +JDK 25 is the first LTS where you get it without an opt-in flag or a non-generational fallback to +worry about. + +For a batch job, it is a straightforward loss. + +Most systems are somewhere in between, which is why the only defensible answer is to run +[`scripts/run-all.ps1`](../scripts/run-all.ps1) against a workload shaped like yours. + +--- + +Back to the [README](../README.md). diff --git a/env/Env.java b/env/Env.java new file mode 100644 index 0000000..ef23c7b --- /dev/null +++ b/env/Env.java @@ -0,0 +1,74 @@ +// Env.java -- prints everything a GC measurement needs in order to be reproducible. +// +// Run it (JDK 25 single-file source launch, no compile step needed): +// +// java env/Env.java +// java -XX:+UseZGC -Xms2g -Xmx2g env/Env.java +// java -XX:+UseG1GC -Xms2g -Xmx2g env/Env.java +// +// Why this file exists: a GC benchmark without the environment printed next to it +// is an anecdote. Heap size, CPU count, GC selection and the *ergonomic* values the +// JVM picked for you (SoftMaxHeapSize, region size, GC thread counts) all move the +// numbers more than the code under test does. + +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.RuntimeMXBean; + +public final class Env { + + public static void main(String[] args) { + RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); + + System.out.println("=== Runtime ==="); + System.out.printf("java.version : %s%n", System.getProperty("java.version")); + System.out.printf("java.vm.name : %s%n", System.getProperty("java.vm.name")); + System.out.printf("java.vm.version : %s%n", System.getProperty("java.vm.version")); + System.out.printf("java.vendor : %s%n", System.getProperty("java.vendor")); + System.out.printf("os.name / os.arch : %s / %s%n", + System.getProperty("os.name"), System.getProperty("os.arch")); + System.out.printf("availableProcessors : %d%n", Runtime.getRuntime().availableProcessors()); + System.out.printf("maxMemory (-Xmx) : %s%n", mb(Runtime.getRuntime().maxMemory())); + System.out.printf("totalMemory (now) : %s%n", mb(Runtime.getRuntime().totalMemory())); + + System.out.println(); + System.out.println("=== Collector in use ==="); + // On JDK 25 the ZGC bean names are "ZGC Major Cycles" / "ZGC Minor Cycles" (and the + // matching "... Pauses" beans). The presence of BOTH a Minor and a Major bean is the + // cheapest programmatic proof that you are running *generational* ZGC. + boolean sawMinor = false, sawMajor = false; + for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { + System.out.printf(" bean: %-24s count=%-6d timeMs=%d%n", + gc.getName(), gc.getCollectionCount(), gc.getCollectionTime()); + String n = gc.getName().toLowerCase(); + if (n.contains("minor") || n.contains("young")) sawMinor = true; + if (n.contains("major") || n.contains("old") || n.contains("full")) sawMajor = true; + } + System.out.printf(" generational? : %s%n", + (sawMinor && sawMajor) ? "yes (separate young + old cycles reported)" : "no / single cycle"); + + System.out.println(); + System.out.println("=== Memory pools ==="); + for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { + System.out.printf(" %-28s type=%-10s max=%s%n", + pool.getName(), pool.getType(), mb(pool.getUsage().getMax())); + } + + System.out.println(); + System.out.println("=== JVM arguments actually in effect ==="); + if (runtime.getInputArguments().isEmpty()) { + System.out.println(" (none -- everything below is ergonomic)"); + } + runtime.getInputArguments().forEach(a -> System.out.println(" " + a)); + + System.out.println(); + System.out.println("Tip: dump every ergonomic value the JVM chose with"); + System.out.println(" java -XX:+UseZGC -Xms2g -Xmx2g -XX:+PrintFlagsFinal -version"); + } + + private static String mb(long bytes) { + if (bytes < 0) return "unbounded"; + return String.format("%,d bytes (%.0f MB)", bytes, bytes / 1024.0 / 1024.0); + } +} diff --git a/internals/src/com/ankurm/zgc/internals/PageSizeDemo.java b/internals/src/com/ankurm/zgc/internals/PageSizeDemo.java new file mode 100644 index 0000000..d231927 --- /dev/null +++ b/internals/src/com/ankurm/zgc/internals/PageSizeDemo.java @@ -0,0 +1,222 @@ +package com.ankurm.zgc.internals; + +import com.sun.management.HotSpotDiagnosticMXBean; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; + +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * Where does a large object actually go? + * + *

Both collectors chop the heap into fixed units, and both have a special path for objects too + * big for one unit -- but the thresholds, the names and the consequences are completely different, + * and almost nothing written about ZGC explains the ZGC half. + * + *

G1: regions and humongous objects

+ * G1 divides the heap into equal regions ({@code G1HeapRegionSize}, chosen ergonomically as roughly + * heap/2048, clamped to a power of two between 1 MB and 32 MB). An object larger than half a + * region is humongous: it is allocated directly into the old generation, in a run of + * contiguous regions, and it never gets the cheap young-collection treatment. On a 2 GB heap the + * region size is typically 1 MB, so an ordinary 600 KB byte array is already humongous. Humongous + * allocation is a well known source of surprise fragmentation and premature concurrent cycles. + * + *

ZGC: three page classes

+ * ZGC uses pages in three size classes rather than one region size: + *
    + *
  • Small -- 2 MB pages, for objects up to 1/8 of the page (256 KB).
  • + *
  • Medium -- 32 MB by default, for objects up to 4 MB. Since JDK 23 the medium page + * size is chosen ergonomically from the heap size rather than being hard-wired, which is why + * {@code ZPageSizeMedium} may read differently on a small heap than on a large one.
  • + *
  • Large -- one page per object, sized to the object. Despite the name these are the + * pages ZGC cannot relocate cheaply; a large page is not compacted, it is simply + * freed when the object dies.
  • + *
+ * + *

The practical consequence: on G1 a moderately large array is a special case at ~512 KB; on ZGC + * it stays ordinary until 256 KB, becomes "medium" up to 4 MB, and only then becomes a page of its + * own. Applications that allocate many 1-4 MB buffers behave very differently on the two. + * + *

How this program shows it

+ * It reads {@code G1HeapRegionSize} / {@code ZPageSizeMedium} straight out of the running VM via + * {@link HotSpotDiagnosticMXBean}, prints the derived thresholds, then allocates one object of each + * of several sizes while a JFR recording captures {@code jdk.ZPageAllocation}. Reading those events + * back shows, empirically, which page class each allocation landed in -- not from documentation, + * from the running VM. + * + *
+ * java -XX:+UseZGC  -Xms2g -Xmx2g -cp out com.ankurm.zgc.internals.PageSizeDemo
+ * java -XX:+UseG1GC -Xms2g -Xmx2g -cp out com.ankurm.zgc.internals.PageSizeDemo
+ * 
+ */ +public final class PageSizeDemo { + + /** Sizes chosen to straddle every threshold discussed above. */ + private static final int[] SIZES = { + 64 * 1024, // 64 KB -- small on both + 256 * 1024, // 256 KB -- exactly ZGC's small-object limit + 512 * 1024, // 512 KB -- humongous on G1 with a 1 MB region + 2 * 1024 * 1024, // 2 MB -- ZGC medium + 4 * 1024 * 1024, // 4 MB -- ZGC's medium-object limit + 16 * 1024 * 1024, // 16 MB -- ZGC large, multi-region humongous on G1 + }; + + private static Object[] keepAlive; + + public static void main(String[] args) throws Exception { + HotSpotDiagnosticMXBean diag = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); + + System.out.println("=".repeat(74)); + System.out.println("Page / region geometry as reported by THIS JVM"); + System.out.println("=".repeat(74)); + System.out.printf("max heap : %,d MB%n", Runtime.getRuntime().maxMemory() / 1024 / 1024); + + String regionSize = flag(diag, "G1HeapRegionSize"); + boolean g1 = "true".equals(flag(diag, "UseG1GC")); + boolean zgc = "true".equals(flag(diag, "UseZGC")); + + System.out.printf("UseG1GC / UseZGC : %s / %s%n", g1, zgc); + System.out.printf("G1HeapRegionSize : %s%n", human(regionSize)); + + if (g1 && isNumeric(regionSize)) { + long region = Long.parseLong(regionSize); + System.out.printf("=> G1 humongous threshold: objects larger than %s go straight to old gen%n", + human(String.valueOf(region / 2))); + } + if (zgc) { + System.out.println("=> ZGC small pages are 2 MB; objects up to 1/8 of a page (256 KB) use them."); + System.out.println(" Larger objects use a medium page, and anything bigger gets a Large page"); + System.out.println(" of its own -- which ZGC frees rather than relocates."); + System.out.println(); + System.out.println("ZGC internals flags visible in this JVM"); + // These are all {diagnostic} rather than {product}, which is why they appear in no + // tuning guide -- but they name the mechanisms that matter. + for (String name : new String[]{ + "ZUseMediumPageSizeRange", // JDK 25: medium page size is a RANGE, not a constant + "ZBufferStoreBarriers", // the store barrier added by generational ZGC, buffered + "ZTenuringThreshold", // -1 == adaptive; ZGC ages objects like any generational GC + "ZIndexDistributorStrategy", + "ZStatisticsInterval", + "ZFragmentationLimit", + "ZCollectionIntervalMinor", + "ZCollectionIntervalMajor", + "ZAllocationSpikeTolerance", + "ZUncommit", + "ZUncommitDelay", + "SoftMaxHeapSize"}) { + String v = flag(diag, name); + if (!v.startsWith("n/a")) { + System.out.printf(" %-28s = %s%n", name, name.contains("Size") ? human(v) : v); + } + } + } + System.out.println(); + + Path jfr = Path.of("page-allocations.jfr"); + Map observed = new LinkedHashMap<>(); + + try (Recording recording = new Recording()) { + try { + recording.enable("jdk.ZPageAllocation").withoutThreshold(); + } catch (RuntimeException e) { + System.out.println("(jdk.ZPageAllocation unavailable -- not running ZGC)"); + } + recording.setToDisk(true); + recording.setDestination(jfr); + recording.start(); + + keepAlive = new Object[SIZES.length]; + for (int i = 0; i < SIZES.length; i++) { + keepAlive[i] = new byte[SIZES[i]]; + ((byte[]) keepAlive[i])[0] = 1; + } + recording.stop(); + } + + if (Files.exists(jfr)) { + Map byType = new TreeMap<>(); // pageType -> {count, totalBytes} + try (RecordingFile file = new RecordingFile(jfr)) { + while (file.hasMoreEvents()) { + RecordedEvent e = file.readEvent(); + if (!e.getEventType().getName().equals("jdk.ZPageAllocation")) continue; + // NOTE: RecordedEvent.getValue is declared T getValue(String). Writing + // String.valueOf(e.getValue("type")) lets javac infer T = char[] (because + // String.valueOf(char[]) is an applicable overload) and blows up at runtime + // with ClassCastException: String cannot be cast to [C. Bind to Object first. + Object typeValue = e.hasField("type") ? e.getValue("type") : null; + Object sizeValue = e.hasField("size") ? e.getValue("size") : null; + String type = typeValue == null ? "?" : typeValue.toString(); + long size = sizeValue instanceof Number n ? n.longValue() : 0L; + long[] agg = byType.computeIfAbsent(type, k -> new long[2]); + agg[0]++; + agg[1] += size; + } + } + if (byType.isEmpty()) { + System.out.println("No jdk.ZPageAllocation events (expected under G1)."); + } else { + System.out.println("ZGC pages actually allocated while creating the objects above"); + System.out.printf(" %-10s %-10s %s%n", "page type", "count", "total bytes"); + byType.forEach((type, agg) -> + System.out.printf(" %-10s %-10d %,d%n", type, agg[0], agg[1])); + } + Files.deleteIfExists(jfr); + } + + System.out.println(); + System.out.println("Objects allocated in this run"); + for (int size : SIZES) { + System.out.printf(" %-24s %s%n", human(String.valueOf(size)), classify(size, regionSize, g1)); + } + System.out.println(); + System.out.println("checksum: " + keepAlive.length); + } + + /** + * Predicts the placement. For ZGC this is only a prediction -- the authoritative answer is the + * {@code jdk.ZPageAllocation} table printed above, which comes from the running collector. + */ + private static String classify(int size, String regionSize, boolean g1) { + if (g1) { + if (!isNumeric(regionSize)) return "(unknown region size)"; + long half = Long.parseLong(regionSize) / 2; + return size > half + ? "HUMONGOUS on G1 -- allocated directly in old gen, spans whole regions" + : "ordinary G1 allocation in an eden region"; + } + // The limits apply to the *object*, header included -- not to the array length you asked + // for. A new byte[4*1024*1024] is 4 MB + 16 bytes of header, which is over the medium-object + // limit, so it lands on a Large page. Exactly the sort of off-by-a-header that makes a + // capacity plan wrong by 8 MB per buffer. The JFR table above is the ground truth. + long objectBytes = size + 16L; + if (objectBytes <= 256 * 1024) return "expect ZGC Small page (2 MB, shared with other objects)"; + if (objectBytes <= 4L * 1024 * 1024) return "expect ZGC Medium page (shared; size is a range in JDK 25)"; + return "expect ZGC Large page -- one page for this object, freed not relocated"; + } + + private static String flag(HotSpotDiagnosticMXBean diag, String name) { + try { + return diag.getVMOption(name).getValue(); + } catch (IllegalArgumentException e) { + return "n/a on this collector"; + } + } + + private static boolean isNumeric(String s) { + return s != null && s.chars().allMatch(Character::isDigit) && !s.isEmpty(); + } + + private static String human(String bytes) { + if (!isNumeric(bytes)) return bytes; + long b = Long.parseLong(bytes); + if (b == 0) return "0 (ergonomic / not applicable)"; + if (b >= 1024 * 1024) return "%,d bytes (%d MB)".formatted(b, b / 1024 / 1024); + return "%,d bytes (%d KB)".formatted(b, b / 1024); + } +} diff --git a/jmh/pom.xml b/jmh/pom.xml new file mode 100644 index 0000000..b2d89f6 --- /dev/null +++ b/jmh/pom.xml @@ -0,0 +1,93 @@ + + + + 4.0.0 + + com.ankurm.zgc + zgc-jmh + 1.0.0 + jar + ZGC vs G1 JMH benchmarks (JDK 25) + + + UTF-8 + 25 + 1.37 + benchmarks + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${maven.compiler.release} + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.3 + + + package + shade + + ${uberjar.name} + + + org.openjdk.jmh.Main + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + diff --git a/jmh/src/main/java/com/ankurm/zgc/jmh/AllocationBench.java b/jmh/src/main/java/com/ankurm/zgc/jmh/AllocationBench.java new file mode 100644 index 0000000..3e03d59 --- /dev/null +++ b/jmh/src/main/java/com/ankurm/zgc/jmh/AllocationBench.java @@ -0,0 +1,70 @@ +package com.ankurm.zgc.jmh; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +/** + * How fast can the application allocate short-lived objects? + * + *

This is the benchmark everyone writes first, and on its own it is close to useless -- but it + * is useful as a baseline, because it isolates the one thing that is almost purely a + * function of the allocation path rather than of the marking or relocation machinery. + * + *

What it actually measures: + * + *

    + *
  • The thread-local allocation buffer (TLAB) fast path, which is a pointer bump plus a bounds + * check on every collector. G1 and ZGC use the same idea here, so raw allocation of tiny + * objects tends to be a near-tie.
  • + *
  • The size of the young generation, indirectly: the more often the allocator has to + * refill a TLAB from a fresh region/page, the more the collector's page-allocation path + * shows up.
  • + *
+ * + *

Run it with {@code -prof gc} and read the {@code gc.alloc.rate.norm} column -- it reports + * bytes allocated per operation. If that number is not exactly what you expect from the source + * code, escape analysis removed an allocation and you are benchmarking nothing: + * + *

+ * java -jar target/benchmarks.jar AllocationBench -prof gc -jvmArgs "-XX:+UseZGC -Xms2g -Xmx2g"
+ * 
+ */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 5, time = 3) +@Fork(1) +public class AllocationBench { + + /** + * Object sizes chosen to straddle the boundaries that matter: + * 64 B is a typical small POJO/array, 1 KB is a request buffer, 32 KB is large enough that + * on G1 it approaches the humongous threshold for small region sizes and on ZGC it stops + * fitting neatly into the small-page allocation path. + */ + @Param({"64", "1024", "32768"}) + public int size; + + @Benchmark + public byte[] allocate() { + // Returned (not consumed by a Blackhole) so JMH's return-value sink keeps it alive just + // long enough to prevent scalar replacement, without adding a second store to the loop. + byte[] b = new byte[size]; + b[0] = 1; + return b; + } + + /** + * The same allocation, but immediately dead. Comparing the two shows how much of the cost is + * the allocation itself versus keeping the reference alive for one more instruction. + */ + @Benchmark + public void allocateAndDrop(Blackhole bh) { + byte[] b = new byte[size]; + b[0] = 1; + bh.consume(b[0]); + } +} diff --git a/jmh/src/main/java/com/ankurm/zgc/jmh/LoadBarrierBench.java b/jmh/src/main/java/com/ankurm/zgc/jmh/LoadBarrierBench.java new file mode 100644 index 0000000..23d31e3 --- /dev/null +++ b/jmh/src/main/java/com/ankurm/zgc/jmh/LoadBarrierBench.java @@ -0,0 +1,120 @@ +package com.ankurm.zgc.jmh; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +/** + * Isolates the cost of ZGC's load barrier. + * + *

This is the benchmark that explains ZGC's throughput deficit, and almost nobody publishes it. + * + *

What a load barrier is

+ * ZGC stores metadata in unused high bits of every heap pointer ("colored pointers"). Whenever your + * code reads a reference field, the JIT emits a few extra instructions that check those bits and, + * if the pointer is stale (its object has been relocated, or has not been marked yet in this + * cycle), fix it up before your code ever sees it. That fix-up is what lets ZGC relocate objects + * while the application keeps running -- there is no stop-the-world phase in which pointers are + * corrected, because every read corrects its own pointer lazily. + * + *

The price is that every reference load costs more. Not primitive loads -- {@code + * int[]} and {@code long} fields are untouched -- only loads of references. G1 has no read barrier + * at all, so on a workload that is dominated by chasing pointers through a large object graph, G1 + * has a structural advantage. + * + *

How this benchmark separates the two

+ * {@link #chaseReferences()} walks a linked structure: every step is a reference load and therefore + * a barrier. {@link #sumPrimitives()} walks an {@code int[]} of identical length: same memory + * traffic, same cache behaviour, zero reference loads and therefore zero barriers. The difference + * between the two, measured under ZGC and again under G1, is as close to "the barrier tax" as you + * can get without reading assembly. + * + *

Both variants are also affected by whether a GC cycle is in progress -- ZGC's barrier is + * cheapest when the heap is "clean" and does more work during marking and relocation. Running with + * {@code -XX:ZCollectionInterval=1} forces cycles during the measurement and shows the worst case. + * + *

+ * java -jar target/benchmarks.jar LoadBarrierBench -jvmArgs "-XX:+UseZGC  -Xms2g -Xmx2g"
+ * java -jar target/benchmarks.jar LoadBarrierBench -jvmArgs "-XX:+UseG1GC -Xms2g -Xmx2g"
+ * 
+ */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@State(Scope.Benchmark) +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 5, time = 3) +@Fork(1) +public class LoadBarrierBench { + + /** Node count. 1<<20 nodes is ~32 MB of nodes -- comfortably beyond L3 on most desktops. */ + @Param({"1048576"}) + public int nodes; + + static final class Node { + Node next; // reference field -- a load barrier fires on every read of this + int value; + } + + private Node head; + private int[] primitives; + + @Setup(Level.Trial) + public void setup() { + // Build the chain in a shuffled order so that pointer-chasing genuinely misses cache + // rather than walking linearly through memory the prefetcher can predict. A benchmark + // whose "random" walk is actually sequential measures the prefetcher, not the barrier. + Node[] all = new Node[nodes]; + for (int i = 0; i < nodes; i++) { + all[i] = new Node(); + all[i].value = i; + } + int[] order = new int[nodes]; + for (int i = 0; i < nodes; i++) order[i] = i; + java.util.Random rnd = new java.util.Random(20260730L); + for (int i = nodes - 1; i > 0; i--) { + int j = rnd.nextInt(i + 1); + int t = order[i]; order[i] = order[j]; order[j] = t; + } + for (int i = 0; i < nodes - 1; i++) { + all[order[i]].next = all[order[i + 1]]; + } + head = all[order[0]]; + + primitives = new int[nodes]; + for (int i = 0; i < nodes; i++) primitives[i] = i; + } + + /** Reference-load dominated: one load barrier per step under ZGC, none under G1. */ + @Benchmark + public int chaseReferences() { + int sum = 0; + Node n = head; + while (n != null) { + sum += n.value; + n = n.next; // <-- ZGC load barrier + } + return sum; + } + + /** Primitive-load control: same element count, no reference loads, no barriers on any GC. */ + @Benchmark + public int sumPrimitives() { + int sum = 0; + for (int v : primitives) sum += v; + return sum; + } + + /** + * A "hot field" read of the same reference over and over. ZGC's barrier has a fast path that is + * just a test-and-branch when the pointer is already good, so this variant shows the *floor* + * of the barrier cost -- what you pay when nothing needs fixing up. + */ + @Benchmark + public void readSameReferenceRepeatedly(Blackhole bh) { + Node n = head; + for (int i = 0; i < 1024; i++) { + bh.consume(n.next); // <-- barrier, but always on an already-good pointer + } + } +} diff --git a/jmh/src/main/java/com/ankurm/zgc/jmh/PromotionBench.java b/jmh/src/main/java/com/ankurm/zgc/jmh/PromotionBench.java new file mode 100644 index 0000000..2f5564f --- /dev/null +++ b/jmh/src/main/java/com/ankurm/zgc/jmh/PromotionBench.java @@ -0,0 +1,75 @@ +package com.ankurm.zgc.jmh; + +import org.openjdk.jmh.annotations.*; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.concurrent.TimeUnit; + +/** + * Medium-lived objects: the workload that decides whether a generational collector actually helps. + * + *

Why this exists

+ * The weak generational hypothesis says most objects die young. When that holds, a young collection + * is nearly free: the collector copies out the few survivors and declares the whole young region + * empty. When it does not hold -- when a large fraction of objects survive long enough to + * be promoted -- a generational collector does its work twice: once tracing them in the young + * generation, once again after promotion. + * + *

Real services sit in the middle. A request-scoped object graph that lives for the duration of + * a slow downstream call, a batch accumulating results, a connection buffer pool refilling itself: + * all of these produce objects that are neither immediately dead nor permanently live. This + * benchmark parameterises exactly that. + * + *

{@code survivorDepth} is the number of objects held alive at any moment. Depth 0 is pure + * young garbage (the friendly case). Large depths force promotion, and on generational ZGC that + * means the promoted objects must also be handled by the old-generation cycle. + * + *

This is also the benchmark where the JDK 25 G1 remembered-set improvements show up: with a + * high promotion rate, G1's mixed collections have more cross-region references to track. + * + *

+ * java -jar target/benchmarks.jar PromotionBench -prof gc -jvmArgs "-XX:+UseZGC -Xms2g -Xmx2g"
+ * 
+ */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 5, time = 3) +@Fork(1) +public class PromotionBench { + + /** + * How many previously allocated payloads stay reachable. + * 0 -> every object dies immediately (best case for any generational GC) + * 4096 -> a modest working set that mostly dies in the young generation + * 262144 -> a large working set that forces sustained promotion into the old generation + */ + @Param({"0", "4096", "262144"}) + public int survivorDepth; + + @Param({"512"}) + public int payloadBytes; + + private Deque survivors; + + @Setup(Level.Iteration) + public void setup() { + survivors = new ArrayDeque<>(Math.max(16, survivorDepth)); + } + + @Benchmark + public byte[] allocateWithSurvival() { + byte[] payload = new byte[payloadBytes]; + payload[0] = 1; + if (survivorDepth == 0) { + return payload; // dies at the end of this method + } + survivors.addLast(payload); + if (survivors.size() > survivorDepth) { + return survivors.pollFirst(); // evicted after surviving `survivorDepth` allocations + } + return payload; + } +} diff --git a/jmh/src/main/java/com/ankurm/zgc/jmh/StoreBarrierBench.java b/jmh/src/main/java/com/ankurm/zgc/jmh/StoreBarrierBench.java new file mode 100644 index 0000000..a40c0ef --- /dev/null +++ b/jmh/src/main/java/com/ankurm/zgc/jmh/StoreBarrierBench.java @@ -0,0 +1,104 @@ +package com.ankurm.zgc.jmh; + +import org.openjdk.jmh.annotations.*; + +import java.util.concurrent.TimeUnit; + +/** + * Isolates the cost of the write/store barrier -- the mechanism every generational collector + * needs in order to collect the young generation without scanning the old one. + * + *

The problem being solved

+ * A young collection wants to mark only young objects. But an old object may hold the only + * reference to a young object. If the collector ignored the old generation entirely it would free a + * live object. Scanning the whole old generation would defeat the point of a young collection. So + * every generational collector intercepts reference stores and records the ones that create an + * old-to-young edge. + * + *
    + *
  • G1 dirties a card (a 512-byte granule of the heap) and hands it to + * concurrent refinement threads, which update per-region remembered sets. G1's barrier is + * famously the more expensive of the two: it has a pre-write component for SATB marking and + * a post-write component for card marking. JDK 24 moved G1's barrier expansion late into C2 + * (JDK-8342382, "late barrier expansion"), which lets the optimiser see through more of it. + *
  • ZGC before JEP 439 had no store barrier at all -- which is exactly why + * non-generational ZGC had to mark the entire heap every cycle. Generational ZGC added one, + * feeding per-page remembered sets stored as double-buffered bitmaps.
  • + *
+ * + *

What this benchmark does

+ * {@link #storeOldToYoung()} writes a freshly allocated (young) object into an array that has been + * alive since {@code @Setup} and has therefore been promoted -- the barrier fires and records a + * cross-generational edge. {@link #storeNullIntoOld()} performs an identically shaped reference + * store whose value is {@code null}, which cannot create a cross-generational edge; comparing them + * separates "the barrier ran" from "the barrier had work to do". {@link #storePrimitiveIntoOld()} + * is the control: an {@code int} store into a long-lived array, which no collector needs to track. + * + *
+ * java -jar target/benchmarks.jar StoreBarrierBench -jvmArgs "-XX:+UseZGC  -Xms2g -Xmx2g"
+ * java -jar target/benchmarks.jar StoreBarrierBench -jvmArgs "-XX:+UseG1GC -Xms2g -Xmx2g"
+ * 
+ */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 5, time = 3) +@Fork(1) +public class StoreBarrierBench { + + /** Size of the long-lived array being written into. Larger = more cards / more pages touched. */ + @Param({"1048576"}) + public int slots; + + private Object[] oldArray; + private int[] oldPrimitiveArray; + private int cursor; + + @Setup(Level.Trial) + public void setup() { + oldArray = new Object[slots]; + oldPrimitiveArray = new int[slots]; + for (int i = 0; i < slots; i++) { + oldArray[i] = new Object(); + } + // Force the array (and its contents) into the old generation before measuring, otherwise + // the first iterations measure young-to-young stores, which no barrier needs to record. + System.gc(); + System.gc(); + } + + private int nextSlot() { + // A strided walk rather than a sequential one, so consecutive stores land on different + // cards / pages. A sequential walk would dirty the same card repeatedly and the barrier's + // "already dirty" fast path would hide most of the cost. + cursor = (cursor + 4099) & (slots - 1); + return cursor; + } + + /** Old-to-young reference store: the barrier fires AND has real work to record. */ + @Benchmark + public void storeOldToYoung() { + oldArray[nextSlot()] = new Object(); + } + + /** Reference store of null: barrier code still runs, but records no cross-generational edge. */ + @Benchmark + public void storeNullIntoOld() { + oldArray[nextSlot()] = null; + } + + /** Old-to-old reference store: no new cross-generational edge is created. */ + @Benchmark + public void storeOldToOld() { + oldArray[nextSlot()] = oldArray; + } + + /** Control: a primitive store into an equally long-lived array. No barrier on any collector. */ + @Benchmark + public int storePrimitiveIntoOld() { + int slot = nextSlot(); + oldPrimitiveArray[slot] = slot; + return slot; + } +} diff --git a/latency/src/com/ankurm/zgc/latency/Config.java b/latency/src/com/ankurm/zgc/latency/Config.java new file mode 100644 index 0000000..238e67f --- /dev/null +++ b/latency/src/com/ankurm/zgc/latency/Config.java @@ -0,0 +1,87 @@ +package com.ankurm.zgc.latency; + +/** + * All knobs of the latency harness in one place, so a run is fully described by one line of output. + * + *

Every value is a system property so that the JVM command line -- which is where the GC is + * selected anyway -- is the single source of truth for a run: + * + *

+ * java -XX:+UseZGC -Xms2g -Xmx2g -Drate=40000 -Dseconds=60 ...
+ * 
+ */ +public record Config( + int threads, + int ratePerSecond, + int warmupSeconds, + int measureSeconds, + int liveSetEntries, + int liveSetPayloadBytes, + int perRequestGarbageBytes, + int readsPerRequest, + double mutationProbability, + long seed) { + + public static Config fromSystemProperties() { + return new Config( + // Each worker busy-spins between arrivals (see LatencyHarness#parkUntil), so it + // occupies a core. A third of the logical CPUs leaves room for the collector's own + // concurrent threads -- starving those would make ZGC look bad for the wrong reason. + intProp("threads", Math.max(2, Runtime.getRuntime().availableProcessors() / 3)), + intProp("rate", 20_000), + intProp("warmupSeconds", 15), + intProp("seconds", 30), + // 150k entries x ~4 KB ~= 600 MB of genuinely live data in a 2 GB heap. The point is + // to make the OLD generation expensive to mark, which is where G1 and ZGC diverge. + intProp("liveSetEntries", 150_000), + intProp("liveSetPayloadBytes", 4_096), + // 20k req/s x 16 KB ~= 320 MB/s of young garbage: a realistic allocation rate for a + // busy JVM service, and high enough that young collections actually happen. + intProp("garbageBytes", 16_384), + intProp("readsPerRequest", 64), + doubleProp("mutationProbability", 0.20), + longProp("seed", 20260730L)); + } + + /** Bytes of young garbage this configuration creates per second, ignoring promotion. */ + public long allocationRateBytesPerSecond() { + return (long) ratePerSecond * perRequestGarbageBytes + + (long) (ratePerSecond * mutationProbability * liveSetPayloadBytes); + } + + /** Requests each worker thread must issue during the measured window. */ + public long requestsPerThread() { + return (long) measureSeconds * ratePerSecond / threads; + } + + /** Nanoseconds between two request arrivals *for one worker thread*. */ + public long interArrivalNanos() { + return 1_000_000_000L * threads / ratePerSecond; + } + + public String describe() { + return """ + threads=%d rate=%,d/s warmup=%ds measure=%ds + liveSet=%,d entries x %,d B (~%,d MB live) + garbage=%,d B/request reads=%d/request mutationProbability=%.2f + nominal allocation rate ~%,d MB/s seed=%d""" + .formatted(threads, ratePerSecond, warmupSeconds, measureSeconds, + liveSetEntries, liveSetPayloadBytes, + (long) liveSetEntries * liveSetPayloadBytes / 1024 / 1024, + perRequestGarbageBytes, readsPerRequest, mutationProbability, + allocationRateBytesPerSecond() / 1024 / 1024, seed); + } + + private static int intProp(String k, int def) { + return Integer.getInteger(k, def); + } + + private static long longProp(String k, long def) { + return Long.getLong(k, def); + } + + private static double doubleProp(String k, double def) { + String v = System.getProperty(k); + return v == null ? def : Double.parseDouble(v); + } +} diff --git a/latency/src/com/ankurm/zgc/latency/GcObserver.java b/latency/src/com/ankurm/zgc/latency/GcObserver.java new file mode 100644 index 0000000..4267687 --- /dev/null +++ b/latency/src/com/ankurm/zgc/latency/GcObserver.java @@ -0,0 +1,68 @@ +package com.ankurm.zgc.latency; + +import java.lang.management.GarbageCollectorMXBean; +import java.lang.management.ManagementFactory; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Snapshots {@link GarbageCollectorMXBean} counters so a run can report GC activity in the same + * output as the latency numbers. + * + *

The trap this class exists to expose. On ZGC the {@code getCollectionTime()} value is + * not stop-the-world time. The "ZGC Major Cycles" / "ZGC Minor Cycles" beans report the + * duration of the whole concurrent cycle, most of which runs alongside your application. + * The separate "ZGC Major Pauses" / "ZGC Minor Pauses" beans report the actual stop-the-world time. + * On G1 there is only one bean per generation and it is pause time. + * + *

Comparing G1's pause bean against ZGC's cycle bean is the single most common way people + * accidentally "prove" that ZGC is slower. This class keeps them apart on purpose. + */ +public final class GcObserver { + + private final Map baseline = new LinkedHashMap<>(); + + public GcObserver() { + reset(); + } + + /** Re-baselines all counters. Call after warm-up so warm-up GCs are not counted. */ + public void reset() { + baseline.clear(); + for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { + baseline.put(gc.getName(), new long[]{gc.getCollectionCount(), gc.getCollectionTime()}); + } + } + + public String report() { + StringBuilder sb = new StringBuilder("GC activity during the measured window\n"); + for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { + long[] base = baseline.getOrDefault(gc.getName(), new long[]{0, 0}); + long collections = gc.getCollectionCount() - base[0]; + long millis = gc.getCollectionTime() - base[1]; + String kind = isPauseBean(gc.getName()) ? "stop-the-world" : "cycle (mostly concurrent)"; + sb.append(" %-22s collections=%-6d time=%,7d ms [%s]%n" + .formatted(gc.getName(), collections, millis, kind)); + } + return sb.toString(); + } + + /** + * Classifies a bean as reporting stop-the-world time or concurrent time. + * + *

    + *
  • ZGC exposes four beans: "ZGC Minor/Major Cycles" (concurrent cycle duration) and + * "ZGC Minor/Major Pauses" (real stop-the-world time). Only the latter are pauses.
  • + *
  • G1 exposes "G1 Young Generation" and "G1 Old Generation", which are pauses, plus + * "G1 Concurrent GC", which -- despite sitting in the same bean list -- reports the + * concurrent marking cycle and is not stop-the-world.
  • + *
  • Parallel and Serial beans are all pauses.
  • + *
+ */ + private static boolean isPauseBean(String name) { + String n = name.toLowerCase(); + if (n.contains("concurrent")) return false; + if (n.startsWith("zgc")) return n.contains("pause"); + return true; + } +} diff --git a/latency/src/com/ankurm/zgc/latency/Histogram.java b/latency/src/com/ankurm/zgc/latency/Histogram.java new file mode 100644 index 0000000..de47d68 --- /dev/null +++ b/latency/src/com/ankurm/zgc/latency/Histogram.java @@ -0,0 +1,102 @@ +package com.ankurm.zgc.latency; + +import java.util.Arrays; + +/** + * A deliberately dumb latency recorder: it keeps every raw sample in a pre-allocated + * {@code long[]} and sorts once at the end. + * + *

Why not HdrHistogram? Two reasons, both about honesty: + * + *

    + *
  1. No dependency. This repository must run with nothing but a JDK.
  2. + *
  3. No bucketing error. HdrHistogram is excellent, but it quantises values. When you are + * arguing about whether p99.99 is 3 ms or 11 ms, exact samples remove one thing to argue + * about.
  4. + *
+ * + *

The array is allocated before the measured window and never grows, so the recorder + * itself contributes zero allocation to the workload it is measuring. That matters here: a + * histogram that allocates during a GC benchmark is measuring itself. + */ +public final class Histogram { + + private final long[] samples; + private int count; + + public Histogram(int capacity) { + this.samples = new long[capacity]; + } + + /** Records one sample. Silently drops overflow rather than resizing mid-measurement. */ + public void record(long nanos) { + if (count < samples.length) { + samples[count++] = nanos; + } + } + + public int count() { + return count; + } + + /** Sorts in place. Call exactly once, after the measured window. */ + public Histogram freeze() { + Arrays.sort(samples, 0, count); + return this; + } + + /** @param p percentile in [0, 100], e.g. 99.99 */ + public long percentileNanos(double p) { + if (count == 0) return 0; + int idx = (int) Math.ceil(p / 100.0 * count) - 1; + return samples[Math.clamp(idx, 0, count - 1)]; + } + + public long maxNanos() { + return count == 0 ? 0 : samples[count - 1]; + } + + public double meanMillis() { + long sum = 0; + for (int i = 0; i < count; i++) sum += samples[i]; + return count == 0 ? 0 : sum / (double) count / 1_000_000.0; + } + + /** Merges another histogram's samples into this one (used to combine per-thread recorders). */ + public void mergeFrom(Histogram other) { + int n = Math.min(other.count, samples.length - count); + System.arraycopy(other.samples, 0, samples, count, n); + count += n; + } + + public String report(String label) { + return """ + %s (n=%,d) + mean %8.3f ms + p50 %8.3f ms + p90 %8.3f ms + p99 %8.3f ms + p99.9 %8.3f ms + p99.99 %8.3f ms + max %8.3f ms""" + .formatted(label, count, meanMillis(), + ms(percentileNanos(50)), ms(percentileNanos(90)), ms(percentileNanos(99)), + ms(percentileNanos(99.9)), ms(percentileNanos(99.99)), ms(maxNanos())); + } + + /** Machine-readable one-liner, so runs can be diffed and pasted into a table. */ + public String csvRow(String collector) { + return "%s,%d,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f,%.3f".formatted( + collector, count, meanMillis(), + ms(percentileNanos(50)), ms(percentileNanos(90)), ms(percentileNanos(99)), + ms(percentileNanos(99.9)), ms(percentileNanos(99.99)), ms(maxNanos())); + } + + public static String csvHeader() { + return "collector,n,mean_ms,p50_ms,p90_ms,p99_ms,p999_ms,p9999_ms,max_ms"; + } + + private static double ms(long nanos) { + return nanos / 1_000_000.0; + } +} diff --git a/latency/src/com/ankurm/zgc/latency/LatencyHarness.java b/latency/src/com/ankurm/zgc/latency/LatencyHarness.java new file mode 100644 index 0000000..cc337fb --- /dev/null +++ b/latency/src/com/ankurm/zgc/latency/LatencyHarness.java @@ -0,0 +1,258 @@ +package com.ankurm.zgc.latency; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.locks.LockSupport; + +/** + * An open-loop latency harness for comparing collectors. + * + *

This is the part of a GC comparison that most benchmarks get wrong, so it is worth being + * explicit about what "open loop" means and why it changes the answer. + * + *

Closed loop (wrong for this question)

+ * A closed-loop benchmark has N threads in a {@code while(true) { doRequest(); }} loop. If a GC + * pause freezes the application for 50 ms, those threads simply do not issue requests during the + * pause. When they resume, they measure one slow request each -- and then the throughput number + * quietly absorbs the rest. The pause is real, your users felt it as 50 ms of queueing, and the + * benchmark reports it as a handful of samples. Gil Tene named this coordinated omission: + * the load generator has "coordinated" with the system under test to stop sending load exactly when + * the system was least able to serve it. + * + *

Open loop (what this harness does)

+ * Each worker thread has a fixed arrival schedule computed up front: + * {@code intended[i] = start + i * interArrivalNanos}. Latency for request {@code i} is measured + * from {@code intended[i]}, not from when the thread actually got around to it. A 50 ms pause + * therefore shows up as ~2000 requests at 40k/s whose latency includes the queueing delay they + * really suffered -- which is what a load balancer, and a user, would have seen. + * + *

The harness reports both numbers side by side so the difference is visible rather than + * asserted: + *

    + *
  • response time = completion − intended arrival (the honest number)
  • + *
  • service time = completion − actual start (the flattering number)
  • + *
+ * + *

Running it

+ *
+ * javac -d out $(find latency/src -name '*.java')
+ * java -XX:+UseZGC   -Xms2g -Xmx2g -cp out com.ankurm.zgc.latency.LatencyHarness
+ * java -XX:+UseG1GC  -Xms2g -Xmx2g -cp out com.ankurm.zgc.latency.LatencyHarness
+ * 
+ */ +public final class LatencyHarness { + + public static void main(String[] args) throws Exception { + Config cfg = Config.fromSystemProperties(); + String collector = detectCollector(); + + System.out.println("=".repeat(78)); + System.out.println("ZGC / G1 open-loop latency harness"); + System.out.println("=".repeat(78)); + System.out.println("collector : " + collector); + System.out.println("java : " + System.getProperty("java.vm.version")); + System.out.println(cfg.describe()); + System.out.println("-".repeat(78)); + + System.out.print("building live set ... "); + long t0 = System.nanoTime(); + LiveSet liveSet = new LiveSet(cfg.liveSetEntries(), cfg.liveSetPayloadBytes()); + System.out.printf("%,d entries, ~%,d MB live, took %,d ms%n", + liveSet.entries(), + liveSet.approximateLiveBytes() / 1024 / 1024, + (System.nanoTime() - t0) / 1_000_000); + + // ---- Warm-up ------------------------------------------------------------------- + // Two things warm up here: the JIT (C2 needs to compile the request path) and the heap + // (ZGC and G1 both need a few cycles before their heuristics settle). Measuring before + // both have happened produces a benchmark of the interpreter, not of the collector. + System.out.printf("warming up for %d s at %,d req/s ...%n", cfg.warmupSeconds(), cfg.ratePerSecond()); + runPhase(cfg, liveSet, cfg.warmupSeconds(), null, null); + + // ---- Measure ------------------------------------------------------------------- + GcObserver gcObserver = new GcObserver(); // baseline AFTER warm-up + int capacity = (int) Math.min(Integer.MAX_VALUE - 8L, + (long) cfg.measureSeconds() * cfg.ratePerSecond() + 1024); + Histogram responseTime = new Histogram(capacity); + Histogram serviceTime = new Histogram(capacity); + + System.out.printf("measuring for %d s at %,d req/s ...%n", cfg.measureSeconds(), cfg.ratePerSecond()); + long wallStart = System.nanoTime(); + runPhase(cfg, liveSet, cfg.measureSeconds(), responseTime, serviceTime); + long wallNanos = System.nanoTime() - wallStart; + + responseTime.freeze(); + serviceTime.freeze(); + + // ---- Report -------------------------------------------------------------------- + System.out.println(); + System.out.println("-".repeat(78)); + System.out.printf("achieved throughput : %,.0f req/s over %.1f s%n", + responseTime.count() / (wallNanos / 1e9), wallNanos / 1e9); + System.out.println(); + System.out.println(responseTime.report("RESPONSE TIME (from intended arrival -- the honest number)")); + System.out.println(); + System.out.println(serviceTime.report("SERVICE TIME (from actual start -- hides queueing)")); + System.out.println(); + System.out.printf("coordinated-omission gap at p99.9 : %.3f ms response vs %.3f ms service (%.1fx)%n", + responseTime.percentileNanos(99.9) / 1e6, + serviceTime.percentileNanos(99.9) / 1e6, + safeRatio(responseTime.percentileNanos(99.9), serviceTime.percentileNanos(99.9))); + System.out.println(); + System.out.print(gcObserver.report()); + System.out.println(); + System.out.println("CSV (response time)"); + System.out.println(Histogram.csvHeader()); + System.out.println(responseTime.csvRow(collector)); + + // Keep the live set reachable to the very end, otherwise a clever JIT could shorten its + // lifetime and quietly delete the old generation we spent the whole run building. + System.out.println("\nliveSet checksum: " + liveSet.touch()); + } + + /** + * Runs one phase. Passing {@code null} histograms makes it a warm-up phase (no recording, + * and therefore no measurement bias from recording code that is not yet JIT-compiled). + */ + private static void runPhase(Config cfg, LiveSet liveSet, int seconds, + Histogram responseOut, Histogram serviceOut) throws Exception { + + int threads = cfg.threads(); + long interArrival = cfg.interArrivalNanos(); + long perThread = (long) seconds * cfg.ratePerSecond() / threads; + + CountDownLatch ready = new CountDownLatch(threads); + CountDownLatch go = new CountDownLatch(1); + List workers = new ArrayList<>(threads); + List responseParts = new ArrayList<>(threads); + List serviceParts = new ArrayList<>(threads); + + for (int t = 0; t < threads; t++) { + Histogram r = responseOut == null ? null : new Histogram((int) perThread + 16); + Histogram s = serviceOut == null ? null : new Histogram((int) perThread + 16); + if (r != null) { responseParts.add(r); serviceParts.add(s); } + + Thread worker = new Thread(() -> { + ready.countDown(); + try { + go.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + long start = System.nanoTime(); + for (long i = 0; i < perThread; i++) { + long intended = start + i * interArrival; + parkUntil(intended); + long actualStart = System.nanoTime(); + handleRequest(cfg, liveSet); + long done = System.nanoTime(); + if (r != null) { + r.record(done - intended); // includes queueing caused by GC pauses + s.record(done - actualStart); // the number a closed-loop harness reports + } + } + }, "worker-" + t); + worker.setDaemon(true); + workers.add(worker); + worker.start(); + } + + ready.await(); + go.countDown(); + for (Thread w : workers) w.join(); + + if (responseOut != null) { + for (int i = 0; i < responseParts.size(); i++) { + responseOut.mergeFrom(responseParts.get(i).freeze()); + serviceOut.mergeFrom(serviceParts.get(i).freeze()); + } + } + } + + /** + * One "request": allocate short-lived garbage, read from the live set, and occasionally write + * a new object into it. This is a deliberately ordinary shape -- a request handler that builds + * a response buffer, reads a cache, and sometimes refreshes a cache entry. + */ + private static void handleRequest(Config cfg, LiveSet liveSet) { + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + + // Young garbage: dies before the next young collection. This is the cheap part for every + // generational collector, and the whole reason generational ZGC exists. + byte[] scratch = new byte[cfg.perRequestGarbageBytes()]; + scratch[0] = (byte) rnd.nextInt(); + int sum = scratch[0]; + + // Reads from the old generation: on ZGC every one of these goes through a load barrier. + // The count is deliberately high enough that a request does measurable work (tens of + // microseconds) rather than a few nanoseconds -- a harness whose requests are shorter than + // its own timer resolution measures the timer. + int reads = cfg.readsPerRequest(); + for (int i = 0; i < reads; i++) { + sum += liveSet.touch(); + } + + // Old-to-young store: on ZGC this goes through the store barrier added by JEP 439 and + // updates a remembered set. On G1 it dirties a card. + if (rnd.nextDouble() < cfg.mutationProbability()) { + byte[] evicted = liveSet.mutate(); + sum += evicted.length & 1; + } + + Blackhole.consume(sum); + } + + /** + * Sleeps until an absolute {@link System#nanoTime()} deadline. + * + *

Why this is not simply {@code LockSupport.parkNanos(remaining)}

+ * The default Windows timer tick is ~15.6 ms and, even with the multimedia timer raised, a + * park rounds up to roughly 1 ms. At a 200 microsecond inter-arrival interval that means every + * park overshoots by several intervals. The thread then blasts through the backlog, parks, + * overshoots again -- and the harness reports a p50 of half a millisecond on a request that + * takes three microseconds. The first version of this file did exactly that and it looked like + * a real GC effect. It was the sleep. + * + *

So: only park when the deadline is far enough away that a 1 ms overshoot does not matter + * ({@link #PARK_THRESHOLD_NANOS}), and busy-spin otherwise. Spinning costs a core per worker + * thread, which is why {@code threads} defaults to a fraction of the CPU count -- the GC needs + * cores too, and starving its concurrent threads would be a different kind of measurement lie. + * + *

If the deadline has already passed the method returns immediately: the request is + * late, and that lateness is precisely what we want in the response-time histogram. + */ + private static final long PARK_THRESHOLD_NANOS = 3_000_000L; // 3 ms >> Windows timer slack + + private static void parkUntil(long deadlineNanos) { + long remaining = deadlineNanos - System.nanoTime(); + if (remaining <= 0) return; // already behind schedule -- do not sleep + if (remaining > PARK_THRESHOLD_NANOS) { + LockSupport.parkNanos(remaining - PARK_THRESHOLD_NANOS); + } + while (System.nanoTime() < deadlineNanos) { + Thread.onSpinWait(); + } + } + + private static double safeRatio(long a, long b) { + return b == 0 ? 0 : (double) a / b; + } + + private static String detectCollector() { + StringBuilder sb = new StringBuilder(); + for (var gc : java.lang.management.ManagementFactory.getGarbageCollectorMXBeans()) { + if (!sb.isEmpty()) sb.append(" + "); + sb.append(gc.getName()); + } + return sb.toString(); + } + + /** Minimal dead-code sink; JMH's Blackhole is not available in a dependency-free module. */ + static final class Blackhole { + static volatile int sink; + static void consume(int v) { sink = v; } + } +} diff --git a/latency/src/com/ankurm/zgc/latency/LiveSet.java b/latency/src/com/ankurm/zgc/latency/LiveSet.java new file mode 100644 index 0000000..ec25ea9 --- /dev/null +++ b/latency/src/com/ankurm/zgc/latency/LiveSet.java @@ -0,0 +1,77 @@ +package com.ankurm.zgc.latency; + +import java.util.concurrent.ThreadLocalRandom; + +/** + * The old generation, made explicit. + * + *

A GC benchmark that only allocates short-lived garbage measures almost nothing interesting: + * every collector on earth is good at throwing away objects that die immediately (that is the weak + * generational hypothesis doing the work, not the collector). The interesting question is what + * happens when there is a large, long-lived, *slowly mutating* object graph -- a cache, a session + * store, an in-memory index -- because that is what has to be marked, and marking cost is what + * separates collectors. + * + *

This class holds {@code entries} byte arrays alive for the whole run. Periodically a slot is + * overwritten with a freshly allocated array. That single store is the most important line in this + * repository: + * + *

{@code slots[i] = newPayload;}
+ * + *

It writes a reference to a young object into a field of an old object. Every + * generational collector needs to know that this happened, or a young collection would wrongly + * conclude the new object is unreachable. G1 records it in a card table + remembered sets; ZGC -- + * since JEP 439 -- records it with a store barrier feeding per-page remembered sets. Before + * generational ZGC there was no store barrier at all, which is exactly why old ZGC had to mark the + * entire heap on every cycle. + * + *

Turning {@code mutationProbability} up and down changes how much cross-generational traffic + * the collector sees, and is the knob that makes the ZGC-vs-G1 gap open and close. + */ +public final class LiveSet { + + private final byte[][] slots; + private final int payloadBytes; + + public LiveSet(int entries, int payloadBytes) { + this.slots = new byte[entries][]; + this.payloadBytes = payloadBytes; + // Fill up front so the measured window starts with a fully populated old generation + // rather than measuring the ramp-up. + for (int i = 0; i < entries; i++) { + slots[i] = new byte[payloadBytes]; + } + } + + /** + * Overwrites one random slot -- an old-to-young reference store. + * + * @return the previous occupant, returned only so the JIT cannot delete the store as dead code + */ + public byte[] mutate() { + int i = ThreadLocalRandom.current().nextInt(slots.length); + byte[] previous = slots[i]; + byte[] payload = new byte[payloadBytes]; + // Touch a few bytes so the array cannot be optimised into a zero-fill the JIT elides. + payload[0] = 1; + payload[payload.length - 1] = 2; + slots[i] = payload; // <-- the store barrier fires here + return previous; + } + + /** Reads one random slot -- a load barrier fires here on every ZGC read. */ + public int touch() { + int i = ThreadLocalRandom.current().nextInt(slots.length); + byte[] payload = slots[i]; // <-- ZGC load barrier fires here + return payload.length == 0 ? 0 : payload[0]; + } + + public int entries() { + return slots.length; + } + + public long approximateLiveBytes() { + // 16 bytes of object header + length for each array, rounded, plus the slots array itself. + return (long) slots.length * (payloadBytes + 16L) + slots.length * 8L; + } +} diff --git a/results/01-env-g1.txt b/results/01-env-g1.txt new file mode 100644 index 0000000..f5ab0a6 --- /dev/null +++ b/results/01-env-g1.txt @@ -0,0 +1,34 @@ +=== Runtime === +java.version : 25.0.3 +java.vm.name : Java HotSpot(TM) 64-Bit Server VM +java.vm.version : 25.0.3+9-LTS-195 +java.vendor : Oracle Corporation +os.name / os.arch : Windows 11 / amd64 +availableProcessors : 12 +maxMemory (-Xmx) : 2,147,483,648 bytes (2048 MB) +totalMemory (now) : 2,147,483,648 bytes (2048 MB) + +=== Collector in use === + bean: G1 Young Generation count=0 timeMs=0 + bean: G1 Concurrent GC count=0 timeMs=0 + bean: G1 Old Generation count=0 timeMs=0 + generational? : yes (separate young + old cycles reported) + +=== Memory pools === + CodeHeap 'non-nmethods' type=Non-heap memory max=5,832,704 bytes (6 MB) + Metaspace type=Non-heap memory max=unbounded + CodeHeap 'profiled nmethods' type=Non-heap memory max=122,880,000 bytes (117 MB) + Compressed Class Space type=Non-heap memory max=1,073,741,824 bytes (1024 MB) + G1 Eden Space type=Heap memory max=unbounded + G1 Old Gen type=Heap memory max=2,147,483,648 bytes (2048 MB) + G1 Survivor Space type=Heap memory max=unbounded + CodeHeap 'non-profiled nmethods' type=Non-heap memory max=122,945,536 bytes (117 MB) + +=== JVM arguments actually in effect === + -XX:+UseG1GC + -Xms2g + -Xmx2g + --add-modules=ALL-DEFAULT + +Tip: dump every ergonomic value the JVM chose with + java -XX:+UseZGC -Xms2g -Xmx2g -XX:+PrintFlagsFinal -version diff --git a/results/01-env-zgc.txt b/results/01-env-zgc.txt new file mode 100644 index 0000000..6a72139 --- /dev/null +++ b/results/01-env-zgc.txt @@ -0,0 +1,34 @@ +=== Runtime === +java.version : 25.0.3 +java.vm.name : Java HotSpot(TM) 64-Bit Server VM +java.vm.version : 25.0.3+9-LTS-195 +java.vendor : Oracle Corporation +os.name / os.arch : Windows 11 / amd64 +availableProcessors : 12 +maxMemory (-Xmx) : 2,147,483,648 bytes (2048 MB) +totalMemory (now) : 2,147,483,648 bytes (2048 MB) + +=== Collector in use === + bean: ZGC Minor Cycles count=0 timeMs=0 + bean: ZGC Minor Pauses count=0 timeMs=0 + bean: ZGC Major Cycles count=0 timeMs=0 + bean: ZGC Major Pauses count=0 timeMs=0 + generational? : yes (separate young + old cycles reported) + +=== Memory pools === + CodeHeap 'non-nmethods' type=Non-heap memory max=5,832,704 bytes (6 MB) + Metaspace type=Non-heap memory max=unbounded + CodeHeap 'profiled nmethods' type=Non-heap memory max=122,880,000 bytes (117 MB) + Compressed Class Space type=Non-heap memory max=1,073,741,824 bytes (1024 MB) + ZGC Old Generation type=Heap memory max=2,147,483,648 bytes (2048 MB) + ZGC Young Generation type=Heap memory max=2,147,483,648 bytes (2048 MB) + CodeHeap 'non-profiled nmethods' type=Non-heap memory max=122,945,536 bytes (117 MB) + +=== JVM arguments actually in effect === + -XX:+UseZGC + -Xms2g + -Xmx2g + --add-modules=ALL-DEFAULT + +Tip: dump every ergonomic value the JVM chose with + java -XX:+UseZGC -Xms2g -Xmx2g -XX:+PrintFlagsFinal -version diff --git a/results/02-flags-g1.txt b/results/02-flags-g1.txt new file mode 100644 index 0000000..d6ad7a1 --- /dev/null +++ b/results/02-flags-g1.txt @@ -0,0 +1,513 @@ +[Global flags] + ccstr AOTCache = {product} {default} + ccstr AOTCacheOutput = {product} {default} + bool AOTClassLinking = false {product} {default} + ccstr AOTConfiguration = {product} {default} + ccstr AOTMode = {product} {default} + int ActiveProcessorCount = -1 {product} {default} + uintx AdaptiveSizeDecrementScaleFactor = 4 {product} {default} + uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product} {default} + uintx AdaptiveSizePolicyInitializingSteps = 20 {product} {default} + uintx AdaptiveSizePolicyOutputInterval = 0 {product} {default} + uint AdaptiveSizePolicyWeight = 10 {product} {default} + uint AdaptiveSizeThroughPutPolicy = 0 {product} {default} + uint AdaptiveTimeWeight = 25 {product} {default} + bool AggressiveHeap = false {product} {default} + bool AlignVector = false {C2 product} {default} + ccstr AllocateHeapAt = {product} {default} + int AllocateInstancePrefetchLines = 1 {product} {default} + int AllocatePrefetchDistance = 256 {product} {default} + intx AllocatePrefetchInstr = 0 {product} {default} + int AllocatePrefetchLines = 3 {product} {default} + int AllocatePrefetchStepSize = 64 {product} {default} + int AllocatePrefetchStyle = 1 {product} {default} + bool AllowParallelDefineClass = false {product} {default} + bool AllowRedefinitionToAddDeleteMethods = false {product} {default} + bool AllowUserSignalHandlers = false {product} {default} + bool AllowVectorizeOnDemand = true {C2 product} {default} + bool AlwaysActAsServerClassMachine = false {product} {default} + bool AlwaysCompileLoopMethods = false {product} {default} + bool AlwaysPreTouch = false {product} {default} + bool AlwaysRestoreFPU = false {product} {default} + bool AlwaysTenure = false {product} {default} + ccstr ArchiveClassesAtExit = {product} {default} + intx ArrayCopyLoadStoreMaxElem = 8 {C2 product} {default} + size_t AsyncLogBufferSize = 2097152 {product} {default} + intx AutoBoxCacheMax = 128 {C2 product} {default} + bool AutoCreateSharedArchive = false {product} {default} + intx BCEATraceLevel = 0 {product} {default} + bool BackgroundCompilation = true {pd product} {default} + bool BlockLayoutByFrequency = true {C2 product} {default} + intx BlockLayoutMinDiamondPercentage = 20 {C2 product} {default} + bool BlockLayoutRotateLoops = true {C2 product} {default} + intx C1InlineStackLimit = 5 {C1 product} {default} + intx C1MaxInlineLevel = 9 {C1 product} {default} + intx C1MaxInlineSize = 35 {C1 product} {default} + intx C1MaxRecursiveInlineLevel = 1 {C1 product} {default} + intx C1MaxTrivialSize = 6 {C1 product} {default} + bool C1OptimizeVirtualCallProfiling = true {C1 product} {default} + bool C1ProfileBranches = true {C1 product} {default} + bool C1ProfileCalls = true {C1 product} {default} + bool C1ProfileCheckcasts = true {C1 product} {default} + bool C1ProfileInlinedCalls = true {C1 product} {default} + bool C1ProfileVirtualCalls = true {C1 product} {default} + bool C1UpdateMethodData = true {C1 product} {default} + intx CICompilerCount = 4 {product} {ergonomic} + bool CICompilerCountPerCPU = true {product} {default} + bool CITime = false {product} {default} + bool CheckJNICalls = false {product} {default} + bool ClassUnloading = true {product} {default} + bool ClassUnloadingWithConcurrentMark = true {product} {default} + bool ClipInlining = true {product} {default} + uintx CodeCacheExpansionSize = 65536 {pd product} {default} + bool CompactStrings = true {pd product} {default} + ccstr CompilationMode = default {product} {default} +ccstrlist CompileCommand = {product} {default} + ccstr CompileCommandFile = {product} {default} +ccstrlist CompileOnly = {product} {default} + intx CompileThreshold = 10000 {pd product} {default} + double CompileThresholdScaling = 1.000000 {product} {default} + int CompilerThreadPriority = -1 {product} {default} + intx CompilerThreadStackSize = 0 {pd product} {default} + size_t CompressedClassSpaceSize = 1073741824 {product} {default} + uint ConcGCThreads = 3 {product} {ergonomic} + intx ConditionalMoveLimit = 3 {C2 pd product} {default} + int ContendedPaddingWidth = 128 {product} {default} + bool CrashOnOutOfMemoryError = false {product} {default} + bool CreateCoredumpOnCrash = true {product} {default} + bool DTraceAllocProbes = false {product} {default} + bool DTraceMethodProbes = false {product} {default} + bool DTraceMonitorProbes = false {product} {default} + bool DisableAttachMechanism = false {product} {default} + bool DisableExplicitGC = false {product} {default} + bool DisplayVMOutputToStderr = false {product} {default} + bool DisplayVMOutputToStdout = false {product} {default} + bool DoEscapeAnalysis = true {C2 product} {default} + bool DontCompileHugeMethods = true {product} {default} + ccstr DumpLoadedClassList = {product} {default} + bool DumpReplayDataOnError = true {product} {default} + bool EagerXrunInit = false {product} {default} + intx EliminateAllocationArraySizeLimit = 64 {C2 product} {default} + bool EliminateAllocations = true {C2 product} {default} + bool EliminateAutoBox = true {C2 product} {default} + bool EliminateLocks = true {C2 product} {default} + bool EliminateNestedLocks = true {C2 product} {default} + bool EnableAllLargePageSizesForWindows = false {product} {default} + bool EnableContended = true {product} {default} + bool EnableDynamicAgentLoading = true {product} {default} + size_t ErgoHeapSizeLimit = 0 {product} {default} + ccstr ErrorFile = {product} {default} + bool ErrorFileToStderr = false {product} {default} + bool ErrorFileToStdout = false {product} {default} + uint64_t ErrorLogTimeout = 120 {product} {default} + double EscapeAnalysisTimeout = 20.000000 {C2 product} {default} + bool EstimateArgEscape = true {product} {default} + bool ExecutingUnitTests = false {product} {default} + bool ExitOnOutOfMemoryError = false {product} {default} + bool ExplicitGCInvokesConcurrent = false {product} {default} + bool ExtensiveErrorReports = false {product} {default} + ccstr ExtraSharedClassListFile = {product} {default} + bool FlightRecorder = false {product} {default} + ccstr FlightRecorderOptions = {product} {default} + bool ForceTimeHighResolution = false {product} {default} + intx FreqInlineSize = 325 {C2 pd product} {default} + uint FullGCHeapDumpLimit = 0 {manageable} {default} + double G1ConcMarkStepDurationMillis = 10.000000 {product} {default} + uint G1ConcRefinementThreads = 10 {product} {ergonomic} + uint G1ConfidencePercent = 50 {product} {default} + size_t G1HeapRegionSize = 1048576 {product} {ergonomic} + uint G1HeapWastePercent = 5 {product} {default} + uintx G1MixedGCCountTarget = 8 {product} {default} + uintx G1PeriodicGCInterval = 0 {manageable} {default} + bool G1PeriodicGCInvokesConcurrent = true {product} {default} + double G1PeriodicGCSystemLoadThreshold = 0.000000 {manageable} {default} + uint G1RSetUpdatingPauseTimePercent = 10 {product} {default} + uint G1RefProcDrainInterval = 1000 {product} {default} + uint G1ReservePercent = 10 {product} {default} + uint G1SATBBufferEnqueueingThresholdPercent = 60 {product} {default} + size_t G1SATBBufferSize = 1024 {product} {default} + size_t G1UpdateBufferSize = 256 {product} {default} + bool G1UseAdaptiveIHOP = true {product} {default} + uint GCCardSizeInBytes = 512 {product} {default} + uint GCDrainStackTargetSize = 64 {product} {default} + uint GCHeapFreeLimit = 2 {product} {default} + uintx GCPauseIntervalMillis = 201 {product} {default} + uint GCTimeLimit = 98 {product} {default} + uint GCTimeRatio = 12 {product} {default} + size_t HeapBaseMinAddress = 2147483648 {pd product} {default} + bool HeapDumpAfterFullGC = false {manageable} {default} + bool HeapDumpBeforeFullGC = false {manageable} {default} + int HeapDumpGzipLevel = 0 {manageable} {default} + bool HeapDumpOnOutOfMemoryError = false {manageable} {default} + ccstr HeapDumpPath = {manageable} {default} + uintx HeapMaximumCompactionInterval = 20 {product} {default} + uintx HeapSearchSteps = 3 {product} {default} + size_t HeapSizePerGCThread = 43620760 {product} {default} + bool IgnoreEmptyClassPaths = false {product} {default} + bool IgnoreUnrecognizedVMOptions = false {product} {default} + uintx IncreaseFirstTierCompileThresholdAt = 50 {product} {default} + bool IncrementalInline = true {C2 product} {default} + uintx InitialCodeCacheSize = 2555904 {pd product} {default} + size_t InitialHeapSize = 2147483648 {product} {command line} + double InitialRAMPercentage = 1.562500 {product} {default} + uintx InitialSurvivorRatio = 8 {product} {default} + uint InitialTenuringThreshold = 7 {product} {default} + uint InitiatingHeapOccupancyPercent = 45 {product} {default} + bool Inline = true {product} {default} + ccstr InlineDataFile = {product} {default} + intx InlineSmallCode = 2500 {C2 pd product} {default} + bool InlineSynchronizedMethods = true {C1 product} {default} + intx InteriorEntryAlignment = 16 {C2 pd product} {default} + intx InterpreterProfilePercentage = 33 {product} {default} + bool JavaMonitorsInStackTrace = true {product} {default} + int JavaPriority10_To_OSPriority = -1 {product} {default} + int JavaPriority1_To_OSPriority = -1 {product} {default} + int JavaPriority2_To_OSPriority = -1 {product} {default} + int JavaPriority3_To_OSPriority = -1 {product} {default} + int JavaPriority4_To_OSPriority = -1 {product} {default} + int JavaPriority5_To_OSPriority = -1 {product} {default} + int JavaPriority6_To_OSPriority = -1 {product} {default} + int JavaPriority7_To_OSPriority = -1 {product} {default} + int JavaPriority8_To_OSPriority = -1 {product} {default} + int JavaPriority9_To_OSPriority = -1 {product} {default} + size_t LargePageHeapSizeThreshold = 134217728 {product} {default} + size_t LargePageSizeInBytes = 0 {product} {default} + intx LiveNodeCountInliningCutoff = 40000 {C2 product} {default} + int LockingMode = 2 {product} {default} + ccstr LogClassLoadingCauseFor = {product} {default} + intx LoopMaxUnroll = 16 {C2 product} {default} + intx LoopOptsCount = 43 {C2 product} {default} + intx LoopPercentProfileLimit = 10 {C2 pd product} {default} + uintx LoopStripMiningIter = 1000 {C2 product} {default} + uintx LoopStripMiningIterShortLoop = 100 {C2 product} {default} + intx LoopUnrollLimit = 60 {C2 pd product} {default} + intx LoopUnrollMin = 4 {C2 product} {default} + bool LoopUnswitching = true {C2 product} {default} + bool ManagementServer = false {product} {default} + size_t MarkStackSize = 4194304 {product} {ergonomic} + size_t MarkStackSizeMax = 536870912 {product} {ergonomic} + uint MarkSweepAlwaysCompactCount = 4 {product} {default} + uint MarkSweepDeadRatio = 5 {product} {default} + intx MaxBCEAEstimateLevel = 5 {product} {default} + intx MaxBCEAEstimateSize = 150 {product} {default} + uint64_t MaxDirectMemorySize = 0 {product} {default} + bool MaxFDLimit = true {product} {default} + uintx MaxGCPauseMillis = 200 {product} {default} + uintx MaxHeapFreeRatio = 70 {manageable} {default} + size_t MaxHeapSize = 2147483648 {product} {command line} + intx MaxInlineLevel = 15 {C2 product} {default} + intx MaxInlineSize = 35 {C2 product} {default} + intx MaxJNILocalCapacity = 65536 {product} {default} + int MaxJavaStackTraceDepth = 1024 {product} {default} + intx MaxJumpTableSize = 65000 {C2 product} {default} + intx MaxJumpTableSparseness = 5 {C2 product} {default} + intx MaxLabelRootDepth = 1100 {C2 product} {default} + intx MaxLoopPad = 15 {C2 product} {default} + size_t MaxMetaspaceExpansion = 5439488 {product} {default} + uint MaxMetaspaceFreeRatio = 70 {product} {default} + size_t MaxMetaspaceSize = 18446744073709551615 {product} {default} + size_t MaxNewSize = 1287651328 {product} {ergonomic} + intx MaxNodeLimit = 80000 {C2 product} {default} + uint64_t MaxRAM = 137438953472 {pd product} {default} + double MaxRAMPercentage = 25.000000 {product} {default} + intx MaxRecursiveInlineLevel = 1 {C2 product} {default} + uint MaxTenuringThreshold = 15 {product} {default} + intx MaxTrivialSize = 6 {C2 product} {default} + intx MaxVectorSize = 32 {C2 product} {default} + size_t MetaspaceSize = 22020096 {product} {default} + bool MethodFlushing = true {product} {default} + size_t MinHeapDeltaBytes = 1048576 {product} {ergonomic} + uintx MinHeapFreeRatio = 40 {manageable} {default} + size_t MinHeapSize = 2147483648 {product} {command line} + intx MinJumpTableSize = 10 {C2 pd product} {default} + size_t MinMetaspaceExpansion = 327680 {product} {default} + uint MinMetaspaceFreeRatio = 40 {product} {default} + double MinRAMPercentage = 50.000000 {product} {default} + uintx MinSurvivorRatio = 3 {product} {default} + size_t MinTLABSize = 2048 {product} {default} + intx MultiArrayExpandLimit = 6 {C2 product} {default} + uintx NUMAChunkResizeWeight = 20 {product} {default} + size_t NUMAInterleaveGranularity = 2097152 {product} {default} + size_t NUMASpaceResizeRate = 1073741824 {product} {default} + bool NUMAStats = false {product} {default} + ccstr NativeMemoryTracking = off {product} {default} + bool NeverActAsServerClassMachine = false {pd product} {default} + bool NeverTenure = false {product} {default} + uintx NewRatio = 2 {product} {default} + size_t NewSize = 1363144 {product} {default} + size_t NewSizeThreadIncrease = 5320 {pd product} {default} + intx NmethodSweepActivity = 4 {product} {default} + intx NodeLimitFudgeFactor = 2000 {C2 product} {default} + uintx NonNMethodCodeHeapSize = 5832704 {pd product} {ergonomic} + uintx NonProfiledCodeHeapSize = 122945536 {pd product} {ergonomic} + intx NumberOfLoopInstrToAlign = 4 {C2 product} {default} + int ObjectAlignmentInBytes = 8 {product lp64_product} {default} + size_t OldPLABSize = 1024 {product} {default} + bool OmitStackTraceInFastThrow = true {product} {default} +ccstrlist OnError = {product} {default} +ccstrlist OnOutOfMemoryError = {product} {default} + intx OnStackReplacePercentage = 140 {pd product} {default} + bool OptimizeFill = false {C2 product} {default} + bool OptimizePtrCompare = true {C2 product} {default} + bool OptimizeStringConcat = true {C2 product} {default} + bool OptoBundling = false {C2 pd product} {default} + intx OptoLoopAlignment = 16 {pd product} {default} + bool OptoRegScheduling = true {C2 pd product} {default} + bool OptoScheduling = false {C2 pd product} {default} + uint PLABWeight = 75 {product} {default} + bool PSChunkLargeArrays = true {product} {default} + int ParGCArrayScanChunk = 50 {product} {default} + uint ParallelGCBufferWastePct = 10 {product} {default} + uint ParallelGCThreads = 10 {product} {default} + bool ParallelRefProcBalancingEnabled = true {product} {default} + bool ParallelRefProcEnabled = true {product} {default} + bool PartialPeelAtUnsignedTests = true {C2 product} {default} + bool PartialPeelLoop = true {C2 product} {default} + intx PartialPeelNewPhiDelta = 0 {C2 product} {default} + uint PausePadding = 1 {product} {default} + intx PerBytecodeRecompilationCutoff = 200 {product} {default} + intx PerBytecodeTrapLimit = 4 {product} {default} + intx PerMethodRecompilationCutoff = 400 {product} {default} + intx PerMethodTrapLimit = 100 {product} {default} + bool PerfAllowAtExitRegistration = false {product} {default} + bool PerfBypassFileSystemCheck = false {product} {default} + int PerfDataMemorySize = 32768 {product} {default} + ccstr PerfDataSaveFile = {product} {default} + bool PerfDataSaveToFile = false {product} {default} + bool PerfDisableSharedMem = false {product} {default} + int PerfMaxStringConstLength = 1024 {product} {default} + size_t PreTouchParallelChunkSize = 1073741824 {pd product} {default} + bool PreferInterpreterNativeStubs = false {pd product} {default} + intx PrefetchCopyIntervalInBytes = 576 {product} {default} + intx PrefetchScanIntervalInBytes = 576 {product} {default} + bool PreserveFramePointer = false {pd product} {default} + size_t PretenureSizeThreshold = 0 {product} {default} + bool PrintClassHistogram = false {manageable} {default} + bool PrintCodeCache = false {product} {default} + bool PrintCodeCacheOnCompilation = false {product} {default} + bool PrintCommandLineFlags = false {product} {default} + bool PrintCompilation = false {product} {default} + bool PrintConcurrentLocks = false {manageable} {default} + bool PrintExtendedThreadInfo = false {product} {default} + bool PrintFlagsFinal = true {product} {command line} + bool PrintFlagsInitial = false {product} {default} + bool PrintFlagsRanges = false {product} {default} + bool PrintGC = false {product} {default} + bool PrintGCDetails = false {product} {default} + bool PrintHeapAtSIGBREAK = true {product} {default} + bool PrintSharedArchiveAndExit = false {product} {default} + bool PrintStringTableStatistics = false {product} {default} + bool PrintTieredEvents = false {product} {default} + bool PrintVMOptions = false {product} {default} + bool PrintWarnings = true {product} {default} + bool ProfileExceptionHandlers = true {product} {default} + bool ProfileInterpreter = true {pd product} {default} + intx ProfileMaturityPercentage = 20 {product} {default} + uintx ProfiledCodeHeapSize = 122880000 {pd product} {ergonomic} + uint PromotedPadding = 3 {product} {default} + uintx QueuedAllocationWarningCount = 0 {product} {default} + bool RangeCheckElimination = true {product} {default} + bool ReassociateInvariants = true {C2 product} {default} + bool RecordDynamicDumpInfo = false {product} {default} + bool ReduceBulkZeroing = true {C2 product} {default} + bool ReduceFieldZeroing = true {C2 product} {default} + bool ReduceInitialCardMarks = true {C2 product} {default} + bool ReduceSignalUsage = false {product} {default} + bool RelaxAccessControlCheck = false {product} {default} + ccstr ReplayDataFile = {product} {default} + uintx ReservedCodeCacheSize = 251658240 {pd product} {ergonomic} + bool ResizePLAB = true {product} {default} + bool ResizeTLAB = true {product} {default} + bool RestoreMXCSROnJNICalls = false {product} {default} + bool RestrictContended = true {product} {default} + bool RestrictReservedStack = true {product} {default} + bool RewriteBytecodes = true {pd product} {default} + bool RewriteFrequentPairs = true {pd product} {default} + bool SafepointTimeout = false {product} {default} + double SafepointTimeoutDelay = 10000.000000 {product} {default} + bool SegmentedCodeCache = true {product} {ergonomic} + double SelfDestructTimer = 0.000000 {product} {default} + ccstr SharedArchiveConfigFile = {product} {default} + ccstr SharedArchiveFile = {product} {default} + size_t SharedBaseAddress = 100663296 {product} {default} + ccstr SharedClassListFile = {product} {default} + uint SharedSymbolTableBucketSize = 4 {product} {default} + bool ShowCodeDetailsInExceptionMessages = true {manageable} {default} + bool ShowMessageBoxOnError = false {product} {default} + bool ShrinkHeapInSteps = true {product} {default} + size_t SoftMaxHeapSize = 2147483648 {manageable} {ergonomic} + intx SoftRefLRUPolicyMSPerMB = 1000 {product} {default} + bool SplitIfBlocks = true {C2 product} {default} + intx StackRedPages = 1 {pd product} {default} + intx StackReservedPages = 0 {pd product} {default} + intx StackShadowPages = 8 {pd product} {default} + bool StackTraceInThrowable = true {product} {default} + intx StackYellowPages = 3 {pd product} {default} + uintx StartAggressiveSweepingAt = 10 {product} {default} + bool StartAttachListener = false {product} {default} + ccstr StartFlightRecording = {product} {default} + uint StringDeduplicationAgeThreshold = 3 {product} {default} + uintx StringTableSize = 65536 {product} {default} + bool SuperWordLoopUnrollAnalysis = true {C2 pd product} {default} + bool SuperWordReductions = true {C2 product} {default} + bool SuppressFatalErrorMessage = false {product} {default} + uint SurvivorPadding = 3 {product} {default} + uintx SurvivorRatio = 8 {product} {default} + double SweeperThreshold = 15.000000 {product} {default} + uintx TLABAllocationWeight = 35 {product} {default} + uintx TLABRefillWasteFraction = 64 {product} {default} + size_t TLABSize = 0 {product} {default} + uintx TLABWasteIncrement = 4 {product} {default} + uintx TLABWasteTargetPercent = 1 {product} {default} + uint TargetPLABWastePct = 10 {product} {default} + uint TargetSurvivorRatio = 50 {product} {default} + uint TenuredGenerationSizeIncrement = 20 {product} {default} + uint TenuredGenerationSizeSupplement = 80 {product} {default} + uintx TenuredGenerationSizeSupplementDecay = 2 {product} {default} + int ThreadPriorityPolicy = 0 {product} {default} + bool ThreadPriorityVerbose = false {product} {default} + intx ThreadStackSize = 0 {pd product} {default} + uint ThresholdTolerance = 10 {product} {default} + intx Tier0BackedgeNotifyFreqLog = 10 {product} {default} + intx Tier0InvokeNotifyFreqLog = 7 {product} {default} + intx Tier0ProfilingStartPercentage = 200 {product} {default} + intx Tier23InlineeNotifyFreqLog = 20 {product} {default} + intx Tier2BackEdgeThreshold = 0 {product} {default} + intx Tier2BackedgeNotifyFreqLog = 14 {product} {default} + intx Tier2CompileThreshold = 0 {product} {default} + intx Tier2InvokeNotifyFreqLog = 11 {product} {default} + intx Tier3BackEdgeThreshold = 60000 {product} {default} + intx Tier3BackedgeNotifyFreqLog = 13 {product} {default} + intx Tier3CompileThreshold = 2000 {product} {default} + intx Tier3DelayOff = 2 {product} {default} + intx Tier3DelayOn = 5 {product} {default} + intx Tier3InvocationThreshold = 200 {product} {default} + intx Tier3InvokeNotifyFreqLog = 10 {product} {default} + intx Tier3LoadFeedback = 5 {product} {default} + intx Tier3MinInvocationThreshold = 100 {product} {default} + intx Tier4BackEdgeThreshold = 40000 {product} {default} + intx Tier4CompileThreshold = 15000 {product} {default} + intx Tier4InvocationThreshold = 5000 {product} {default} + intx Tier4LoadFeedback = 3 {product} {default} + intx Tier4MinInvocationThreshold = 600 {product} {default} + bool TieredCompilation = true {pd product} {default} + intx TieredCompileTaskTimeout = 50 {product} {default} + intx TieredRateUpdateMaxTime = 25 {product} {default} + intx TieredRateUpdateMinTime = 1 {product} {default} + intx TieredStopAtLevel = 4 {product} {default} + ccstr TraceJVMTI = {product} {default} + intx TrackedInitializationLimit = 50 {C2 product} {default} + bool TrapBasedNullChecks = false {pd product} {default} + bool TrapBasedRangeChecks = false {C2 pd product} {default} + uint TrimNativeHeapInterval = 0 {product} {default} + int TypeProfileArgsLimit = 2 {product} {default} + uint TypeProfileLevel = 111 {pd product} {default} + intx TypeProfileMajorReceiverPercent = 90 {C2 product} {default} + int TypeProfileParmsLimit = 2 {product} {default} + intx TypeProfileSubTypeCheckCommonThreshold = 50 {C2 product} {default} + intx TypeProfileWidth = 2 {product} {default} + int UnguardOnExecutionViolation = 0 {product} {default} + bool UseAES = true {product} {default} + int UseAVX = 2 {ARCH product} {default} + bool UseAdaptiveGenerationSizePolicyAtMajorCollection = true {product} {default} + bool UseAdaptiveGenerationSizePolicyAtMinorCollection = true {product} {default} + bool UseAdaptiveNUMAChunkSizing = true {product} {default} + bool UseAdaptiveSizeDecayMajorGCCost = true {product} {default} + bool UseAdaptiveSizePolicy = true {product} {default} + bool UseAdaptiveSizePolicyFootprintGoal = true {product} {default} + bool UseAdaptiveSizePolicyWithSystemGC = false {product} {default} + bool UseAddressNop = true {ARCH product} {default} + bool UseAllWindowsProcessorGroups = false {product} {default} + bool UseBASE64Intrinsics = true {product} {default} + bool UseBMI1Instructions = true {ARCH product} {default} + bool UseBMI2Instructions = true {ARCH product} {default} + bool UseBimorphicInlining = true {C2 product} {default} + bool UseCLMUL = true {ARCH product} {default} + bool UseCMoveUnconditionally = false {C2 product} {default} + bool UseCodeCacheFlushing = true {product} {default} + bool UseCompactObjectHeaders = false {product lp64_product} {default} + bool UseCompiler = true {product} {default} + bool UseCompressedClassPointers = true {product lp64_product} {default} + bool UseCompressedOops = true {product lp64_product} {ergonomic} + bool UseCondCardMark = false {product} {default} + bool UseCountLeadingZerosInstruction = true {ARCH product} {default} + bool UseCountTrailingZerosInstruction = true {ARCH product} {default} + bool UseCountedLoopSafepoints = true {C2 product} {default} + bool UseDivMod = true {C2 product} {default} + bool UseDynamicNumberOfCompilerThreads = true {product} {default} + bool UseDynamicNumberOfGCThreads = true {product} {default} + bool UseFMA = true {product} {default} + bool UseFPUForSpilling = true {C2 product} {default} + bool UseFastJNIAccessors = true {product} {default} + bool UseFastStosb = false {ARCH product} {default} + bool UseG1GC = true {product} {command line} + bool UseGCOverheadLimit = true {product} {default} + bool UseInlineCaches = true {product} {default} + bool UseInterpreter = true {product} {default} + bool UseJumpTables = true {C2 product} {default} + bool UseLargePages = false {pd product} {default} + bool UseLargePagesIndividualAllocation = false {pd product} {ergonomic} + bool UseLoopCounter = true {product} {default} + bool UseLoopInvariantCodeMotion = true {C1 product} {default} + bool UseLoopPredicate = true {C2 product} {default} + bool UseMaximumCompactionOnSystemGC = true {product} {default} + bool UseNUMA = false {product} {default} + bool UseNUMAInterleaving = false {product} {default} + bool UseNewLongLShift = true {ARCH product} {default} + bool UseOSErrorReporting = false {product} {default} + bool UseOnStackReplacement = true {pd product} {default} + bool UseOnlyInlinedBimorphic = true {C2 product} {default} + bool UsePSAdaptiveSurvivorSizePolicy = true {product} {default} + bool UseParallelGC = false {product} {default} + bool UsePerfData = true {product} {default} + bool UsePopCountInstruction = true {product} {default} + bool UseProfiledLoopPredicate = true {C2 product} {default} + bool UseSHA = true {product} {default} + int UseSSE = 4 {ARCH product} {default} + bool UseSSE42Intrinsics = true {ARCH product} {default} + bool UseSerialGC = false {product} {default} + bool UseShenandoahGC = false {product} {default} + bool UseSignalChaining = true {product} {default} + bool UseStoreImmI16 = true {ARCH product} {default} + bool UseStringDeduplication = false {product} {default} + bool UseSubwordForMaxVector = true {C2 product} {default} + bool UseSuperWord = true {C2 product} {default} + bool UseSystemMemoryBarrier = false {product} {default} + bool UseTLAB = true {product} {default} + bool UseThreadPriorities = true {pd product} {default} + bool UseTypeProfile = true {product} {default} + bool UseTypeSpeculation = true {C2 product} {default} + bool UseUnalignedLoadStores = true {ARCH product} {default} + bool UseVectorCmov = false {C2 product} {default} + bool UseXMMForArrayCopy = true {product} {default} + bool UseXMMForObjInit = true {ARCH product} {default} + bool UseXmmI2D = true {ARCH product} {default} + bool UseXmmI2F = true {ARCH product} {default} + bool UseXmmLoadAndClearUpper = true {ARCH product} {default} + bool UseXmmRegToRegMoveAll = true {ARCH product} {default} + bool UseZGC = false {product} {default} + intx UserThreadWaitAttemptsAtExit = 30 {product} {default} + int VMThreadPriority = -1 {product} {default} + intx VMThreadStackSize = 0 {pd product} {default} + intx ValueMapInitialSize = 11 {C1 product} {default} + intx ValueMapMaxLoopSize = 8 {C1 product} {default} + intx ValueSearchLimit = 1000 {C2 product} {default} + bool VerifySharedSpaces = false {product} {default} + uint YoungGenerationSizeIncrement = 20 {product} {default} + uint YoungGenerationSizeSupplement = 80 {product} {default} + uintx YoungGenerationSizeSupplementDecay = 8 {product} {default} + size_t YoungPLABSize = 4096 {product} {default} + double ZAllocationSpikeTolerance = 2.000000 {product} {default} + double ZCollectionInterval = 0.000000 {product} {default} + double ZCollectionIntervalMajor = -1.000000 {product} {default} + double ZCollectionIntervalMinor = -1.000000 {product} {default} + bool ZCollectionIntervalOnly = false {product} {default} + double ZFragmentationLimit = 5.000000 {product} {default} + bool ZProactive = true {product} {default} + bool ZUncommit = true {product} {default} + uintx ZUncommitDelay = 300 {product} {default} + double ZYoungCompactionLimit = 25.000000 {product} {default} + bool ZeroTLAB = false {product} {default} +java version "25.0.3" 2026-04-21 LTS +Java(TM) SE Runtime Environment (build 25.0.3+9-LTS-195) +Java HotSpot(TM) 64-Bit Server VM (build 25.0.3+9-LTS-195, mixed mode, sharing) diff --git a/results/02-flags-zgc.txt b/results/02-flags-zgc.txt new file mode 100644 index 0000000..505abc4 --- /dev/null +++ b/results/02-flags-zgc.txt @@ -0,0 +1,513 @@ +[Global flags] + ccstr AOTCache = {product} {default} + ccstr AOTCacheOutput = {product} {default} + bool AOTClassLinking = false {product} {default} + ccstr AOTConfiguration = {product} {default} + ccstr AOTMode = {product} {default} + int ActiveProcessorCount = -1 {product} {default} + uintx AdaptiveSizeDecrementScaleFactor = 4 {product} {default} + uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product} {default} + uintx AdaptiveSizePolicyInitializingSteps = 20 {product} {default} + uintx AdaptiveSizePolicyOutputInterval = 0 {product} {default} + uint AdaptiveSizePolicyWeight = 10 {product} {default} + uint AdaptiveSizeThroughPutPolicy = 0 {product} {default} + uint AdaptiveTimeWeight = 25 {product} {default} + bool AggressiveHeap = false {product} {default} + bool AlignVector = false {C2 product} {default} + ccstr AllocateHeapAt = {product} {default} + int AllocateInstancePrefetchLines = 1 {product} {default} + int AllocatePrefetchDistance = 256 {product} {default} + intx AllocatePrefetchInstr = 0 {product} {default} + int AllocatePrefetchLines = 3 {product} {default} + int AllocatePrefetchStepSize = 64 {product} {default} + int AllocatePrefetchStyle = 1 {product} {default} + bool AllowParallelDefineClass = false {product} {default} + bool AllowRedefinitionToAddDeleteMethods = false {product} {default} + bool AllowUserSignalHandlers = false {product} {default} + bool AllowVectorizeOnDemand = true {C2 product} {default} + bool AlwaysActAsServerClassMachine = false {product} {default} + bool AlwaysCompileLoopMethods = false {product} {default} + bool AlwaysPreTouch = false {product} {default} + bool AlwaysRestoreFPU = false {product} {default} + bool AlwaysTenure = false {product} {default} + ccstr ArchiveClassesAtExit = {product} {default} + intx ArrayCopyLoadStoreMaxElem = 8 {C2 product} {default} + size_t AsyncLogBufferSize = 2097152 {product} {default} + intx AutoBoxCacheMax = 128 {C2 product} {default} + bool AutoCreateSharedArchive = false {product} {default} + intx BCEATraceLevel = 0 {product} {default} + bool BackgroundCompilation = true {pd product} {default} + bool BlockLayoutByFrequency = true {C2 product} {default} + intx BlockLayoutMinDiamondPercentage = 20 {C2 product} {default} + bool BlockLayoutRotateLoops = true {C2 product} {default} + intx C1InlineStackLimit = 5 {C1 product} {default} + intx C1MaxInlineLevel = 9 {C1 product} {default} + intx C1MaxInlineSize = 35 {C1 product} {default} + intx C1MaxRecursiveInlineLevel = 1 {C1 product} {default} + intx C1MaxTrivialSize = 6 {C1 product} {default} + bool C1OptimizeVirtualCallProfiling = true {C1 product} {default} + bool C1ProfileBranches = true {C1 product} {default} + bool C1ProfileCalls = true {C1 product} {default} + bool C1ProfileCheckcasts = true {C1 product} {default} + bool C1ProfileInlinedCalls = true {C1 product} {default} + bool C1ProfileVirtualCalls = true {C1 product} {default} + bool C1UpdateMethodData = true {C1 product} {default} + intx CICompilerCount = 4 {product} {ergonomic} + bool CICompilerCountPerCPU = true {product} {default} + bool CITime = false {product} {default} + bool CheckJNICalls = false {product} {default} + bool ClassUnloading = true {product} {default} + bool ClassUnloadingWithConcurrentMark = true {product} {default} + bool ClipInlining = true {product} {default} + uintx CodeCacheExpansionSize = 65536 {pd product} {default} + bool CompactStrings = true {pd product} {default} + ccstr CompilationMode = default {product} {default} +ccstrlist CompileCommand = {product} {default} + ccstr CompileCommandFile = {product} {default} +ccstrlist CompileOnly = {product} {default} + intx CompileThreshold = 10000 {pd product} {default} + double CompileThresholdScaling = 1.000000 {product} {default} + int CompilerThreadPriority = -1 {product} {default} + intx CompilerThreadStackSize = 0 {pd product} {default} + size_t CompressedClassSpaceSize = 1073741824 {product} {default} + uint ConcGCThreads = 3 {product} {default} + intx ConditionalMoveLimit = 3 {C2 pd product} {default} + int ContendedPaddingWidth = 128 {product} {default} + bool CrashOnOutOfMemoryError = false {product} {default} + bool CreateCoredumpOnCrash = true {product} {default} + bool DTraceAllocProbes = false {product} {default} + bool DTraceMethodProbes = false {product} {default} + bool DTraceMonitorProbes = false {product} {default} + bool DisableAttachMechanism = false {product} {default} + bool DisableExplicitGC = false {product} {default} + bool DisplayVMOutputToStderr = false {product} {default} + bool DisplayVMOutputToStdout = false {product} {default} + bool DoEscapeAnalysis = true {C2 product} {default} + bool DontCompileHugeMethods = true {product} {default} + ccstr DumpLoadedClassList = {product} {default} + bool DumpReplayDataOnError = true {product} {default} + bool EagerXrunInit = false {product} {default} + intx EliminateAllocationArraySizeLimit = 64 {C2 product} {default} + bool EliminateAllocations = true {C2 product} {default} + bool EliminateAutoBox = true {C2 product} {default} + bool EliminateLocks = true {C2 product} {default} + bool EliminateNestedLocks = true {C2 product} {default} + bool EnableAllLargePageSizesForWindows = false {product} {default} + bool EnableContended = true {product} {default} + bool EnableDynamicAgentLoading = true {product} {default} + size_t ErgoHeapSizeLimit = 0 {product} {default} + ccstr ErrorFile = {product} {default} + bool ErrorFileToStderr = false {product} {default} + bool ErrorFileToStdout = false {product} {default} + uint64_t ErrorLogTimeout = 120 {product} {default} + double EscapeAnalysisTimeout = 20.000000 {C2 product} {default} + bool EstimateArgEscape = true {product} {default} + bool ExecutingUnitTests = false {product} {default} + bool ExitOnOutOfMemoryError = false {product} {default} + bool ExplicitGCInvokesConcurrent = false {product} {default} + bool ExtensiveErrorReports = false {product} {default} + ccstr ExtraSharedClassListFile = {product} {default} + bool FlightRecorder = false {product} {default} + ccstr FlightRecorderOptions = {product} {default} + bool ForceTimeHighResolution = false {product} {default} + intx FreqInlineSize = 325 {C2 pd product} {default} + uint FullGCHeapDumpLimit = 0 {manageable} {default} + double G1ConcMarkStepDurationMillis = 10.000000 {product} {default} + uint G1ConcRefinementThreads = 0 {product} {default} + uint G1ConfidencePercent = 50 {product} {default} + size_t G1HeapRegionSize = 0 {product} {default} + uint G1HeapWastePercent = 5 {product} {default} + uintx G1MixedGCCountTarget = 8 {product} {default} + uintx G1PeriodicGCInterval = 0 {manageable} {default} + bool G1PeriodicGCInvokesConcurrent = true {product} {default} + double G1PeriodicGCSystemLoadThreshold = 0.000000 {manageable} {default} + uint G1RSetUpdatingPauseTimePercent = 10 {product} {default} + uint G1RefProcDrainInterval = 1000 {product} {default} + uint G1ReservePercent = 10 {product} {default} + uint G1SATBBufferEnqueueingThresholdPercent = 60 {product} {default} + size_t G1SATBBufferSize = 1024 {product} {default} + size_t G1UpdateBufferSize = 256 {product} {default} + bool G1UseAdaptiveIHOP = true {product} {default} + uint GCCardSizeInBytes = 512 {product} {default} + uint GCDrainStackTargetSize = 64 {product} {default} + uint GCHeapFreeLimit = 2 {product} {default} + uintx GCPauseIntervalMillis = 0 {product} {default} + uint GCTimeLimit = 98 {product} {default} + uint GCTimeRatio = 99 {product} {default} + size_t HeapBaseMinAddress = 2147483648 {pd product} {default} + bool HeapDumpAfterFullGC = false {manageable} {default} + bool HeapDumpBeforeFullGC = false {manageable} {default} + int HeapDumpGzipLevel = 0 {manageable} {default} + bool HeapDumpOnOutOfMemoryError = false {manageable} {default} + ccstr HeapDumpPath = {manageable} {default} + uintx HeapMaximumCompactionInterval = 20 {product} {default} + uintx HeapSearchSteps = 3 {product} {default} + size_t HeapSizePerGCThread = 43620760 {product} {default} + bool IgnoreEmptyClassPaths = false {product} {default} + bool IgnoreUnrecognizedVMOptions = false {product} {default} + uintx IncreaseFirstTierCompileThresholdAt = 50 {product} {default} + bool IncrementalInline = true {C2 product} {default} + uintx InitialCodeCacheSize = 2555904 {pd product} {default} + size_t InitialHeapSize = 2147483648 {product} {command line} + double InitialRAMPercentage = 1.562500 {product} {default} + uintx InitialSurvivorRatio = 8 {product} {default} + uint InitialTenuringThreshold = 7 {product} {default} + uint InitiatingHeapOccupancyPercent = 45 {product} {default} + bool Inline = true {product} {default} + ccstr InlineDataFile = {product} {default} + intx InlineSmallCode = 2500 {C2 pd product} {default} + bool InlineSynchronizedMethods = true {C1 product} {default} + intx InteriorEntryAlignment = 16 {C2 pd product} {default} + intx InterpreterProfilePercentage = 33 {product} {default} + bool JavaMonitorsInStackTrace = true {product} {default} + int JavaPriority10_To_OSPriority = -1 {product} {default} + int JavaPriority1_To_OSPriority = -1 {product} {default} + int JavaPriority2_To_OSPriority = -1 {product} {default} + int JavaPriority3_To_OSPriority = -1 {product} {default} + int JavaPriority4_To_OSPriority = -1 {product} {default} + int JavaPriority5_To_OSPriority = -1 {product} {default} + int JavaPriority6_To_OSPriority = -1 {product} {default} + int JavaPriority7_To_OSPriority = -1 {product} {default} + int JavaPriority8_To_OSPriority = -1 {product} {default} + int JavaPriority9_To_OSPriority = -1 {product} {default} + size_t LargePageHeapSizeThreshold = 134217728 {product} {default} + size_t LargePageSizeInBytes = 0 {product} {default} + intx LiveNodeCountInliningCutoff = 40000 {C2 product} {default} + int LockingMode = 2 {product} {default} + ccstr LogClassLoadingCauseFor = {product} {default} + intx LoopMaxUnroll = 16 {C2 product} {default} + intx LoopOptsCount = 43 {C2 product} {default} + intx LoopPercentProfileLimit = 10 {C2 pd product} {default} + uintx LoopStripMiningIter = 1000 {C2 product} {default} + uintx LoopStripMiningIterShortLoop = 100 {C2 product} {default} + intx LoopUnrollLimit = 60 {C2 pd product} {default} + intx LoopUnrollMin = 4 {C2 product} {default} + bool LoopUnswitching = true {C2 product} {default} + bool ManagementServer = false {product} {default} + size_t MarkStackSize = 4194304 {product} {default} + size_t MarkStackSizeMax = 536870912 {product} {default} + uint MarkSweepAlwaysCompactCount = 4 {product} {default} + uint MarkSweepDeadRatio = 5 {product} {default} + intx MaxBCEAEstimateLevel = 5 {product} {default} + intx MaxBCEAEstimateSize = 150 {product} {default} + uint64_t MaxDirectMemorySize = 0 {product} {default} + bool MaxFDLimit = true {product} {default} + uintx MaxGCPauseMillis = 18446744073709551614 {product} {default} + uintx MaxHeapFreeRatio = 70 {manageable} {default} + size_t MaxHeapSize = 2147483648 {product} {command line} + intx MaxInlineLevel = 15 {C2 product} {default} + intx MaxInlineSize = 35 {C2 product} {default} + intx MaxJNILocalCapacity = 65536 {product} {default} + int MaxJavaStackTraceDepth = 1024 {product} {default} + intx MaxJumpTableSize = 65000 {C2 product} {default} + intx MaxJumpTableSparseness = 5 {C2 product} {default} + intx MaxLabelRootDepth = 1100 {C2 product} {default} + intx MaxLoopPad = 15 {C2 product} {default} + size_t MaxMetaspaceExpansion = 5439488 {product} {default} + uint MaxMetaspaceFreeRatio = 70 {product} {default} + size_t MaxMetaspaceSize = 18446744073709551615 {product} {default} + size_t MaxNewSize = 18446744073709551615 {product} {default} + intx MaxNodeLimit = 80000 {C2 product} {default} + uint64_t MaxRAM = 137438953472 {pd product} {default} + double MaxRAMPercentage = 25.000000 {product} {default} + intx MaxRecursiveInlineLevel = 1 {C2 product} {default} + uint MaxTenuringThreshold = 14 {product} {default} + intx MaxTrivialSize = 6 {C2 product} {default} + intx MaxVectorSize = 32 {C2 product} {default} + size_t MetaspaceSize = 22020096 {product} {default} + bool MethodFlushing = true {product} {default} + size_t MinHeapDeltaBytes = 2097152 {product} {ergonomic} + uintx MinHeapFreeRatio = 40 {manageable} {default} + size_t MinHeapSize = 2147483648 {product} {command line} + intx MinJumpTableSize = 10 {C2 pd product} {default} + size_t MinMetaspaceExpansion = 327680 {product} {default} + uint MinMetaspaceFreeRatio = 40 {product} {default} + double MinRAMPercentage = 50.000000 {product} {default} + uintx MinSurvivorRatio = 3 {product} {default} + size_t MinTLABSize = 2048 {product} {default} + intx MultiArrayExpandLimit = 6 {C2 product} {default} + uintx NUMAChunkResizeWeight = 20 {product} {default} + size_t NUMAInterleaveGranularity = 2097152 {product} {default} + size_t NUMASpaceResizeRate = 1073741824 {product} {default} + bool NUMAStats = false {product} {default} + ccstr NativeMemoryTracking = off {product} {default} + bool NeverActAsServerClassMachine = false {pd product} {default} + bool NeverTenure = false {product} {default} + uintx NewRatio = 2 {product} {default} + size_t NewSize = 1363144 {product} {default} + size_t NewSizeThreadIncrease = 5320 {pd product} {default} + intx NmethodSweepActivity = 4 {product} {default} + intx NodeLimitFudgeFactor = 2000 {C2 product} {default} + uintx NonNMethodCodeHeapSize = 5832704 {pd product} {ergonomic} + uintx NonProfiledCodeHeapSize = 122945536 {pd product} {ergonomic} + intx NumberOfLoopInstrToAlign = 4 {C2 product} {default} + int ObjectAlignmentInBytes = 8 {product lp64_product} {default} + size_t OldPLABSize = 1024 {product} {default} + bool OmitStackTraceInFastThrow = true {product} {default} +ccstrlist OnError = {product} {default} +ccstrlist OnOutOfMemoryError = {product} {default} + intx OnStackReplacePercentage = 140 {pd product} {default} + bool OptimizeFill = false {C2 product} {default} + bool OptimizePtrCompare = true {C2 product} {default} + bool OptimizeStringConcat = true {C2 product} {default} + bool OptoBundling = false {C2 pd product} {default} + intx OptoLoopAlignment = 16 {pd product} {default} + bool OptoRegScheduling = true {C2 pd product} {default} + bool OptoScheduling = false {C2 pd product} {default} + uint PLABWeight = 75 {product} {default} + bool PSChunkLargeArrays = true {product} {default} + int ParGCArrayScanChunk = 50 {product} {default} + uint ParallelGCBufferWastePct = 10 {product} {default} + uint ParallelGCThreads = 8 {product} {default} + bool ParallelRefProcBalancingEnabled = true {product} {default} + bool ParallelRefProcEnabled = false {product} {default} + bool PartialPeelAtUnsignedTests = true {C2 product} {default} + bool PartialPeelLoop = true {C2 product} {default} + intx PartialPeelNewPhiDelta = 0 {C2 product} {default} + uint PausePadding = 1 {product} {default} + intx PerBytecodeRecompilationCutoff = 200 {product} {default} + intx PerBytecodeTrapLimit = 4 {product} {default} + intx PerMethodRecompilationCutoff = 400 {product} {default} + intx PerMethodTrapLimit = 100 {product} {default} + bool PerfAllowAtExitRegistration = false {product} {default} + bool PerfBypassFileSystemCheck = false {product} {default} + int PerfDataMemorySize = 32768 {product} {default} + ccstr PerfDataSaveFile = {product} {default} + bool PerfDataSaveToFile = false {product} {default} + bool PerfDisableSharedMem = false {product} {default} + int PerfMaxStringConstLength = 1024 {product} {default} + size_t PreTouchParallelChunkSize = 1073741824 {pd product} {default} + bool PreferInterpreterNativeStubs = false {pd product} {default} + intx PrefetchCopyIntervalInBytes = 576 {product} {default} + intx PrefetchScanIntervalInBytes = 576 {product} {default} + bool PreserveFramePointer = false {pd product} {default} + size_t PretenureSizeThreshold = 0 {product} {default} + bool PrintClassHistogram = false {manageable} {default} + bool PrintCodeCache = false {product} {default} + bool PrintCodeCacheOnCompilation = false {product} {default} + bool PrintCommandLineFlags = false {product} {default} + bool PrintCompilation = false {product} {default} + bool PrintConcurrentLocks = false {manageable} {default} + bool PrintExtendedThreadInfo = false {product} {default} + bool PrintFlagsFinal = true {product} {command line} + bool PrintFlagsInitial = false {product} {default} + bool PrintFlagsRanges = false {product} {default} + bool PrintGC = false {product} {default} + bool PrintGCDetails = false {product} {default} + bool PrintHeapAtSIGBREAK = true {product} {default} + bool PrintSharedArchiveAndExit = false {product} {default} + bool PrintStringTableStatistics = false {product} {default} + bool PrintTieredEvents = false {product} {default} + bool PrintVMOptions = false {product} {default} + bool PrintWarnings = true {product} {default} + bool ProfileExceptionHandlers = true {product} {default} + bool ProfileInterpreter = true {pd product} {default} + intx ProfileMaturityPercentage = 20 {product} {default} + uintx ProfiledCodeHeapSize = 122880000 {pd product} {ergonomic} + uint PromotedPadding = 3 {product} {default} + uintx QueuedAllocationWarningCount = 0 {product} {default} + bool RangeCheckElimination = true {product} {default} + bool ReassociateInvariants = true {C2 product} {default} + bool RecordDynamicDumpInfo = false {product} {default} + bool ReduceBulkZeroing = true {C2 product} {default} + bool ReduceFieldZeroing = true {C2 product} {default} + bool ReduceInitialCardMarks = true {C2 product} {default} + bool ReduceSignalUsage = false {product} {default} + bool RelaxAccessControlCheck = false {product} {default} + ccstr ReplayDataFile = {product} {default} + uintx ReservedCodeCacheSize = 251658240 {pd product} {ergonomic} + bool ResizePLAB = true {product} {default} + bool ResizeTLAB = true {product} {default} + bool RestoreMXCSROnJNICalls = false {product} {default} + bool RestrictContended = true {product} {default} + bool RestrictReservedStack = true {product} {default} + bool RewriteBytecodes = true {pd product} {default} + bool RewriteFrequentPairs = true {pd product} {default} + bool SafepointTimeout = false {product} {default} + double SafepointTimeoutDelay = 10000.000000 {product} {default} + bool SegmentedCodeCache = true {product} {ergonomic} + double SelfDestructTimer = 0.000000 {product} {default} + ccstr SharedArchiveConfigFile = {product} {default} + ccstr SharedArchiveFile = {product} {default} + size_t SharedBaseAddress = 2600468480 {product} {default} + ccstr SharedClassListFile = {product} {default} + uint SharedSymbolTableBucketSize = 4 {product} {default} + bool ShowCodeDetailsInExceptionMessages = true {manageable} {default} + bool ShowMessageBoxOnError = false {product} {default} + bool ShrinkHeapInSteps = true {product} {default} + size_t SoftMaxHeapSize = 2147483648 {manageable} {ergonomic} + intx SoftRefLRUPolicyMSPerMB = 1000 {product} {default} + bool SplitIfBlocks = true {C2 product} {default} + intx StackRedPages = 1 {pd product} {default} + intx StackReservedPages = 0 {pd product} {default} + intx StackShadowPages = 8 {pd product} {default} + bool StackTraceInThrowable = true {product} {default} + intx StackYellowPages = 3 {pd product} {default} + uintx StartAggressiveSweepingAt = 10 {product} {default} + bool StartAttachListener = false {product} {default} + ccstr StartFlightRecording = {product} {default} + uint StringDeduplicationAgeThreshold = 3 {product} {default} + uintx StringTableSize = 65536 {product} {default} + bool SuperWordLoopUnrollAnalysis = true {C2 pd product} {default} + bool SuperWordReductions = true {C2 product} {default} + bool SuppressFatalErrorMessage = false {product} {default} + uint SurvivorPadding = 3 {product} {default} + uintx SurvivorRatio = 8 {product} {default} + double SweeperThreshold = 15.000000 {product} {default} + uintx TLABAllocationWeight = 35 {product} {default} + uintx TLABRefillWasteFraction = 64 {product} {default} + size_t TLABSize = 262144 {product} {default} + uintx TLABWasteIncrement = 4 {product} {default} + uintx TLABWasteTargetPercent = 1 {product} {default} + uint TargetPLABWastePct = 10 {product} {default} + uint TargetSurvivorRatio = 50 {product} {default} + uint TenuredGenerationSizeIncrement = 20 {product} {default} + uint TenuredGenerationSizeSupplement = 80 {product} {default} + uintx TenuredGenerationSizeSupplementDecay = 2 {product} {default} + int ThreadPriorityPolicy = 0 {product} {default} + bool ThreadPriorityVerbose = false {product} {default} + intx ThreadStackSize = 0 {pd product} {default} + uint ThresholdTolerance = 10 {product} {default} + intx Tier0BackedgeNotifyFreqLog = 10 {product} {default} + intx Tier0InvokeNotifyFreqLog = 7 {product} {default} + intx Tier0ProfilingStartPercentage = 200 {product} {default} + intx Tier23InlineeNotifyFreqLog = 20 {product} {default} + intx Tier2BackEdgeThreshold = 0 {product} {default} + intx Tier2BackedgeNotifyFreqLog = 14 {product} {default} + intx Tier2CompileThreshold = 0 {product} {default} + intx Tier2InvokeNotifyFreqLog = 11 {product} {default} + intx Tier3BackEdgeThreshold = 60000 {product} {default} + intx Tier3BackedgeNotifyFreqLog = 13 {product} {default} + intx Tier3CompileThreshold = 2000 {product} {default} + intx Tier3DelayOff = 2 {product} {default} + intx Tier3DelayOn = 5 {product} {default} + intx Tier3InvocationThreshold = 200 {product} {default} + intx Tier3InvokeNotifyFreqLog = 10 {product} {default} + intx Tier3LoadFeedback = 5 {product} {default} + intx Tier3MinInvocationThreshold = 100 {product} {default} + intx Tier4BackEdgeThreshold = 40000 {product} {default} + intx Tier4CompileThreshold = 15000 {product} {default} + intx Tier4InvocationThreshold = 5000 {product} {default} + intx Tier4LoadFeedback = 3 {product} {default} + intx Tier4MinInvocationThreshold = 600 {product} {default} + bool TieredCompilation = true {pd product} {default} + intx TieredCompileTaskTimeout = 50 {product} {default} + intx TieredRateUpdateMaxTime = 25 {product} {default} + intx TieredRateUpdateMinTime = 1 {product} {default} + intx TieredStopAtLevel = 4 {product} {default} + ccstr TraceJVMTI = {product} {default} + intx TrackedInitializationLimit = 50 {C2 product} {default} + bool TrapBasedNullChecks = false {pd product} {default} + bool TrapBasedRangeChecks = false {C2 pd product} {default} + uint TrimNativeHeapInterval = 0 {product} {default} + int TypeProfileArgsLimit = 2 {product} {default} + uint TypeProfileLevel = 111 {pd product} {default} + intx TypeProfileMajorReceiverPercent = 90 {C2 product} {default} + int TypeProfileParmsLimit = 2 {product} {default} + intx TypeProfileSubTypeCheckCommonThreshold = 50 {C2 product} {default} + intx TypeProfileWidth = 2 {product} {default} + int UnguardOnExecutionViolation = 0 {product} {default} + bool UseAES = true {product} {default} + int UseAVX = 2 {ARCH product} {default} + bool UseAdaptiveGenerationSizePolicyAtMajorCollection = true {product} {default} + bool UseAdaptiveGenerationSizePolicyAtMinorCollection = true {product} {default} + bool UseAdaptiveNUMAChunkSizing = true {product} {default} + bool UseAdaptiveSizeDecayMajorGCCost = true {product} {default} + bool UseAdaptiveSizePolicy = true {product} {default} + bool UseAdaptiveSizePolicyFootprintGoal = true {product} {default} + bool UseAdaptiveSizePolicyWithSystemGC = false {product} {default} + bool UseAddressNop = true {ARCH product} {default} + bool UseAllWindowsProcessorGroups = false {product} {default} + bool UseBASE64Intrinsics = true {product} {default} + bool UseBMI1Instructions = true {ARCH product} {default} + bool UseBMI2Instructions = true {ARCH product} {default} + bool UseBimorphicInlining = true {C2 product} {default} + bool UseCLMUL = true {ARCH product} {default} + bool UseCMoveUnconditionally = false {C2 product} {default} + bool UseCodeCacheFlushing = true {product} {default} + bool UseCompactObjectHeaders = false {product lp64_product} {default} + bool UseCompiler = true {product} {default} + bool UseCompressedClassPointers = true {product lp64_product} {default} + bool UseCompressedOops = false {product lp64_product} {ergonomic} + bool UseCondCardMark = false {product} {default} + bool UseCountLeadingZerosInstruction = true {ARCH product} {default} + bool UseCountTrailingZerosInstruction = true {ARCH product} {default} + bool UseCountedLoopSafepoints = true {C2 product} {default} + bool UseDivMod = true {C2 product} {default} + bool UseDynamicNumberOfCompilerThreads = true {product} {default} + bool UseDynamicNumberOfGCThreads = true {product} {default} + bool UseFMA = true {product} {default} + bool UseFPUForSpilling = true {C2 product} {default} + bool UseFastJNIAccessors = true {product} {default} + bool UseFastStosb = false {ARCH product} {default} + bool UseG1GC = false {product} {default} + bool UseGCOverheadLimit = true {product} {default} + bool UseInlineCaches = true {product} {default} + bool UseInterpreter = true {product} {default} + bool UseJumpTables = true {C2 product} {default} + bool UseLargePages = false {pd product} {default} + bool UseLargePagesIndividualAllocation = false {pd product} {ergonomic} + bool UseLoopCounter = true {product} {default} + bool UseLoopInvariantCodeMotion = true {C1 product} {default} + bool UseLoopPredicate = true {C2 product} {default} + bool UseMaximumCompactionOnSystemGC = true {product} {default} + bool UseNUMA = false {product} {default} + bool UseNUMAInterleaving = false {product} {default} + bool UseNewLongLShift = true {ARCH product} {default} + bool UseOSErrorReporting = false {product} {default} + bool UseOnStackReplacement = true {pd product} {default} + bool UseOnlyInlinedBimorphic = true {C2 product} {default} + bool UsePSAdaptiveSurvivorSizePolicy = true {product} {default} + bool UseParallelGC = false {product} {default} + bool UsePerfData = true {product} {default} + bool UsePopCountInstruction = true {product} {default} + bool UseProfiledLoopPredicate = true {C2 product} {default} + bool UseSHA = true {product} {default} + int UseSSE = 4 {ARCH product} {default} + bool UseSSE42Intrinsics = true {ARCH product} {default} + bool UseSerialGC = false {product} {default} + bool UseShenandoahGC = false {product} {default} + bool UseSignalChaining = true {product} {default} + bool UseStoreImmI16 = true {ARCH product} {default} + bool UseStringDeduplication = false {product} {default} + bool UseSubwordForMaxVector = true {C2 product} {default} + bool UseSuperWord = true {C2 product} {default} + bool UseSystemMemoryBarrier = false {product} {default} + bool UseTLAB = true {product} {default} + bool UseThreadPriorities = true {pd product} {default} + bool UseTypeProfile = true {product} {default} + bool UseTypeSpeculation = true {C2 product} {default} + bool UseUnalignedLoadStores = true {ARCH product} {default} + bool UseVectorCmov = false {C2 product} {default} + bool UseXMMForArrayCopy = true {product} {default} + bool UseXMMForObjInit = true {ARCH product} {default} + bool UseXmmI2D = true {ARCH product} {default} + bool UseXmmI2F = true {ARCH product} {default} + bool UseXmmLoadAndClearUpper = true {ARCH product} {default} + bool UseXmmRegToRegMoveAll = true {ARCH product} {default} + bool UseZGC = true {product} {command line} + intx UserThreadWaitAttemptsAtExit = 30 {product} {default} + int VMThreadPriority = -1 {product} {default} + intx VMThreadStackSize = 0 {pd product} {default} + intx ValueMapInitialSize = 11 {C1 product} {default} + intx ValueMapMaxLoopSize = 8 {C1 product} {default} + intx ValueSearchLimit = 1000 {C2 product} {default} + bool VerifySharedSpaces = false {product} {default} + uint YoungGenerationSizeIncrement = 20 {product} {default} + uint YoungGenerationSizeSupplement = 80 {product} {default} + uintx YoungGenerationSizeSupplementDecay = 8 {product} {default} + size_t YoungPLABSize = 4096 {product} {default} + double ZAllocationSpikeTolerance = 2.000000 {product} {default} + double ZCollectionInterval = 0.000000 {product} {default} + double ZCollectionIntervalMajor = -1.000000 {product} {default} + double ZCollectionIntervalMinor = -1.000000 {product} {default} + bool ZCollectionIntervalOnly = false {product} {default} + double ZFragmentationLimit = 5.000000 {product} {default} + bool ZProactive = true {product} {default} + bool ZUncommit = false {product} {ergonomic} + uintx ZUncommitDelay = 300 {product} {default} + double ZYoungCompactionLimit = 25.000000 {product} {default} + bool ZeroTLAB = false {product} {default} +java version "25.0.3" 2026-04-21 LTS +Java(TM) SE Runtime Environment (build 25.0.3+9-LTS-195) +Java HotSpot(TM) 64-Bit Server VM (build 25.0.3+9-LTS-195, mixed mode, sharing) diff --git a/results/03-latency-g1.txt b/results/03-latency-g1.txt new file mode 100644 index 0000000..fd4ffca --- /dev/null +++ b/results/03-latency-g1.txt @@ -0,0 +1,47 @@ +============================================================================== +ZGC / G1 open-loop latency harness +============================================================================== +collector : G1 Young Generation + G1 Concurrent GC + G1 Old Generation +java : 25.0.3+9-LTS-195 +threads=4 rate=20,000/s warmup=20s measure=60s +liveSet=150,000 entries x 4,096 B (~585 MB live) +garbage=16,384 B/request reads=64/request mutationProbability=0.20 +nominal allocation rate ~328 MB/s seed=20260730 +------------------------------------------------------------------------------ +building live set ... 150,000 entries, ~589 MB live, took 266 ms +warming up for 20 s at 20,000 req/s ... +measuring for 60 s at 20,000 req/s ... + +------------------------------------------------------------------------------ +achieved throughput : 19,976 req/s over 60.1 s + +RESPONSE TIME (from intended arrival -- the honest number) (n=1,200,000) + mean 0.388 ms + p50 0.005 ms + p90 0.009 ms + p99 8.042 ms + p99.9 95.169 ms + p99.99 126.949 ms + max 133.018 ms + +SERVICE TIME (from actual start -- hides queueing) (n=1,200,000) + mean 0.007 ms + p50 0.005 ms + p90 0.008 ms + p99 0.016 ms + p99.9 0.033 ms + p99.99 0.171 ms + max 113.864 ms + +coordinated-omission gap at p99.9 : 95.169 ms response vs 0.033 ms service (2910.4x) + +GC activity during the measured window + G1 Young Generation collections=36 time= 604 ms [stop-the-world] + G1 Concurrent GC collections=19 time= 15 ms [cycle (mostly concurrent)] + G1 Old Generation collections=2 time= 208 ms [stop-the-world] + +CSV (response time) +collector,n,mean_ms,p50_ms,p90_ms,p99_ms,p999_ms,p9999_ms,max_ms +G1 Young Generation + G1 Concurrent GC + G1 Old Generation,1200000,0.388,0.005,0.009,8.042,95.169,126.949,133.018 + +liveSet checksum: 0 diff --git a/results/03-latency-zgc.txt b/results/03-latency-zgc.txt new file mode 100644 index 0000000..1a15281 --- /dev/null +++ b/results/03-latency-zgc.txt @@ -0,0 +1,48 @@ +============================================================================== +ZGC / G1 open-loop latency harness +============================================================================== +collector : ZGC Minor Cycles + ZGC Minor Pauses + ZGC Major Cycles + ZGC Major Pauses +java : 25.0.3+9-LTS-195 +threads=4 rate=20,000/s warmup=20s measure=60s +liveSet=150,000 entries x 4,096 B (~585 MB live) +garbage=16,384 B/request reads=64/request mutationProbability=0.20 +nominal allocation rate ~328 MB/s seed=20260730 +------------------------------------------------------------------------------ +building live set ... 150,000 entries, ~589 MB live, took 310 ms +warming up for 20 s at 20,000 req/s ... +measuring for 60 s at 20,000 req/s ... + +------------------------------------------------------------------------------ +achieved throughput : 19,973 req/s over 60.1 s + +RESPONSE TIME (from intended arrival -- the honest number) (n=1,200,000) + mean 0.016 ms + p50 0.006 ms + p90 0.009 ms + p99 0.029 ms + p99.9 1.437 ms + p99.99 23.675 ms + max 32.178 ms + +SERVICE TIME (from actual start -- hides queueing) (n=1,200,000) + mean 0.007 ms + p50 0.006 ms + p90 0.009 ms + p99 0.025 ms + p99.9 0.143 ms + p99.99 0.269 ms + max 8.353 ms + +coordinated-omission gap at p99.9 : 1.437 ms response vs 0.143 ms service (10.0x) + +GC activity during the measured window + ZGC Minor Cycles collections=18 time= 919 ms [cycle (mostly concurrent)] + ZGC Minor Pauses collections=54 time= 0 ms [stop-the-world] + ZGC Major Cycles collections=3 time= 667 ms [cycle (mostly concurrent)] + ZGC Major Pauses collections=15 time= 0 ms [stop-the-world] + +CSV (response time) +collector,n,mean_ms,p50_ms,p90_ms,p99_ms,p999_ms,p9999_ms,max_ms +ZGC Minor Cycles + ZGC Minor Pauses + ZGC Major Cycles + ZGC Major Pauses,1200000,0.016,0.006,0.009,0.029,1.437,23.675,32.178 + +liveSet checksum: 1 diff --git a/results/04-stalls-g1.txt b/results/04-stalls-g1.txt new file mode 100644 index 0000000..43b5515 --- /dev/null +++ b/results/04-stalls-g1.txt @@ -0,0 +1,20 @@ +max heap : 512 MB +target live set : 281 MB (55% of heap) +threads : 12, duration: 20 s + +filling live set ... +live set filled: 4,505 chunks x 64 KB +now allocating hard for 20 s -- expect stalls + +allocation phase done + +======================================================================== +JFR summary (C:\Users\Ankur\allocation-stalls.jfr) +======================================================================== +young collections : 0 +old collections : 0 +page allocations : 0 +ALLOCATION STALLS : 0 + +No stalls recorded. Either the heap was big enough, or you are not +running ZGC. Shrink -Xmx or raise -Dseconds and try again. diff --git a/results/04-stalls-zgc-baseline.txt b/results/04-stalls-zgc-baseline.txt new file mode 100644 index 0000000..b7868dc --- /dev/null +++ b/results/04-stalls-zgc-baseline.txt @@ -0,0 +1,41 @@ +max heap : 512 MB +target live set : 281 MB (55% of heap) +threads : 12, duration: 20 s + +filling live set ... +live set filled: 4,505 chunks x 64 KB +now allocating hard for 20 s -- expect stalls + +allocation phase done + +======================================================================== +JFR summary (C:\Users\Ankur\allocation-stalls.jfr) +======================================================================== +young collections : 1,771 +old collections : 217 +page allocations : 39,796 +ALLOCATION STALLS : 32,200 + +total time threads spent stalled : 139,439 ms +mean stall : 4.33 ms +longest stall : 48.32 ms + +stalls by ZGC page type + Small count=32,200 total=139,439 ms mean=4.33 ms + +ten longest stalls + duration page size thread + 48.32 ms Small 2097152 allocator-3 + 47.99 ms Small 2097152 allocator-10 + 46.39 ms Small 2097152 allocator-1 + 46.23 ms Small 2097152 allocator-0 + 46.19 ms Small 2097152 allocator-7 + 46.18 ms Small 2097152 allocator-5 + 45.11 ms Small 2097152 allocator-6 + 44.85 ms Small 2097152 allocator-7 + 44.68 ms Small 2097152 allocator-10 + 44.49 ms Small 2097152 allocator-0 + +Compare against your pause-time chart: none of the above is a pause. +Inspect the raw events, including the stack that was stalled, with: + jfr print --events ZAllocationStall allocation-stalls.jfr diff --git a/results/04-stalls-zgc-softmax.txt b/results/04-stalls-zgc-softmax.txt new file mode 100644 index 0000000..7c85f7b --- /dev/null +++ b/results/04-stalls-zgc-softmax.txt @@ -0,0 +1,41 @@ +max heap : 512 MB +target live set : 281 MB (55% of heap) +threads : 12, duration: 20 s + +filling live set ... +live set filled: 4,505 chunks x 64 KB +now allocating hard for 20 s -- expect stalls + +allocation phase done + +======================================================================== +JFR summary (C:\Users\Ankur\allocation-stalls.jfr) +======================================================================== +young collections : 1,778 +old collections : 217 +page allocations : 39,685 +ALLOCATION STALLS : 31,967 + +total time threads spent stalled : 138,521 ms +mean stall : 4.33 ms +longest stall : 51.41 ms + +stalls by ZGC page type + Small count=31,967 total=138,521 ms mean=4.33 ms + +ten longest stalls + duration page size thread + 51.41 ms Small 2097152 allocator-10 + 50.18 ms Small 2097152 allocator-0 + 48.12 ms Small 2097152 allocator-5 + 47.93 ms Small 2097152 allocator-1 + 46.90 ms Small 2097152 allocator-1 + 46.14 ms Small 2097152 allocator-11 + 46.14 ms Small 2097152 allocator-11 + 46.08 ms Small 2097152 allocator-6 + 46.02 ms Small 2097152 allocator-4 + 45.68 ms Small 2097152 allocator-9 + +Compare against your pause-time chart: none of the above is a pause. +Inspect the raw events, including the stack that was stalled, with: + jfr print --events ZAllocationStall allocation-stalls.jfr diff --git a/results/04-stalls-zgc-spiketolerance.txt b/results/04-stalls-zgc-spiketolerance.txt new file mode 100644 index 0000000..59b0b63 --- /dev/null +++ b/results/04-stalls-zgc-spiketolerance.txt @@ -0,0 +1,41 @@ +max heap : 512 MB +target live set : 281 MB (55% of heap) +threads : 12, duration: 20 s + +filling live set ... +live set filled: 4,505 chunks x 64 KB +now allocating hard for 20 s -- expect stalls + +allocation phase done + +======================================================================== +JFR summary (C:\Users\Ankur\allocation-stalls.jfr) +======================================================================== +young collections : 1,722 +old collections : 219 +page allocations : 39,803 +ALLOCATION STALLS : 32,442 + +total time threads spent stalled : 140,558 ms +mean stall : 4.33 ms +longest stall : 50.33 ms + +stalls by ZGC page type + Small count=32,442 total=140,558 ms mean=4.33 ms + +ten longest stalls + duration page size thread + 50.33 ms Small 2097152 allocator-10 + 48.98 ms Small 2097152 allocator-5 + 48.96 ms Small 2097152 allocator-6 + 48.84 ms Small 2097152 allocator-7 + 48.79 ms Small 2097152 allocator-1 + 47.89 ms Small 2097152 allocator-0 + 47.33 ms Small 2097152 allocator-10 + 47.12 ms Small 2097152 allocator-3 + 46.96 ms Small 2097152 allocator-5 + 46.71 ms Small 2097152 allocator-1 + +Compare against your pause-time chart: none of the above is a pause. +Inspect the raw events, including the stack that was stalled, with: + jfr print --events ZAllocationStall allocation-stalls.jfr diff --git a/results/05-pages-g1.txt b/results/05-pages-g1.txt new file mode 100644 index 0000000..a2818de --- /dev/null +++ b/results/05-pages-g1.txt @@ -0,0 +1,19 @@ +========================================================================== +Page / region geometry as reported by THIS JVM +========================================================================== +max heap : 2,048 MB +UseG1GC / UseZGC : true / false +G1HeapRegionSize : 1,048,576 bytes (1 MB) +=> G1 humongous threshold: objects larger than 524,288 bytes (512 KB) go straight to old gen + +No jdk.ZPageAllocation events (expected under G1). + +Objects allocated in this run + 65,536 bytes (64 KB) ordinary G1 allocation in an eden region + 262,144 bytes (256 KB) ordinary G1 allocation in an eden region + 524,288 bytes (512 KB) ordinary G1 allocation in an eden region + 2,097,152 bytes (2 MB) HUMONGOUS on G1 -- allocated directly in old gen, spans whole regions + 4,194,304 bytes (4 MB) HUMONGOUS on G1 -- allocated directly in old gen, spans whole regions + 16,777,216 bytes (16 MB) HUMONGOUS on G1 -- allocated directly in old gen, spans whole regions + +checksum: 6 diff --git a/results/05-pages-zgc.txt b/results/05-pages-zgc.txt new file mode 100644 index 0000000..d12c505 --- /dev/null +++ b/results/05-pages-zgc.txt @@ -0,0 +1,33 @@ +========================================================================== +Page / region geometry as reported by THIS JVM +========================================================================== +max heap : 2,048 MB +UseG1GC / UseZGC : false / true +G1HeapRegionSize : 0 (ergonomic / not applicable) +=> ZGC small pages are 2 MB; objects up to 1/8 of a page (256 KB) use them. + Larger objects use a medium page, and anything bigger gets a Large page + of its own -- which ZGC frees rather than relocates. + +ZGC internals flags visible in this JVM + ZFragmentationLimit = 5.0 + ZCollectionIntervalMinor = -1.0 + ZCollectionIntervalMajor = -1.0 + ZAllocationSpikeTolerance = 2.0 + ZUncommit = false + ZUncommitDelay = 300 + SoftMaxHeapSize = 2,147,483,648 bytes (2048 MB) + +ZGC pages actually allocated while creating the objects above + page type count total bytes + Large 2 25,165,824 + Medium 1 33,554,432 + +Objects allocated in this run + 65,536 bytes (64 KB) expect ZGC Small page (2 MB, shared with other objects) + 262,144 bytes (256 KB) expect ZGC Medium page (shared; size is a range in JDK 25) + 524,288 bytes (512 KB) expect ZGC Medium page (shared; size is a range in JDK 25) + 2,097,152 bytes (2 MB) expect ZGC Medium page (shared; size is a range in JDK 25) + 4,194,304 bytes (4 MB) expect ZGC Large page -- one page for this object, freed not relocated + 16,777,216 bytes (16 MB) expect ZGC Large page -- one page for this object, freed not relocated + +checksum: 6 diff --git a/results/06-gclog-g1.txt b/results/06-gclog-g1.txt new file mode 100644 index 0000000..20046e1 --- /dev/null +++ b/results/06-gclog-g1.txt @@ -0,0 +1,40 @@ +============================================================================== +GC log analysis: g1-latency.log +============================================================================== +lines parsed : 1,257 +young / minor cycles : 94 +old / major cycles : 0 +ZGC allocation stalls : 0 +G1 evacuation failures : 16 +full GCs : 4 + +STOP-THE-WORLD PAUSES (this is application freeze time) + count : 68 + total : 1,139.624 ms + mean : 16.759 ms + p50 : 12.857 ms + p99 : 104.449 ms + max : 104.449 ms + + by phase + Pause Young (Normal) n=17 total= 403.699 ms max=103.308 ms + Pause Young (Concurrent Start) n=11 total= 153.384 ms max= 20.587 ms + Pause Remark n=10 total= 13.736 ms max= 1.745 ms + Pause Cleanup n=9 total= 2.472 ms max= 0.438 ms + Pause Young (Prepare Mixed) n=8 total= 110.491 ms max= 24.639 ms + Pause Young (Mixed) n=11 total= 247.284 ms max= 30.879 ms + Pause Full n=2 total= 208.558 ms max=104.449 ms + +CONCURRENT PHASES (application keeps running -- NOT freeze time) + Concurrent Scan Root Regions n=11 total= 12.317 ms max= 1.867 ms + Concurrent Mark From Roots n=11 total= 191.931 ms max=102.516 ms + Concurrent Preclean n=10 total= 0.265 ms max= 0.050 ms + Concurrent Mark n=10 total= 106.217 ms max= 14.524 ms + Concurrent Rebuild Remembered Sets and Scrub Regions n=10 total= 146.586 ms max=113.784 ms + Concurrent Clear Claimed Marks n=9 total= 0.227 ms max= 0.039 ms + Concurrent Cleanup for Next Mark n=9 total= 31.227 ms max= 4.862 ms + Concurrent Mark Cycle n=11 total= 406.062 ms max=125.183 ms + + Adding the block above to the pause block would be a category error: + concurrent time overlaps application execution by design. + diff --git a/results/06-gclog-zgc.txt b/results/06-gclog-zgc.txt new file mode 100644 index 0000000..80fd621 --- /dev/null +++ b/results/06-gclog-zgc.txt @@ -0,0 +1,36 @@ +============================================================================== +GC log analysis: zgc-latency.log +============================================================================== +lines parsed : 2,247 +young / minor cycles : 45 +old / major cycles : 17 +ZGC allocation stalls : 40 +G1 evacuation failures : 0 +full GCs : 0 + +STOP-THE-WORLD PAUSES (this is application freeze time) + count : 106 + total : 1.503 ms + mean : 0.014 ms + p50 : 0.014 ms + p99 : 0.044 ms + max : 0.054 ms + + by phase + Pause Mark Start (Major) n=8 total= 0.139 ms max= 0.021 ms + Pause Mark End n=38 total= 0.683 ms max= 0.044 ms + Pause Relocate Start n=38 total= 0.330 ms max= 0.021 ms + Pause Mark Start n=22 total= 0.351 ms max= 0.054 ms + +CONCURRENT PHASES (application keeps running -- NOT freeze time) + Concurrent Mark n=38 total= 894.499 ms max= 78.403 ms + Concurrent Mark Free n=38 total= 0.097 ms max= 0.033 ms + Concurrent Reset Relocation Set n=38 total= 4.331 ms max= 0.934 ms + Concurrent Select Relocation Set n=38 total= 48.991 ms max= 5.372 ms + Concurrent Relocate n=38 total=1092.392 ms max=151.380 ms + Concurrent Process Non n=8 total= 5.635 ms max= 0.984 ms + Concurrent Remap Roots n=8 total= 10.919 ms max= 2.207 ms + + Adding the block above to the pause block would be a category error: + concurrent time overlaps application execution by design. + diff --git a/results/07-jmh-g1.json b/results/07-jmh-g1.json new file mode 100644 index 0000000..86ff1a6 --- /dev/null +++ b/results/07-jmh-g1.json @@ -0,0 +1,2659 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocate", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "64" + }, + "primaryMetric" : { + "score" : 109398.89489397492, + "scoreError" : 3927.820602912446, + "scoreConfidence" : [ + 105471.07429106248, + 113326.71549688737 + ], + "scorePercentiles" : { + "0.0" : 108216.34392857712, + "50.0" : 109526.92424662814, + "90.0" : 110510.17531937174, + "95.0" : 110510.17531937174, + "99.0" : 110510.17531937174, + "99.9" : 110510.17531937174, + "99.99" : 110510.17531937174, + "99.999" : 110510.17531937174, + "99.9999" : 110510.17531937174, + "100.0" : 110510.17531937174 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 109526.92424662814, + 110510.17531937174, + 108216.34392857712, + 110239.58793715932, + 108501.44303813837 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 8345.78033031376, + "scoreError" : 299.9050071896369, + "scoreConfidence" : [ + 8045.8753231241235, + 8645.685337503397 + ], + "scorePercentiles" : { + "0.0" : 8255.50913574631, + "50.0" : 8355.488350948275, + "90.0" : 8430.634916801757, + "95.0" : 8430.634916801757, + "99.0" : 8430.634916801757, + "99.9" : 8430.634916801757, + "99.99" : 8430.634916801757, + "99.999" : 8430.634916801757, + "99.9999" : 8430.634916801757, + "100.0" : 8430.634916801757 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 8355.488350948275, + 8430.634916801757, + 8255.50913574631, + 8410.009552058369, + 8277.259696014093 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 80.00002123057752, + "scoreError" : 7.663020872752789E-7, + "scoreConfidence" : [ + 80.00002046427542, + 80.00002199687961 + ], + "scorePercentiles" : { + "0.0" : 80.00002101296273, + "50.0" : 80.00002120565506, + "90.0" : 80.00002146268163, + "95.0" : 80.00002146268163, + "99.0" : 80.00002146268163, + "99.9" : 80.00002146268163, + "99.99" : 80.00002146268163, + "99.999" : 80.00002146268163, + "99.9999" : 80.00002146268163, + "100.0" : 80.00002146268163 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 80.00002120565506, + 80.00002101296273, + 80.00002146268163, + 80.00002106770214, + 80.00002140388611 + ] + ] + }, + "gc.count" : { + "score" : 102.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 102.0, + 102.0 + ], + "scorePercentiles" : { + "0.0" : 20.0, + "50.0" : 20.0, + "90.0" : 21.0, + "95.0" : 21.0, + "99.0" : 21.0, + "99.9" : 21.0, + "99.99" : 21.0, + "99.999" : 21.0, + "99.9999" : 21.0, + "100.0" : 21.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 21.0, + 20.0, + 20.0, + 21.0, + 20.0 + ] + ] + }, + "gc.time" : { + "score" : 137.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 137.0, + 137.0 + ], + "scorePercentiles" : { + "0.0" : 26.0, + "50.0" : 28.0, + "90.0" : 29.0, + "95.0" : 29.0, + "99.0" : 29.0, + "99.9" : 29.0, + "99.99" : 29.0, + "99.999" : 29.0, + "99.9999" : 29.0, + "100.0" : 29.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 26.0, + 26.0, + 28.0, + 28.0, + 29.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocate", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "1024" + }, + "primaryMetric" : { + "score" : 7988.094992553338, + "scoreError" : 714.8580246926015, + "scoreConfidence" : [ + 7273.2369678607365, + 8702.95301724594 + ], + "scorePercentiles" : { + "0.0" : 7701.879332448786, + "50.0" : 7966.047044738368, + "90.0" : 8164.541223047242, + "95.0" : 8164.541223047242, + "99.0" : 8164.541223047242, + "99.9" : 8164.541223047242, + "99.99" : 8164.541223047242, + "99.999" : 8164.541223047242, + "99.9999" : 8164.541223047242, + "100.0" : 8164.541223047242 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 7701.879332448786, + 7965.596714843766, + 8142.410647688525, + 8164.541223047242, + 7966.047044738368 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 7921.904021768931, + "scoreError" : 708.6125487683848, + "scoreConfidence" : [ + 7213.291473000546, + 8630.516570537315 + ], + "scorePercentiles" : { + "0.0" : 7638.122612982929, + "50.0" : 7900.144343131304, + "90.0" : 8097.066067830137, + "95.0" : 8097.066067830137, + "99.0" : 8097.066067830137, + "99.9" : 8097.066067830137, + "99.99" : 8097.066067830137, + "99.999" : 8097.066067830137, + "99.9999" : 8097.066067830137, + "100.0" : 8097.066067830137 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 7638.122612982929, + 7899.705041677984, + 8074.482043222303, + 8097.066067830137, + 7900.144343131304 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 1040.0002908176796, + "scoreError" : 2.633956994413332E-5, + "scoreConfidence" : [ + 1040.0002644781096, + 1040.0003171572496 + ], + "scorePercentiles" : { + "0.0" : 1040.0002844545816, + "50.0" : 1040.0002914225372, + "90.0" : 1040.0003015156572, + "95.0" : 1040.0003015156572, + "99.0" : 1040.0003015156572, + "99.9" : 1040.0003015156572, + "99.99" : 1040.0003015156572, + "99.999" : 1040.0003015156572, + "99.9999" : 1040.0003015156572, + "100.0" : 1040.0003015156572 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 1040.0003015156572, + 1040.0002914225372, + 1040.0002852127777, + 1040.0002844545816, + 1040.0002914828444 + ] + ] + }, + "gc.count" : { + "score" : 97.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 97.0, + 97.0 + ], + "scorePercentiles" : { + "0.0" : 19.0, + "50.0" : 19.0, + "90.0" : 20.0, + "95.0" : 20.0, + "99.0" : 20.0, + "99.9" : 20.0, + "99.99" : 20.0, + "99.999" : 20.0, + "99.9999" : 20.0, + "100.0" : 20.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 19.0, + 19.0, + 20.0, + 20.0, + 19.0 + ] + ] + }, + "gc.time" : { + "score" : 152.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 152.0, + 152.0 + ], + "scorePercentiles" : { + "0.0" : 27.0, + "50.0" : 31.0, + "90.0" : 32.0, + "95.0" : 32.0, + "99.0" : 32.0, + "99.9" : 32.0, + "99.99" : 32.0, + "99.999" : 32.0, + "99.9999" : 32.0, + "100.0" : 32.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 31.0, + 31.0, + 31.0, + 32.0, + 27.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocate", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "32768" + }, + "primaryMetric" : { + "score" : 259.45176000991614, + "scoreError" : 16.083901357887687, + "scoreConfidence" : [ + 243.36785865202845, + 275.5356613678038 + ], + "scorePercentiles" : { + "0.0" : 254.05293816460747, + "50.0" : 258.7559901215624, + "90.0" : 264.4968041604801, + "95.0" : 264.4968041604801, + "99.0" : 264.4968041604801, + "99.9" : 264.4968041604801, + "99.99" : 264.4968041604801, + "99.999" : 264.4968041604801, + "99.9999" : 264.4968041604801, + "100.0" : 264.4968041604801 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 257.31639948477886, + 254.05293816460747, + 264.4968041604801, + 262.63666811815204, + 258.7559901215624 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 8111.036498203738, + "scoreError" : 502.74850447626363, + "scoreConfidence" : [ + 7608.287993727475, + 8613.785002680002 + ], + "scorePercentiles" : { + "0.0" : 7942.2808937768295, + "50.0" : 8089.201842763397, + "90.0" : 8268.734575427314, + "95.0" : 8268.734575427314, + "99.0" : 8268.734575427314, + "99.9" : 8268.734575427314, + "99.99" : 8268.734575427314, + "99.999" : 8268.734575427314, + "99.9999" : 8268.734575427314, + "100.0" : 8268.734575427314 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 8044.352858693922, + 7942.2808937768295, + 8268.734575427314, + 8210.61232035723, + 8089.201842763397 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 32784.008950311785, + "scoreError" : 5.577410695908633E-4, + "scoreConfidence" : [ + 32784.008392570715, + 32784.009508052855 + ], + "scorePercentiles" : { + "0.0" : 32784.00877712305, + "50.0" : 32784.008973530144, + "90.0" : 32784.00913977507, + "95.0" : 32784.00913977507, + "99.0" : 32784.00913977507, + "99.9" : 32784.00913977507, + "99.99" : 32784.00913977507, + "99.999" : 32784.00913977507, + "99.9999" : 32784.00913977507, + "100.0" : 32784.00913977507 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 32784.00902196839, + 32784.00913977507, + 32784.00877712305, + 32784.008839162256, + 32784.008973530144 + ] + ] + }, + "gc.count" : { + "score" : 103.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 103.0, + 103.0 + ], + "scorePercentiles" : { + "0.0" : 20.0, + "50.0" : 21.0, + "90.0" : 21.0, + "95.0" : 21.0, + "99.0" : 21.0, + "99.9" : 21.0, + "99.99" : 21.0, + "99.999" : 21.0, + "99.9999" : 21.0, + "100.0" : 21.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 21.0, + 20.0, + 20.0, + 21.0, + 21.0 + ] + ] + }, + "gc.time" : { + "score" : 162.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 162.0, + 162.0 + ], + "scorePercentiles" : { + "0.0" : 31.0, + "50.0" : 33.0, + "90.0" : 34.0, + "95.0" : 34.0, + "99.0" : 34.0, + "99.9" : 34.0, + "99.99" : 34.0, + "99.999" : 34.0, + "99.9999" : 34.0, + "100.0" : 34.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 33.0, + 33.0, + 31.0, + 31.0, + 34.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "64" + }, + "primaryMetric" : { + "score" : 108943.52663376971, + "scoreError" : 8618.787108903065, + "scoreConfidence" : [ + 100324.73952486664, + 117562.31374267278 + ], + "scorePercentiles" : { + "0.0" : 105429.14828579927, + "50.0" : 109006.73676922463, + "90.0" : 110960.77420297479, + "95.0" : 110960.77420297479, + "99.0" : 110960.77420297479, + "99.9" : 110960.77420297479, + "99.99" : 110960.77420297479, + "99.999" : 110960.77420297479, + "99.9999" : 110960.77420297479, + "100.0" : 110960.77420297479 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 110797.86049112171, + 110960.77420297479, + 108523.11341972814, + 109006.73676922463, + 105429.14828579927 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 8311.005339899639, + "scoreError" : 657.605318387097, + "scoreConfidence" : [ + 7653.400021512542, + 8968.610658286736 + ], + "scorePercentiles" : { + "0.0" : 8042.852047157894, + "50.0" : 8315.860225396995, + "90.0" : 8464.883921027553, + "95.0" : 8464.883921027553, + "99.0" : 8464.883921027553, + "99.9" : 8464.883921027553, + "99.99" : 8464.883921027553, + "99.999" : 8464.883921027553, + "99.9999" : 8464.883921027553, + "100.0" : 8464.883921027553 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 8452.507514980998, + 8464.883921027553, + 8278.922990934749, + 8315.860225396995, + 8042.852047157894 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 80.00002132451024, + "scoreError" : 1.7076085103450955E-6, + "scoreConfidence" : [ + 80.00001961690174, + 80.00002303211875 + ], + "scorePercentiles" : { + "0.0" : 80.00002092887024, + "50.0" : 80.00002130650543, + "90.0" : 80.00002202514187, + "95.0" : 80.00002202514187, + "99.0" : 80.00002202514187, + "99.9" : 80.00002202514187, + "99.99" : 80.00002202514187, + "99.999" : 80.00002202514187, + "99.9999" : 80.00002202514187, + "100.0" : 80.00002202514187 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 80.00002095998708, + 80.00002092887024, + 80.0000214020466, + 80.00002130650543, + 80.00002202514187 + ] + ] + }, + "gc.count" : { + "score" : 102.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 102.0, + 102.0 + ], + "scorePercentiles" : { + "0.0" : 20.0, + "50.0" : 20.0, + "90.0" : 21.0, + "95.0" : 21.0, + "99.0" : 21.0, + "99.9" : 21.0, + "99.99" : 21.0, + "99.999" : 21.0, + "99.9999" : 21.0, + "100.0" : 21.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 21.0, + 21.0, + 20.0, + 20.0, + 20.0 + ] + ] + }, + "gc.time" : { + "score" : 134.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 134.0, + 134.0 + ], + "scorePercentiles" : { + "0.0" : 26.0, + "50.0" : 27.0, + "90.0" : 28.0, + "95.0" : 28.0, + "99.0" : 28.0, + "99.9" : 28.0, + "99.99" : 28.0, + "99.999" : 28.0, + "99.9999" : 28.0, + "100.0" : 28.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 27.0, + 28.0, + 26.0, + 26.0, + 27.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "1024" + }, + "primaryMetric" : { + "score" : 8155.042417410188, + "scoreError" : 210.1404818975382, + "scoreConfidence" : [ + 7944.90193551265, + 8365.182899307727 + ], + "scorePercentiles" : { + "0.0" : 8093.092211441557, + "50.0" : 8146.332364827549, + "90.0" : 8243.42941516659, + "95.0" : 8243.42941516659, + "99.0" : 8243.42941516659, + "99.9" : 8243.42941516659, + "99.99" : 8243.42941516659, + "99.999" : 8243.42941516659, + "99.9999" : 8243.42941516659, + "100.0" : 8243.42941516659 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 8146.332364827549, + 8243.42941516659, + 8150.0323487520445, + 8142.325746863197, + 8093.092211441557 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 8087.490086807798, + "scoreError" : 208.52839660856702, + "scoreConfidence" : [ + 7878.961690199231, + 8296.018483416365 + ], + "scorePercentiles" : { + "0.0" : 8026.130382203547, + "50.0" : 8078.8159089386445, + "90.0" : 8175.266195229863, + "95.0" : 8175.266195229863, + "99.0" : 8175.266195229863, + "99.9" : 8175.266195229863, + "99.99" : 8175.266195229863, + "99.999" : 8175.266195229863, + "99.9999" : 8175.266195229863, + "100.0" : 8175.266195229863 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 8078.8159089386445, + 8175.266195229863, + 8082.387262890627, + 8074.850684776306, + 8026.130382203547 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 1040.0002847447115, + "scoreError" : 7.327196962902556E-6, + "scoreConfidence" : [ + 1040.0002774175146, + 1040.0002920719085 + ], + "scorePercentiles" : { + "0.0" : 1040.0002816722974, + "50.0" : 1040.0002849629686, + "90.0" : 1040.000286918761, + "95.0" : 1040.000286918761, + "99.0" : 1040.000286918761, + "99.9" : 1040.000286918761, + "99.99" : 1040.000286918761, + "99.999" : 1040.000286918761, + "99.9999" : 1040.000286918761, + "100.0" : 1040.000286918761 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 1040.000284946526, + 1040.0002816722974, + 1040.0002849629686, + 1040.0002852230045, + 1040.000286918761 + ] + ] + }, + "gc.count" : { + "score" : 99.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 99.0, + 99.0 + ], + "scorePercentiles" : { + "0.0" : 19.0, + "50.0" : 20.0, + "90.0" : 20.0, + "95.0" : 20.0, + "99.0" : 20.0, + "99.9" : 20.0, + "99.99" : 20.0, + "99.999" : 20.0, + "99.9999" : 20.0, + "100.0" : 20.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 20.0, + 20.0, + 20.0, + 20.0, + 19.0 + ] + ] + }, + "gc.time" : { + "score" : 154.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 154.0, + 154.0 + ], + "scorePercentiles" : { + "0.0" : 29.0, + "50.0" : 31.0, + "90.0" : 32.0, + "95.0" : 32.0, + "99.0" : 32.0, + "99.9" : 32.0, + "99.99" : 32.0, + "99.999" : 32.0, + "99.9999" : 32.0, + "100.0" : 32.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 31.0, + 31.0, + 32.0, + 31.0, + 29.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "32768" + }, + "primaryMetric" : { + "score" : 266.90488592836016, + "scoreError" : 6.916719344419699, + "scoreConfidence" : [ + 259.9881665839405, + 273.82160527277983 + ], + "scorePercentiles" : { + "0.0" : 263.87214786560423, + "50.0" : 267.33264756673015, + "90.0" : 268.60830950170583, + "95.0" : 268.60830950170583, + "99.0" : 268.60830950170583, + "99.9" : 268.60830950170583, + "99.99" : 268.60830950170583, + "99.999" : 268.60830950170583, + "99.9999" : 268.60830950170583, + "100.0" : 268.60830950170583 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 267.02586989465425, + 267.33264756673015, + 263.87214786560423, + 268.60830950170583, + 267.6854548131063 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 8343.928215000566, + "scoreError" : 215.62419708486655, + "scoreConfidence" : [ + 8128.304017915699, + 8559.552412085432 + ], + "scorePercentiles" : { + "0.0" : 8249.262098960611, + "50.0" : 8357.47198092997, + "90.0" : 8396.631720698639, + "95.0" : 8396.631720698639, + "99.0" : 8396.631720698639, + "99.9" : 8396.631720698639, + "99.99" : 8396.631720698639, + "99.999" : 8396.631720698639, + "99.9999" : 8396.631720698639, + "100.0" : 8396.631720698639 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 8347.744421543695, + 8357.47198092997, + 8249.262098960611, + 8396.631720698639, + 8368.530852869915 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 32784.00870011185, + "scoreError" : 2.2597471126300508E-4, + "scoreConfidence" : [ + 32784.00847413714, + 32784.008926086564 + ], + "scorePercentiles" : { + "0.0" : 32784.00864631985, + "50.0" : 32784.008687878486, + "90.0" : 32784.00879995756, + "95.0" : 32784.00879995756, + "99.0" : 32784.00879995756, + "99.9" : 32784.00879995756, + "99.99" : 32784.00879995756, + "99.999" : 32784.00879995756, + "99.9999" : 32784.00879995756, + "100.0" : 32784.00879995756 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 32784.00869298349, + 32784.008687878486, + 32784.00879995756, + 32784.00864631985, + 32784.00867341985 + ] + ] + }, + "gc.count" : { + "score" : 105.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 105.0, + 105.0 + ], + "scorePercentiles" : { + "0.0" : 21.0, + "50.0" : 21.0, + "90.0" : 21.0, + "95.0" : 21.0, + "99.0" : 21.0, + "99.9" : 21.0, + "99.99" : 21.0, + "99.999" : 21.0, + "99.9999" : 21.0, + "100.0" : 21.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 21.0, + 21.0, + 21.0, + 21.0, + 21.0 + ] + ] + }, + "gc.time" : { + "score" : 171.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 171.0, + 171.0 + ], + "scorePercentiles" : { + "0.0" : 33.0, + "50.0" : 34.0, + "90.0" : 35.0, + "95.0" : 35.0, + "99.0" : 35.0, + "99.9" : 35.0, + "99.99" : 35.0, + "99.999" : 35.0, + "99.9999" : 35.0, + "100.0" : 35.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 35.0, + 33.0, + 34.0, + 35.0, + 34.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "payloadBytes" : "512", + "survivorDepth" : "0" + }, + "primaryMetric" : { + "score" : 14815.57166847854, + "scoreError" : 380.35231274347245, + "scoreConfidence" : [ + 14435.219355735067, + 15195.923981222013 + ], + "scorePercentiles" : { + "0.0" : 14665.745986275591, + "50.0" : 14844.881535062415, + "90.0" : 14902.270633512884, + "95.0" : 14902.270633512884, + "99.0" : 14902.270633512884, + "99.9" : 14902.270633512884, + "99.99" : 14902.270633512884, + "99.999" : 14902.270633512884, + "99.9999" : 14902.270633512884, + "100.0" : 14902.270633512884 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 14770.70746011631, + 14665.745986275591, + 14894.252727425503, + 14902.270633512884, + 14844.881535062415 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 7459.2875418741005, + "scoreError" : 191.27221176622683, + "scoreConfidence" : [ + 7268.0153301078735, + 7650.5597536403275 + ], + "scorePercentiles" : { + "0.0" : 7384.116194930712, + "50.0" : 7474.270136750213, + "90.0" : 7503.209626162454, + "95.0" : 7503.209626162454, + "99.0" : 7503.209626162454, + "99.9" : 7503.209626162454, + "99.99" : 7503.209626162454, + "99.999" : 7503.209626162454, + "99.9999" : 7503.209626162454, + "100.0" : 7503.209626162454 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 7436.333246464321, + 7384.116194930712, + 7498.508505062805, + 7503.209626162454, + 7474.270136750213 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 528.0001593978604, + "scoreError" : 4.174753446580878E-6, + "scoreConfidence" : [ + 528.000155223107, + 528.0001635726139 + ], + "scorePercentiles" : { + "0.0" : 528.0001583114554, + "50.0" : 528.0001596618939, + "90.0" : 528.0001609138233, + "95.0" : 528.0001609138233, + "99.0" : 528.0001609138233, + "99.9" : 528.0001609138233, + "99.99" : 528.0001609138233, + "99.999" : 528.0001609138233, + "99.9999" : 528.0001609138233, + "100.0" : 528.0001609138233 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 528.0001597267247, + 528.0001609138233, + 528.0001583754048, + 528.0001583114554, + 528.0001596618939 + ] + ] + }, + "gc.count" : { + "score" : 92.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 92.0, + 92.0 + ], + "scorePercentiles" : { + "0.0" : 18.0, + "50.0" : 18.0, + "90.0" : 19.0, + "95.0" : 19.0, + "99.0" : 19.0, + "99.9" : 19.0, + "99.99" : 19.0, + "99.999" : 19.0, + "99.9999" : 19.0, + "100.0" : 19.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 19.0, + 18.0, + 18.0, + 18.0, + 19.0 + ] + ] + }, + "gc.time" : { + "score" : 141.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 141.0, + 141.0 + ], + "scorePercentiles" : { + "0.0" : 27.0, + "50.0" : 28.0, + "90.0" : 29.0, + "95.0" : 29.0, + "99.0" : 29.0, + "99.9" : 29.0, + "99.99" : 29.0, + "99.999" : 29.0, + "99.9999" : 29.0, + "100.0" : 29.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 28.0, + 28.0, + 29.0, + 27.0, + 29.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "payloadBytes" : "512", + "survivorDepth" : "4096" + }, + "primaryMetric" : { + "score" : 14421.195993775103, + "scoreError" : 366.6062234342232, + "scoreConfidence" : [ + 14054.589770340881, + 14787.802217209326 + ], + "scorePercentiles" : { + "0.0" : 14313.205950643802, + "50.0" : 14460.679738839155, + "90.0" : 14519.554878745854, + "95.0" : 14519.554878745854, + "99.0" : 14519.554878745854, + "99.9" : 14519.554878745854, + "99.99" : 14519.554878745854, + "99.999" : 14519.554878745854, + "99.9999" : 14519.554878745854, + "100.0" : 14519.554878745854 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 14313.205950643802, + 14460.679738839155, + 14486.632051556702, + 14519.554878745854, + 14325.907349090008 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 7260.877361645607, + "scoreError" : 184.54695521130887, + "scoreConfidence" : [ + 7076.330406434298, + 7445.424316856916 + ], + "scorePercentiles" : { + "0.0" : 7206.449380881749, + "50.0" : 7280.682712869871, + "90.0" : 7310.497584484451, + "95.0" : 7310.497584484451, + "99.0" : 7310.497584484451, + "99.9" : 7310.497584484451, + "99.99" : 7310.497584484451, + "99.999" : 7310.497584484451, + "99.9999" : 7310.497584484451, + "100.0" : 7310.497584484451 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 7206.449380881749, + 7280.682712869871, + 7293.742022860905, + 7310.497584484451, + 7213.015107131058 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 528.0011091591476, + "scoreError" : 2.8222432726627597E-5, + "scoreConfidence" : [ + 528.0010809367149, + 528.0011373815804 + ], + "scorePercentiles" : { + "0.0" : 528.0011018332416, + "50.0" : 528.0011062037659, + "90.0" : 528.0011172662134, + "95.0" : 528.0011172662134, + "99.0" : 528.0011172662134, + "99.9" : 528.0011172662134, + "99.99" : 528.0011172662134, + "99.999" : 528.0011172662134, + "99.9999" : 528.0011172662134, + "100.0" : 528.0011172662134 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 528.0011172662134, + 528.0011062037659, + 528.0011037508051, + 528.0011018332416, + 528.0011167417125 + ] + ] + }, + "gc.count" : { + "score" : 90.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 90.0, + 90.0 + ], + "scorePercentiles" : { + "0.0" : 18.0, + "50.0" : 18.0, + "90.0" : 18.0, + "95.0" : 18.0, + "99.0" : 18.0, + "99.9" : 18.0, + "99.99" : 18.0, + "99.999" : 18.0, + "99.9999" : 18.0, + "100.0" : 18.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 18.0, + 18.0, + 18.0, + 18.0, + 18.0 + ] + ] + }, + "gc.time" : { + "score" : 209.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 209.0, + 209.0 + ], + "scorePercentiles" : { + "0.0" : 41.0, + "50.0" : 42.0, + "90.0" : 43.0, + "95.0" : 43.0, + "99.0" : 43.0, + "99.9" : 43.0, + "99.99" : 43.0, + "99.999" : 43.0, + "99.9999" : 43.0, + "100.0" : 43.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 42.0, + 43.0, + 41.0, + 41.0, + 42.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "payloadBytes" : "512", + "survivorDepth" : "262144" + }, + "primaryMetric" : { + "score" : 11452.134694784934, + "scoreError" : 538.3700523846873, + "scoreConfidence" : [ + 10913.764642400247, + 11990.504747169622 + ], + "scorePercentiles" : { + "0.0" : 11269.89490649887, + "50.0" : 11434.973086410908, + "90.0" : 11602.4228572038, + "95.0" : 11602.4228572038, + "99.0" : 11602.4228572038, + "99.9" : 11602.4228572038, + "99.99" : 11602.4228572038, + "99.999" : 11602.4228572038, + "99.9999" : 11602.4228572038, + "100.0" : 11602.4228572038 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 11374.485039868687, + 11602.4228572038, + 11434.973086410908, + 11269.89490649887, + 11578.897583942411 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 5766.394154030592, + "scoreError" : 270.67836245033595, + "scoreConfidence" : [ + 5495.715791580256, + 6037.072516480928 + ], + "scorePercentiles" : { + "0.0" : 5674.91405693332, + "50.0" : 5757.4542897962065, + "90.0" : 5842.459802434346, + "95.0" : 5842.459802434346, + "99.0" : 5842.459802434346, + "99.9" : 5842.459802434346, + "99.99" : 5842.459802434346, + "99.999" : 5842.459802434346, + "99.9999" : 5842.459802434346, + "100.0" : 5842.459802434346 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 5727.414286353601, + 5842.459802434346, + 5757.4542897962065, + 5674.91405693332, + 5829.728334635488 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 528.0764943500852, + "scoreError" : 0.003548361443034707, + "scoreConfidence" : [ + 528.0729459886422, + 528.0800427115282 + ], + "scorePercentiles" : { + "0.0" : 528.0755025019137, + "50.0" : 528.0765995302288, + "90.0" : 528.0776922727686, + "95.0" : 528.0776922727686, + "99.0" : 528.0776922727686, + "99.9" : 528.0776922727686, + "99.99" : 528.0776922727686, + "99.999" : 528.0776922727686, + "99.9999" : 528.0776922727686, + "100.0" : 528.0776922727686 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 528.0770163478661, + 528.0755025019137, + 528.0765995302288, + 528.0776922727686, + 528.075661097649 + ] + ] + }, + "gc.count" : { + "score" : 92.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 92.0, + 92.0 + ], + "scorePercentiles" : { + "0.0" : 17.0, + "50.0" : 18.0, + "90.0" : 20.0, + "95.0" : 20.0, + "99.0" : 20.0, + "99.9" : 20.0, + "99.99" : 20.0, + "99.999" : 20.0, + "99.9999" : 20.0, + "100.0" : 20.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 19.0, + 17.0, + 20.0, + 18.0, + 18.0 + ] + ] + }, + "gc.time" : { + "score" : 2477.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 2477.0, + 2477.0 + ], + "scorePercentiles" : { + "0.0" : 475.0, + "50.0" : 495.0, + "90.0" : 524.0, + "95.0" : 524.0, + "99.0" : 524.0, + "99.9" : 524.0, + "99.99" : 524.0, + "99.999" : 524.0, + "99.9999" : 524.0, + "100.0" : 524.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 495.0, + 505.0, + 524.0, + 478.0, + 475.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "nodes" : "1048576" + }, + "primaryMetric" : { + "score" : 82080.59872372373, + "scoreError" : 5967.4821485814655, + "scoreConfidence" : [ + 76113.11657514227, + 88048.08087230519 + ], + "scorePercentiles" : { + "0.0" : 80917.4, + "50.0" : 81601.45675675676, + "90.0" : 84794.0638888889, + "95.0" : 84794.0638888889, + "99.0" : 84794.0638888889, + "99.9" : 84794.0638888889, + "99.99" : 84794.0638888889, + "99.999" : 84794.0638888889, + "99.9999" : 84794.0638888889, + "100.0" : 84794.0638888889 + }, + "scoreUnit" : "us/op", + "rawData" : [ + [ + 81754.28918918919, + 81601.45675675676, + 84794.0638888889, + 80917.4, + 81335.78378378379 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0021809052320858496, + "scoreError" : 5.6958226787361025E-5, + "scoreConfidence" : [ + 0.0021239470052984884, + 0.002237863458873211 + ], + "scorePercentiles" : { + "0.0" : 0.0021634272802775684, + "50.0" : 0.0021830214825934603, + "90.0" : 0.0022000076983739983, + "95.0" : 0.0022000076983739983, + "99.0" : 0.0022000076983739983, + "99.9" : 0.0022000076983739983, + "99.99" : 0.0022000076983739983, + "99.999" : 0.0022000076983739983, + "99.9999" : 0.0022000076983739983, + "100.0" : 0.0022000076983739983 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.0021888669284737244, + 0.0021830214825934603, + 0.002169202770710497, + 0.0021634272802775684, + 0.0022000076983739983 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 187.7259996838944, + "scoreError" : 12.871767823737075, + "scoreConfidence" : [ + 174.8542318601573, + 200.5977675076315 + ], + "scorePercentiles" : { + "0.0" : 183.57894736842104, + "50.0" : 187.67567567567568, + "90.0" : 192.88888888888889, + "95.0" : 192.88888888888889, + "99.0" : 192.88888888888889, + "99.9" : 192.88888888888889, + "99.99" : 192.88888888888889, + "99.999" : 192.88888888888889, + "99.9999" : 192.88888888888889, + "100.0" : 192.88888888888889 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 187.67567567567568, + 186.8108108108108, + 192.88888888888889, + 183.57894736842104, + 187.67567567567568 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "nodes" : "1048576" + }, + "primaryMetric" : { + "score" : 0.02164312294891882, + "scoreError" : 7.705914098439794E-4, + "scoreConfidence" : [ + 0.02087253153907484, + 0.0224137143587628 + ], + "scorePercentiles" : { + "0.0" : 0.021408116825852783, + "50.0" : 0.021630863729111337, + "90.0" : 0.021945951728286586, + "95.0" : 0.021945951728286586, + "99.0" : 0.021945951728286586, + "99.9" : 0.021945951728286586, + "99.99" : 0.021945951728286586, + "99.999" : 0.021945951728286586, + "99.9999" : 0.021945951728286586, + "100.0" : 0.021945951728286586 + }, + "scoreUnit" : "us/op", + "rawData" : [ + [ + 0.021408116825852783, + 0.021945951728286586, + 0.021539297817852267, + 0.021691384643491116, + 0.021630863729111337 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0021964411558716506, + "scoreError" : 1.56555515595109E-6, + "scoreConfidence" : [ + 0.0021948756007156996, + 0.0021980067110276016 + ], + "scorePercentiles" : { + "0.0" : 0.0021957651854566046, + "50.0" : 0.0021965674826351024, + "90.0" : 0.002196836875669765, + "95.0" : 0.002196836875669765, + "99.0" : 0.002196836875669765, + "99.9" : 0.002196836875669765, + "99.99" : 0.002196836875669765, + "99.999" : 0.002196836875669765, + "99.9999" : 0.002196836875669765, + "100.0" : 0.002196836875669765 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.0021964184663975104, + 0.002196617769199271, + 0.0021957651854566046, + 0.002196836875669765, + 0.0021965674826351024 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 4.98526013146811E-5, + "scoreError" : 1.7913802531533667E-6, + "scoreConfidence" : [ + 4.806122106152774E-5, + 5.1643981567834466E-5 + ], + "scorePercentiles" : { + "0.0" : 4.931008013965254E-5, + "50.0" : 4.983088750692285E-5, + "90.0" : 5.055377151321891E-5, + "95.0" : 5.055377151321891E-5, + "99.0" : 5.055377151321891E-5, + "99.9" : 5.055377151321891E-5, + "99.99" : 5.055377151321891E-5, + "99.999" : 5.055377151321891E-5, + "99.9999" : 5.055377151321891E-5, + "100.0" : 5.055377151321891E-5 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 4.931008013965254E-5, + 5.055377151321891E-5, + 4.959720212079703E-5, + 4.997106529281421E-5, + 4.983088750692285E-5 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "nodes" : "1048576" + }, + "primaryMetric" : { + "score" : 270.5487132030655, + "scoreError" : 3.034496336252809, + "scoreConfidence" : [ + 267.5142168668127, + 273.5832095393183 + ], + "scorePercentiles" : { + "0.0" : 269.8209059859788, + "50.0" : 270.46045778138233, + "90.0" : 271.6983067729084, + "95.0" : 271.6983067729084, + "99.0" : 271.6983067729084, + "99.9" : 271.6983067729084, + "99.99" : 271.6983067729084, + "99.999" : 271.6983067729084, + "99.9999" : 271.6983067729084, + "100.0" : 271.6983067729084 + }, + "scoreUnit" : "us/op", + "rawData" : [ + [ + 269.8483720093542, + 271.6983067729084, + 270.46045778138233, + 269.8209059859788, + 270.915523465704 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0022063400679190664, + "scoreError" : 2.4320101841940513E-6, + "scoreConfidence" : [ + 0.0022039080577348725, + 0.0022087720781032603 + ], + "scorePercentiles" : { + "0.0" : 0.0022055509346252723, + "50.0" : 0.002206296392658466, + "90.0" : 0.002207112307694641, + "95.0" : 0.002207112307694641, + "99.0" : 0.002207112307694641, + "99.9" : 0.002207112307694641, + "99.99" : 0.002207112307694641, + "99.999" : 0.002207112307694641, + "99.9999" : 0.002207112307694641, + "100.0" : 0.002207112307694641 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.002207112307694641, + 0.0022068020771229707, + 0.002206296392658466, + 0.0022055509346252723, + 0.002205938627493984 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 0.6259847291145666, + "scoreError" : 0.007134722429282701, + "scoreConfidence" : [ + 0.6188500066852839, + 0.6331194515438493 + ], + "scorePercentiles" : { + "0.0" : 0.6241236742764695, + "50.0" : 0.6257547084797693, + "90.0" : 0.6287576964867801, + "95.0" : 0.6287576964867801, + "99.0" : 0.6287576964867801, + "99.9" : 0.6287576964867801, + "99.99" : 0.6287576964867801, + "99.999" : 0.6287576964867801, + "99.9999" : 0.6287576964867801, + "100.0" : 0.6287576964867801 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 0.6245727648857708, + 0.6287576964867801, + 0.6257547084797693, + 0.6241236742764695, + 0.6267148014440433 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 1.9434612632669808, + "scoreError" : 0.11827622949395342, + "scoreConfidence" : [ + 1.8251850337730273, + 2.061737492760934 + ], + "scorePercentiles" : { + "0.0" : 1.9219030520864717, + "50.0" : 1.9308040986327506, + "90.0" : 1.9953678368260783, + "95.0" : 1.9953678368260783, + "99.0" : 1.9953678368260783, + "99.9" : 1.9953678368260783, + "99.99" : 1.9953678368260783, + "99.999" : 1.9953678368260783, + "99.9999" : 1.9953678368260783, + "100.0" : 1.9953678368260783 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 1.9468250703131478, + 1.9219030520864717, + 1.9308040986327506, + 1.9953678368260783, + 1.9224062584764554 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.002196183801562551, + "scoreError" : 1.5705082757774558E-6, + "scoreConfidence" : [ + 0.0021946132932867735, + 0.0021977543098383287 + ], + "scorePercentiles" : { + "0.0" : 0.002195741560782661, + "50.0" : 0.002196356845749124, + "90.0" : 0.0021966278707082044, + "95.0" : 0.0021966278707082044, + "99.0" : 0.0021966278707082044, + "99.9" : 0.0021966278707082044, + "99.99" : 0.0021966278707082044, + "99.999" : 0.0021966278707082044, + "99.9999" : 0.0021966278707082044, + "100.0" : 0.0021966278707082044 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.002196433542759551, + 0.002195741560782661, + 0.002196356845749124, + 0.0021957591878132145, + 0.0021966278707082044 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 4.475987376364739E-6, + "scoreError" : 2.7065120031626184E-7, + "scoreConfidence" : [ + 4.2053361760484775E-6, + 4.746638576681001E-6 + ], + "scorePercentiles" : { + "0.0" : 4.425406880148576E-6, + "50.0" : 4.447274632027257E-6, + "90.0" : 4.594551927228046E-6, + "95.0" : 4.594551927228046E-6, + "99.0" : 4.594551927228046E-6, + "99.9" : 4.594551927228046E-6, + "99.99" : 4.594551927228046E-6, + "99.999" : 4.594551927228046E-6, + "99.9999" : 4.594551927228046E-6, + "100.0" : 4.594551927228046E-6 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 4.484187985363193E-6, + 4.425406880148576E-6, + 4.447274632027257E-6, + 4.594551927228046E-6, + 4.428515457056624E-6 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 3.7799682008606865, + "scoreError" : 0.3785990025307056, + "scoreConfidence" : [ + 3.4013691983299807, + 4.158567203391392 + ], + "scorePercentiles" : { + "0.0" : 3.6851249277787326, + "50.0" : 3.7832652961287296, + "90.0" : 3.9240049037650047, + "95.0" : 3.9240049037650047, + "99.0" : 3.9240049037650047, + "99.9" : 3.9240049037650047, + "99.99" : 3.9240049037650047, + "99.999" : 3.9240049037650047, + "99.9999" : 3.9240049037650047, + "100.0" : 3.9240049037650047 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 3.6851249277787326, + 3.9240049037650047, + 3.7832652961287296, + 3.8151140083871757, + 3.692331868243792 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.002198773345689165, + "scoreError" : 1.667956778266745E-5, + "scoreConfidence" : [ + 0.0021820937779064974, + 0.0022154529134718326 + ], + "scorePercentiles" : { + "0.0" : 0.0021967381881610225, + "50.0" : 0.002196896399945049, + "90.0" : 0.0022065209738235474, + "95.0" : 0.0022065209738235474, + "99.0" : 0.0022065209738235474, + "99.9" : 0.0022065209738235474, + "99.99" : 0.0022065209738235474, + "99.999" : 0.0022065209738235474, + "99.9999" : 0.0022065209738235474, + "100.0" : 0.0022065209738235474 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.0022065209738235474, + 0.0021968010747993824, + 0.0021967381881610225, + 0.002196896399945049, + 0.0021969100917168236 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 8.715646311107752E-6, + "scoreError" : 8.384288607855876E-7, + "scoreConfidence" : [ + 7.877217450322164E-6, + 9.55407517189334E-6 + ], + "scorePercentiles" : { + "0.0" : 8.506621376488969E-6, + "50.0" : 8.715503254454911E-6, + "90.0" : 9.03968031233351E-6, + "95.0" : 9.03968031233351E-6, + "99.0" : 9.03968031233351E-6, + "99.9" : 9.03968031233351E-6, + "99.99" : 9.03968031233351E-6, + "99.999" : 9.03968031233351E-6, + "99.9999" : 9.03968031233351E-6, + "100.0" : 9.03968031233351E-6 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 8.527156884377332E-6, + 9.03968031233351E-6, + 8.715503254454911E-6, + 8.789269727884032E-6, + 8.506621376488969E-6 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 4.934135242904984, + "scoreError" : 0.34704739229470716, + "scoreConfidence" : [ + 4.587087850610277, + 5.2811826351996904 + ], + "scorePercentiles" : { + "0.0" : 4.8559045509230305, + "50.0" : 4.916361625019645, + "90.0" : 5.080199694616183, + "95.0" : 5.080199694616183, + "99.0" : 5.080199694616183, + "99.9" : 5.080199694616183, + "99.99" : 5.080199694616183, + "99.999" : 5.080199694616183, + "99.9999" : 5.080199694616183, + "100.0" : 5.080199694616183 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 4.8559045509230305, + 5.080199694616183, + 4.916361625019645, + 4.867465016484686, + 4.950745327481375 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 3092.8990797227843, + "scoreError" : 214.38728876844763, + "scoreConfidence" : [ + 2878.511790954337, + 3307.2863684912318 + ], + "scorePercentiles" : { + "0.0" : 3003.3366292447813, + "50.0" : 3103.0594940519563, + "90.0" : 3141.9657335424126, + "95.0" : 3141.9657335424126, + "99.0" : 3141.9657335424126, + "99.9" : 3141.9657335424126, + "99.99" : 3141.9657335424126, + "99.999" : 3141.9657335424126, + "99.9999" : 3141.9657335424126, + "100.0" : 3141.9657335424126 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 3141.9657335424126, + 3003.3366292447813, + 3103.0594940519563, + 3134.5885793001253, + 3081.5449624746466 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 16.000011447700253, + "scoreError" : 8.5482347464224E-7, + "scoreConfidence" : [ + 16.000010592876777, + 16.00001230252373 + ], + "scorePercentiles" : { + "0.0" : 16.000011224723114, + "50.0" : 16.00001141682472, + "90.0" : 16.00001179845149, + "95.0" : 16.00001179845149, + "99.0" : 16.00001179845149, + "99.9" : 16.00001179845149, + "99.99" : 16.00001179845149, + "99.999" : 16.00001179845149, + "99.9999" : 16.00001179845149, + "100.0" : 16.00001179845149 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 16.000011224723114, + 16.00001179845149, + 16.00001141682472, + 16.000011302468177, + 16.000011496033764 + ] + ] + }, + "gc.count" : { + "score" : 38.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 38.0, + 38.0 + ], + "scorePercentiles" : { + "0.0" : 7.0, + "50.0" : 8.0, + "90.0" : 8.0, + "95.0" : 8.0, + "99.0" : 8.0, + "99.9" : 8.0, + "99.99" : 8.0, + "99.999" : 8.0, + "99.9999" : 8.0, + "100.0" : 8.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 8.0, + 7.0, + 8.0, + 8.0, + 7.0 + ] + ] + }, + "gc.time" : { + "score" : 447.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 447.0, + 447.0 + ], + "scorePercentiles" : { + "0.0" : 84.0, + "50.0" : 90.0, + "90.0" : 96.0, + "95.0" : 96.0, + "99.0" : 96.0, + "99.9" : 96.0, + "99.99" : 96.0, + "99.999" : 96.0, + "99.9999" : 96.0, + "100.0" : 96.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 90.0, + 86.0, + 91.0, + 96.0, + 84.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseG1GC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 2.2018327420685595, + "scoreError" : 1.10500977891234, + "scoreConfidence" : [ + 1.0968229631562194, + 3.3068425209809 + ], + "scorePercentiles" : { + "0.0" : 2.0191142520365477, + "50.0" : 2.093597163697863, + "90.0" : 2.7099197567822473, + "95.0" : 2.7099197567822473, + "99.0" : 2.7099197567822473, + "99.9" : 2.7099197567822473, + "99.99" : 2.7099197567822473, + "99.999" : 2.7099197567822473, + "99.9999" : 2.7099197567822473, + "100.0" : 2.7099197567822473 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 2.7099197567822473, + 2.093597163697863, + 2.057386647576988, + 2.129145890249151, + 2.0191142520365477 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.002198259395180415, + "scoreError" : 1.8837541279633866E-5, + "scoreConfidence" : [ + 0.002179421853900781, + 0.002217096936460049 + ], + "scorePercentiles" : { + "0.0" : 0.0021956491880677446, + "50.0" : 0.002195996704904016, + "90.0" : 0.0022069663751961956, + "95.0" : 0.0022069663751961956, + "99.0" : 0.0022069663751961956, + "99.9" : 0.0022069663751961956, + "99.99" : 0.0022069663751961956, + "99.999" : 0.0022069663751961956, + "99.9999" : 0.0022069663751961956, + "100.0" : 0.0022069663751961956 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.0022069663751961956, + 0.0021957793019904827, + 0.002195996704904016, + 0.0021956491880677446, + 0.002196905405743638 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 5.0770669655621076E-6, + "scoreError" : 2.5968062409634488E-6, + "scoreConfidence" : [ + 2.4802607245986588E-6, + 7.673873206525556E-6 + ], + "scorePercentiles" : { + "0.0" : 4.651809282253354E-6, + "50.0" : 4.820784961663977E-6, + "90.0" : 6.271821064540395E-6, + "95.0" : 6.271821064540395E-6, + "99.0" : 6.271821064540395E-6, + "99.9" : 6.271821064540395E-6, + "99.99" : 6.271821064540395E-6, + "99.999" : 6.271821064540395E-6, + "99.9999" : 6.271821064540395E-6, + "100.0" : 6.271821064540395E-6 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 6.271821064540395E-6, + 4.820784961663977E-6, + 4.738271880101847E-6, + 4.902647639250964E-6, + 4.651809282253354E-6 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + } +] + + diff --git a/results/07-jmh-g1.txt b/results/07-jmh-g1.txt new file mode 100644 index 0000000..f7fc5a6 --- /dev/null +++ b/results/07-jmh-g1.txt @@ -0,0 +1,1295 @@ +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocate +# Parameters: (size = 64) + +# Run progress: 0.00% complete, ETA 00:06:24 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 94476.816 ops/ms +# Warmup Iteration 2: 89744.206 ops/ms +# Warmup Iteration 3: 101163.992 ops/ms +Iteration 1: 109526.924 ops/ms + gc.alloc.rate: 8355.488 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 21.000 counts + gc.time: 26.000 ms + +Iteration 2: 110510.175 ops/ms + gc.alloc.rate: 8430.635 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 20.000 counts + gc.time: 26.000 ms + +Iteration 3: 108216.344 ops/ms + gc.alloc.rate: 8255.509 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 20.000 counts + gc.time: 28.000 ms + +Iteration 4: 110239.588 ops/ms + gc.alloc.rate: 8410.010 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 21.000 counts + gc.time: 28.000 ms + +Iteration 5: 108501.443 ops/ms + gc.alloc.rate: 8277.260 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 20.000 counts + gc.time: 29.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocate": + 109398.895 ±(99.9%) 3927.821 ops/ms [Average] + (min, avg, max) = (108216.344, 109398.895, 110510.175), stdev = 1020.043 + CI (99.9%): [105471.074, 113326.715] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate": + 8345.780 ±(99.9%) 299.905 MB/sec [Average] + (min, avg, max) = (8255.509, 8345.780, 8430.635), stdev = 77.884 + CI (99.9%): [8045.875, 8645.685] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate.norm": + 80.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (80.000, 80.000, 80.000), stdev = 0.001 + CI (99.9%): [80.000, 80.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.count": + 102.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (20.000, 20.400, 21.000), stdev = 0.548 + CI (99.9%): [102.000, 102.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.time": + 137.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (26.000, 27.400, 29.000), stdev = 1.342 + CI (99.9%): [137.000, 137.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocate +# Parameters: (size = 1024) + +# Run progress: 6.25% complete, ETA 00:06:07 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 6945.278 ops/ms +# Warmup Iteration 2: 7387.542 ops/ms +# Warmup Iteration 3: 8129.432 ops/ms +Iteration 1: 7701.879 ops/ms + gc.alloc.rate: 7638.123 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 19.000 counts + gc.time: 31.000 ms + +Iteration 2: 7965.597 ops/ms + gc.alloc.rate: 7899.705 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 19.000 counts + gc.time: 31.000 ms + +Iteration 3: 8142.411 ops/ms + gc.alloc.rate: 8074.482 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 20.000 counts + gc.time: 31.000 ms + +Iteration 4: 8164.541 ops/ms + gc.alloc.rate: 8097.066 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 20.000 counts + gc.time: 32.000 ms + +Iteration 5: 7966.047 ops/ms + gc.alloc.rate: 7900.144 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 19.000 counts + gc.time: 27.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocate": + 7988.095 ±(99.9%) 714.858 ops/ms [Average] + (min, avg, max) = (7701.879, 7988.095, 8164.541), stdev = 185.646 + CI (99.9%): [7273.237, 8702.953] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate": + 7921.904 ±(99.9%) 708.613 MB/sec [Average] + (min, avg, max) = (7638.123, 7921.904, 8097.066), stdev = 184.024 + CI (99.9%): [7213.291, 8630.517] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate.norm": + 1040.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (1040.000, 1040.000, 1040.000), stdev = 0.001 + CI (99.9%): [1040.000, 1040.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.count": + 97.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (19.000, 19.400, 20.000), stdev = 0.548 + CI (99.9%): [97.000, 97.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.time": + 152.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (27.000, 30.400, 32.000), stdev = 1.949 + CI (99.9%): [152.000, 152.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocate +# Parameters: (size = 32768) + +# Run progress: 12.50% complete, ETA 00:05:42 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 232.324 ops/ms +# Warmup Iteration 2: 231.619 ops/ms +# Warmup Iteration 3: 252.348 ops/ms +Iteration 1: 257.316 ops/ms + gc.alloc.rate: 8044.353 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 33.000 ms + +Iteration 2: 254.053 ops/ms + gc.alloc.rate: 7942.281 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 20.000 counts + gc.time: 33.000 ms + +Iteration 3: 264.497 ops/ms + gc.alloc.rate: 8268.735 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 20.000 counts + gc.time: 31.000 ms + +Iteration 4: 262.637 ops/ms + gc.alloc.rate: 8210.612 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 31.000 ms + +Iteration 5: 258.756 ops/ms + gc.alloc.rate: 8089.202 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 34.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocate": + 259.452 ±(99.9%) 16.084 ops/ms [Average] + (min, avg, max) = (254.053, 259.452, 264.497), stdev = 4.177 + CI (99.9%): [243.368, 275.536] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate": + 8111.036 ±(99.9%) 502.749 MB/sec [Average] + (min, avg, max) = (7942.281, 8111.036, 8268.735), stdev = 130.562 + CI (99.9%): [7608.288, 8613.785] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate.norm": + 32784.009 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (32784.009, 32784.009, 32784.009), stdev = 0.001 + CI (99.9%): [32784.008, 32784.010] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.count": + 103.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (20.000, 20.600, 21.000), stdev = 0.548 + CI (99.9%): [103.000, 103.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.time": + 162.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (31.000, 32.400, 34.000), stdev = 1.342 + CI (99.9%): [162.000, 162.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop +# Parameters: (size = 64) + +# Run progress: 18.75% complete, ETA 00:05:18 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 101992.702 ops/ms +# Warmup Iteration 2: 103825.729 ops/ms +# Warmup Iteration 3: 108687.913 ops/ms +Iteration 1: 110797.860 ops/ms + gc.alloc.rate: 8452.508 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 21.000 counts + gc.time: 27.000 ms + +Iteration 2: 110960.774 ops/ms + gc.alloc.rate: 8464.884 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 21.000 counts + gc.time: 28.000 ms + +Iteration 3: 108523.113 ops/ms + gc.alloc.rate: 8278.923 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 20.000 counts + gc.time: 26.000 ms + +Iteration 4: 109006.737 ops/ms + gc.alloc.rate: 8315.860 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 20.000 counts + gc.time: 26.000 ms + +Iteration 5: 105429.148 ops/ms + gc.alloc.rate: 8042.852 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 20.000 counts + gc.time: 27.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop": + 108943.527 ±(99.9%) 8618.787 ops/ms [Average] + (min, avg, max) = (105429.148, 108943.527, 110960.774), stdev = 2238.272 + CI (99.9%): [100324.740, 117562.314] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate": + 8311.005 ±(99.9%) 657.605 MB/sec [Average] + (min, avg, max) = (8042.852, 8311.005, 8464.884), stdev = 170.778 + CI (99.9%): [7653.400, 8968.611] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate.norm": + 80.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (80.000, 80.000, 80.000), stdev = 0.001 + CI (99.9%): [80.000, 80.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.count": + 102.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (20.000, 20.400, 21.000), stdev = 0.548 + CI (99.9%): [102.000, 102.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.time": + 134.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (26.000, 26.800, 28.000), stdev = 0.837 + CI (99.9%): [134.000, 134.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop +# Parameters: (size = 1024) + +# Run progress: 25.00% complete, ETA 00:04:53 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 7454.930 ops/ms +# Warmup Iteration 2: 7560.485 ops/ms +# Warmup Iteration 3: 8238.081 ops/ms +Iteration 1: 8146.332 ops/ms + gc.alloc.rate: 8078.816 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 20.000 counts + gc.time: 31.000 ms + +Iteration 2: 8243.429 ops/ms + gc.alloc.rate: 8175.266 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 20.000 counts + gc.time: 31.000 ms + +Iteration 3: 8150.032 ops/ms + gc.alloc.rate: 8082.387 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 20.000 counts + gc.time: 32.000 ms + +Iteration 4: 8142.326 ops/ms + gc.alloc.rate: 8074.851 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 20.000 counts + gc.time: 31.000 ms + +Iteration 5: 8093.092 ops/ms + gc.alloc.rate: 8026.130 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 19.000 counts + gc.time: 29.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop": + 8155.042 ±(99.9%) 210.140 ops/ms [Average] + (min, avg, max) = (8093.092, 8155.042, 8243.429), stdev = 54.573 + CI (99.9%): [7944.902, 8365.183] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate": + 8087.490 ±(99.9%) 208.528 MB/sec [Average] + (min, avg, max) = (8026.130, 8087.490, 8175.266), stdev = 54.154 + CI (99.9%): [7878.962, 8296.018] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate.norm": + 1040.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (1040.000, 1040.000, 1040.000), stdev = 0.001 + CI (99.9%): [1040.000, 1040.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.count": + 99.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (19.000, 19.800, 20.000), stdev = 0.447 + CI (99.9%): [99.000, 99.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.time": + 154.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (29.000, 30.800, 32.000), stdev = 1.095 + CI (99.9%): [154.000, 154.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop +# Parameters: (size = 32768) + +# Run progress: 31.25% complete, ETA 00:04:29 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 237.515 ops/ms +# Warmup Iteration 2: 248.953 ops/ms +# Warmup Iteration 3: 264.322 ops/ms +Iteration 1: 267.026 ops/ms + gc.alloc.rate: 8347.744 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 35.000 ms + +Iteration 2: 267.333 ops/ms + gc.alloc.rate: 8357.472 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 33.000 ms + +Iteration 3: 263.872 ops/ms + gc.alloc.rate: 8249.262 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 34.000 ms + +Iteration 4: 268.608 ops/ms + gc.alloc.rate: 8396.632 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 35.000 ms + +Iteration 5: 267.685 ops/ms + gc.alloc.rate: 8368.531 MB/sec + gc.alloc.rate.norm: 32784.009 B/op + gc.count: 21.000 counts + gc.time: 34.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop": + 266.905 ±(99.9%) 6.917 ops/ms [Average] + (min, avg, max) = (263.872, 266.905, 268.608), stdev = 1.796 + CI (99.9%): [259.988, 273.822] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate": + 8343.928 ±(99.9%) 215.624 MB/sec [Average] + (min, avg, max) = (8249.262, 8343.928, 8396.632), stdev = 55.997 + CI (99.9%): [8128.304, 8559.552] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate.norm": + 32784.009 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (32784.009, 32784.009, 32784.009), stdev = 0.001 + CI (99.9%): [32784.008, 32784.009] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.count": + 105.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (21.000, 21.000, 21.000), stdev = 0.001 + CI (99.9%): [105.000, 105.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.time": + 171.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (33.000, 34.200, 35.000), stdev = 0.837 + CI (99.9%): [171.000, 171.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival +# Parameters: (payloadBytes = 512, survivorDepth = 0) + +# Run progress: 37.50% complete, ETA 00:04:04 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 13049.142 ops/ms +# Warmup Iteration 2: 13567.531 ops/ms +# Warmup Iteration 3: 14405.101 ops/ms +Iteration 1: 14770.707 ops/ms + gc.alloc.rate: 7436.333 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 19.000 counts + gc.time: 28.000 ms + +Iteration 2: 14665.746 ops/ms + gc.alloc.rate: 7384.116 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 18.000 counts + gc.time: 28.000 ms + +Iteration 3: 14894.253 ops/ms + gc.alloc.rate: 7498.509 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 18.000 counts + gc.time: 29.000 ms + +Iteration 4: 14902.271 ops/ms + gc.alloc.rate: 7503.210 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 18.000 counts + gc.time: 27.000 ms + +Iteration 5: 14844.882 ops/ms + gc.alloc.rate: 7474.270 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 19.000 counts + gc.time: 29.000 ms + + + +Result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival": + 14815.572 ±(99.9%) 380.352 ops/ms [Average] + (min, avg, max) = (14665.746, 14815.572, 14902.271), stdev = 98.776 + CI (99.9%): [14435.219, 15195.924] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate": + 7459.288 ±(99.9%) 191.272 MB/sec [Average] + (min, avg, max) = (7384.116, 7459.288, 7503.210), stdev = 49.673 + CI (99.9%): [7268.015, 7650.560] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate.norm": + 528.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (528.000, 528.000, 528.000), stdev = 0.001 + CI (99.9%): [528.000, 528.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.count": + 92.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (18.000, 18.400, 19.000), stdev = 0.548 + CI (99.9%): [92.000, 92.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.time": + 141.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (27.000, 28.200, 29.000), stdev = 0.837 + CI (99.9%): [141.000, 141.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival +# Parameters: (payloadBytes = 512, survivorDepth = 4096) + +# Run progress: 43.75% complete, ETA 00:03:40 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 12513.468 ops/ms +# Warmup Iteration 2: 12455.459 ops/ms +# Warmup Iteration 3: 14481.408 ops/ms +Iteration 1: 14313.206 ops/ms + gc.alloc.rate: 7206.449 MB/sec + gc.alloc.rate.norm: 528.001 B/op + gc.count: 18.000 counts + gc.time: 42.000 ms + +Iteration 2: 14460.680 ops/ms + gc.alloc.rate: 7280.683 MB/sec + gc.alloc.rate.norm: 528.001 B/op + gc.count: 18.000 counts + gc.time: 43.000 ms + +Iteration 3: 14486.632 ops/ms + gc.alloc.rate: 7293.742 MB/sec + gc.alloc.rate.norm: 528.001 B/op + gc.count: 18.000 counts + gc.time: 41.000 ms + +Iteration 4: 14519.555 ops/ms + gc.alloc.rate: 7310.498 MB/sec + gc.alloc.rate.norm: 528.001 B/op + gc.count: 18.000 counts + gc.time: 41.000 ms + +Iteration 5: 14325.907 ops/ms + gc.alloc.rate: 7213.015 MB/sec + gc.alloc.rate.norm: 528.001 B/op + gc.count: 18.000 counts + gc.time: 42.000 ms + + + +Result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival": + 14421.196 ±(99.9%) 366.606 ops/ms [Average] + (min, avg, max) = (14313.206, 14421.196, 14519.555), stdev = 95.206 + CI (99.9%): [14054.590, 14787.802] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate": + 7260.877 ±(99.9%) 184.547 MB/sec [Average] + (min, avg, max) = (7206.449, 7260.877, 7310.498), stdev = 47.926 + CI (99.9%): [7076.330, 7445.424] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate.norm": + 528.001 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (528.001, 528.001, 528.001), stdev = 0.001 + CI (99.9%): [528.001, 528.001] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.count": + 90.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (18.000, 18.000, 18.000), stdev = 0.001 + CI (99.9%): [90.000, 90.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.time": + 209.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (41.000, 41.800, 43.000), stdev = 0.837 + CI (99.9%): [209.000, 209.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival +# Parameters: (payloadBytes = 512, survivorDepth = 262144) + +# Run progress: 50.00% complete, ETA 00:03:15 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 10725.155 ops/ms +# Warmup Iteration 2: 9695.279 ops/ms +# Warmup Iteration 3: 11448.309 ops/ms +Iteration 1: 11374.485 ops/ms + gc.alloc.rate: 5727.414 MB/sec + gc.alloc.rate.norm: 528.077 B/op + gc.count: 19.000 counts + gc.time: 495.000 ms + +Iteration 2: 11602.423 ops/ms + gc.alloc.rate: 5842.460 MB/sec + gc.alloc.rate.norm: 528.076 B/op + gc.count: 17.000 counts + gc.time: 505.000 ms + +Iteration 3: 11434.973 ops/ms + gc.alloc.rate: 5757.454 MB/sec + gc.alloc.rate.norm: 528.077 B/op + gc.count: 20.000 counts + gc.time: 524.000 ms + +Iteration 4: 11269.895 ops/ms + gc.alloc.rate: 5674.914 MB/sec + gc.alloc.rate.norm: 528.078 B/op + gc.count: 18.000 counts + gc.time: 478.000 ms + +Iteration 5: 11578.898 ops/ms + gc.alloc.rate: 5829.728 MB/sec + gc.alloc.rate.norm: 528.076 B/op + gc.count: 18.000 counts + gc.time: 475.000 ms + + + +Result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival": + 11452.135 ±(99.9%) 538.370 ops/ms [Average] + (min, avg, max) = (11269.895, 11452.135, 11602.423), stdev = 139.813 + CI (99.9%): [10913.765, 11990.505] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate": + 5766.394 ±(99.9%) 270.678 MB/sec [Average] + (min, avg, max) = (5674.914, 5766.394, 5842.460), stdev = 70.294 + CI (99.9%): [5495.716, 6037.073] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate.norm": + 528.076 ±(99.9%) 0.004 B/op [Average] + (min, avg, max) = (528.076, 528.076, 528.078), stdev = 0.001 + CI (99.9%): [528.073, 528.080] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.count": + 92.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (17.000, 18.400, 20.000), stdev = 1.140 + CI (99.9%): [92.000, 92.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.time": + 2477.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (475.000, 495.400, 524.000), stdev = 20.182 + CI (99.9%): [2477.000, 2477.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences +# Parameters: (nodes = 1048576) + +# Run progress: 56.25% complete, ETA 00:02:51 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 81541.678 us/op +# Warmup Iteration 2: 81197.711 us/op +# Warmup Iteration 3: 82273.397 us/op +Iteration 1: 81754.289 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 187.676 B/op + gc.count: ≈ 0 counts + +Iteration 2: 81601.457 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 186.811 B/op + gc.count: ≈ 0 counts + +Iteration 3: 84794.064 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 192.889 B/op + gc.count: ≈ 0 counts + +Iteration 4: 80917.400 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 183.579 B/op + gc.count: ≈ 0 counts + +Iteration 5: 81335.784 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 187.676 B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences": + 82080.599 ±(99.9%) 5967.482 us/op [Average] + (min, avg, max) = (80917.400, 82080.599, 84794.064), stdev = 1549.736 + CI (99.9%): [76113.117, 88048.081] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences:gc.alloc.rate": + 0.002 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.002, 0.002, 0.002), stdev = 0.001 + CI (99.9%): [0.002, 0.002] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences:gc.alloc.rate.norm": + 187.726 ±(99.9%) 12.872 B/op [Average] + (min, avg, max) = (183.579, 187.726, 192.889), stdev = 3.343 + CI (99.9%): [174.854, 200.598] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly +# Parameters: (nodes = 1048576) + +# Run progress: 62.50% complete, ETA 00:02:26 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 0.021 us/op +# Warmup Iteration 2: 0.022 us/op +# Warmup Iteration 3: 0.022 us/op +Iteration 1: 0.021 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 2: 0.022 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 3: 0.022 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 4: 0.022 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 5: 0.022 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly": + 0.022 ±(99.9%) 0.001 us/op [Average] + (min, avg, max) = (0.021, 0.022, 0.022), stdev = 0.001 + CI (99.9%): [0.021, 0.022] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate": + 0.002 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.002, 0.002, 0.002), stdev = 0.001 + CI (99.9%): [0.002, 0.002] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate.norm": + ≈ 10⁻⁴ B/op + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives +# Parameters: (nodes = 1048576) + +# Run progress: 68.75% complete, ETA 00:02:02 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 268.875 us/op +# Warmup Iteration 2: 269.168 us/op +# Warmup Iteration 3: 272.299 us/op +Iteration 1: 269.848 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 0.625 B/op + gc.count: ≈ 0 counts + +Iteration 2: 271.698 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 0.629 B/op + gc.count: ≈ 0 counts + +Iteration 3: 270.460 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 0.626 B/op + gc.count: ≈ 0 counts + +Iteration 4: 269.821 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 0.624 B/op + gc.count: ≈ 0 counts + +Iteration 5: 270.916 us/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: 0.627 B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives": + 270.549 ±(99.9%) 3.034 us/op [Average] + (min, avg, max) = (269.821, 270.549, 271.698), stdev = 0.788 + CI (99.9%): [267.514, 273.583] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives:gc.alloc.rate": + 0.002 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.002, 0.002, 0.002), stdev = 0.001 + CI (99.9%): [0.002, 0.002] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives:gc.alloc.rate.norm": + 0.626 ±(99.9%) 0.007 B/op [Average] + (min, avg, max) = (0.624, 0.626, 0.629), stdev = 0.002 + CI (99.9%): [0.619, 0.633] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld +# Parameters: (slots = 1048576) + +# Run progress: 75.00% complete, ETA 00:01:37 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 1.947 ns/op +# Warmup Iteration 2: 1.957 ns/op +# Warmup Iteration 3: 1.917 ns/op +Iteration 1: 1.947 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 2: 1.922 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 3: 1.931 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 4: 1.995 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 5: 1.922 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld": + 1.943 ±(99.9%) 0.118 ns/op [Average] + (min, avg, max) = (1.922, 1.943, 1.995), stdev = 0.031 + CI (99.9%): [1.825, 2.062] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld:gc.alloc.rate": + 0.002 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.002, 0.002, 0.002), stdev = 0.001 + CI (99.9%): [0.002, 0.002] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld:gc.alloc.rate.norm": + ≈ 10⁻⁵ B/op + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld +# Parameters: (slots = 1048576) + +# Run progress: 81.25% complete, ETA 00:01:13 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 3.713 ns/op +# Warmup Iteration 2: 3.724 ns/op +# Warmup Iteration 3: 3.818 ns/op +Iteration 1: 3.685 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 2: 3.924 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 3: 3.783 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 4: 3.815 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 5: 3.692 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld": + 3.780 ±(99.9%) 0.379 ns/op [Average] + (min, avg, max) = (3.685, 3.780, 3.924), stdev = 0.098 + CI (99.9%): [3.401, 4.159] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld:gc.alloc.rate": + 0.002 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.002, 0.002, 0.002), stdev = 0.001 + CI (99.9%): [0.002, 0.002] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld:gc.alloc.rate.norm": + ≈ 10⁻⁵ B/op + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung +# Parameters: (slots = 1048576) + +# Run progress: 87.50% complete, ETA 00:00:48 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 5.673 ns/op +# Warmup Iteration 2: 5.146 ns/op +# Warmup Iteration 3: 5.013 ns/op +Iteration 1: 4.856 ns/op + gc.alloc.rate: 3141.966 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 8.000 counts + gc.time: 90.000 ms + +Iteration 2: 5.080 ns/op + gc.alloc.rate: 3003.337 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 7.000 counts + gc.time: 86.000 ms + +Iteration 3: 4.916 ns/op + gc.alloc.rate: 3103.059 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 8.000 counts + gc.time: 91.000 ms + +Iteration 4: 4.867 ns/op + gc.alloc.rate: 3134.589 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 8.000 counts + gc.time: 96.000 ms + +Iteration 5: 4.951 ns/op + gc.alloc.rate: 3081.545 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 7.000 counts + gc.time: 84.000 ms + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung": + 4.934 ±(99.9%) 0.347 ns/op [Average] + (min, avg, max) = (4.856, 4.934, 5.080), stdev = 0.090 + CI (99.9%): [4.587, 5.281] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.alloc.rate": + 3092.899 ±(99.9%) 214.387 MB/sec [Average] + (min, avg, max) = (3003.337, 3092.899, 3141.966), stdev = 55.676 + CI (99.9%): [2878.512, 3307.286] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.alloc.rate.norm": + 16.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (16.000, 16.000, 16.000), stdev = 0.001 + CI (99.9%): [16.000, 16.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.count": + 38.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (7.000, 7.600, 8.000), stdev = 0.548 + CI (99.9%): [38.000, 38.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.time": + 447.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (84.000, 89.400, 96.000), stdev = 4.669 + CI (99.9%): [447.000, 447.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseG1GC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld +# Parameters: (slots = 1048576) + +# Run progress: 93.75% complete, ETA 00:00:24 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 2.031 ns/op +# Warmup Iteration 2: 2.137 ns/op +# Warmup Iteration 3: 3.499 ns/op +Iteration 1: 2.710 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 2: 2.094 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 3: 2.057 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 4: 2.129 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 5: 2.019 ns/op + gc.alloc.rate: 0.002 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld": + 2.202 ±(99.9%) 1.105 ns/op [Average] + (min, avg, max) = (2.019, 2.202, 2.710), stdev = 0.287 + CI (99.9%): [1.097, 3.307] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate": + 0.002 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.002, 0.002, 0.002), stdev = 0.001 + CI (99.9%): [0.002, 0.002] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate.norm": + ≈ 10⁻⁵ B/op + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld:gc.count": + ≈ 0 counts + + +# Run complete. Total time: 00:06:31 + +REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on +why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial +experiments, perform baseline and negative tests that provide experimental control, make sure +the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts. +Do not assume the numbers tell you what you want them to tell. + +NOTE: Current JVM experimentally supports Compiler Blackholes, and they are in use. Please exercise +extra caution when trusting the results, look into the generated code to check the benchmark still +works, and factor in a small probability of new VM bugs. Additionally, while comparisons between +different JVMs are already problematic, the performance difference caused by different Blackhole +modes can be very significant. Please make sure you use the consistent Blackhole mode for comparisons. + +Benchmark (nodes) (payloadBytes) (size) (slots) (survivorDepth) Mode Cnt Score Error Units +AllocationBench.allocate N/A N/A 64 N/A N/A thrpt 5 109398.895 ± 3927.821 ops/ms +AllocationBench.allocate:gc.alloc.rate N/A N/A 64 N/A N/A thrpt 5 8345.780 ± 299.905 MB/sec +AllocationBench.allocate:gc.alloc.rate.norm N/A N/A 64 N/A N/A thrpt 5 80.000 ± 0.001 B/op +AllocationBench.allocate:gc.count N/A N/A 64 N/A N/A thrpt 5 102.000 counts +AllocationBench.allocate:gc.time N/A N/A 64 N/A N/A thrpt 5 137.000 ms +AllocationBench.allocate N/A N/A 1024 N/A N/A thrpt 5 7988.095 ± 714.858 ops/ms +AllocationBench.allocate:gc.alloc.rate N/A N/A 1024 N/A N/A thrpt 5 7921.904 ± 708.613 MB/sec +AllocationBench.allocate:gc.alloc.rate.norm N/A N/A 1024 N/A N/A thrpt 5 1040.000 ± 0.001 B/op +AllocationBench.allocate:gc.count N/A N/A 1024 N/A N/A thrpt 5 97.000 counts +AllocationBench.allocate:gc.time N/A N/A 1024 N/A N/A thrpt 5 152.000 ms +AllocationBench.allocate N/A N/A 32768 N/A N/A thrpt 5 259.452 ± 16.084 ops/ms +AllocationBench.allocate:gc.alloc.rate N/A N/A 32768 N/A N/A thrpt 5 8111.036 ± 502.749 MB/sec +AllocationBench.allocate:gc.alloc.rate.norm N/A N/A 32768 N/A N/A thrpt 5 32784.009 ± 0.001 B/op +AllocationBench.allocate:gc.count N/A N/A 32768 N/A N/A thrpt 5 103.000 counts +AllocationBench.allocate:gc.time N/A N/A 32768 N/A N/A thrpt 5 162.000 ms +AllocationBench.allocateAndDrop N/A N/A 64 N/A N/A thrpt 5 108943.527 ± 8618.787 ops/ms +AllocationBench.allocateAndDrop:gc.alloc.rate N/A N/A 64 N/A N/A thrpt 5 8311.005 ± 657.605 MB/sec +AllocationBench.allocateAndDrop:gc.alloc.rate.norm N/A N/A 64 N/A N/A thrpt 5 80.000 ± 0.001 B/op +AllocationBench.allocateAndDrop:gc.count N/A N/A 64 N/A N/A thrpt 5 102.000 counts +AllocationBench.allocateAndDrop:gc.time N/A N/A 64 N/A N/A thrpt 5 134.000 ms +AllocationBench.allocateAndDrop N/A N/A 1024 N/A N/A thrpt 5 8155.042 ± 210.140 ops/ms +AllocationBench.allocateAndDrop:gc.alloc.rate N/A N/A 1024 N/A N/A thrpt 5 8087.490 ± 208.528 MB/sec +AllocationBench.allocateAndDrop:gc.alloc.rate.norm N/A N/A 1024 N/A N/A thrpt 5 1040.000 ± 0.001 B/op +AllocationBench.allocateAndDrop:gc.count N/A N/A 1024 N/A N/A thrpt 5 99.000 counts +AllocationBench.allocateAndDrop:gc.time N/A N/A 1024 N/A N/A thrpt 5 154.000 ms +AllocationBench.allocateAndDrop N/A N/A 32768 N/A N/A thrpt 5 266.905 ± 6.917 ops/ms +AllocationBench.allocateAndDrop:gc.alloc.rate N/A N/A 32768 N/A N/A thrpt 5 8343.928 ± 215.624 MB/sec +AllocationBench.allocateAndDrop:gc.alloc.rate.norm N/A N/A 32768 N/A N/A thrpt 5 32784.009 ± 0.001 B/op +AllocationBench.allocateAndDrop:gc.count N/A N/A 32768 N/A N/A thrpt 5 105.000 counts +AllocationBench.allocateAndDrop:gc.time N/A N/A 32768 N/A N/A thrpt 5 171.000 ms +PromotionBench.allocateWithSurvival N/A 512 N/A N/A 0 thrpt 5 14815.572 ± 380.352 ops/ms +PromotionBench.allocateWithSurvival:gc.alloc.rate N/A 512 N/A N/A 0 thrpt 5 7459.288 ± 191.272 MB/sec +PromotionBench.allocateWithSurvival:gc.alloc.rate.norm N/A 512 N/A N/A 0 thrpt 5 528.000 ± 0.001 B/op +PromotionBench.allocateWithSurvival:gc.count N/A 512 N/A N/A 0 thrpt 5 92.000 counts +PromotionBench.allocateWithSurvival:gc.time N/A 512 N/A N/A 0 thrpt 5 141.000 ms +PromotionBench.allocateWithSurvival N/A 512 N/A N/A 4096 thrpt 5 14421.196 ± 366.606 ops/ms +PromotionBench.allocateWithSurvival:gc.alloc.rate N/A 512 N/A N/A 4096 thrpt 5 7260.877 ± 184.547 MB/sec +PromotionBench.allocateWithSurvival:gc.alloc.rate.norm N/A 512 N/A N/A 4096 thrpt 5 528.001 ± 0.001 B/op +PromotionBench.allocateWithSurvival:gc.count N/A 512 N/A N/A 4096 thrpt 5 90.000 counts +PromotionBench.allocateWithSurvival:gc.time N/A 512 N/A N/A 4096 thrpt 5 209.000 ms +PromotionBench.allocateWithSurvival N/A 512 N/A N/A 262144 thrpt 5 11452.135 ± 538.370 ops/ms +PromotionBench.allocateWithSurvival:gc.alloc.rate N/A 512 N/A N/A 262144 thrpt 5 5766.394 ± 270.678 MB/sec +PromotionBench.allocateWithSurvival:gc.alloc.rate.norm N/A 512 N/A N/A 262144 thrpt 5 528.076 ± 0.004 B/op +PromotionBench.allocateWithSurvival:gc.count N/A 512 N/A N/A 262144 thrpt 5 92.000 counts +PromotionBench.allocateWithSurvival:gc.time N/A 512 N/A N/A 262144 thrpt 5 2477.000 ms +LoadBarrierBench.chaseReferences 1048576 N/A N/A N/A N/A avgt 5 82080.599 ± 5967.482 us/op +LoadBarrierBench.chaseReferences:gc.alloc.rate 1048576 N/A N/A N/A N/A avgt 5 0.002 ± 0.001 MB/sec +LoadBarrierBench.chaseReferences:gc.alloc.rate.norm 1048576 N/A N/A N/A N/A avgt 5 187.726 ± 12.872 B/op +LoadBarrierBench.chaseReferences:gc.count 1048576 N/A N/A N/A N/A avgt 5 ≈ 0 counts +LoadBarrierBench.readSameReferenceRepeatedly 1048576 N/A N/A N/A N/A avgt 5 0.022 ± 0.001 us/op +LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate 1048576 N/A N/A N/A N/A avgt 5 0.002 ± 0.001 MB/sec +LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate.norm 1048576 N/A N/A N/A N/A avgt 5 ≈ 10⁻⁴ B/op +LoadBarrierBench.readSameReferenceRepeatedly:gc.count 1048576 N/A N/A N/A N/A avgt 5 ≈ 0 counts +LoadBarrierBench.sumPrimitives 1048576 N/A N/A N/A N/A avgt 5 270.549 ± 3.034 us/op +LoadBarrierBench.sumPrimitives:gc.alloc.rate 1048576 N/A N/A N/A N/A avgt 5 0.002 ± 0.001 MB/sec +LoadBarrierBench.sumPrimitives:gc.alloc.rate.norm 1048576 N/A N/A N/A N/A avgt 5 0.626 ± 0.007 B/op +LoadBarrierBench.sumPrimitives:gc.count 1048576 N/A N/A N/A N/A avgt 5 ≈ 0 counts +StoreBarrierBench.storeNullIntoOld N/A N/A N/A 1048576 N/A avgt 5 1.943 ± 0.118 ns/op +StoreBarrierBench.storeNullIntoOld:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 0.002 ± 0.001 MB/sec +StoreBarrierBench.storeNullIntoOld:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 ≈ 10⁻⁵ B/op +StoreBarrierBench.storeNullIntoOld:gc.count N/A N/A N/A 1048576 N/A avgt 5 ≈ 0 counts +StoreBarrierBench.storeOldToOld N/A N/A N/A 1048576 N/A avgt 5 3.780 ± 0.379 ns/op +StoreBarrierBench.storeOldToOld:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 0.002 ± 0.001 MB/sec +StoreBarrierBench.storeOldToOld:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 ≈ 10⁻⁵ B/op +StoreBarrierBench.storeOldToOld:gc.count N/A N/A N/A 1048576 N/A avgt 5 ≈ 0 counts +StoreBarrierBench.storeOldToYoung N/A N/A N/A 1048576 N/A avgt 5 4.934 ± 0.347 ns/op +StoreBarrierBench.storeOldToYoung:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 3092.899 ± 214.387 MB/sec +StoreBarrierBench.storeOldToYoung:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 16.000 ± 0.001 B/op +StoreBarrierBench.storeOldToYoung:gc.count N/A N/A N/A 1048576 N/A avgt 5 38.000 counts +StoreBarrierBench.storeOldToYoung:gc.time N/A N/A N/A 1048576 N/A avgt 5 447.000 ms +StoreBarrierBench.storePrimitiveIntoOld N/A N/A N/A 1048576 N/A avgt 5 2.202 ± 1.105 ns/op +StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 0.002 ± 0.001 MB/sec +StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 ≈ 10⁻⁵ B/op +StoreBarrierBench.storePrimitiveIntoOld:gc.count N/A N/A N/A 1048576 N/A avgt 5 ≈ 0 counts + +Benchmark result is saved to C:\Users\Ankur\ankurm-blog-tools\projects\zgc-jdk25-benchmarks\results\07-jmh-g1.json diff --git a/results/07-jmh-zgc.json b/results/07-jmh-zgc.json new file mode 100644 index 0000000..0935582 --- /dev/null +++ b/results/07-jmh-zgc.json @@ -0,0 +1,2659 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocate", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "64" + }, + "primaryMetric" : { + "score" : 113180.40226339805, + "scoreError" : 3074.5516315173218, + "scoreConfidence" : [ + 110105.85063188073, + 116254.95389491536 + ], + "scorePercentiles" : { + "0.0" : 111831.5782358896, + "50.0" : 113499.8747832871, + "90.0" : 113883.94558637982, + "95.0" : 113883.94558637982, + "99.0" : 113883.94558637982, + "99.9" : 113883.94558637982, + "99.99" : 113883.94558637982, + "99.999" : 113883.94558637982, + "99.9999" : 113883.94558637982, + "100.0" : 113883.94558637982 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 113499.8747832871, + 111831.5782358896, + 113544.12996016344, + 113883.94558637982, + 113142.48275127025 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 8633.874072510924, + "scoreError" : 234.52955194538674, + "scoreConfidence" : [ + 8399.344520565537, + 8868.40362445631 + ], + "scorePercentiles" : { + "0.0" : 8531.006923988425, + "50.0" : 8658.189953779649, + "90.0" : 8687.542757166977, + "95.0" : 8687.542757166977, + "99.0" : 8687.542757166977, + "99.9" : 8687.542757166977, + "99.99" : 8687.542757166977, + "99.999" : 8687.542757166977, + "99.9999" : 8687.542757166977, + "100.0" : 8687.542757166977 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 8658.189953779649, + 8531.006923988425, + 8661.736686430208, + 8687.542757166977, + 8630.89404118936 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 80.00003144623146, + "scoreError" : 8.777853572655563E-7, + "scoreConfidence" : [ + 80.0000305684461, + 80.00003232401681 + ], + "scorePercentiles" : { + "0.0" : 80.00003123816623, + "50.0" : 80.00003136151065, + "90.0" : 80.00003182910513, + "95.0" : 80.00003182910513, + "99.0" : 80.00003182910513, + "99.9" : 80.00003182910513, + "99.99" : 80.00003182910513, + "99.999" : 80.00003182910513, + "99.9999" : 80.00003182910513, + "100.0" : 80.00003182910513 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 80.00003136151065, + 80.00003182910513, + 80.0000313431332, + 80.00003123816623, + 80.00003145924207 + ] + ] + }, + "gc.count" : { + "score" : 332.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 332.0, + 332.0 + ], + "scorePercentiles" : { + "0.0" : 64.0, + "50.0" : 66.0, + "90.0" : 70.0, + "95.0" : 70.0, + "99.0" : 70.0, + "99.9" : 70.0, + "99.99" : 70.0, + "99.999" : 70.0, + "99.9999" : 70.0, + "100.0" : 70.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 64.0, + 66.0, + 66.0, + 70.0, + 66.0 + ] + ] + }, + "gc.time" : { + "score" : 354.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 354.0, + 354.0 + ], + "scorePercentiles" : { + "0.0" : 62.0, + "50.0" : 72.0, + "90.0" : 75.0, + "95.0" : 75.0, + "99.0" : 75.0, + "99.9" : 75.0, + "99.99" : 75.0, + "99.999" : 75.0, + "99.9999" : 75.0, + "100.0" : 75.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 62.0, + 71.0, + 75.0, + 72.0, + 74.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocate", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "1024" + }, + "primaryMetric" : { + "score" : 7856.555198680649, + "scoreError" : 551.8061199354306, + "scoreConfidence" : [ + 7304.749078745218, + 8408.36131861608 + ], + "scorePercentiles" : { + "0.0" : 7627.121937471512, + "50.0" : 7931.341573482751, + "90.0" : 7978.651928742275, + "95.0" : 7978.651928742275, + "99.0" : 7978.651928742275, + "99.9" : 7978.651928742275, + "99.99" : 7978.651928742275, + "99.999" : 7978.651928742275, + "99.9999" : 7978.651928742275, + "100.0" : 7978.651928742275 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 7627.121937471512, + 7931.341573482751, + 7978.651928742275, + 7807.744939489475, + 7937.915614217226 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 7791.2354210639005, + "scoreError" : 547.5227976449675, + "scoreConfidence" : [ + 7243.712623418933, + 8338.758218708868 + ], + "scorePercentiles" : { + "0.0" : 7563.523686899209, + "50.0" : 7865.581528341102, + "90.0" : 7912.350258105849, + "95.0" : 7912.350258105849, + "99.0" : 7912.350258105849, + "99.9" : 7912.350258105849, + "99.99" : 7912.350258105849, + "99.999" : 7912.350258105849, + "99.9999" : 7912.350258105849, + "100.0" : 7912.350258105849 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 7563.523686899209, + 7865.581528341102, + 7912.350258105849, + 7742.928414120835, + 7871.793217852505 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 1040.0004531063119, + "scoreError" : 3.2366558900652634E-5, + "scoreConfidence" : [ + 1040.000420739753, + 1040.0004854728707 + ], + "scorePercentiles" : { + "0.0" : 1040.0004460821021, + "50.0" : 1040.0004486824491, + "90.0" : 1040.0004667012788, + "95.0" : 1040.0004667012788, + "99.0" : 1040.0004667012788, + "99.9" : 1040.0004667012788, + "99.99" : 1040.0004667012788, + "99.999" : 1040.0004667012788, + "99.9999" : 1040.0004667012788, + "100.0" : 1040.0004667012788 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 1040.0004667012788, + 1040.0004486824491, + 1040.0004460821021, + 1040.0004556778224, + 1040.000448387907 + ] + ] + }, + "gc.count" : { + "score" : 306.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 306.0, + 306.0 + ], + "scorePercentiles" : { + "0.0" : 56.0, + "50.0" : 62.0, + "90.0" : 66.0, + "95.0" : 66.0, + "99.0" : 66.0, + "99.9" : 66.0, + "99.99" : 66.0, + "99.999" : 66.0, + "99.9999" : 66.0, + "100.0" : 66.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 56.0, + 62.0, + 60.0, + 62.0, + 66.0 + ] + ] + }, + "gc.time" : { + "score" : 394.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 394.0, + 394.0 + ], + "scorePercentiles" : { + "0.0" : 66.0, + "50.0" : 77.0, + "90.0" : 90.0, + "95.0" : 90.0, + "99.0" : 90.0, + "99.9" : 90.0, + "99.99" : 90.0, + "99.999" : 90.0, + "99.9999" : 90.0, + "100.0" : 90.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 74.0, + 90.0, + 66.0, + 87.0, + 77.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocate", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "32768" + }, + "primaryMetric" : { + "score" : 253.3455575655424, + "scoreError" : 11.130658368805793, + "scoreConfidence" : [ + 242.2148991967366, + 264.4762159343482 + ], + "scorePercentiles" : { + "0.0" : 249.5663132527872, + "50.0" : 255.15341820671904, + "90.0" : 255.87907813360476, + "95.0" : 255.87907813360476, + "99.0" : 255.87907813360476, + "99.9" : 255.87907813360476, + "99.99" : 255.87907813360476, + "99.999" : 255.87907813360476, + "99.9999" : 255.87907813360476, + "100.0" : 255.87907813360476 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 255.22022825455704, + 255.87907813360476, + 250.90874998004404, + 255.15341820671904, + 249.5663132527872 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 7919.8498010975945, + "scoreError" : 347.8340098512748, + "scoreConfidence" : [ + 7572.01579124632, + 8267.683810948869 + ], + "scorePercentiles" : { + "0.0" : 7801.720704651917, + "50.0" : 7975.999712101567, + "90.0" : 7999.237074428632, + "95.0" : 7999.237074428632, + "99.0" : 7999.237074428632, + "99.9" : 7999.237074428632, + "99.99" : 7999.237074428632, + "99.999" : 7999.237074428632, + "99.9999" : 7999.237074428632, + "100.0" : 7999.237074428632 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 7978.5174225614655, + 7999.237074428632, + 7843.774091744399, + 7975.999712101567, + 7801.720704651917 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 32784.01404856559, + "scoreError" : 6.258586077381788E-4, + "scoreConfidence" : [ + 32784.01342270698, + 32784.014674424194 + ], + "scorePercentiles" : { + "0.0" : 32784.013904511936, + "50.0" : 32784.01395049924, + "90.0" : 32784.01425992587, + "95.0" : 32784.01425992587, + "99.0" : 32784.01425992587, + "99.9" : 32784.01425992587, + "99.99" : 32784.01425992587, + "99.999" : 32784.01425992587, + "99.9999" : 32784.01425992587, + "100.0" : 32784.01425992587 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 32784.013941157355, + 32784.013904511936, + 32784.01418673355, + 32784.01395049924, + 32784.01425992587 + ] + ] + }, + "gc.count" : { + "score" : 316.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 316.0, + 316.0 + ], + "scorePercentiles" : { + "0.0" : 60.0, + "50.0" : 62.0, + "90.0" : 66.0, + "95.0" : 66.0, + "99.0" : 66.0, + "99.9" : 66.0, + "99.99" : 66.0, + "99.999" : 66.0, + "99.9999" : 66.0, + "100.0" : 66.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 60.0, + 62.0, + 66.0, + 66.0, + 62.0 + ] + ] + }, + "gc.time" : { + "score" : 420.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 420.0, + 420.0 + ], + "scorePercentiles" : { + "0.0" : 70.0, + "50.0" : 84.0, + "90.0" : 91.0, + "95.0" : 91.0, + "99.0" : 91.0, + "99.9" : 91.0, + "99.99" : 91.0, + "99.999" : 91.0, + "99.9999" : 91.0, + "100.0" : 91.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 70.0, + 84.0, + 91.0, + 91.0, + 84.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "64" + }, + "primaryMetric" : { + "score" : 110471.57608980188, + "scoreError" : 3078.497925329369, + "scoreConfidence" : [ + 107393.0781644725, + 113550.07401513125 + ], + "scorePercentiles" : { + "0.0" : 109411.09752370935, + "50.0" : 110667.25618742694, + "90.0" : 111486.66712551969, + "95.0" : 111486.66712551969, + "99.0" : 111486.66712551969, + "99.9" : 111486.66712551969, + "99.99" : 111486.66712551969, + "99.999" : 111486.66712551969, + "99.9999" : 111486.66712551969, + "100.0" : 111486.66712551969 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 110667.25618742694, + 109976.88294739272, + 109411.09752370935, + 111486.66712551969, + 110815.97666496066 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 8427.272821242434, + "scoreError" : 235.09984656448862, + "scoreConfidence" : [ + 8192.172974677946, + 8662.372667806922 + ], + "scorePercentiles" : { + "0.0" : 8346.345438116648, + "50.0" : 8442.189410454406, + "90.0" : 8504.876924969614, + "95.0" : 8504.876924969614, + "99.0" : 8504.876924969614, + "99.9" : 8504.876924969614, + "99.99" : 8504.876924969614, + "99.999" : 8504.876924969614, + "99.9999" : 8504.876924969614, + "100.0" : 8504.876924969614 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 8442.189410454406, + 8389.465603749055, + 8346.345438116648, + 8504.876924969614, + 8453.48672892244 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 80.00003221648572, + "scoreError" : 8.807854618480771E-7, + "scoreConfidence" : [ + 80.00003133570026, + 80.00003309727119 + ], + "scorePercentiles" : { + "0.0" : 80.00003192957365, + "50.0" : 80.0000321605436, + "90.0" : 80.00003252186242, + "95.0" : 80.00003252186242, + "99.0" : 80.00003252186242, + "99.9" : 80.00003252186242, + "99.99" : 80.00003252186242, + "99.999" : 80.00003252186242, + "99.9999" : 80.00003252186242, + "100.0" : 80.00003252186242 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 80.0000321605436, + 80.00003235744873, + 80.00003252186242, + 80.00003192957365, + 80.00003211300023 + ] + ] + }, + "gc.count" : { + "score" : 332.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 332.0, + 332.0 + ], + "scorePercentiles" : { + "0.0" : 62.0, + "50.0" : 66.0, + "90.0" : 72.0, + "95.0" : 72.0, + "99.0" : 72.0, + "99.9" : 72.0, + "99.99" : 72.0, + "99.999" : 72.0, + "99.9999" : 72.0, + "100.0" : 72.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 70.0, + 62.0, + 72.0, + 62.0, + 66.0 + ] + ] + }, + "gc.time" : { + "score" : 371.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 371.0, + 371.0 + ], + "scorePercentiles" : { + "0.0" : 70.0, + "50.0" : 73.0, + "90.0" : 84.0, + "95.0" : 84.0, + "99.0" : 84.0, + "99.9" : 84.0, + "99.99" : 84.0, + "99.999" : 84.0, + "99.9999" : 84.0, + "100.0" : 84.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 73.0, + 70.0, + 84.0, + 71.0, + 73.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "1024" + }, + "primaryMetric" : { + "score" : 7828.989511320683, + "scoreError" : 670.0949148931466, + "scoreConfidence" : [ + 7158.894596427536, + 8499.084426213829 + ], + "scorePercentiles" : { + "0.0" : 7537.316669603706, + "50.0" : 7899.555012160726, + "90.0" : 7960.275015789034, + "95.0" : 7960.275015789034, + "99.0" : 7960.275015789034, + "99.9" : 7960.275015789034, + "99.99" : 7960.275015789034, + "99.999" : 7960.275015789034, + "99.9999" : 7960.275015789034, + "100.0" : 7960.275015789034 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 7803.859161924847, + 7899.555012160726, + 7943.941697125105, + 7537.316669603706, + 7960.275015789034 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 7763.834143934831, + "scoreError" : 664.8813332794696, + "scoreConfidence" : [ + 7098.952810655362, + 8428.7154772143 + ], + "scorePercentiles" : { + "0.0" : 7474.365345511942, + "50.0" : 7834.069013545946, + "90.0" : 7894.009309105091, + "95.0" : 7894.009309105091, + "99.0" : 7894.009309105091, + "99.9" : 7894.009309105091, + "99.99" : 7894.009309105091, + "99.999" : 7894.009309105091, + "99.9999" : 7894.009309105091, + "100.0" : 7894.009309105091 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 7739.009605246467, + 7834.069013545946, + 7877.71744626471, + 7474.365345511942, + 7894.009309105091 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 1040.0004547551914, + "scoreError" : 3.942692993965783E-5, + "scoreConfidence" : [ + 1040.0004153282614, + 1040.0004941821214 + ], + "scorePercentiles" : { + "0.0" : 1040.0004470989993, + "50.0" : 1040.0004505987267, + "90.0" : 1040.000472019414, + "95.0" : 1040.000472019414, + "99.0" : 1040.000472019414, + "99.9" : 1040.000472019414, + "99.99" : 1040.000472019414, + "99.999" : 1040.000472019414, + "99.9999" : 1040.000472019414, + "100.0" : 1040.000472019414 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 1040.000455937465, + 1040.0004505987267, + 1040.0004481213518, + 1040.000472019414, + 1040.0004470989993 + ] + ] + }, + "gc.count" : { + "score" : 302.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 302.0, + 302.0 + ], + "scorePercentiles" : { + "0.0" : 58.0, + "50.0" : 62.0, + "90.0" : 62.0, + "95.0" : 62.0, + "99.0" : 62.0, + "99.9" : 62.0, + "99.99" : 62.0, + "99.999" : 62.0, + "99.9999" : 62.0, + "100.0" : 62.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 58.0, + 58.0, + 62.0, + 62.0, + 62.0 + ] + ] + }, + "gc.time" : { + "score" : 398.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 398.0, + 398.0 + ], + "scorePercentiles" : { + "0.0" : 75.0, + "50.0" : 79.0, + "90.0" : 85.0, + "95.0" : 85.0, + "99.0" : 85.0, + "99.9" : 85.0, + "99.99" : 85.0, + "99.999" : 85.0, + "99.9999" : 85.0, + "100.0" : 85.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 78.0, + 81.0, + 79.0, + 85.0, + 75.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "size" : "32768" + }, + "primaryMetric" : { + "score" : 250.78206653389333, + "scoreError" : 12.989172818880549, + "scoreConfidence" : [ + 237.79289371501278, + 263.7712393527739 + ], + "scorePercentiles" : { + "0.0" : 246.5628928904993, + "50.0" : 249.97859755169316, + "90.0" : 255.77303282127272, + "95.0" : 255.77303282127272, + "99.0" : 255.77303282127272, + "99.9" : 255.77303282127272, + "99.99" : 255.77303282127272, + "99.999" : 255.77303282127272, + "99.9999" : 255.77303282127272, + "100.0" : 255.77303282127272 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 249.7591687773807, + 249.97859755169316, + 255.77303282127272, + 251.83664062862073, + 246.5628928904993 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 7839.684309763205, + "scoreError" : 405.956461902257, + "scoreConfidence" : [ + 7433.727847860949, + 8245.640771665463 + ], + "scorePercentiles" : { + "0.0" : 7707.692418606932, + "50.0" : 7814.71101330847, + "90.0" : 7995.586710601519, + "95.0" : 7995.586710601519, + "99.0" : 7995.586710601519, + "99.9" : 7995.586710601519, + "99.99" : 7995.586710601519, + "99.999" : 7995.586710601519, + "99.9999" : 7995.586710601519, + "100.0" : 7995.586710601519 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 7807.761245124227, + 7814.71101330847, + 7995.586710601519, + 7872.670161174875, + 7707.692418606932 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 32784.01419303672, + "scoreError" : 7.337695799190518E-4, + "scoreConfidence" : [ + 32784.01345926714, + 32784.014926806296 + ], + "scorePercentiles" : { + "0.0" : 32784.01391507375, + "50.0" : 32784.01423176455, + "90.0" : 32784.01443563168, + "95.0" : 32784.01443563168, + "99.0" : 32784.01443563168, + "99.9" : 32784.01443563168, + "99.99" : 32784.01443563168, + "99.999" : 32784.01443563168, + "99.9999" : 32784.01443563168, + "100.0" : 32784.01443563168 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 32784.014253112866, + 32784.01423176455, + 32784.01391507375, + 32784.01412960072, + 32784.01443563168 + ] + ] + }, + "gc.count" : { + "score" : 300.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 300.0, + 300.0 + ], + "scorePercentiles" : { + "0.0" : 56.0, + "50.0" : 60.0, + "90.0" : 62.0, + "95.0" : 62.0, + "99.0" : 62.0, + "99.9" : 62.0, + "99.99" : 62.0, + "99.999" : 62.0, + "99.9999" : 62.0, + "100.0" : 62.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 62.0, + 56.0, + 60.0, + 60.0, + 62.0 + ] + ] + }, + "gc.time" : { + "score" : 397.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 397.0, + 397.0 + ], + "scorePercentiles" : { + "0.0" : 72.0, + "50.0" : 76.0, + "90.0" : 90.0, + "95.0" : 90.0, + "99.0" : 90.0, + "99.9" : 90.0, + "99.99" : 90.0, + "99.999" : 90.0, + "99.9999" : 90.0, + "100.0" : 90.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 90.0, + 76.0, + 73.0, + 72.0, + 86.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "payloadBytes" : "512", + "survivorDepth" : "0" + }, + "primaryMetric" : { + "score" : 13903.782674944028, + "scoreError" : 1178.8567008634968, + "scoreConfidence" : [ + 12724.925974080532, + 15082.639375807525 + ], + "scorePercentiles" : { + "0.0" : 13462.27604178749, + "50.0" : 13934.815342402413, + "90.0" : 14251.990535296489, + "95.0" : 14251.990535296489, + "99.0" : 14251.990535296489, + "99.9" : 14251.990535296489, + "99.99" : 14251.990535296489, + "99.999" : 14251.990535296489, + "99.9999" : 14251.990535296489, + "100.0" : 14251.990535296489 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 13767.850621744612, + 13462.27604178749, + 14101.980833489151, + 14251.990535296489, + 13934.815342402413 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 6999.825441103732, + "scoreError" : 594.6104982548703, + "scoreConfidence" : [ + 6405.214942848862, + 7594.435939358603 + ], + "scorePercentiles" : { + "0.0" : 6777.314573530771, + "50.0" : 7015.722499723505, + "90.0" : 7175.507832564711, + "95.0" : 7175.507832564711, + "99.0" : 7175.507832564711, + "99.9" : 7175.507832564711, + "99.99" : 7175.507832564711, + "99.999" : 7175.507832564711, + "99.9999" : 7175.507832564711, + "100.0" : 7175.507832564711 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 6930.811095337087, + 6777.314573530771, + 7099.771204362588, + 7175.507832564711, + 7015.722499723505 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 528.0002604721557, + "scoreError" : 2.2469702601161056E-5, + "scoreConfidence" : [ + 528.0002380024531, + 528.0002829418582 + ], + "scorePercentiles" : { + "0.0" : 528.0002539403233, + "50.0" : 528.0002598681236, + "90.0" : 528.0002689764308, + "95.0" : 528.0002689764308, + "99.0" : 528.0002689764308, + "99.9" : 528.0002689764308, + "99.99" : 528.0002689764308, + "99.999" : 528.0002689764308, + "99.9999" : 528.0002689764308, + "100.0" : 528.0002689764308 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 528.0002629434799, + 528.0002689764308, + 528.0002566324209, + 528.0002539403233, + 528.0002598681236 + ] + ] + }, + "gc.count" : { + "score" : 265.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 265.0, + 265.0 + ], + "scorePercentiles" : { + "0.0" : 44.0, + "50.0" : 54.0, + "90.0" : 58.0, + "95.0" : 58.0, + "99.0" : 58.0, + "99.9" : 58.0, + "99.99" : 58.0, + "99.999" : 58.0, + "99.9999" : 58.0, + "100.0" : 58.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 53.0, + 44.0, + 56.0, + 54.0, + 58.0 + ] + ] + }, + "gc.time" : { + "score" : 381.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 381.0, + 381.0 + ], + "scorePercentiles" : { + "0.0" : 68.0, + "50.0" : 74.0, + "90.0" : 88.0, + "95.0" : 88.0, + "99.0" : 88.0, + "99.9" : 88.0, + "99.99" : 88.0, + "99.999" : 88.0, + "99.9999" : 88.0, + "100.0" : 88.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 74.0, + 72.0, + 68.0, + 79.0, + 88.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "payloadBytes" : "512", + "survivorDepth" : "4096" + }, + "primaryMetric" : { + "score" : 13636.60355598157, + "scoreError" : 1198.622505755969, + "scoreConfidence" : [ + 12437.9810502256, + 14835.22606173754 + ], + "scorePercentiles" : { + "0.0" : 13216.162652941186, + "50.0" : 13653.90254991153, + "90.0" : 13939.70024877388, + "95.0" : 13939.70024877388, + "99.0" : 13939.70024877388, + "99.9" : 13939.70024877388, + "99.99" : 13939.70024877388, + "99.999" : 13939.70024877388, + "99.9999" : 13939.70024877388, + "100.0" : 13939.70024877388 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 13216.162652941186, + 13939.70024877388, + 13448.261759740884, + 13924.990568540383, + 13653.90254991153 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 6865.623086756355, + "scoreError" : 603.4937771065861, + "scoreConfidence" : [ + 6262.129309649769, + 7469.1168638629415 + ], + "scorePercentiles" : { + "0.0" : 6653.987804310966, + "50.0" : 6874.370527668311, + "90.0" : 7018.1576519099835, + "95.0" : 7018.1576519099835, + "99.0" : 7018.1576519099835, + "99.9" : 7018.1576519099835, + "99.99" : 7018.1576519099835, + "99.999" : 7018.1576519099835, + "99.9999" : 7018.1576519099835, + "100.0" : 7018.1576519099835 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 6653.987804310966, + 7018.1576519099835, + 6770.693739253476, + 7010.905710639042, + 6874.370527668311 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 528.0022660836757, + "scoreError" : 2.0009102419014257E-4, + "scoreConfidence" : [ + 528.0020659926515, + 528.0024661747 + ], + "scorePercentiles" : { + "0.0" : 528.0022160388754, + "50.0" : 528.0022622888627, + "90.0" : 528.0023369615072, + "95.0" : 528.0023369615072, + "99.0" : 528.0023369615072, + "99.9" : 528.0023369615072, + "99.99" : 528.0023369615072, + "99.999" : 528.0023369615072, + "99.9999" : 528.0023369615072, + "100.0" : 528.0023369615072 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 528.0023369615072, + 528.0022160388754, + 528.0022970165304, + 528.002218112603, + 528.0022622888627 + ] + ] + }, + "gc.count" : { + "score" : 264.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 264.0, + 264.0 + ], + "scorePercentiles" : { + "0.0" : 51.0, + "50.0" : 52.0, + "90.0" : 55.0, + "95.0" : 55.0, + "99.0" : 55.0, + "99.9" : 55.0, + "99.99" : 55.0, + "99.999" : 55.0, + "99.9999" : 55.0, + "100.0" : 55.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 52.0, + 54.0, + 52.0, + 55.0, + 51.0 + ] + ] + }, + "gc.time" : { + "score" : 398.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 398.0, + 398.0 + ], + "scorePercentiles" : { + "0.0" : 69.0, + "50.0" : 75.0, + "90.0" : 92.0, + "95.0" : 92.0, + "99.0" : 92.0, + "99.9" : 92.0, + "99.99" : 92.0, + "99.999" : 92.0, + "99.9999" : 92.0, + "100.0" : 92.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 69.0, + 89.0, + 73.0, + 75.0, + 92.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival", + "mode" : "thrpt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "payloadBytes" : "512", + "survivorDepth" : "262144" + }, + "primaryMetric" : { + "score" : 12640.643438747637, + "scoreError" : 825.6841309590111, + "scoreConfidence" : [ + 11814.959307788626, + 13466.327569706647 + ], + "scorePercentiles" : { + "0.0" : 12345.64910255038, + "50.0" : 12621.127395416841, + "90.0" : 12897.269195144376, + "95.0" : 12897.269195144376, + "99.0" : 12897.269195144376, + "99.9" : 12897.269195144376, + "99.99" : 12897.269195144376, + "99.999" : 12897.269195144376, + "99.9999" : 12897.269195144376, + "100.0" : 12897.269195144376 + }, + "scoreUnit" : "ops/ms", + "rawData" : [ + [ + 12621.127395416841, + 12549.20704949713, + 12345.64910255038, + 12789.964451129452, + 12897.269195144376 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 6365.146687282447, + "scoreError" : 415.7486474670637, + "scoreConfidence" : [ + 5949.398039815383, + 6780.895334749511 + ], + "scorePercentiles" : { + "0.0" : 6216.270499600908, + "50.0" : 6355.516265069727, + "90.0" : 6494.219126705681, + "95.0" : 6494.219126705681, + "99.0" : 6494.219126705681, + "99.9" : 6494.219126705681, + "99.99" : 6494.219126705681, + "99.999" : 6494.219126705681, + "99.9999" : 6494.219126705681, + "100.0" : 6494.219126705681 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 6355.516265069727, + 6319.53495168803, + 6216.270499600908, + 6440.192593347887, + 6494.219126705681 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 528.1385306892081, + "scoreError" : 0.00901540976452295, + "scoreConfidence" : [ + 528.1295152794436, + 528.1475460989726 + ], + "scorePercentiles" : { + "0.0" : 528.1357738358398, + "50.0" : 528.1387153801012, + "90.0" : 528.1418111665996, + "95.0" : 528.1418111665996, + "99.0" : 528.1418111665996, + "99.9" : 528.1418111665996, + "99.99" : 528.1418111665996, + "99.999" : 528.1418111665996, + "99.9999" : 528.1418111665996, + "100.0" : 528.1418111665996 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 528.1387153801012, + 528.1394570598159, + 528.1418111665996, + 528.1368960036839, + 528.1357738358398 + ] + ] + }, + "gc.count" : { + "score" : 340.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 340.0, + 340.0 + ], + "scorePercentiles" : { + "0.0" : 66.0, + "50.0" : 66.0, + "90.0" : 72.0, + "95.0" : 72.0, + "99.0" : 72.0, + "99.9" : 72.0, + "99.99" : 72.0, + "99.999" : 72.0, + "99.9999" : 72.0, + "100.0" : 72.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 70.0, + 72.0, + 66.0, + 66.0, + 66.0 + ] + ] + }, + "gc.time" : { + "score" : 2687.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 2687.0, + 2687.0 + ], + "scorePercentiles" : { + "0.0" : 472.0, + "50.0" : 559.0, + "90.0" : 595.0, + "95.0" : 595.0, + "99.0" : 595.0, + "99.9" : 595.0, + "99.99" : 595.0, + "99.999" : 595.0, + "99.9999" : 595.0, + "100.0" : 595.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 595.0, + 559.0, + 572.0, + 489.0, + 472.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "nodes" : "1048576" + }, + "primaryMetric" : { + "score" : 92328.97936185382, + "scoreError" : 18617.021853273676, + "scoreConfidence" : [ + 73711.95750858015, + 110946.0012151275 + ], + "scorePercentiles" : { + "0.0" : 89239.85588235295, + "50.0" : 89837.53823529412, + "90.0" : 100691.66, + "95.0" : 100691.66, + "99.0" : 100691.66, + "99.9" : 100691.66, + "99.99" : 100691.66, + "99.999" : 100691.66, + "99.9999" : 100691.66, + "100.0" : 100691.66 + }, + "scoreUnit" : "us/op", + "rawData" : [ + [ + 89837.53823529412, + 92342.55151515151, + 100691.66, + 89533.2911764706, + 89239.85588235295 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0033343730901597432, + "scoreError" : 6.505735605705893E-5, + "scoreConfidence" : [ + 0.003269315734102684, + 0.0033994304462168024 + ], + "scorePercentiles" : { + "0.0" : 0.003317909703072371, + "50.0" : 0.0033295652185460008, + "90.0" : 0.0033588246979196204, + "95.0" : 0.0033588246979196204, + "99.0" : 0.0033588246979196204, + "99.9" : 0.0033588246979196204, + "99.99" : 0.0033588246979196204, + "99.999" : 0.0033588246979196204, + "99.9999" : 0.0033588246979196204, + "100.0" : 0.0033588246979196204 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.003321721893112557, + 0.0033295652185460008, + 0.0033588246979196204, + 0.003317909703072371, + 0.0033438439381481646 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 322.90053475935827, + "scoreError" : 70.39926174653553, + "scoreConfidence" : [ + 252.50127301282274, + 393.2997965058938 + ], + "scorePercentiles" : { + "0.0" : 311.52941176470586, + "50.0" : 312.94117647058823, + "90.0" : 354.6666666666667, + "95.0" : 354.6666666666667, + "99.0" : 354.6666666666667, + "99.9" : 354.6666666666667, + "99.99" : 354.6666666666667, + "99.999" : 354.6666666666667, + "99.9999" : 354.6666666666667, + "100.0" : 354.6666666666667 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 312.94117647058823, + 322.42424242424244, + 354.6666666666667, + 311.52941176470586, + 312.94117647058823 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "nodes" : "1048576" + }, + "primaryMetric" : { + "score" : 0.02316438686241045, + "scoreError" : 0.005728253152658764, + "scoreConfidence" : [ + 0.017436133709751687, + 0.028892640015069214 + ], + "scorePercentiles" : { + "0.0" : 0.022065150018007015, + "50.0" : 0.02274348186494304, + "90.0" : 0.025756960707324677, + "95.0" : 0.025756960707324677, + "99.0" : 0.025756960707324677, + "99.9" : 0.025756960707324677, + "99.99" : 0.025756960707324677, + "99.999" : 0.025756960707324677, + "99.9999" : 0.025756960707324677, + "100.0" : 0.025756960707324677 + }, + "scoreUnit" : "us/op", + "rawData" : [ + [ + 0.022065150018007015, + 0.02274348186494304, + 0.022919672977731818, + 0.022336668744045697, + 0.025756960707324677 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0033737634317976663, + "scoreError" : 2.6572689873143182E-5, + "scoreConfidence" : [ + 0.003347190741924523, + 0.0034003361216708096 + ], + "scorePercentiles" : { + "0.0" : 0.003368101047520573, + "50.0" : 0.0033691996877570803, + "90.0" : 0.003381527304540832, + "95.0" : 0.003381527304540832, + "99.0" : 0.003381527304540832, + "99.9" : 0.003381527304540832, + "99.99" : 0.003381527304540832, + "99.999" : 0.003381527304540832, + "99.9999" : 0.003381527304540832, + "100.0" : 0.003381527304540832 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.003381527304540832, + 0.003368101047520573, + 0.0033691996877570803, + 0.0033810891112295294, + 0.0033689000079403174 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 8.195006376742389E-5, + "scoreError" : 1.9889179598729256E-5, + "scoreConfidence" : [ + 6.206088416869464E-5, + 1.0183924336615314E-4 + ], + "scorePercentiles" : { + "0.0" : 7.824501203307538E-5, + "50.0" : 8.033142076598602E-5, + "90.0" : 9.099715680242034E-5, + "95.0" : 9.099715680242034E-5, + "99.0" : 9.099715680242034E-5, + "99.9" : 9.099715680242034E-5, + "99.99" : 9.099715680242034E-5, + "99.999" : 9.099715680242034E-5, + "99.9999" : 9.099715680242034E-5, + "100.0" : 9.099715680242034E-5 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 7.824501203307538E-5, + 8.033142076598602E-5, + 8.097893323884365E-5, + 7.919779599679407E-5, + 9.099715680242034E-5 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "nodes" : "1048576" + }, + "primaryMetric" : { + "score" : 270.5803206070388, + "scoreError" : 3.98643315711393, + "scoreConfidence" : [ + 266.59388744992486, + 274.56675376415274 + ], + "scorePercentiles" : { + "0.0" : 269.8874156696951, + "50.0" : 270.20708562168, + "90.0" : 272.367846447046, + "95.0" : 272.367846447046, + "99.0" : 272.367846447046, + "99.9" : 272.367846447046, + "99.99" : 272.367846447046, + "99.999" : 272.367846447046, + "99.9999" : 272.367846447046, + "100.0" : 272.367846447046 + }, + "scoreUnit" : "us/op", + "rawData" : [ + [ + 269.8874156696951, + 270.5453709546561, + 272.367846447046, + 270.20708562168, + 269.8938843421171 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0033808829647037353, + "scoreError" : 1.8498674986097086E-6, + "scoreConfidence" : [ + 0.0033790330972051255, + 0.003382732832202345 + ], + "scorePercentiles" : { + "0.0" : 0.0033804054005236632, + "50.0" : 0.0033807564576235115, + "90.0" : 0.003381677977334371, + "95.0" : 0.003381677977334371, + "99.0" : 0.003381677977334371, + "99.9" : 0.003381677977334371, + "99.99" : 0.003381677977334371, + "99.999" : 0.003381677977334371, + "99.9999" : 0.003381677977334371, + "100.0" : 0.003381677977334371 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.003381677977334371, + 0.0033807564576235115, + 0.0033804054005236632, + 0.0033806674757146105, + 0.0033809075123225215 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 0.9593472142203143, + "scoreError" : 0.013897429953041917, + "scoreConfidence" : [ + 0.9454497842672724, + 0.9732446441733562 + ], + "scorePercentiles" : { + "0.0" : 0.9569205863836676, + "50.0" : 0.9579544431439633, + "90.0" : 0.9656048643252564, + "95.0" : 0.9656048643252564, + "99.0" : 0.9656048643252564, + "99.9" : 0.9656048643252564, + "99.99" : 0.9656048643252564, + "99.999" : 0.9656048643252564, + "99.9999" : 0.9656048643252564, + "100.0" : 0.9656048643252564 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 0.9570927408473509, + 0.9591634364013342, + 0.9656048643252564, + 0.9579544431439633, + 0.9569205863836676 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 3.239042176679324, + "scoreError" : 0.476662928597759, + "scoreConfidence" : [ + 2.762379248081565, + 3.715705105277083 + ], + "scorePercentiles" : { + "0.0" : 3.091414044051246, + "50.0" : 3.2730501915245256, + "90.0" : 3.368274761747213, + "95.0" : 3.368274761747213, + "99.0" : 3.368274761747213, + "99.9" : 3.368274761747213, + "99.99" : 3.368274761747213, + "99.999" : 3.368274761747213, + "99.9999" : 3.368274761747213, + "100.0" : 3.368274761747213 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 3.127505089712369, + 3.2730501915245256, + 3.091414044051246, + 3.3349667963612655, + 3.368274761747213 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.003368245710734839, + "scoreError" : 3.2048574412037784E-6, + "scoreConfidence" : [ + 0.003365040853293635, + 0.0033714505681760425 + ], + "scorePercentiles" : { + "0.0" : 0.003367081739239855, + "50.0" : 0.0033682381840521775, + "90.0" : 0.0033691973296336017, + "95.0" : 0.0033691973296336017, + "99.0" : 0.0033691973296336017, + "99.9" : 0.0033691973296336017, + "99.99" : 0.0033691973296336017, + "99.999" : 0.0033691973296336017, + "99.9999" : 0.0033691973296336017, + "100.0" : 0.0033691973296336017 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.0033678626001926813, + 0.0033688487005558744, + 0.003367081739239855, + 0.0033691973296336017, + 0.0033682381840521775 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 1.1441414158074954E-5, + "scoreError" : 1.6905982924896593E-6, + "scoreConfidence" : [ + 9.750815865585296E-6, + 1.3132012450564613E-5 + ], + "scorePercentiles" : { + "0.0" : 1.0915703507467731E-5, + "50.0" : 1.1562961187616123E-5, + "90.0" : 1.1897621407773616E-5, + "95.0" : 1.1897621407773616E-5, + "99.0" : 1.1897621407773616E-5, + "99.9" : 1.1897621407773616E-5, + "99.99" : 1.1897621407773616E-5, + "99.999" : 1.1897621407773616E-5, + "99.9999" : 1.1897621407773616E-5, + "100.0" : 1.1897621407773616E-5 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 1.1047689775067952E-5, + 1.1562961187616123E-5, + 1.0915703507467731E-5, + 1.1783094912449349E-5, + 1.1897621407773616E-5 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 3.4620731637376294, + "scoreError" : 0.3922106411576235, + "scoreConfidence" : [ + 3.069862522580006, + 3.854283804895253 + ], + "scorePercentiles" : { + "0.0" : 3.331660080080304, + "50.0" : 3.467457523703339, + "90.0" : 3.592489958108695, + "95.0" : 3.592489958108695, + "99.0" : 3.592489958108695, + "99.9" : 3.592489958108695, + "99.99" : 3.592489958108695, + "99.999" : 3.592489958108695, + "99.9999" : 3.592489958108695, + "100.0" : 3.592489958108695 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 3.3983920658365885, + 3.331660080080304, + 3.467457523703339, + 3.5203661909592183, + 3.592489958108695 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0033736363041292614, + "scoreError" : 2.7467079602604263E-5, + "scoreConfidence" : [ + 0.003346169224526657, + 0.0034011033837318657 + ], + "scorePercentiles" : { + "0.0" : 0.00336801856897827, + "50.0" : 0.0033692498828826324, + "90.0" : 0.003381803078636036, + "95.0" : 0.003381803078636036, + "99.0" : 0.003381803078636036, + "99.9" : 0.003381803078636036, + "99.99" : 0.003381803078636036, + "99.999" : 0.003381803078636036, + "99.9999" : 0.003381803078636036, + "100.0" : 0.003381803078636036 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.0033810488919238002, + 0.0033692498828826324, + 0.003368061098225567, + 0.00336801856897827, + 0.003381803078636036 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 1.2248780407553344E-5, + "scoreError" : 1.4199073944476746E-6, + "scoreConfidence" : [ + 1.082887301310567E-5, + 1.3668687802001018E-5 + ], + "scorePercentiles" : { + "0.0" : 1.177150815481944E-5, + "50.0" : 1.2247930484518008E-5, + "90.0" : 1.2740766418121616E-5, + "95.0" : 1.2740766418121616E-5, + "99.0" : 1.2740766418121616E-5, + "99.9" : 1.2740766418121616E-5, + "99.99" : 1.2740766418121616E-5, + "99.999" : 1.2740766418121616E-5, + "99.9999" : 1.2740766418121616E-5, + "100.0" : 1.2740766418121616E-5 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 1.2049550624126973E-5, + 1.177150815481944E-5, + 1.2247930484518008E-5, + 1.2434146356180682E-5, + 1.2740766418121616E-5 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 6.581877342874139, + "scoreError" : 0.9787690394143025, + "scoreConfidence" : [ + 5.603108303459837, + 7.560646382288442 + ], + "scorePercentiles" : { + "0.0" : 6.229139848325649, + "50.0" : 6.556820782582807, + "90.0" : 6.909460558996732, + "95.0" : 6.909460558996732, + "99.0" : 6.909460558996732, + "99.9" : 6.909460558996732, + "99.99" : 6.909460558996732, + "99.999" : 6.909460558996732, + "99.9999" : 6.909460558996732, + "100.0" : 6.909460558996732 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 6.556820782582807, + 6.229139848325649, + 6.718368400331931, + 6.495597124133573, + 6.909460558996732 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 2320.7385953309677, + "scoreError" : 347.2043831584557, + "scoreConfidence" : [ + 1973.534212172512, + 2667.9429784894232 + ], + "scorePercentiles" : { + "0.0" : 2208.1068541844334, + "50.0" : 2326.8378850033364, + "90.0" : 2449.2666498389963, + "95.0" : 2449.2666498389963, + "99.0" : 2449.2666498389963, + "99.9" : 2449.2666498389963, + "99.99" : 2449.2666498389963, + "99.999" : 2449.2666498389963, + "99.9999" : 2449.2666498389963, + "100.0" : 2449.2666498389963 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 2326.8378850033364, + 2449.2666498389963, + 2270.7760102200828, + 2348.7055774079886, + 2208.1068541844334 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 16.000023404672824, + "scoreError" : 3.5185278623129333E-6, + "scoreConfidence" : [ + 16.000019886144962, + 16.000026923200686 + ], + "scorePercentiles" : { + "0.0" : 16.000022161931714, + "50.0" : 16.000023332403824, + "90.0" : 16.00002458979938, + "95.0" : 16.00002458979938, + "99.0" : 16.00002458979938, + "99.9" : 16.00002458979938, + "99.99" : 16.00002458979938, + "99.999" : 16.00002458979938, + "99.9999" : 16.00002458979938, + "100.0" : 16.00002458979938 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 16.000023332403824, + 16.000022161931714, + 16.000023903879438, + 16.000023035349766, + 16.00002458979938 + ] + ] + }, + "gc.count" : { + "score" : 113.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 113.0, + 113.0 + ], + "scorePercentiles" : { + "0.0" : 20.0, + "50.0" : 23.0, + "90.0" : 24.0, + "95.0" : 24.0, + "99.0" : 24.0, + "99.9" : 24.0, + "99.99" : 24.0, + "99.999" : 24.0, + "99.9999" : 24.0, + "100.0" : 24.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 24.0, + 20.0, + 22.0, + 24.0, + 23.0 + ] + ] + }, + "gc.time" : { + "score" : 2317.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 2317.0, + 2317.0 + ], + "scorePercentiles" : { + "0.0" : 383.0, + "50.0" : 446.0, + "90.0" : 536.0, + "95.0" : 536.0, + "99.0" : 536.0, + "99.9" : 536.0, + "99.99" : 536.0, + "99.999" : 536.0, + "99.9999" : 536.0, + "100.0" : 536.0 + }, + "scoreUnit" : "ms", + "rawData" : [ + [ + 511.0, + 383.0, + 441.0, + 536.0, + 446.0 + ] + ] + } + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld", + "mode" : "avgt", + "threads" : 1, + "forks" : 1, + "jvm" : "C:\\Program Files\\Java\\jdk-25.0.3\\bin\\java.exe", + "jvmArgs" : [ + "-XX:+UseZGC", + "-Xms2g", + "-Xmx2g" + ], + "jdkVersion" : "25.0.3", + "vmName" : "Java HotSpot(TM) 64-Bit Server VM", + "vmVersion" : "25.0.3+9-LTS-195", + "warmupIterations" : 3, + "warmupTime" : "3 s", + "warmupBatchSize" : 1, + "measurementIterations" : 5, + "measurementTime" : "3 s", + "measurementBatchSize" : 1, + "params" : { + "slots" : "1048576" + }, + "primaryMetric" : { + "score" : 1.8788002432574626, + "scoreError" : 0.1345427201327799, + "scoreConfidence" : [ + 1.7442575231246829, + 2.0133429633902424 + ], + "scorePercentiles" : { + "0.0" : 1.850918390011838, + "50.0" : 1.8667259467133068, + "90.0" : 1.9396897450647115, + "95.0" : 1.9396897450647115, + "99.0" : 1.9396897450647115, + "99.9" : 1.9396897450647115, + "99.99" : 1.9396897450647115, + "99.999" : 1.9396897450647115, + "99.9999" : 1.9396897450647115, + "100.0" : 1.9396897450647115 + }, + "scoreUnit" : "ns/op", + "rawData" : [ + [ + 1.850918390011838, + 1.8642419519335587, + 1.8667259467133068, + 1.9396897450647115, + 1.8724251825638978 + ] + ] + }, + "secondaryMetrics" : { + "gc.alloc.rate" : { + "score" : 0.0033709540103636845, + "scoreError" : 2.2663587383550436E-5, + "scoreConfidence" : [ + 0.0033482904229801343, + 0.0033936175977472348 + ], + "scorePercentiles" : { + "0.0" : 0.0033674489601515202, + "50.0" : 0.0033689226869759257, + "90.0" : 0.00338140301241057, + "95.0" : 0.00338140301241057, + "99.0" : 0.00338140301241057, + "99.9" : 0.00338140301241057, + "99.99" : 0.00338140301241057, + "99.999" : 0.00338140301241057, + "99.9999" : 0.00338140301241057, + "100.0" : 0.00338140301241057 + }, + "scoreUnit" : "MB/sec", + "rawData" : [ + [ + 0.0033674489601515202, + 0.003367825461553803, + 0.003369169930726605, + 0.0033689226869759257, + 0.00338140301241057 + ] + ] + }, + "gc.alloc.rate.norm" : { + "score" : 6.6416664218697905E-6, + "scoreError" : 4.760617861258884E-7, + "scoreConfidence" : [ + 6.165604635743902E-6, + 7.117728207995679E-6 + ], + "scorePercentiles" : { + "0.0" : 6.5362334882502065E-6, + "50.0" : 6.595484263940182E-6, + "90.0" : 6.8527517571520594E-6, + "95.0" : 6.8527517571520594E-6, + "99.0" : 6.8527517571520594E-6, + "99.9" : 6.8527517571520594E-6, + "99.99" : 6.8527517571520594E-6, + "99.999" : 6.8527517571520594E-6, + "99.9999" : 6.8527517571520594E-6, + "100.0" : 6.8527517571520594E-6 + }, + "scoreUnit" : "B/op", + "rawData" : [ + [ + 6.5362334882502065E-6, + 6.583958511923337E-6, + 6.595484263940182E-6, + 6.8527517571520594E-6, + 6.63990408808317E-6 + ] + ] + }, + "gc.count" : { + "score" : 0.0, + "scoreError" : "NaN", + "scoreConfidence" : [ + 0.0, + 0.0 + ], + "scorePercentiles" : { + "0.0" : 0.0, + "50.0" : 0.0, + "90.0" : 0.0, + "95.0" : 0.0, + "99.0" : 0.0, + "99.9" : 0.0, + "99.99" : 0.0, + "99.999" : 0.0, + "99.9999" : 0.0, + "100.0" : 0.0 + }, + "scoreUnit" : "counts", + "rawData" : [ + [ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ] + } + } + } +] + + diff --git a/results/07-jmh-zgc.txt b/results/07-jmh-zgc.txt new file mode 100644 index 0000000..ea87777 --- /dev/null +++ b/results/07-jmh-zgc.txt @@ -0,0 +1,1295 @@ +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocate +# Parameters: (size = 64) + +# Run progress: 0.00% complete, ETA 00:06:24 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 89505.196 ops/ms +# Warmup Iteration 2: 110710.155 ops/ms +# Warmup Iteration 3: 109186.832 ops/ms +Iteration 1: 113499.875 ops/ms + gc.alloc.rate: 8658.190 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 64.000 counts + gc.time: 62.000 ms + +Iteration 2: 111831.578 ops/ms + gc.alloc.rate: 8531.007 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 66.000 counts + gc.time: 71.000 ms + +Iteration 3: 113544.130 ops/ms + gc.alloc.rate: 8661.737 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 66.000 counts + gc.time: 75.000 ms + +Iteration 4: 113883.946 ops/ms + gc.alloc.rate: 8687.543 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 70.000 counts + gc.time: 72.000 ms + +Iteration 5: 113142.483 ops/ms + gc.alloc.rate: 8630.894 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 66.000 counts + gc.time: 74.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocate": + 113180.402 ±(99.9%) 3074.552 ops/ms [Average] + (min, avg, max) = (111831.578, 113180.402, 113883.946), stdev = 798.451 + CI (99.9%): [110105.851, 116254.954] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate": + 8633.874 ±(99.9%) 234.530 MB/sec [Average] + (min, avg, max) = (8531.007, 8633.874, 8687.543), stdev = 60.907 + CI (99.9%): [8399.345, 8868.404] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate.norm": + 80.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (80.000, 80.000, 80.000), stdev = 0.001 + CI (99.9%): [80.000, 80.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.count": + 332.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (64.000, 66.400, 70.000), stdev = 2.191 + CI (99.9%): [332.000, 332.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.time": + 354.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (62.000, 70.800, 75.000), stdev = 5.167 + CI (99.9%): [354.000, 354.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocate +# Parameters: (size = 1024) + +# Run progress: 6.25% complete, ETA 00:06:10 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 6299.951 ops/ms +# Warmup Iteration 2: 7807.387 ops/ms +# Warmup Iteration 3: 7967.237 ops/ms +Iteration 1: 7627.122 ops/ms + gc.alloc.rate: 7563.524 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 56.000 counts + gc.time: 74.000 ms + +Iteration 2: 7931.342 ops/ms + gc.alloc.rate: 7865.582 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 62.000 counts + gc.time: 90.000 ms + +Iteration 3: 7978.652 ops/ms + gc.alloc.rate: 7912.350 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 60.000 counts + gc.time: 66.000 ms + +Iteration 4: 7807.745 ops/ms + gc.alloc.rate: 7742.928 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 62.000 counts + gc.time: 87.000 ms + +Iteration 5: 7937.916 ops/ms + gc.alloc.rate: 7871.793 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 66.000 counts + gc.time: 77.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocate": + 7856.555 ±(99.9%) 551.806 ops/ms [Average] + (min, avg, max) = (7627.122, 7856.555, 7978.652), stdev = 143.302 + CI (99.9%): [7304.749, 8408.361] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate": + 7791.235 ±(99.9%) 547.523 MB/sec [Average] + (min, avg, max) = (7563.524, 7791.235, 7912.350), stdev = 142.190 + CI (99.9%): [7243.713, 8338.758] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate.norm": + 1040.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (1040.000, 1040.000, 1040.000), stdev = 0.001 + CI (99.9%): [1040.000, 1040.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.count": + 306.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (56.000, 61.200, 66.000), stdev = 3.633 + CI (99.9%): [306.000, 306.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.time": + 394.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (66.000, 78.800, 90.000), stdev = 9.783 + CI (99.9%): [394.000, 394.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocate +# Parameters: (size = 32768) + +# Run progress: 12.50% complete, ETA 00:05:45 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 208.276 ops/ms +# Warmup Iteration 2: 250.983 ops/ms +# Warmup Iteration 3: 253.784 ops/ms +Iteration 1: 255.220 ops/ms + gc.alloc.rate: 7978.517 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 60.000 counts + gc.time: 70.000 ms + +Iteration 2: 255.879 ops/ms + gc.alloc.rate: 7999.237 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 62.000 counts + gc.time: 84.000 ms + +Iteration 3: 250.909 ops/ms + gc.alloc.rate: 7843.774 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 66.000 counts + gc.time: 91.000 ms + +Iteration 4: 255.153 ops/ms + gc.alloc.rate: 7976.000 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 66.000 counts + gc.time: 91.000 ms + +Iteration 5: 249.566 ops/ms + gc.alloc.rate: 7801.721 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 62.000 counts + gc.time: 84.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocate": + 253.346 ±(99.9%) 11.131 ops/ms [Average] + (min, avg, max) = (249.566, 253.346, 255.879), stdev = 2.891 + CI (99.9%): [242.215, 264.476] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate": + 7919.850 ±(99.9%) 347.834 MB/sec [Average] + (min, avg, max) = (7801.721, 7919.850, 7999.237), stdev = 90.331 + CI (99.9%): [7572.016, 8267.684] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.alloc.rate.norm": + 32784.014 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (32784.014, 32784.014, 32784.014), stdev = 0.001 + CI (99.9%): [32784.013, 32784.015] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.count": + 316.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (60.000, 63.200, 66.000), stdev = 2.683 + CI (99.9%): [316.000, 316.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocate:gc.time": + 420.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (70.000, 84.000, 91.000), stdev = 8.573 + CI (99.9%): [420.000, 420.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop +# Parameters: (size = 64) + +# Run progress: 18.75% complete, ETA 00:05:21 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 86590.155 ops/ms +# Warmup Iteration 2: 113184.286 ops/ms +# Warmup Iteration 3: 106911.607 ops/ms +Iteration 1: 110667.256 ops/ms + gc.alloc.rate: 8442.189 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 70.000 counts + gc.time: 73.000 ms + +Iteration 2: 109976.883 ops/ms + gc.alloc.rate: 8389.466 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 62.000 counts + gc.time: 70.000 ms + +Iteration 3: 109411.098 ops/ms + gc.alloc.rate: 8346.345 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 72.000 counts + gc.time: 84.000 ms + +Iteration 4: 111486.667 ops/ms + gc.alloc.rate: 8504.877 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 62.000 counts + gc.time: 71.000 ms + +Iteration 5: 110815.977 ops/ms + gc.alloc.rate: 8453.487 MB/sec + gc.alloc.rate.norm: 80.000 B/op + gc.count: 66.000 counts + gc.time: 73.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop": + 110471.576 ±(99.9%) 3078.498 ops/ms [Average] + (min, avg, max) = (109411.098, 110471.576, 111486.667), stdev = 799.476 + CI (99.9%): [107393.078, 113550.074] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate": + 8427.273 ±(99.9%) 235.100 MB/sec [Average] + (min, avg, max) = (8346.345, 8427.273, 8504.877), stdev = 61.055 + CI (99.9%): [8192.173, 8662.373] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate.norm": + 80.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (80.000, 80.000, 80.000), stdev = 0.001 + CI (99.9%): [80.000, 80.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.count": + 332.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (62.000, 66.400, 72.000), stdev = 4.561 + CI (99.9%): [332.000, 332.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.time": + 371.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (70.000, 74.200, 84.000), stdev = 5.630 + CI (99.9%): [371.000, 371.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop +# Parameters: (size = 1024) + +# Run progress: 25.00% complete, ETA 00:04:56 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 6240.137 ops/ms +# Warmup Iteration 2: 7690.908 ops/ms +# Warmup Iteration 3: 7956.648 ops/ms +Iteration 1: 7803.859 ops/ms + gc.alloc.rate: 7739.010 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 58.000 counts + gc.time: 78.000 ms + +Iteration 2: 7899.555 ops/ms + gc.alloc.rate: 7834.069 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 58.000 counts + gc.time: 81.000 ms + +Iteration 3: 7943.942 ops/ms + gc.alloc.rate: 7877.717 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 62.000 counts + gc.time: 79.000 ms + +Iteration 4: 7537.317 ops/ms + gc.alloc.rate: 7474.365 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 62.000 counts + gc.time: 85.000 ms + +Iteration 5: 7960.275 ops/ms + gc.alloc.rate: 7894.009 MB/sec + gc.alloc.rate.norm: 1040.000 B/op + gc.count: 62.000 counts + gc.time: 75.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop": + 7828.990 ±(99.9%) 670.095 ops/ms [Average] + (min, avg, max) = (7537.317, 7828.990, 7960.275), stdev = 174.022 + CI (99.9%): [7158.895, 8499.084] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate": + 7763.834 ±(99.9%) 664.881 MB/sec [Average] + (min, avg, max) = (7474.365, 7763.834, 7894.009), stdev = 172.668 + CI (99.9%): [7098.953, 8428.715] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate.norm": + 1040.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (1040.000, 1040.000, 1040.000), stdev = 0.001 + CI (99.9%): [1040.000, 1040.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.count": + 302.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (58.000, 60.400, 62.000), stdev = 2.191 + CI (99.9%): [302.000, 302.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.time": + 398.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (75.000, 79.600, 85.000), stdev = 3.715 + CI (99.9%): [398.000, 398.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop +# Parameters: (size = 32768) + +# Run progress: 31.25% complete, ETA 00:04:31 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 212.430 ops/ms +# Warmup Iteration 2: 249.395 ops/ms +# Warmup Iteration 3: 256.676 ops/ms +Iteration 1: 249.759 ops/ms + gc.alloc.rate: 7807.761 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 62.000 counts + gc.time: 90.000 ms + +Iteration 2: 249.979 ops/ms + gc.alloc.rate: 7814.711 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 56.000 counts + gc.time: 76.000 ms + +Iteration 3: 255.773 ops/ms + gc.alloc.rate: 7995.587 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 60.000 counts + gc.time: 73.000 ms + +Iteration 4: 251.837 ops/ms + gc.alloc.rate: 7872.670 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 60.000 counts + gc.time: 72.000 ms + +Iteration 5: 246.563 ops/ms + gc.alloc.rate: 7707.692 MB/sec + gc.alloc.rate.norm: 32784.014 B/op + gc.count: 62.000 counts + gc.time: 86.000 ms + + + +Result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop": + 250.782 ±(99.9%) 12.989 ops/ms [Average] + (min, avg, max) = (246.563, 250.782, 255.773), stdev = 3.373 + CI (99.9%): [237.793, 263.771] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate": + 7839.684 ±(99.9%) 405.956 MB/sec [Average] + (min, avg, max) = (7707.692, 7839.684, 7995.587), stdev = 105.426 + CI (99.9%): [7433.728, 8245.641] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.alloc.rate.norm": + 32784.014 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (32784.014, 32784.014, 32784.014), stdev = 0.001 + CI (99.9%): [32784.013, 32784.015] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.count": + 300.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (56.000, 60.000, 62.000), stdev = 2.449 + CI (99.9%): [300.000, 300.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.AllocationBench.allocateAndDrop:gc.time": + 397.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (72.000, 79.400, 90.000), stdev = 8.112 + CI (99.9%): [397.000, 397.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival +# Parameters: (payloadBytes = 512, survivorDepth = 0) + +# Run progress: 37.50% complete, ETA 00:04:06 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 11057.708 ops/ms +# Warmup Iteration 2: 13483.130 ops/ms +# Warmup Iteration 3: 11971.642 ops/ms +Iteration 1: 13767.851 ops/ms + gc.alloc.rate: 6930.811 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 53.000 counts + gc.time: 74.000 ms + +Iteration 2: 13462.276 ops/ms + gc.alloc.rate: 6777.315 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 44.000 counts + gc.time: 72.000 ms + +Iteration 3: 14101.981 ops/ms + gc.alloc.rate: 7099.771 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 56.000 counts + gc.time: 68.000 ms + +Iteration 4: 14251.991 ops/ms + gc.alloc.rate: 7175.508 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 54.000 counts + gc.time: 79.000 ms + +Iteration 5: 13934.815 ops/ms + gc.alloc.rate: 7015.722 MB/sec + gc.alloc.rate.norm: 528.000 B/op + gc.count: 58.000 counts + gc.time: 88.000 ms + + + +Result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival": + 13903.783 ±(99.9%) 1178.857 ops/ms [Average] + (min, avg, max) = (13462.276, 13903.783, 14251.991), stdev = 306.145 + CI (99.9%): [12724.926, 15082.639] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate": + 6999.825 ±(99.9%) 594.610 MB/sec [Average] + (min, avg, max) = (6777.315, 6999.825, 7175.508), stdev = 154.418 + CI (99.9%): [6405.215, 7594.436] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate.norm": + 528.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (528.000, 528.000, 528.000), stdev = 0.001 + CI (99.9%): [528.000, 528.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.count": + 265.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (44.000, 53.000, 58.000), stdev = 5.385 + CI (99.9%): [265.000, 265.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.time": + 381.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (68.000, 76.200, 88.000), stdev = 7.694 + CI (99.9%): [381.000, 381.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival +# Parameters: (payloadBytes = 512, survivorDepth = 4096) + +# Run progress: 43.75% complete, ETA 00:03:42 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 10803.212 ops/ms +# Warmup Iteration 2: 12623.875 ops/ms +# Warmup Iteration 3: 13769.490 ops/ms +Iteration 1: 13216.163 ops/ms + gc.alloc.rate: 6653.988 MB/sec + gc.alloc.rate.norm: 528.002 B/op + gc.count: 52.000 counts + gc.time: 69.000 ms + +Iteration 2: 13939.700 ops/ms + gc.alloc.rate: 7018.158 MB/sec + gc.alloc.rate.norm: 528.002 B/op + gc.count: 54.000 counts + gc.time: 89.000 ms + +Iteration 3: 13448.262 ops/ms + gc.alloc.rate: 6770.694 MB/sec + gc.alloc.rate.norm: 528.002 B/op + gc.count: 52.000 counts + gc.time: 73.000 ms + +Iteration 4: 13924.991 ops/ms + gc.alloc.rate: 7010.906 MB/sec + gc.alloc.rate.norm: 528.002 B/op + gc.count: 55.000 counts + gc.time: 75.000 ms + +Iteration 5: 13653.903 ops/ms + gc.alloc.rate: 6874.371 MB/sec + gc.alloc.rate.norm: 528.002 B/op + gc.count: 51.000 counts + gc.time: 92.000 ms + + + +Result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival": + 13636.604 ±(99.9%) 1198.623 ops/ms [Average] + (min, avg, max) = (13216.163, 13636.604, 13939.700), stdev = 311.278 + CI (99.9%): [12437.981, 14835.226] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate": + 6865.623 ±(99.9%) 603.494 MB/sec [Average] + (min, avg, max) = (6653.988, 6865.623, 7018.158), stdev = 156.725 + CI (99.9%): [6262.129, 7469.117] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate.norm": + 528.002 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (528.002, 528.002, 528.002), stdev = 0.001 + CI (99.9%): [528.002, 528.002] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.count": + 264.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (51.000, 52.800, 55.000), stdev = 1.643 + CI (99.9%): [264.000, 264.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.time": + 398.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (69.000, 79.600, 92.000), stdev = 10.237 + CI (99.9%): [398.000, 398.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Throughput, ops/time +# Benchmark: com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival +# Parameters: (payloadBytes = 512, survivorDepth = 262144) + +# Run progress: 50.00% complete, ETA 00:03:17 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 10383.438 ops/ms +# Warmup Iteration 2: 11535.805 ops/ms +# Warmup Iteration 3: 12596.328 ops/ms +Iteration 1: 12621.127 ops/ms + gc.alloc.rate: 6355.516 MB/sec + gc.alloc.rate.norm: 528.139 B/op + gc.count: 70.000 counts + gc.time: 595.000 ms + +Iteration 2: 12549.207 ops/ms + gc.alloc.rate: 6319.535 MB/sec + gc.alloc.rate.norm: 528.139 B/op + gc.count: 72.000 counts + gc.time: 559.000 ms + +Iteration 3: 12345.649 ops/ms + gc.alloc.rate: 6216.270 MB/sec + gc.alloc.rate.norm: 528.142 B/op + gc.count: 66.000 counts + gc.time: 572.000 ms + +Iteration 4: 12789.964 ops/ms + gc.alloc.rate: 6440.193 MB/sec + gc.alloc.rate.norm: 528.137 B/op + gc.count: 66.000 counts + gc.time: 489.000 ms + +Iteration 5: 12897.269 ops/ms + gc.alloc.rate: 6494.219 MB/sec + gc.alloc.rate.norm: 528.136 B/op + gc.count: 66.000 counts + gc.time: 472.000 ms + + + +Result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival": + 12640.643 ±(99.9%) 825.684 ops/ms [Average] + (min, avg, max) = (12345.649, 12640.643, 12897.269), stdev = 214.428 + CI (99.9%): [11814.959, 13466.328] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate": + 6365.147 ±(99.9%) 415.749 MB/sec [Average] + (min, avg, max) = (6216.270, 6365.147, 6494.219), stdev = 107.969 + CI (99.9%): [5949.398, 6780.895] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.alloc.rate.norm": + 528.139 ±(99.9%) 0.009 B/op [Average] + (min, avg, max) = (528.136, 528.139, 528.142), stdev = 0.002 + CI (99.9%): [528.130, 528.148] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.count": + 340.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (66.000, 68.000, 72.000), stdev = 2.828 + CI (99.9%): [340.000, 340.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.PromotionBench.allocateWithSurvival:gc.time": + 2687.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (472.000, 537.400, 595.000), stdev = 53.854 + CI (99.9%): [2687.000, 2687.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences +# Parameters: (nodes = 1048576) + +# Run progress: 56.25% complete, ETA 00:02:52 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 87222.686 us/op +# Warmup Iteration 2: 87336.766 us/op +# Warmup Iteration 3: 92527.000 us/op +Iteration 1: 89837.538 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 312.941 B/op + gc.count: ≈ 0 counts + +Iteration 2: 92342.552 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 322.424 B/op + gc.count: ≈ 0 counts + +Iteration 3: 100691.660 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 354.667 B/op + gc.count: ≈ 0 counts + +Iteration 4: 89533.291 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 311.529 B/op + gc.count: ≈ 0 counts + +Iteration 5: 89239.856 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 312.941 B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences": + 92328.979 ±(99.9%) 18617.022 us/op [Average] + (min, avg, max) = (89239.856, 92328.979, 100691.660), stdev = 4834.781 + CI (99.9%): [73711.958, 110946.001] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences:gc.alloc.rate": + 0.003 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.003, 0.003, 0.003), stdev = 0.001 + CI (99.9%): [0.003, 0.003] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences:gc.alloc.rate.norm": + 322.901 ±(99.9%) 70.399 B/op [Average] + (min, avg, max) = (311.529, 322.901, 354.667), stdev = 18.282 + CI (99.9%): [252.501, 393.300] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.chaseReferences:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly +# Parameters: (nodes = 1048576) + +# Run progress: 62.50% complete, ETA 00:02:28 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 0.021 us/op +# Warmup Iteration 2: 0.023 us/op +# Warmup Iteration 3: 0.022 us/op +Iteration 1: 0.022 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 2: 0.023 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 3: 0.023 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 4: 0.022 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + +Iteration 5: 0.026 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁴ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly": + 0.023 ±(99.9%) 0.006 us/op [Average] + (min, avg, max) = (0.022, 0.023, 0.026), stdev = 0.001 + CI (99.9%): [0.017, 0.029] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate": + 0.003 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.003, 0.003, 0.003), stdev = 0.001 + CI (99.9%): [0.003, 0.003] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate.norm": + ≈ 10⁻⁴ B/op + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.readSameReferenceRepeatedly:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives +# Parameters: (nodes = 1048576) + +# Run progress: 68.75% complete, ETA 00:02:03 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 269.713 us/op +# Warmup Iteration 2: 271.486 us/op +# Warmup Iteration 3: 271.731 us/op +Iteration 1: 269.887 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 0.957 B/op + gc.count: ≈ 0 counts + +Iteration 2: 270.545 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 0.959 B/op + gc.count: ≈ 0 counts + +Iteration 3: 272.368 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 0.966 B/op + gc.count: ≈ 0 counts + +Iteration 4: 270.207 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 0.958 B/op + gc.count: ≈ 0 counts + +Iteration 5: 269.894 us/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: 0.957 B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives": + 270.580 ±(99.9%) 3.986 us/op [Average] + (min, avg, max) = (269.887, 270.580, 272.368), stdev = 1.035 + CI (99.9%): [266.594, 274.567] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives:gc.alloc.rate": + 0.003 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.003, 0.003, 0.003), stdev = 0.001 + CI (99.9%): [0.003, 0.003] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives:gc.alloc.rate.norm": + 0.959 ±(99.9%) 0.014 B/op [Average] + (min, avg, max) = (0.957, 0.959, 0.966), stdev = 0.004 + CI (99.9%): [0.945, 0.973] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.LoadBarrierBench.sumPrimitives:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld +# Parameters: (slots = 1048576) + +# Run progress: 75.00% complete, ETA 00:01:38 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 3.048 ns/op +# Warmup Iteration 2: 3.256 ns/op +# Warmup Iteration 3: 3.191 ns/op +Iteration 1: 3.128 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 2: 3.273 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 3: 3.091 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 4: 3.335 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 5: 3.368 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld": + 3.239 ±(99.9%) 0.477 ns/op [Average] + (min, avg, max) = (3.091, 3.239, 3.368), stdev = 0.124 + CI (99.9%): [2.762, 3.716] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld:gc.alloc.rate": + 0.003 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.003, 0.003, 0.003), stdev = 0.001 + CI (99.9%): [0.003, 0.003] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld:gc.alloc.rate.norm": + ≈ 10⁻⁵ B/op + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeNullIntoOld:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld +# Parameters: (slots = 1048576) + +# Run progress: 81.25% complete, ETA 00:01:13 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 3.299 ns/op +# Warmup Iteration 2: 3.543 ns/op +# Warmup Iteration 3: 3.325 ns/op +Iteration 1: 3.398 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 2: 3.332 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 3: 3.467 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 4: 3.520 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 5: 3.592 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld": + 3.462 ±(99.9%) 0.392 ns/op [Average] + (min, avg, max) = (3.332, 3.462, 3.592), stdev = 0.102 + CI (99.9%): [3.070, 3.854] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld:gc.alloc.rate": + 0.003 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.003, 0.003, 0.003), stdev = 0.001 + CI (99.9%): [0.003, 0.003] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld:gc.alloc.rate.norm": + ≈ 10⁻⁵ B/op + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToOld:gc.count": + ≈ 0 counts + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung +# Parameters: (slots = 1048576) + +# Run progress: 87.50% complete, ETA 00:00:49 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 8.306 ns/op +# Warmup Iteration 2: 5.958 ns/op +# Warmup Iteration 3: 6.544 ns/op +Iteration 1: 6.557 ns/op + gc.alloc.rate: 2326.838 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 24.000 counts + gc.time: 511.000 ms + +Iteration 2: 6.229 ns/op + gc.alloc.rate: 2449.267 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 20.000 counts + gc.time: 383.000 ms + +Iteration 3: 6.718 ns/op + gc.alloc.rate: 2270.776 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 22.000 counts + gc.time: 441.000 ms + +Iteration 4: 6.496 ns/op + gc.alloc.rate: 2348.706 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 24.000 counts + gc.time: 536.000 ms + +Iteration 5: 6.909 ns/op + gc.alloc.rate: 2208.107 MB/sec + gc.alloc.rate.norm: 16.000 B/op + gc.count: 23.000 counts + gc.time: 446.000 ms + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung": + 6.582 ±(99.9%) 0.979 ns/op [Average] + (min, avg, max) = (6.229, 6.582, 6.909), stdev = 0.254 + CI (99.9%): [5.603, 7.561] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.alloc.rate": + 2320.739 ±(99.9%) 347.204 MB/sec [Average] + (min, avg, max) = (2208.107, 2320.739, 2449.267), stdev = 90.168 + CI (99.9%): [1973.534, 2667.943] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.alloc.rate.norm": + 16.000 ±(99.9%) 0.001 B/op [Average] + (min, avg, max) = (16.000, 16.000, 16.000), stdev = 0.001 + CI (99.9%): [16.000, 16.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.count": + 113.000 ±(99.9%) 0.001 counts [Sum] + (min, avg, max) = (20.000, 22.600, 24.000), stdev = 1.673 + CI (99.9%): [113.000, 113.000] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storeOldToYoung:gc.time": + 2317.000 ±(99.9%) 0.001 ms [Sum] + (min, avg, max) = (383.000, 463.400, 536.000), stdev = 60.838 + CI (99.9%): [2317.000, 2317.000] (assumes normal distribution) + + +# JMH version: 1.37 +# VM version: JDK 25.0.3, Java HotSpot(TM) 64-Bit Server VM, 25.0.3+9-LTS-195 +# VM invoker: C:\Program Files\Java\jdk-25.0.3\bin\java.exe +# VM options: -XX:+UseZGC -Xms2g -Xmx2g +# Blackhole mode: compiler (auto-detected, use -Djmh.blackhole.autoDetect=false to disable) +# Warmup: 3 iterations, 3 s each +# Measurement: 5 iterations, 3 s each +# Timeout: 10 min per iteration +# Threads: 1 thread, will synchronize iterations +# Benchmark mode: Average time, time/op +# Benchmark: com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld +# Parameters: (slots = 1048576) + +# Run progress: 93.75% complete, ETA 00:00:24 +# Fork: 1 of 1 +WARNING: A terminally deprecated method in sun.misc.Unsafe has been called +WARNING: sun.misc.Unsafe::objectFieldOffset has been called by org.openjdk.jmh.util.Utils (file:/C:/Users/Ankur/ankurm-blog-tools/projects/zgc-jdk25-benchmarks/jmh/target/benchmarks.jar) +WARNING: Please consider reporting this to the maintainers of class org.openjdk.jmh.util.Utils +WARNING: sun.misc.Unsafe::objectFieldOffset will be removed in a future release +# Warmup Iteration 1: 1.796 ns/op +# Warmup Iteration 2: 1.804 ns/op +# Warmup Iteration 3: 1.875 ns/op +Iteration 1: 1.851 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 2: 1.864 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 3: 1.867 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 4: 1.940 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + +Iteration 5: 1.872 ns/op + gc.alloc.rate: 0.003 MB/sec + gc.alloc.rate.norm: ≈ 10⁻⁵ B/op + gc.count: ≈ 0 counts + + + +Result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld": + 1.879 ±(99.9%) 0.135 ns/op [Average] + (min, avg, max) = (1.851, 1.879, 1.940), stdev = 0.035 + CI (99.9%): [1.744, 2.013] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate": + 0.003 ±(99.9%) 0.001 MB/sec [Average] + (min, avg, max) = (0.003, 0.003, 0.003), stdev = 0.001 + CI (99.9%): [0.003, 0.003] (assumes normal distribution) + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate.norm": + ≈ 10⁻⁵ B/op + +Secondary result "com.ankurm.zgc.jmh.StoreBarrierBench.storePrimitiveIntoOld:gc.count": + ≈ 0 counts + + +# Run complete. Total time: 00:06:34 + +REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on +why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial +experiments, perform baseline and negative tests that provide experimental control, make sure +the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts. +Do not assume the numbers tell you what you want them to tell. + +NOTE: Current JVM experimentally supports Compiler Blackholes, and they are in use. Please exercise +extra caution when trusting the results, look into the generated code to check the benchmark still +works, and factor in a small probability of new VM bugs. Additionally, while comparisons between +different JVMs are already problematic, the performance difference caused by different Blackhole +modes can be very significant. Please make sure you use the consistent Blackhole mode for comparisons. + +Benchmark (nodes) (payloadBytes) (size) (slots) (survivorDepth) Mode Cnt Score Error Units +AllocationBench.allocate N/A N/A 64 N/A N/A thrpt 5 113180.402 ± 3074.552 ops/ms +AllocationBench.allocate:gc.alloc.rate N/A N/A 64 N/A N/A thrpt 5 8633.874 ± 234.530 MB/sec +AllocationBench.allocate:gc.alloc.rate.norm N/A N/A 64 N/A N/A thrpt 5 80.000 ± 0.001 B/op +AllocationBench.allocate:gc.count N/A N/A 64 N/A N/A thrpt 5 332.000 counts +AllocationBench.allocate:gc.time N/A N/A 64 N/A N/A thrpt 5 354.000 ms +AllocationBench.allocate N/A N/A 1024 N/A N/A thrpt 5 7856.555 ± 551.806 ops/ms +AllocationBench.allocate:gc.alloc.rate N/A N/A 1024 N/A N/A thrpt 5 7791.235 ± 547.523 MB/sec +AllocationBench.allocate:gc.alloc.rate.norm N/A N/A 1024 N/A N/A thrpt 5 1040.000 ± 0.001 B/op +AllocationBench.allocate:gc.count N/A N/A 1024 N/A N/A thrpt 5 306.000 counts +AllocationBench.allocate:gc.time N/A N/A 1024 N/A N/A thrpt 5 394.000 ms +AllocationBench.allocate N/A N/A 32768 N/A N/A thrpt 5 253.346 ± 11.131 ops/ms +AllocationBench.allocate:gc.alloc.rate N/A N/A 32768 N/A N/A thrpt 5 7919.850 ± 347.834 MB/sec +AllocationBench.allocate:gc.alloc.rate.norm N/A N/A 32768 N/A N/A thrpt 5 32784.014 ± 0.001 B/op +AllocationBench.allocate:gc.count N/A N/A 32768 N/A N/A thrpt 5 316.000 counts +AllocationBench.allocate:gc.time N/A N/A 32768 N/A N/A thrpt 5 420.000 ms +AllocationBench.allocateAndDrop N/A N/A 64 N/A N/A thrpt 5 110471.576 ± 3078.498 ops/ms +AllocationBench.allocateAndDrop:gc.alloc.rate N/A N/A 64 N/A N/A thrpt 5 8427.273 ± 235.100 MB/sec +AllocationBench.allocateAndDrop:gc.alloc.rate.norm N/A N/A 64 N/A N/A thrpt 5 80.000 ± 0.001 B/op +AllocationBench.allocateAndDrop:gc.count N/A N/A 64 N/A N/A thrpt 5 332.000 counts +AllocationBench.allocateAndDrop:gc.time N/A N/A 64 N/A N/A thrpt 5 371.000 ms +AllocationBench.allocateAndDrop N/A N/A 1024 N/A N/A thrpt 5 7828.990 ± 670.095 ops/ms +AllocationBench.allocateAndDrop:gc.alloc.rate N/A N/A 1024 N/A N/A thrpt 5 7763.834 ± 664.881 MB/sec +AllocationBench.allocateAndDrop:gc.alloc.rate.norm N/A N/A 1024 N/A N/A thrpt 5 1040.000 ± 0.001 B/op +AllocationBench.allocateAndDrop:gc.count N/A N/A 1024 N/A N/A thrpt 5 302.000 counts +AllocationBench.allocateAndDrop:gc.time N/A N/A 1024 N/A N/A thrpt 5 398.000 ms +AllocationBench.allocateAndDrop N/A N/A 32768 N/A N/A thrpt 5 250.782 ± 12.989 ops/ms +AllocationBench.allocateAndDrop:gc.alloc.rate N/A N/A 32768 N/A N/A thrpt 5 7839.684 ± 405.956 MB/sec +AllocationBench.allocateAndDrop:gc.alloc.rate.norm N/A N/A 32768 N/A N/A thrpt 5 32784.014 ± 0.001 B/op +AllocationBench.allocateAndDrop:gc.count N/A N/A 32768 N/A N/A thrpt 5 300.000 counts +AllocationBench.allocateAndDrop:gc.time N/A N/A 32768 N/A N/A thrpt 5 397.000 ms +PromotionBench.allocateWithSurvival N/A 512 N/A N/A 0 thrpt 5 13903.783 ± 1178.857 ops/ms +PromotionBench.allocateWithSurvival:gc.alloc.rate N/A 512 N/A N/A 0 thrpt 5 6999.825 ± 594.610 MB/sec +PromotionBench.allocateWithSurvival:gc.alloc.rate.norm N/A 512 N/A N/A 0 thrpt 5 528.000 ± 0.001 B/op +PromotionBench.allocateWithSurvival:gc.count N/A 512 N/A N/A 0 thrpt 5 265.000 counts +PromotionBench.allocateWithSurvival:gc.time N/A 512 N/A N/A 0 thrpt 5 381.000 ms +PromotionBench.allocateWithSurvival N/A 512 N/A N/A 4096 thrpt 5 13636.604 ± 1198.623 ops/ms +PromotionBench.allocateWithSurvival:gc.alloc.rate N/A 512 N/A N/A 4096 thrpt 5 6865.623 ± 603.494 MB/sec +PromotionBench.allocateWithSurvival:gc.alloc.rate.norm N/A 512 N/A N/A 4096 thrpt 5 528.002 ± 0.001 B/op +PromotionBench.allocateWithSurvival:gc.count N/A 512 N/A N/A 4096 thrpt 5 264.000 counts +PromotionBench.allocateWithSurvival:gc.time N/A 512 N/A N/A 4096 thrpt 5 398.000 ms +PromotionBench.allocateWithSurvival N/A 512 N/A N/A 262144 thrpt 5 12640.643 ± 825.684 ops/ms +PromotionBench.allocateWithSurvival:gc.alloc.rate N/A 512 N/A N/A 262144 thrpt 5 6365.147 ± 415.749 MB/sec +PromotionBench.allocateWithSurvival:gc.alloc.rate.norm N/A 512 N/A N/A 262144 thrpt 5 528.139 ± 0.009 B/op +PromotionBench.allocateWithSurvival:gc.count N/A 512 N/A N/A 262144 thrpt 5 340.000 counts +PromotionBench.allocateWithSurvival:gc.time N/A 512 N/A N/A 262144 thrpt 5 2687.000 ms +LoadBarrierBench.chaseReferences 1048576 N/A N/A N/A N/A avgt 5 92328.979 ± 18617.022 us/op +LoadBarrierBench.chaseReferences:gc.alloc.rate 1048576 N/A N/A N/A N/A avgt 5 0.003 ± 0.001 MB/sec +LoadBarrierBench.chaseReferences:gc.alloc.rate.norm 1048576 N/A N/A N/A N/A avgt 5 322.901 ± 70.399 B/op +LoadBarrierBench.chaseReferences:gc.count 1048576 N/A N/A N/A N/A avgt 5 ≈ 0 counts +LoadBarrierBench.readSameReferenceRepeatedly 1048576 N/A N/A N/A N/A avgt 5 0.023 ± 0.006 us/op +LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate 1048576 N/A N/A N/A N/A avgt 5 0.003 ± 0.001 MB/sec +LoadBarrierBench.readSameReferenceRepeatedly:gc.alloc.rate.norm 1048576 N/A N/A N/A N/A avgt 5 ≈ 10⁻⁴ B/op +LoadBarrierBench.readSameReferenceRepeatedly:gc.count 1048576 N/A N/A N/A N/A avgt 5 ≈ 0 counts +LoadBarrierBench.sumPrimitives 1048576 N/A N/A N/A N/A avgt 5 270.580 ± 3.986 us/op +LoadBarrierBench.sumPrimitives:gc.alloc.rate 1048576 N/A N/A N/A N/A avgt 5 0.003 ± 0.001 MB/sec +LoadBarrierBench.sumPrimitives:gc.alloc.rate.norm 1048576 N/A N/A N/A N/A avgt 5 0.959 ± 0.014 B/op +LoadBarrierBench.sumPrimitives:gc.count 1048576 N/A N/A N/A N/A avgt 5 ≈ 0 counts +StoreBarrierBench.storeNullIntoOld N/A N/A N/A 1048576 N/A avgt 5 3.239 ± 0.477 ns/op +StoreBarrierBench.storeNullIntoOld:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 0.003 ± 0.001 MB/sec +StoreBarrierBench.storeNullIntoOld:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 ≈ 10⁻⁵ B/op +StoreBarrierBench.storeNullIntoOld:gc.count N/A N/A N/A 1048576 N/A avgt 5 ≈ 0 counts +StoreBarrierBench.storeOldToOld N/A N/A N/A 1048576 N/A avgt 5 3.462 ± 0.392 ns/op +StoreBarrierBench.storeOldToOld:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 0.003 ± 0.001 MB/sec +StoreBarrierBench.storeOldToOld:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 ≈ 10⁻⁵ B/op +StoreBarrierBench.storeOldToOld:gc.count N/A N/A N/A 1048576 N/A avgt 5 ≈ 0 counts +StoreBarrierBench.storeOldToYoung N/A N/A N/A 1048576 N/A avgt 5 6.582 ± 0.979 ns/op +StoreBarrierBench.storeOldToYoung:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 2320.739 ± 347.204 MB/sec +StoreBarrierBench.storeOldToYoung:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 16.000 ± 0.001 B/op +StoreBarrierBench.storeOldToYoung:gc.count N/A N/A N/A 1048576 N/A avgt 5 113.000 counts +StoreBarrierBench.storeOldToYoung:gc.time N/A N/A N/A 1048576 N/A avgt 5 2317.000 ms +StoreBarrierBench.storePrimitiveIntoOld N/A N/A N/A 1048576 N/A avgt 5 1.879 ± 0.135 ns/op +StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate N/A N/A N/A 1048576 N/A avgt 5 0.003 ± 0.001 MB/sec +StoreBarrierBench.storePrimitiveIntoOld:gc.alloc.rate.norm N/A N/A N/A 1048576 N/A avgt 5 ≈ 10⁻⁵ B/op +StoreBarrierBench.storePrimitiveIntoOld:gc.count N/A N/A N/A 1048576 N/A avgt 5 ≈ 0 counts + +Benchmark result is saved to C:\Users\Ankur\ankurm-blog-tools\projects\zgc-jdk25-benchmarks\results\07-jmh-zgc.json diff --git a/scripts/run-all.ps1 b/scripts/run-all.ps1 new file mode 100644 index 0000000..0cfea97 --- /dev/null +++ b/scripts/run-all.ps1 @@ -0,0 +1,143 @@ +<# +.SYNOPSIS + Compiles and runs the whole ZGC-vs-G1 suite, writing every raw output into results/. + +.DESCRIPTION + Every number published in the companion blog post comes from this script. It is deliberately + boring and sequential: GC benchmarks that run concurrently with each other measure the scheduler. + +.PARAMETER JavaHome + Path to a JDK 25 (or newer) installation. Generational ZGC is the only ZGC from JDK 24 onward. + +.EXAMPLE + pwsh scripts/run-all.ps1 -JavaHome 'C:\Program Files\Java\jdk-25.0.3' +#> +param( + [string]$JavaHome = $env:JAVA_HOME, + [string]$MavenHome = "$HOME\ankurm-blog-tools\apache-maven-3.9.9", + [int]$MeasureSeconds = 60, + [int]$WarmupSeconds = 20, + [switch]$SkipJmh +) + +$ErrorActionPreference = 'Stop' +if (-not $JavaHome) { throw "Set -JavaHome or JAVA_HOME to a JDK 25+ installation." } + +$Root = Split-Path -Parent $PSScriptRoot +$Java = Join-Path $JavaHome 'bin\java.exe' +$Javac = Join-Path $JavaHome 'bin\javac.exe' +$Out = Join-Path $Root 'out' +$Results = Join-Path $Root 'results' +$Logs = Join-Path $Root 'logs' + +New-Item -ItemType Directory -Force -Path $Out, $Results, $Logs | Out-Null + +# Fixed heap for every run. -Xms == -Xmx removes heap resizing as a variable; a benchmark that lets +# the heap grow during measurement is partly measuring the resize policy. +$Heap = @('-Xms2g', '-Xmx2g') + +Write-Host "==> compiling" -ForegroundColor Cyan +$sources = Get-ChildItem "$Root\latency\src", "$Root\tuning\src", "$Root\internals\src", "$Root\analysis\src" ` + -Recurse -Filter *.java -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName } +& $Javac -d $Out @sources +if ($LASTEXITCODE -ne 0) { throw "compilation failed" } + +# NOTE: several of these commands (notably `java -version` and `-XX:+PrintFlagsFinal`) write to +# stderr. PowerShell turns native stderr into error records, and with $ErrorActionPreference='Stop' +# that aborts the whole script on a perfectly successful run. Routing through cmd.exe with a plain +# 2>&1 merge keeps stderr as text where it belongs. +function Invoke-Capture { + param([string]$Name, [string[]]$JvmArgs, [string[]]$AppArgs) + $file = Join-Path $Results "$Name.txt" + Write-Host "==> $Name" -ForegroundColor Cyan + $quoted = @("`"$Java`"") + ($JvmArgs + $AppArgs | ForEach-Object { + if ($_ -match '[\s]') { "`"$_`"" } else { $_ } + }) + $line = ($quoted -join ' ') + $output = cmd /c "$line 2>&1" + $output | Out-File -FilePath $file -Encoding utf8 + $output | Select-Object -Last 6 | ForEach-Object { Write-Host " $_" -ForegroundColor DarkGray } + Write-Host " -> results/$Name.txt" -ForegroundColor DarkGray +} + +# --------------------------------------------------------------------------------------------- +# 1. Environment -- printed once per collector so the results file is self-describing. +# --------------------------------------------------------------------------------------------- +Invoke-Capture -Name '01-env-zgc' -JvmArgs (@('-XX:+UseZGC') + $Heap) -AppArgs @("$Root\env\Env.java") +Invoke-Capture -Name '01-env-g1' -JvmArgs (@('-XX:+UseG1GC') + $Heap) -AppArgs @("$Root\env\Env.java") + +Invoke-Capture -Name '02-flags-zgc' -JvmArgs (@('-XX:+UseZGC') + $Heap + @('-XX:+PrintFlagsFinal')) -AppArgs @('-version') +Invoke-Capture -Name '02-flags-g1' -JvmArgs (@('-XX:+UseG1GC') + $Heap + @('-XX:+PrintFlagsFinal')) -AppArgs @('-version') + +# --------------------------------------------------------------------------------------------- +# 2. Open-loop latency, with full unified GC logging written alongside. +# --------------------------------------------------------------------------------------------- +$latencyProps = @("-DwarmupSeconds=$WarmupSeconds", "-Dseconds=$MeasureSeconds") + +Invoke-Capture -Name '03-latency-zgc' ` + -JvmArgs (@('-XX:+UseZGC') + $Heap + $latencyProps + @("-Xlog:gc*,gc+heap=debug:file=$Logs\zgc-latency.log:time,uptime,level,tags")) ` + -AppArgs @('-cp', $Out, 'com.ankurm.zgc.latency.LatencyHarness') + +Invoke-Capture -Name '03-latency-g1' ` + -JvmArgs (@('-XX:+UseG1GC') + $Heap + $latencyProps + @("-Xlog:gc*,gc+heap=debug:file=$Logs\g1-latency.log:time,uptime,level,tags")) ` + -AppArgs @('-cp', $Out, 'com.ankurm.zgc.latency.LatencyHarness') + +# --------------------------------------------------------------------------------------------- +# 3. Allocation stalls -- deliberately undersized heap. This is the section most GC posts skip. +# --------------------------------------------------------------------------------------------- +$stallHeap = @('-Xms512m', '-Xmx512m') + +Invoke-Capture -Name '04-stalls-zgc-baseline' ` + -JvmArgs (@('-XX:+UseZGC') + $stallHeap + @('-Dseconds=20')) ` + -AppArgs @('-cp', $Out, 'com.ankurm.zgc.tuning.AllocationStallDemo') + +Invoke-Capture -Name '04-stalls-zgc-softmax' ` + -JvmArgs (@('-XX:+UseZGC', '-XX:SoftMaxHeapSize=400m') + $stallHeap + @('-Dseconds=20')) ` + -AppArgs @('-cp', $Out, 'com.ankurm.zgc.tuning.AllocationStallDemo') + +Invoke-Capture -Name '04-stalls-zgc-spiketolerance' ` + -JvmArgs (@('-XX:+UseZGC', '-XX:ZAllocationSpikeTolerance=5') + $stallHeap + @('-Dseconds=20')) ` + -AppArgs @('-cp', $Out, 'com.ankurm.zgc.tuning.AllocationStallDemo') + +# The same stress under G1: ZGC's stalls become G1's evacuation failures and Full GCs. +Invoke-Capture -Name '04-stalls-g1' ` + -JvmArgs (@('-XX:+UseG1GC') + $stallHeap + @('-Dseconds=20', "-Xlog:gc:file=$Logs\g1-stress.log:time,uptime")) ` + -AppArgs @('-cp', $Out, 'com.ankurm.zgc.tuning.AllocationStallDemo') + +# --------------------------------------------------------------------------------------------- +# 4. Page-size / humongous behaviour. +# --------------------------------------------------------------------------------------------- +Invoke-Capture -Name '05-pages-zgc' ` + -JvmArgs (@('-XX:+UseZGC') + $Heap) -AppArgs @('-cp', $Out, 'com.ankurm.zgc.internals.PageSizeDemo') +Invoke-Capture -Name '05-pages-g1' ` + -JvmArgs (@('-XX:+UseG1GC') + $Heap) -AppArgs @('-cp', $Out, 'com.ankurm.zgc.internals.PageSizeDemo') + +# --------------------------------------------------------------------------------------------- +# 5. GC log analysis -- turns the raw unified logs above into pause distributions. +# --------------------------------------------------------------------------------------------- +Invoke-Capture -Name '06-gclog-zgc' -JvmArgs @() -AppArgs @('-cp', $Out, 'com.ankurm.zgc.analysis.GcLogParser', "$Logs\zgc-latency.log") +Invoke-Capture -Name '06-gclog-g1' -JvmArgs @() -AppArgs @('-cp', $Out, 'com.ankurm.zgc.analysis.GcLogParser', "$Logs\g1-latency.log") + +# --------------------------------------------------------------------------------------------- +# 6. JMH throughput / barrier microbenchmarks. +# --------------------------------------------------------------------------------------------- +if (-not $SkipJmh) { + Write-Host "==> building JMH module" -ForegroundColor Cyan + Push-Location "$Root\jmh" + $env:JAVA_HOME = $JavaHome + & (Join-Path $MavenHome 'bin\mvn.cmd') -q -B clean package + Pop-Location + + foreach ($gc in @('UseZGC', 'UseG1GC')) { + $tag = if ($gc -eq 'UseZGC') { 'zgc' } else { 'g1' } + # IMPORTANT: the GC flag must go in -jvmArgs. JMH forks a fresh JVM for every trial, and a + # GC flag on the outer `java -jar` command is NOT inherited by the fork. Getting this wrong + # is the single most common way to publish a GC benchmark that measured the default GC twice. + Invoke-Capture -Name "07-jmh-$tag" -JvmArgs @('-jar', "$Root\jmh\target\benchmarks.jar") ` + -AppArgs @('-jvmArgs', "-XX:+$gc -Xms2g -Xmx2g", '-prof', 'gc', '-rf', 'json', + '-rff', "$Results\07-jmh-$tag.json") + } +} + +Write-Host "" +Write-Host "All raw output is in $Results" -ForegroundColor Green diff --git a/scripts/run-all.sh b/scripts/run-all.sh new file mode 100644 index 0000000..4aa8bf2 --- /dev/null +++ b/scripts/run-all.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# Linux / macOS equivalent of run-all.ps1. +# +# ./scripts/run-all.sh /path/to/jdk-25 [measureSeconds] [warmupSeconds] +# +# Everything published in the companion blog post came from the PowerShell version on Windows; +# this script produces the same set of files in results/ so the comparison can be repeated on +# server hardware, which is where you should actually make a decision. + +set -euo pipefail + +JAVA_HOME_ARG="${1:-${JAVA_HOME:-}}" +MEASURE_SECONDS="${2:-60}" +WARMUP_SECONDS="${3:-20}" + +if [[ -z "$JAVA_HOME_ARG" ]]; then + echo "usage: $0 /path/to/jdk-25 [measureSeconds] [warmupSeconds]" >&2 + exit 2 +fi + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +JAVA="$JAVA_HOME_ARG/bin/java" +JAVAC="$JAVA_HOME_ARG/bin/javac" +OUT="$ROOT/out" +RESULTS="$ROOT/results" +LOGS="$ROOT/logs" + +mkdir -p "$OUT" "$RESULTS" "$LOGS" + +# Fixed heap: -Xms == -Xmx removes heap resizing as a variable. +HEAP=(-Xms2g -Xmx2g) +STALL_HEAP=(-Xms512m -Xmx512m) + +echo "==> compiling" +mapfile -t SOURCES < <(find "$ROOT/latency/src" "$ROOT/tuning/src" "$ROOT/internals/src" "$ROOT/analysis/src" -name '*.java') +"$JAVAC" -d "$OUT" "${SOURCES[@]}" + +capture() { + local name="$1"; shift + echo "==> $name" + "$@" > "$RESULTS/$name.txt" 2>&1 || true + tail -n 4 "$RESULTS/$name.txt" | sed 's/^/ /' +} + +capture 01-env-zgc "$JAVA" -XX:+UseZGC "${HEAP[@]}" "$ROOT/env/Env.java" +capture 01-env-g1 "$JAVA" -XX:+UseG1GC "${HEAP[@]}" "$ROOT/env/Env.java" + +capture 02-flags-zgc "$JAVA" -XX:+UseZGC "${HEAP[@]}" -XX:+PrintFlagsFinal -version +capture 02-flags-g1 "$JAVA" -XX:+UseG1GC "${HEAP[@]}" -XX:+PrintFlagsFinal -version + +capture 03-latency-zgc "$JAVA" -XX:+UseZGC "${HEAP[@]}" \ + "-DwarmupSeconds=$WARMUP_SECONDS" "-Dseconds=$MEASURE_SECONDS" \ + "-Xlog:gc*,gc+heap=debug:file=$LOGS/zgc-latency.log:time,uptime,level,tags" \ + -cp "$OUT" com.ankurm.zgc.latency.LatencyHarness + +capture 03-latency-g1 "$JAVA" -XX:+UseG1GC "${HEAP[@]}" \ + "-DwarmupSeconds=$WARMUP_SECONDS" "-Dseconds=$MEASURE_SECONDS" \ + "-Xlog:gc*,gc+heap=debug:file=$LOGS/g1-latency.log:time,uptime,level,tags" \ + -cp "$OUT" com.ankurm.zgc.latency.LatencyHarness + +capture 04-stalls-zgc-baseline "$JAVA" -XX:+UseZGC "${STALL_HEAP[@]}" -Dseconds=20 \ + -cp "$OUT" com.ankurm.zgc.tuning.AllocationStallDemo +capture 04-stalls-zgc-softmax "$JAVA" -XX:+UseZGC -XX:SoftMaxHeapSize=400m "${STALL_HEAP[@]}" -Dseconds=20 \ + -cp "$OUT" com.ankurm.zgc.tuning.AllocationStallDemo +capture 04-stalls-zgc-spiketolerance "$JAVA" -XX:+UseZGC -XX:ZAllocationSpikeTolerance=5 "${STALL_HEAP[@]}" -Dseconds=20 \ + -cp "$OUT" com.ankurm.zgc.tuning.AllocationStallDemo +capture 04-stalls-g1 "$JAVA" -XX:+UseG1GC "${STALL_HEAP[@]}" -Dseconds=20 \ + "-Xlog:gc:file=$LOGS/g1-stress.log:time,uptime" \ + -cp "$OUT" com.ankurm.zgc.tuning.AllocationStallDemo + +capture 05-pages-zgc "$JAVA" -XX:+UseZGC "${HEAP[@]}" -cp "$OUT" com.ankurm.zgc.internals.PageSizeDemo +capture 05-pages-g1 "$JAVA" -XX:+UseG1GC "${HEAP[@]}" -cp "$OUT" com.ankurm.zgc.internals.PageSizeDemo + +capture 06-gclog-zgc "$JAVA" -cp "$OUT" com.ankurm.zgc.analysis.GcLogParser "$LOGS/zgc-latency.log" +capture 06-gclog-g1 "$JAVA" -cp "$OUT" com.ankurm.zgc.analysis.GcLogParser "$LOGS/g1-latency.log" + +echo "==> building JMH module" +(cd "$ROOT/jmh" && JAVA_HOME="$JAVA_HOME_ARG" mvn -q -B clean package) + +# NOTE: the GC flag MUST be inside -jvmArgs. JMH forks a fresh JVM per trial and does not inherit +# flags from the outer `java -jar` command. See docs/06-methodology.md section 6.6. +for gc in UseZGC UseG1GC; do + tag=$([[ "$gc" == "UseZGC" ]] && echo zgc || echo g1) + capture "07-jmh-$tag" "$JAVA" -jar "$ROOT/jmh/target/benchmarks.jar" \ + -jvmArgs "-XX:+$gc -Xms2g -Xmx2g" -prof gc -rf json -rff "$RESULTS/07-jmh-$tag.json" +done + +echo +echo "All raw output is in $RESULTS" diff --git a/tuning/src/com/ankurm/zgc/tuning/AllocationStallDemo.java b/tuning/src/com/ankurm/zgc/tuning/AllocationStallDemo.java new file mode 100644 index 0000000..c17ca81 --- /dev/null +++ b/tuning/src/com/ankurm/zgc/tuning/AllocationStallDemo.java @@ -0,0 +1,238 @@ +package com.ankurm.zgc.tuning; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.ThreadLocalRandom; + +/** + * The failure mode nobody screenshots: the ZGC allocation stall. + * + *

Why this program exists

+ * Almost every ZGC article ends with a graph of sub-millisecond pause times and an implied + * conclusion: "ZGC has no latency problem". The pause times are real. The conclusion is not, + * because on ZGC pauses are not where latency comes from. + * + *

ZGC's stop-the-world pauses are O(number of GC roots) and stay in the tens of microseconds + * essentially regardless of heap size. What actually hurts a ZGC application is different: when the + * application allocates faster than the collector can reclaim, a thread that asks for memory and + * cannot be given any is stalled until the collector frees a page. That stall can last tens + * or hundreds of milliseconds. It never appears in a pause-time chart, because it is not a pause -- + * only the allocating thread is blocked, the rest of the JVM keeps running. + * + *

So a ZGC deployment can show a p99.99 pause of 0.2 ms and a p99.99 request latency of 400 ms + * at the same time, and both numbers are correct. If you only monitor the first one you will never + * find the second one. + * + *

What this program does

+ * It starts a JFR recording with {@code jdk.ZAllocationStall} enabled and no threshold (the default + * threshold is 10 ms, which hides the smaller ones), then deliberately drives the heap into the + * ground: a live set that keeps growing while every thread allocates as fast as it can. Afterwards + * it reads its own recording back and prints every stall, with duration and thread. + * + *

Running it

+ * A small heap is the point -- do not "fix" it: + *
+ * java -XX:+UseZGC -Xms512m -Xmx512m \
+ *      -cp out com.ankurm.zgc.tuning.AllocationStallDemo
+ * 
+ * + * Then try the mitigations and watch the stall count move: + *
+ * -XX:SoftMaxHeapSize=400m          # start collecting earlier, before the wall
+ * -XX:ZAllocationSpikeTolerance=5   # assume allocation rate can spike 5x, not 2x
+ * -Xmx1g                            # the honest fix, when you can afford it
+ * 
+ * + *

On G1 this program produces {@code Evacuation Failure} / long Full GCs instead. G1's + * equivalent of a stall is a to-space exhaustion followed by a full, single-threaded-ish + * compaction, which is a stop-the-world pause and does show up in pause charts. + */ +public final class AllocationStallDemo { + + /** How many bytes to keep permanently alive, as a fraction of max heap. */ + private static final double LIVE_FRACTION = + Double.parseDouble(System.getProperty("liveFraction", "0.55")); + + private static final int THREADS = + Integer.getInteger("threads", Runtime.getRuntime().availableProcessors()); + + private static final int SECONDS = Integer.getInteger("seconds", 20); + + /** Kept in a static field so nothing can be collected while the demo runs. */ + private static volatile Object[] retained; + + public static void main(String[] args) throws Exception { + long maxHeap = Runtime.getRuntime().maxMemory(); + System.out.printf("max heap : %,d MB%n", maxHeap / 1024 / 1024); + System.out.printf("target live set : %,d MB (%.0f%% of heap)%n", + (long) (maxHeap * LIVE_FRACTION) / 1024 / 1024, LIVE_FRACTION * 100); + System.out.printf("threads : %d, duration: %d s%n%n", THREADS, SECONDS); + + Path jfr = Path.of("allocation-stalls.jfr"); + + try (Recording recording = new Recording()) { + recording.setName("allocation-stalls"); + // The default threshold for jdk.ZAllocationStall is 10 ms. Anything shorter is silently + // dropped -- which is how a service can be full of 3 ms stalls that no one ever sees. + enable(recording, "jdk.ZAllocationStall"); + enable(recording, "jdk.ZPageAllocation"); + enable(recording, "jdk.ZYoungGarbageCollection"); + enable(recording, "jdk.ZOldGarbageCollection"); + recording.setToDisk(true); + recording.setDestination(jfr); + recording.start(); + + stressHeap(); + + recording.stop(); + } + + report(jfr); + } + + /** Enables an event if this JVM has it -- ZGC events do not exist when running under G1. */ + private static void enable(Recording recording, String event) { + try { + recording.enable(event).withoutThreshold().withStackTrace(); + } catch (RuntimeException e) { + System.out.println("(event not available on this collector: " + event + ")"); + } + } + + private static void stressHeap() throws Exception { + long maxHeap = Runtime.getRuntime().maxMemory(); + int chunk = 64 * 1024; // 64 KB per retained chunk + int retainedSlots = (int) (maxHeap * LIVE_FRACTION / chunk); + Object[] live = new Object[retainedSlots]; + retained = live; + + System.out.println("filling live set ..."); + for (int i = 0; i < retainedSlots; i++) { + live[i] = new byte[chunk]; + } + System.out.printf("live set filled: %,d chunks x %,d KB%n", retainedSlots, chunk / 1024); + System.out.println("now allocating hard for " + SECONDS + " s -- expect stalls\n"); + + long deadline = System.nanoTime() + Duration.ofSeconds(SECONDS).toNanos(); + List threads = new ArrayList<>(); + for (int t = 0; t < THREADS; t++) { + Thread th = new Thread(() -> { + ThreadLocalRandom rnd = ThreadLocalRandom.current(); + long ops = 0; + while (System.nanoTime() < deadline) { + // Churn: allocate short-lived garbage AND keep replacing live-set entries, so + // the collector must both reclaim young pages and relocate old ones. + byte[] garbage = new byte[16 * 1024]; + garbage[0] = 1; + if ((ops & 0x3F) == 0) { + live[rnd.nextInt(live.length)] = new byte[chunk]; + } + ops++; + } + }, "allocator-" + t); + threads.add(th); + th.start(); + } + for (Thread th : threads) th.join(); + System.out.println("allocation phase done\n"); + } + + private static void report(Path jfr) throws Exception { + if (!Files.exists(jfr)) { + System.out.println("no recording produced"); + return; + } + List stalls = new ArrayList<>(); + long youngCycles = 0, oldCycles = 0, pageAllocations = 0; + + try (RecordingFile file = new RecordingFile(jfr)) { + while (file.hasMoreEvents()) { + RecordedEvent e = file.readEvent(); + switch (e.getEventType().getName()) { + case "jdk.ZAllocationStall" -> stalls.add(e); + case "jdk.ZYoungGarbageCollection" -> youngCycles++; + case "jdk.ZOldGarbageCollection" -> oldCycles++; + case "jdk.ZPageAllocation" -> pageAllocations++; + default -> { } + } + } + } + + System.out.println("=".repeat(72)); + System.out.println("JFR summary (" + jfr.toAbsolutePath() + ")"); + System.out.println("=".repeat(72)); + System.out.printf("young collections : %,d%n", youngCycles); + System.out.printf("old collections : %,d%n", oldCycles); + System.out.printf("page allocations : %,d%n", pageAllocations); + System.out.printf("ALLOCATION STALLS : %,d%n%n", stalls.size()); + + if (stalls.isEmpty()) { + System.out.println("No stalls recorded. Either the heap was big enough, or you are not"); + System.out.println("running ZGC. Shrink -Xmx or raise -Dseconds and try again."); + return; + } + + // Note: RecordedEvent::getDuration is overloaded (no-arg and String-arg), so a method + // reference here is ambiguous and will not compile. An explicit lambda pins the overload. + stalls.sort(Comparator.comparing((RecordedEvent e) -> e.getDuration()).reversed()); + long total = 0; + for (RecordedEvent e : stalls) total += e.getDuration().toNanos(); + + System.out.printf("total time threads spent stalled : %,d ms%n", total / 1_000_000); + System.out.printf("mean stall : %,.2f ms%n", + total / (double) stalls.size() / 1_000_000); + System.out.printf("longest stall : %,.2f ms%n%n", + stalls.getFirst().getDuration().toNanos() / 1_000_000.0); + + // Which page size was the thread waiting for? ZGC has three page classes -- Small (2 MB, + // for objects up to 256 KB), Medium (32 MB by default, up to 4 MB objects) and Large (one + // page per object, for anything bigger). Stalls concentrated on Medium or Large pages mean + // something quite different from stalls on Small pages: the first is fragmentation or + // large-object pressure, the second is simply "allocating faster than we collect". + Map byPageType = new TreeMap<>(); // type -> {count, totalNanos} + for (RecordedEvent e : stalls) { + String type = safeString(e, "type"); + long[] agg = byPageType.computeIfAbsent(type, k -> new long[2]); + agg[0]++; + agg[1] += e.getDuration().toNanos(); + } + System.out.println("stalls by ZGC page type"); + byPageType.forEach((type, agg) -> System.out.printf( + " %-8s count=%,-8d total=%,7d ms mean=%.2f ms%n", + type, agg[0], agg[1] / 1_000_000, agg[1] / (double) agg[0] / 1_000_000)); + + System.out.println(); + System.out.println("ten longest stalls"); + System.out.printf(" %-11s %-8s %-10s %s%n", "duration", "page", "size", "thread"); + stalls.stream().limit(10).forEach(e -> System.out.printf(" %8.2f ms %-8s %-10s %s%n", + e.getDuration().toNanos() / 1_000_000.0, + safeString(e, "type"), + safeString(e, "size"), + e.getThread() == null ? "?" : e.getThread().getJavaName())); + + System.out.println(); + System.out.println("Compare against your pause-time chart: none of the above is a pause."); + System.out.println("Inspect the raw events, including the stack that was stalled, with:"); + System.out.println(" jfr print --events ZAllocationStall " + jfr.getFileName()); + } + + private static String safeString(RecordedEvent e, String field) { + try { + if (!e.hasField(field)) return "-"; + Object v = e.getValue(field); + return v == null ? "-" : String.valueOf(v); + } catch (RuntimeException ex) { + return "-"; + } + } +}