jvmlens

mcp
Guvenlik Denetimi
Uyari
Health Uyari
  • License — License: Apache-2.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Gecti
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

LLM-ready JVM profiler — turns a JFR recording into a compact, source-attributed hot-path & allocation summary that AI coding agents can act on. In-process agent, MCP server, and JMH plugin; library + CLI.

README.md

jvmlens

Release
Build
codecov
License
Java
Docs

Turn JVM runtime evidence into a compact, LLM-ready diagnosis.

Ask an AI to "debug this." A raw jfr print dump of a short recording is 2.7 MB ≈ 684K
tokens
— pipe it to a model and the request overflows the context window; it can't even read
it. The same recording through jvmlens is ~1 KB (~250 tokens):

$ jvmlens analyze recording.jfr -r cpu | claude -p "why is this slow and how do I fix it?"
Workload.expensiveHashLoop — 99% (862 of 869 samples), CPU-bound, not blocked.
The time goes to byte-array VarHandle indexing (42%) and Integer→hex formatting (40%) —
the loop rebuilds hash/hex strings every iteration. Hoist that work out of the loop.

Real, checkable numbers and the full before/after Claude transcript:
jvmlens + your AI agent — every artifact is
committed under assets/demo/ so you can reproduce it yourself.

Profiling a JVM is well-served for humans — async-profiler, JFR, and the
commercial GUIs all produce flamegraphs and recordings. None of those formats
are built for an LLM to reason over: a jfr print dump of a short recording
is hundreds of thousands of tokens and routinely overflows a model's context
window. jvmlens reads a JFR recording and emits a few hundred tokens of ranked,
source-attributed signal you can hand straight to a coding agent.

📖 Documentation: https://www.alexmond.org/jvmlens/current/

What it captures

Beyond the classic three (CPU / memory / wait), jvmlens summarizes external I/O,
virtual-thread pinning, deadlocks, and — via the in-process agent — SQL,
HTTP endpoints, messaging, cache, and Micrometer timers, plus variable
snapshots
for correctness and a hedged cross-dimension correlation that ties a slow
endpoint to its query, hot path, and GC. Every row carries an absolute hit count, sections
are tagged [sampled] vs [measured], and the heuristic under-interprets (it never claims
a confident "leak").

Inputs & commands

Command What
analyze <file.jfr|dir> Summarize a recording, or a JMH -prof jfr directory (forks merged); --baseline diffs, --source echoes the source line.
profile <pid> Live attach + timed JFR capture; --engine async for native frames; -w/--warmup, -k/--keep.
bench --main <class> No-JMH harness — runs any main(String[]) in a warmup→timed loop, captures steady-state JFR, summarizes; --cp, -w, -i.
watch <pid> Continuous ring buffer — periodic, or dump-on-trigger (--on-gc-ms/--on-cpu-pct/--on-old-objects).
trend <history.jsonl> Reduce a multi-day agent run to a change-over-time digest.
control <file> <cmd…> In-flight control of a running agent (no ports/JMX).
mcp Stdio MCP server — scoped tools per dimension; reachable over ssh. Serves data only.
-javaagent:jvmlens-agent.jar In-process, container-native; periodic summaries, history=, per-dimension opt-in.
-prof …JvmlensProfiler JMH profiler plugin — prints the summary inline after a benchmark trial.

Output is markdown / JSON / LLM-prompt (-f), narrowable to one concern (-r), and scoped
to your packages (-a/-x). For remote servers, run jvmlens on the host (ssh / kubectl /
docker exec) — only the few-hundred-token summary travels back.

Optimize → measure loop

The agent perf loop, all from the one engine: diff two recordings (analyze --baseline before after — anchored on absolute bytes/ms/samples, so an optimize-loop reduction isn't
mislabelled a regression), gate a regression in CI (--assert "alloc-pct < 0, gc-pct < 10" — non-zero exit), get hedged fix directions (--hints), and budget the size
(--top-k / --max-tokens). Pairs with JMH — JMH gives the number, jvmlens gives the
where/why.

Run it inside one JMH command with the profiler plugin (-prof …JvmlensProfiler:keep=…
then baseline=…), and it gates on measured significance, not a sampled swing: an exact
allocation and throughput A/B verdict (SIGNIFICANT only when the Δ clears the noise
band and the CIs don't overlap), a dispersion signal (a real structural win collapses the
cross-fork variance band; near-deterministic bytes/op is a STOP signal), and honest hedges —
an escape-analysis false-lever caveat, an extract-method allocation-by-type rollup, and
a “a CPU-share shift is not a speedup” note when throughput stays flat.

Runtime control (in-flight)

Like a desktop profiler's live controls, the agent can be steered without a restart through a
watched control file — start/stop, enable/disable a dimension, switch sampling
density, adjust filtering, set per-section top-N — via jvmlens control <file> <cmd> (run on
the host). Launching paused and starting after warm-up is the clean fix for short cold runs
profiling startup. See Usage → Runtime control.

