Jmh
Skill umit/skills/skills/jmh
My personal agent skills — JVM profiling, GC, concurrency, distributed systems. Compatible with Claude Code, Codex, Cursor, Cline, and any agent that supports the skills.sh format.
npx -y skills add umit/skills --skill jmhAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Write Java microbenchmarks with JMH (Java Microbenchmark Harness) that produce trustworthy numbers — not numbers distorted by JIT dead-code elimination, constant folding, insufficient warmup, or single-fork JIT contamination. Use this skill whenever the user writes `@Benchmark`, mentions JMH, microbenchmark, throughput measurement, latency measurement, or compares two implementations performance-wise. Triggers on `@Benchmark`, `@Setup`, `@State`, `Blackhole`, `@Fork`, `@Warmup`, `@Measurement`, `@OperationsPerInvocation`, `Mode.Throughput`, `Mode.AverageTime`, `Mode.SingleShotTime`, `Mode.SampleTime`, `BenchmarkMode`, `OutputTimeUnit`, `BenchmarkRunner`, `jmh-core`, `jmh-generator-annprocess`, `org.openjdk.jmh`, `me.champeau.jmh` (Gradle plugin), `pl.allegro.tech.build.axion-release`, `JMHTask`. Treat any benchmark without `Blackhole.consume()`, with `@Fork(0)`, or with `@Warmup(iterations < 5)` as broken by default — pre-flight statically before running. Pair with `async-profiler` (`-prof async`) for per-benchmark flame graphs to answer not just "which is faster" but "why".
SKILL.md
5.3 KB, as published. Nobody here has run it
JMH — trustworthy Java microbenchmarks
Workflow
- Pre-flight before running — read
references/pitfalls.mdand apply its 15-point checklist to the benchmark source. Catch DCE, constant folding, missingBlackhole,@Fork(0),@Warmup < 5,finalconstants in the op, missing@State, raw loops without@OperationsPerInvocation. Most "fast" results come from broken benchmarks; catching this before running saves hours. - Identify the build system — Maven (
pom.xmlwithjmh-core) or Gradle (me.champeau.jmhplugin). Setup differs; running differs. Seereferences/maven.mdorreferences/gradle.md. - Pick the right
Mode—Throughputfor ops/sec,AverageTimefor ns/op,SingleShotTimefor cold-path / startup,SampleTimefor distribution (p50/p99). Wrong mode → wrong question answered. Seereferences/modes.md. - Write the benchmark — annotate class with
@State(Scope.Benchmark),@BenchmarkMode,@OutputTimeUnit,@Fork(value=3, jvmArgs={"-Xmx2g","-Xms2g"}),@Warmup(iterations=5),@Measurement(iterations=10). Every@Benchmarkmethod either returns a value or takes aBlackholeparameter. Use@Paramfor matrices instead of separate methods. - Re-check the source against the checklist after edits.
- Run with profilers attached — never run benchmarks without
-prof gc(allocation rate context) and ideally-prof async:output=flamegraph(flame graph per benchmark). Seereferences/profilers.md. - Output JSON (
-rf json -rff results.json) — never trust the console table alone; JSON is what diffing and visualization tools consume. - Analyze — drag
results.jsonto https://jmh.morethan.io for charts, or use Bencher/Codspeed in CI for continuous diff. Seereferences/analysis.md. - Report with confidence intervals — JMH prints
Score ± Error (99.9%). Two means are not different if their confidence intervals overlap. Don't claim "10% faster" inside the noise band.
Quick reference
# Maven — build + run a single benchmark class
mvn clean verify -DskipTests
java -jar target/benchmarks.jar MyBench -wi 10 -i 10 -f 3 -prof gc -rf json -rff result.json
# Gradle (me.champeau.jmh plugin) — run all benchmarks in jmh source set
./gradlew jmh
# Run only matching benchmarks (regex)
java -jar target/benchmarks.jar 'com\.acme\..*Hash.*'
# Profile per-benchmark with async-profiler
java -jar target/benchmarks.jar MyBench -prof async:output=flamegraph;dir=profiles
Common modes
| Mode | Unit | When |
|---|---|---|
Throughput | ops/time | "how many per second" — default for hot-path code |
AverageTime | time/op | "how long per call" — typical for latency-sensitive ops |
SampleTime | time/op (sampled) | distribution incl. p50/p95/p99 — outlier-aware |
SingleShotTime | time/op (one-shot, no warmup-loop) | cold start, init code, single-event measurement |
References
| File | When to read |
|---|---|
references/intro.md | Read first — what JMH is, why naive benchmarks lie, minimal example, how to read the score table + GC columns + percentiles, golden-default checklist |
references/pitfalls.md | Always before reviewing/writing a benchmark — 15 antipatterns (DCE, constant folding, false sharing, etc.) + 15-point pre-flight checklist + minimal correct template |
references/maven.md | Maven pom.xml setup, archetype, run command, multi-module projects |
references/gradle.md | me.champeau.jmh plugin config, jmh {} block, source set, IDE integration |
references/modes.md | Mode + State + Scope + @OperationsPerInvocation deep dive |
references/profilers.md | -prof gc, -prof async, -prof perfasm, -prof jfr, -prof stack — when to use which |
references/analysis.md | JSON schema, jmh.morethan.io, statistical interpretation, CI integration (Bencher, Codspeed) |
Output format
- Raw run: console table +
result.json(always emit JSON with-rf json -rff). - For sharing: upload JSON to https://jmh.morethan.io and share the URL.
- For CI: integrate with Bencher (
bencher run) or Codspeed (codspeed run); both have JMH adapters. - For deep analysis: pair with
async-profilerJFR per benchmark; render flame graphs withjfrconv.