>- Performance-overhead review of a code diff / branch / PR for the dd-trace-java tracer. Flags hot-path allocation, unbounded memory, repeated work, escaping objects, native-boundary crossings, and JVM-specific pitfalls (escape analysis, JNI / virtual-thread pinning, backtracking-regex ReDoS, varargs/boxing hashing, String.format, ByteBuddy-Advice anti-patterns) using the tracer performance rubric. Use whenever the user wants a performance / overhead / hot-path review, asks to check a diff or PR for allocation / GC / memory / latency / startup cost, or mentions the "perf rubric" or the "do no harm / assume hot" tracer posture — verify-first findings; it never edits code.
npx skills add https://github.com/DataDog/dd-trace-java --skill perf-review
Review the current branch's changes for performance overhead in the dd-trace-java
tracer, using the tracer performance rubric bundled in references/. This is a
low-friction advisory nudge, not a gate: it reports findings and stops. It
never edits code.
The tracer shares the customer's process, heap, and latency budget. Do no harm:
overhead is a form of incorrect behavior that can escalate to real customer harm —
missed SLAs, OOM kills, container restarts, cold-start churn. So the review's job is
to catch overhead the customer would feel, and to do it *without becoming noise*.
Two forces are in tension, and the resolution defines everything below:
evidence of cold, assume the code runs on every request, under load, at full
concurrency. The burden of proof runs toward *cold*: ask "is there evidence this is
cold or guarded?" — not "is there evidence this is hot?" (that rationalizes itself
into "probably not").
dies of being ignored. Over-flagging kills it faster than under-flagging. This
actively fights your default to be comprehensive and helpful: here, *not* flagging
a borderline case is the correct, skilled move — not a miss.
You reconcile them with the confidence axis and verify-don't-verdict (below):
assume-hot makes you *look* everywhere; precision makes you *speak* only when the
mechanism is certain or the severity is catastrophic.
cannot render a performance verdict from a code read. Every finding routes into
Benchmark → Profile → Improve → Guard. Phrase each as *"this looks like X;
verify with Y"* — never "this is slow."
code: allocation, boxing, copying, unbounded growth, a native crossing. State it
plainly.
see from source: escape elision, inlining/devirtualization, GC impact. Phrase as
"may X; verify with a profiler/benchmark," never as a certainty.
String.format." Flag *"an eager, unconditional expensive call on a hot,
instrumentation-reachable path."* The same API is fine on a cold path. Two failure
shapes, different fixes: result usually discarded → gate/defer; result always
needed but costly → cheapen/cache.
peephole lint can't answer "reachable from a hot entry, unconditional along the
way." Trace *up* (who calls this? is it reachable from an @Advice root / per-span
callback / request handler?) and *down* (follow callbacks, hooks, and listeners to
their sink before flagging). If a per-span hook's every reachable sink is an
atomic counter (LongAdder, AtomicLong) or a no-op-when-disabled, stay silent — a
"verify contention" nudge there is noise.
valuable *and* least reliable part of a finding — residual false positives cluster
in "called it unconditional, missed an upstream guard." Say *"reachable from
Foo.onEnter via A→B→C, no guard on that path"* so the reader can check the
shakiest link at a glance.
a mechanism that has landed (see the toolkit note in checks.md — cite only what
exists; name "coming" primitives as coming). Don't flag a pattern whose only fix is
a mechanism that isn't built yet.
*aggressively* — a false positive there is cheap insurance against a container kill.
Flag low-severity CPU-micro *conservatively or not at all* — false positives there
only erode trust.
data (raw SQL with literals, per-request strings), *not* caching is the correct
choice — caching it would be the worse SEV-1. Flag a cache *keyed by* high-cardinality
data; never flag the decision not to cache.
The trigger is narrow: the change makes a visible tradeoff that could itself regress —
it removes a lock / guard / synchronization, swaps in a hand-rolled cache or data
structure, or explicitly claims "faster / optimized" — and ships no benchmark or
profile. There a static read genuinely can't tell a win from a regression, so raise one
soft *flag-as-measure* nudge: *"this trades <X for Y>; verify with a JMH benchmark / JFR."*
Do not fire it otherwise — if nothing in the diff could plausibly regress, there is
nothing to measure, so stay silent. Specifically not for: a mechanically-obvious win
(hoisting an invariant out of a loop, a denser data structure, removing an allocation);
routine adoption of a known-better idiom (migrating to a lower-overhead builder / API /
toolkit primitive — no visible downside); or a change that ships a benchmark/JFR
(well-evidenced — recognize it). One line; a nudge, not a code-pattern finding.
If the user points you at specific files or pasted code ("review this class / this
method for perf"), review those directly — skip the diff and go to Step 2 with the same
hot-path mapping and checks.
Otherwise, review the branch changes. Find the merge-base against the DataDog
upstream master and diff against it:
UPSTREAM=$(git remote -v | grep -E 'DataDog/[^/]+(\.git)?\s' | head -1 | awk '{print $1}')
[ -z "$UPSTREAM" ] && UPSTREAM="origin"
MERGE_BASE=$(git merge-base HEAD ${UPSTREAM}/master)
echo "Reviewing changes since $MERGE_BASE"
git diff $MERGE_BASE --stat
git diff $MERGE_BASE --name-status
If there are no changes, say so and stop. Otherwise read the diff **and the full
content of the modified source files** (not just the hunks) — the interprocedural
condition (who calls this, what a helper does, where a hook's sink lands) lives
outside the diff window. Ignore the PR description if the user asks for an
independent review.
For each changed method, decide *which multiplier applies* before flagging anything.
Hot anchors (reachable ⇒ assume hot): @Advice.OnMethodEnter/OnMethodExit,
per-span / per-trace callbacks, request / message handlers, streaming chunk handlers.
Hot-path map (where cost is multiplied per-span × spans/request × requests/sec):
span lifecycle (create / setTag / finish), tag-map ops, serialization/encoding, the
metrics/stats path, decorators, propagation (header read/write).
Cold only with positive evidence: one-time init, startup-only path, a genuinely
rare error branch, or behind a guard that provably fires rarely. Watch the
interprocedural trap — a method three helpers deep from an @Advice entry is
still hot. And note domain adjustment: large-denominator domains (LLMObs, CI
Visibility, DSM) absorb per-call CPU/alloc cost, but the risk *inverts* to payload
memory (SEV-1); streaming handlers fire per-chunk, so the large-denominator relief
suspends inside them. See guide.md §6.
Run the changed hot-path code against the rubric. Keep the check index below in mind;
open the references for the precise conditions, confidence, severity, and fix:
references/guide.md — the narrative "how": severity model, hotness rubric,the 6 categories with worked examples, and the false-positive traps. Read this first
if you're calibrating judgment.
references/checks.md — the precise cost-model: 7 universal checks + the Javaaddendum (J1–J11) + the ByteBuddy-Advice fix idioms + the toolkit-availability note.
Read this for the exact confidence/severity/fix of a specific pattern.
Before writing a finding: confirm the reachability path, confirm it's unconditional
along that path (check for upstream guards), and follow any hook/callback to its sink.
Drop anything that resolves to benign. Then report in the format below.
How many findings to report — scale with diff size:
high-confidence finding, ranked by severity. A tight diff with four real allocation
smells should list all four (as the worked example does).
ones may exist — don't bury the important one under a wall of CPU-micro nits.
what earns the review its credibility.
Follow this structure (see references/example-review.md for a full worked instance —
). Showing your suppressed lookalikes and what you cleared is not
filler: it demonstrates the precision that makes the findings trustworthy.
When providing suggestions as code review comments, prefix the comments with "perf: "
# Perf Review — <branch / PR>
**Scope reviewed:** <the hot method(s) and why they're hot — the multiplier>
## Confirmed findings
### 1. <one-line title>
<the offending code, as a short fenced snippet>
- **Confidence:** flag-with-confidence | flag-as-measure
- **Reachability:** <hot from X via A→B→C, no guard on that path>
- **Rubric check:** <#N / JN>
- **Severity:** SEV-<n>
- **Fix / verify-with:** <the actionable fix, or "verify with an allocation profiler">
## Correctly suppressed (not flagged)
<textual lookalikes deliberately left silent — e.g. the same `Objects.hash` pattern
but at class-init (cold), not per-call — and why the posture suppresses them>
## Checked, no issue
<what you examined and cleared: e.g. "no unbounded cache (#3/J5)", "no native
crossing (#6/J3)", "string-literal tag keys are JVM-interned — no per-call alloc">
## Summary
<count + severity spread; e.g. "4 confirmed hot-path findings, all SEV-2/3
(allocation/CPU); 1 cold-path lookalike correctly suppressed">
If nothing survives the confidence bar, say so plainly — "No high-confidence hot-path
findings; here's what I checked and cleared." A clean review is a valid, valuable
result, not a failure to find something.
Universal (language-agnostic):
Java addendum (JVM-specific — full text + mechanism in checks.md):
pinning · J4 GC pressure → tail latency · J5 cardinality-sensitive aggregator
(SEV-1) · J6 WeakReference.get() in a probe loop strengthens the ref ·
J7 substring → SubSequence zero-copy view · J8 backtracking regex on
external input → RE2J (ReDoS) · J9 Objects.hash(...) varargs/boxing →
HashingUtils · J10 hot-path String.format → Strings · J11 composite-key
maps → Hashtable.
review yet (kept as author reference only; it needs a standing audit, not per-PR
flagging). See checks.md for why.
Config.get() hoisting, @Advice.AllArguments →@Advice.Argument, @Advice.SkipOn+cached-boolean, @Advice.Local, switch(String)
three-tier) — in checks.md.
J7–J11 route an *existing* #1/#2/#3 finding to a landed reusable fix — they are not new
triggers. Don't raise a finding you wouldn't have raised anyway.
Execute git commit with conventional commit message analysis, intelligent staging, and message generation. Use when user asks to commit changes, create a git commit, or mentions "/commit". Supports: (1) Auto-detecting type and scope from changes, (2) Generating conventional commit messages from diff, (3) Interactive commit with optional type/scope/description overrides, (4) Intelligent file staging for logical grouping
Comprehensive GitHub code review with AI-powered swarm coordination
Create high-quality git commits: review/stage intended changes, split into logical commits, and write clear commit messages (including Conventional Commits). Use when the user asks to commit, craft a commit message, stage changes, or split work into multiple commits.
Comprehensive truth scoring, code quality verification, and automatic rollback system with 0.95 accuracy threshold for ensuring high-quality agent outputs and codebase reliability.
GitHub CLI (gh) comprehensive reference for repositories, issues, pull requests, Actions, projects, releases, gists, codespaces, organizations, extensions, and all GitHub operations from the command line.
GitHub CLI - manage repositories, issues, pull requests, actions, releases, and more from the command line.
You are a code refactoring expert specializing in clean code principles, SOLID design patterns, and modern software engineering best practices. Analyze and refactor the provided code to improve its quality, maintainability, and performance.
You are a technical debt expert specializing in identifying, quantifying, and prioritizing technical debt in software projects. Analyze the codebase to uncover debt, assess its impact, and create acti
Take datadog/perf-review from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.