Why

A 20-second profile-settings recording of a hot loop dumps ~380K tokens of
raw jfr print — too big to paste. jvmlens turns the same recording into a
~400-token summary that names the hot application method, the leaking
allocation site, or the contended lock. For an LLM, the summary isn't just
cheaper — for non-trivial recordings it's the only input that fits.

Case study — a 7.6 GB allocation hiding in one line

On gotmpl4j (a pure-Java Go text/template engine),
jvmlens put GoFmt.floatString at the top of both the CPU and allocation tables and attributed
the 7.6 GB down to a single line — three throwaway Strings per call to move a decimal point.
Deleting them, byte-identical against the real Go engine:

Metric Before After
JMH gc.alloc.rate.norm (whole op) 1.04 MB/op 0.77 MB/op (−26%)
floatString allocation 7.6 GB 3.6 GB (−52%)

The honest top-line is the −26% per operation (the measured whole-op number), not the flashier
per-method −52%. Full receipts — profile → fix → prove → guard — in
Case study: floatString.

Install

Library — Maven Central. Embed the summarizer (the dependency-free engine, only
jdk.jfr.consumer):

<dependency>
  <groupId>org.alexmond</groupId>
  <artifactId>jvmlens-engine</artifactId>
  <version>0.3.1</version>
</dependency>

CLI / agent / JMH jars. These are runnable artifacts (a Spring Boot fat jar and two
shaded tool jars). They're published to Maven Central and attached as GitHub release
assets — grab whichever is handier. Java 17+ to run:

# the latest tagged release
gh release download 0.3.1 -R alexmond/jvmlens -p 'jvmlens.jar'
# …or the rolling pre-release (every green build on main), no build required:
curl -L -o jvmlens.jar https://github.com/alexmond/jvmlens/releases/download/latest/jvmlens.jar
java -jar jvmlens.jar analyze recording.jfr

Each release also carries jvmlens-agent.jar (the in-process -javaagent) and
jvmlens-jmh.jar (the JMH profiler). The latest URL is stable — it always points at the
newest green build on main.

Claude Code skills. This repo is also a Claude Code
plugin marketplace — two skills that teach an agent to drive jvmlens: jvmlens-perf (the
optimize→measure loop) and jvmlens-monitor (the long-running monitor + trend). See
plugins/README.md.

/plugin marketplace add alexmond/jvmlens
/plugin install jvmlens-perf@jvmlens
/plugin install jvmlens-monitor@jvmlens

Build

mvn -q clean package

Use

# analyze an existing JFR recording (markdown by default) — use the downloaded jar,
# or jvmlens-cli/target/jvmlens.jar if you built from source
java -jar jvmlens.jar analyze recording.jfr

# or emit scoped JSON / an LLM-ready prompt
java -jar jvmlens.jar analyze -f json recording.jfr
java -jar jvmlens.jar analyze -f prompt recording.jfr

# or during development
mvn -q spring-boot:run -Dspring-boot.run.arguments="analyze,recording.jfr"

Example output:

# JVM profile summary (recording.jfr)

Events: 1738 exec samples, 8 alloc types, 2 old-object samples, 10 GC pauses (62 ms).

## Top hot paths (application code, by sample share)
- `com.example.OrderService.reprice` — 100%  (com.example.OrderService.reprice <- ...)
...
## Suspected cause (heuristic)
- CPU-bound — `com.example.OrderService.reprice` accounts for the majority of samples.

Use it from another project

Want to profile a different JVM project (say builder) with jvmlens?
INTEGRATING.md is a portable, copy-paste guide: a decision
table over the integration paths (analyze a .jfr, attach to a running pid, the
always-on -javaagent, an MCP server for coding agents, a Kubernetes sidecar), a
drop-in profile.sh, and a CLAUDE.md snippet to paste into the target project.

Try it end-to-end

examples/Workload.java is a planted-pathology workload (CPU hot path, a memory
leak, lock contention) for producing sample recordings. See examples/README.md.

Design & roadmap

This project graduated from a structured incubation; the design thinking and plan
came with it so work can continue uninterrupted:

  • DESIGN.md — architecture (one engine, two front-ends), key
    decisions (frame attribution, MCP scoped tools, capture modes, prod-vs-dev,
    LLM egress), the v2 variable-snapshot direction, and competitive positioning.
  • ROADMAP.md — staged plan with effort and the immediate next step.
  • examples/experiments.md — how to validate
    summary quality against the planted-pathology workload.
  • docs/competitor-analysis.md — the profiling /
    observability landscape (continuous profilers, JProfiler/YourKit/JMC, APM/OTel,
    Glowroot) and where jvmlens differs, plus docs/extended-profiling.md
    — the epics for going beyond CPU/memory/wait into web/db/messaging.

License

Apache License 2.0 — see LICENSE.

Yorumlar (0)

Sonuc bulunamadi