Changelog

0.3.0

The semantic dimensions grow up: every agent dimension is now source-anchored and feeds the fix-hint + correlation machinery, cross-dimension correlation can confirm a chain, and two new stores (MongoDB, Redis) plus RabbitMQ land — the P1→P5 form-factor cycle.

  • Source anchors + fix-hints on every semantic dimensiondb, web, cache, and messaging rows now carry the app call-site they were issued from (· at UserRepo:88) and feed --hints with their own mechanical levers: N+1 → batch, SELECT * → project, high error rate → validate/handle, low cache hit rate → check key/TTL, synchronous per-message send → batch/async. Built on a shared, bounded, fail-open call-site walk (#137#140).

  • Cross-dimension correlation, confirmed — the correlation note renders an ordered chain (endpoint → SQL → cache → messaging → I/O → hot path → lock → GC) showing each link’s anchor and flag, and upgrades from co-occurrence to a ✓ Confirmed chain when the agent’s captured call-path proves a deeper op ran inside an endpoint’s handler; it degrades to the honest co-occurrence wording offline (#141, #142).

  • ORM N+1 sharpening — a repeated single-row insert/update reads as un-batched writes (enable JDBC batching), and a repeated SELECT that already uses WHERE id IN (…) is the batch-fetch fix, so it’s no longer a false N+1 (#143).

  • MongoDB dimension (mongo) — times sync-driver MongoCollection ops; a repeated find is a possible N+1 document fetch (Filters.in / aggregation), a repeated single-document insertOne/updateOne/deleteOne is un-batched (insertMany/bulkWrite) (#144).

  • Redis dimension (redis) — times direct Lettuce/Jedis commands (distinct from the Spring-Cache cache dimension); many single-key reads read as possible N+1 round-trips — pipeline or MGET/HMGET (#145).

  • RabbitMQ messaging — the messaging dimension now also hooks the low-level com.rabbitmq.client.Channel (basicPublish/basicGet), covering native and Spring AMQP with no double-count; the synchronous-send flag is broker-agnostic. ActiveMQ stays on the JMS path (Classic + Artemis) — instrumenting its core API would double-count JMS-over-Artemis (#148).

0.2.2

More honest profile diffs, still from dogfooding real projects (the unitrack field-findings).

  • Disproportionate-rise CPU hedge — a fixed-duration capture of a now-faster workload runs more iterations, so an unchanged hot-path frame accrues more samples and gains share even as its per-op cost is flat. The diff now hedges a row that outpaced a modestly-rising exec-sample total (its share climbed), and prints a throughput caveat pointing at a fixed-iteration bench A/B for the clean per-op number. This closes the gap the opposing-row hedge (#110, needs a falling row) and the flat-total caveat (#122, needs a ~flat total) both missed (#127).

  • trend restart segmentation — a multi-day monitor spanning rolling redeploys is no longer skewed by each new pod’s cold-start burst. trend detects a restart from the large gap it leaves between sample timestamps, adds a ## Lifecycle note, excludes each lifetime’s first (warmup) window from the steady-state aggregates, and assesses retention within the latest lifetime only (old-object counts reset on restart). A gapless single run is unchanged (#129).

  • -x folds excluded allocated types--exclude now also reaches the Top allocated types block: any type whose package matches an exclude (array descriptors included) rolls up into one accounted «excluded types (-x)» line, so a test capture’s embedded-DB internals (an in-process H2’s MVStore types) stop crowding out the app’s own types. No new flag — the same -x that already scopes hot paths and allocation sites (#128).

  • Agent launch-time scope= arg — a headless long-running monitor can now pin the application scope at startup (scope=app:org.alexmond.unitrack, +-separated, exclude: side supported) instead of relying on heuristic attribution or a mid-run control command. history/trend attribute to the real module from the first sample — the launch equivalent of the in-flight scope app (#133).

0.2.1

Publishing scope, a sharper regex hint, honest CPU-diff hedging, and scope-filter fixes — from the gotmpl4j/jhelm dogfooding loop.

  • CPU flat-total redistribution hedge — when total exec samples are ~flat, a hot-path row is hedged as a larger share of a conserved total (not more work), and the diff adds a caveat that fixed-duration exec-sample deltas conflate per-op cost with throughput — use a fixed-iteration bench A/B (#122).

  • --hints regex rule — a Pattern compiled per call (or a String.replaceAll/matches/ split/replaceFirst on a hot line) now names the concrete fix: hoist the Pattern to a static final field and reuse the Matcher (a structural, parity-safe change) (#119).

  • Scope -x wins inside -a — an exclude prefix now applies even within an include, instead of the include short-circuiting and leaving an excluded (e.g. test) frame in the roll-up; plus a child-process/pipe-wait I/O teaser and a surefire profile <pid> capture tip (#121).

  • Maven Central publishing scope — the test-only jvmlens-it module is kept off Central via the aggregator’s excludeArtifacts (the central-publishing plugin ignores maven.deploy.skip); jvmlens-engine/-cli/-agent/-jmh still publish (#117).

  • Docs — the floatString case study now cross-references the gotmpl4j and jhelm performance pages, where the same loop is worked end-to-end on real workloads (#125).

0.2.0

The optimize→measure loop gets honest about measured significance — so a sampled swing can’t be mistaken for a real win — plus richer source attribution. All from dogfooding real JVM projects (the gotmpl4j field-findings).

Measured A/B verdicts (gate the loop on the wall-clock, not the sampler)

  • Measured allocation A/B — with JMH’s -prof gc and a baseline=, the JMH profiler prints an exact bytes/op before→after verdict that is SIGNIFICANT only if the relative Δ exceeds the combined noise band and the confidence intervals don’t overlap; it reconciles the sampled diff total against the measured one and flags a disagreement as likely sampling redistribution / JIT elision (#104).

  • Measured throughput A/B — the CPU analog: an exact primary-score (ops/s, us/op, …) verdict with the same significance test. When a sampled hot-path share moved but wall-clock throughput is flat, it says so explicitly — a CPU-share shift is not a speedup (#112).

  • Dispersion verdict — a genuine structural allocation removal collapses the cross-fork variance band (the removed allocation was the noise); a ~500× collapse is flagged as a strong real-win signal the mean alone can’t give, and a now near-deterministic bytes/op emits a STOP signal (diminishing returns — pivot off allocation) (#110).

  • Per-benchmark baseline match — the inline baseline= now records the benchmark method in its sidecar; a baseline recorded for a different method is detected and the verdict skipped with a warning, instead of emitting confident wrong per-method numbers (#112).

  • JMH -prof gc header — the summary leads with JMH’s exact gc.alloc.rate.norm next to jvmlens’s sampled per-site bytes, and drops the JMH harness control socket from External I/O noise (#100).

Sharper attribution & honest hedges

  • analyze --source <roots> — echoes the source-line text inline at each file:line anchor (floatString:129 ⟶ mantissa.substring(…)), so a coding agent sees the offending line without opening the file; opt-in, degrades silently (#109).

  • Allocation-by-type rollup — the diff sums allocation sites by declaring type, so an extract-method refactor (caller ▼ + a NEW callee) reads as one net change instead of a regression (#99).

  • Escape-analysis caveat — an allocation site dominated by a boxed primitive or captured lambda is tagged as possibly scalar-replaced (a false lever); the --hints directions hedge the same, so you verify with -prof gc before chasing it (#103).

  • CPU-share redistribution hedge — the diff hedges a hot-path row whose absolute samples rose while total exec samples fell, so a share that climbed only because the rest of the profile shrank isn’t misread as a regression (#110).

0.1.1

  • License corrected to Apache-2.0 across the build and metadata.

0.1.0

First public release. Proof-of-concept graduated from the incubator, then built out into a full JVM-evidence → LLM-ready summarizer with a live control plane.

Commands

  • analyze <file.jfr|dir> — summarize a recording, or a directory of them (a JMH -prof jfr run: every fork’s .jfr merged into one summary), into markdown / JSON / prompt; --baseline <before.jfr> diffs two recordings — anchored on absolute weight (bytes / ms / samples) with share as context, so an optimize-loop reduction isn’t mislabelled a regression; --assert "<rules>" is a CI perf-gate (non-zero exit on regression); --hints adds hedged [possible] fix directions; --top-k <n> / --max-tokens <n> budget the size; --skip-warmup <ms> drops JIT/classload churn (per-file cutoff) for steady-state hot paths.

  • profile <pid> — live attach + timed JFR capture (no pre-recorded file); --engine async adds native frames via async-profiler; -w/--warmup, -k/--keep.

  • bench --main <class> — the no-JMH harness: runs any main(String[]) in a warmup→timed loop, captures a JFR over only the timed phase, and summarizes; --cp, -w/--warmup, -i/--iters, --jfr (keep for a baseline diff).

  • watch <pid> — continuous ring buffer; periodic, or dump-on-trigger (--on-gc-ms / --on-cpu-pct / --on-old-objects).

  • trend <history.jsonl> — reduce a long-running monitor’s accumulated history to a change-over-time digest (per-dimension direction, hot-path shift, hedged retention).

  • control <control-file> <cmd…>in-flight agent control (see Runtime control).

  • mcp — stdio MCP server exposing scoped, navigable tools (one per dimension) plus a live profile tool; reachable remotely over stdio-over-ssh. Serves data only — never calls an LLM.

  • JMH profiler plugin-prof org.alexmond.jvmlens.jmh.JvmlensProfiler prints the summary inline after a benchmark trial; keep=<path> retains the fork’s recording and baseline=<prev.jfr> prints the diff inline (the whole optimize loop inside one JMH run). Ships as a dependency-light jvmlens-jmh.jar (engine + profiler, no Spring/picocli/jmh).

Dimensions summarized

  • CPU — hot paths (application-attributed) + hot leaf methods.

  • Memory — allocation sites + types, GC pressure.

  • Wait — lock contention by method + contended monitors.

  • External I/O — socket + file blocking I/O by endpoint (jdk.SocketRead/Write, jdk.FileRead/Write).

  • Virtual-thread pinningjdk.VirtualThreadPinned by site, with pinnedReason.

  • Deadlocks — authoritative ThreadMXBean.findDeadlockedThreads wait-for cycle (agent).

  • Database (SQL) — agent JDBC instrumentation; sanitized SQL shapes, latency, N+1 flag.

  • HTTP endpoints — agent servlet instrumentation; route-shape, latency, errors.

  • Messaging / cache — agent Kafka/JMS and Spring-Cache operation timing.

  • Micrometer — summarize an existing registry’s timers (no extra instrumentation).

  • Variable snapshots — agent snapshot=Class#method argument digests (correctness).

  • Cross-dimension correlation — a hedged note co-locating the dominant signal per dimension.

Trust & honesty

  • Per-row absolute hit count beside every share; sections tagged [sampled] vs [measured]; a adequacy caveat under 200 execution samples, and a matching per-site allocation caveat when there are too few allocation samples (the total stays reliable).

  • Source-line anchoring — hot-path leaves and allocation sites carry their source line (Svc.compute:88), so a coding agent goes from diagnosis to the edit in one step.

  • Leaf confidence — a hot path’s teaser lists the top leaves with counts and flags ⚠ diffuse when no single leaf dominates, instead of trusting one (possibly stray) frame.

  • The heuristic under-interprets — retention is flagged as possible growth, never a confident "leak"; correlation suggests, never asserts.

Agent & runtime control

  • -javaagent:jvmlens-agent.jar — in-process, container-native, no attach/JMX. Writes periodic summaries; history= appends a JSONL time-series; per-dimension opt-in.

  • Runtime control via a watched control file (control=<file>) + the jvmlens control CLI: start/stop, clear, dump, enable/disable <dim>, settings profile|default, interval, scope app|exclude|reset (filtering), topn [<category>] <n> (rows/section), status — each returns the agent’s state to the caller. No ports, no JMX.

  • paused launch + start-after-warm-up — the clean fix for short cold runs profiling startup.

Outputs & engine

  • Formats md / json / prompt; report focuses full / cpu / memory / locks / gc / io / pinning / db / web / messaging / cache / metrics / deadlock.

  • Application-frame scoping (-a/--app-package, -x/--exclude); runtime-adjustable top-N.

  • Dependency-free engine (jdk.jfr.consumer only) reused by every front-end.

Deploy

  • Standalone Helm chart (deploy/helm/jvmlens) + scripts/deploy-agent.sh attach the agent to any JVM image as a separate release, without touching the app’s own chart.