Repository navigation
Add @PerfContract meta-annotation and @SuppressPerfContract (AI perf review) - #12647
Conversation
Generic exemption mechanism for perf-contract marker annotations (NoEscape, Strategy, StaticLifetime, ...), replacing per-marker exemption channels (bespoke nested annotations, comment-only conventions) with one shared mechanism. @SuppressPerfContract can also be used as a meta-annotation to define named, canned exceptions (e.g. a future @Borrowed for @NoEscape). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Check #8 (@NoEscape field-storage violation) only recognized a retention-justifying comment as compliant. It now also accepts @SuppressPerfContract(value = NoEscape.class, reason = "...") and a canned-exception annotation meta-annotated with it (e.g. a future @Borrowed), matching the mechanism's own Checker contract. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
🟢 Java Benchmark SLOs — All performance SLOs passed
PR vs. master results
Commit: Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion. |
Holding off on applying @Staticlifetime to real cache fields until @SuppressPerfContract (dougqh/perf-contract-suppress, PR #12647) lands -- want the exemption mechanism in place before widening the annotated surface. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
These are cross-cutting, package-independent of any one marker, so they don't belong under datadog.trace.api.function alongside the functional interfaces (TriConsumer, TriFunction) and the markers themselves. datadog.perfcontract follows the existing precedent for top-level datadog.* packages (datadog.appsec, datadog.opentracing, datadog.communication, datadog.telemetry). The existing markers (NoEscape, Strategy, StrategyConsumer, BackgroundOnly, ForegroundSafe, and StaticLifetime/Singleton once #12646 lands) stay put for now -- moving those is a separate PR. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The new package (PerfContract, SuppressPerfContract) had no owner, blocking the PR merge. Same owner as the sibling datadog.trace.api.function package these moved out of. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 68d21c58b5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
sarahchen6
left a comment
There was a problem hiding this comment.
A few nits to simplify / clarify the comments, but otherwise looks good
…Contract Removes references to Singleton/StaticLifetime, which don't exist in this PR's tree (a cross-reference left over from generating two related PRs in one session). Adopts sarahchen6's simplified class javadocs for PerfContract and SuppressPerfContract. Annotates NoEscape, Strategy, and StrategyConsumer with @PerfContract so SuppressPerfContract's own worked example (suppressing a NoEscape finding) is valid, per the Codex/Bits review finding that NoEscape carried no @PerfContract. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
checks.md already documented @SuppressPerfContract(NoEscape.class, ...) and canned-exception annotations as compliant, but NoEscape's own Checker contract only listed the plain comment convention, so an AI reviewer reading NoEscape.java alone would flag a compliant suppression. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
…tate with @PerfContract Relocates both annotations out of the legacy datadog.trace.api.function package into the new datadog.perfcontract package (introduced by #12647), alongside PerfContract/SuppressPerfContract, and adds @PerfContract so tooling can discover them as perf-contract markers the same way it already discovers Strategy/StrategyConsumer/NoEscape. No other code references either annotation, so no import-site updates are needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
#12646) Add @Staticlifetime and @singleton marker annotations @Staticlifetime marks a field that must live for the whole program rather than for its enclosing instance's lifetime (e.g. a cache allocated per-request instead of once). @singleton is its escape valve, declaring a class has exactly one process-wide instance, so an instance field on it can satisfy @Staticlifetime without being static. Wires a matching check into the perf-review checks doc, mirroring the existing @NoEscape field-storage check. APMLP-1846, APMLP-1847 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Add Checker contract section to @singleton javadoc Splits narrative vs. machine-checkable rule, matching the convention established by @NoEscape and @Staticlifetime. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Annotate WebFlux route cache with @Staticlifetime Spot-checks the annotation against the real defect it was modeled on: PR #12561 (commit e6b8756) made this exact DDCache field static after it lived per-instance, unshared, for ~4 years. Serves as the first real call site for @Staticlifetime. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Annotate UTF8 tag/value caches with @Staticlifetime TAG_CACHE/VALUE_CACHE in TraceMapperV0_4 and KEY_CACHE/VALUE_CACHE in OtlpCommonProto are already static final -- marking them adds compliant-example coverage alongside RouteOnSuccessOrError's violation-turned-compliant case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Revert "Annotate WebFlux route cache with @Staticlifetime" Holding off on applying @Staticlifetime to real cache fields until @SuppressPerfContract (dougqh/perf-contract-suppress, PR #12647) lands -- want the exemption mechanism in place before widening the annotated surface. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Revert "Annotate UTF8 tag/value caches with @Staticlifetime" Same reason as the WebFlux route-cache revert: hold off until @SuppressPerfContract lands. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Close StaticLifetime checker-contract gaps: require final, static+non-final Per Bits AI review: the contract accepted "static" fields and singleton-scoped instance fields without requiring final, so a mutable field of either shape could pass while still being reassignable to a fresh, cold instance at runtime -- defeating the amortization guarantee the annotation exists to protect, just via a write instead of via scope. Add an explicit mutability trigger and require final in the Accepted description for both shapes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Fix StaticLifetime's ClassValue paragraph to match its own checker contract Per review: the intro implied a ClassValue-backed holder need not be static itself, contradicting the Accepted list below it, which requires "static final ClassValue<T>". Clarify that it's the per-Class values ClassValue computes that get a free process-wide lifetime, not the holder field referencing the ClassValue instance -- that still has to be static final. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Merge remote-tracking branch 'origin/master' into dougqh/static-lifetime-singleton # Conflicts: # .agents/skills/perf-review/references/checks.md Move StaticLifetime/Singleton into datadog.perfcontract and meta-annotate with @PerfContract Relocates both annotations out of the legacy datadog.trace.api.function package into the new datadog.perfcontract package (introduced by #12647), alongside PerfContract/SuppressPerfContract, and adds @PerfContract so tooling can discover them as perf-contract markers the same way it already discovers Strategy/StrategyConsumer/NoEscape. No other code references either annotation, so no import-site updates are needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Tighten the @singleton Javadoc Applies a review suggestion: a static holder or DI registration does not by itself guarantee a single instance, and only final instance fields satisfy @Staticlifetime. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Restructure the @Staticlifetime Javadoc around one field rule Applies a review suggestion: a single accepted/violation/out-of-scope rule, an accurate ClassValue note, and block examples. Keeps the note on the name echoing Rust's 'static lifetime. Examples use <pre> with escaped @ and generics so javadoc does not read a leading @ as a block tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Require final for @Singleton-held fields in the perf-review StaticLifetime check Matches the @Staticlifetime and @singleton Javadoc: only a final instance field on a @singleton class is accepted, and ClassValue holders follow the plain static final rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
What Does This Do
Adds two new annotations to
datadog.trace.api.function:@PerfContract— a meta-annotation marking an annotation in this package as a perf-contract marker (e.g.@NoEscape,@Strategy,@StaticLifetime,@Singleton), so tooling has one place to discover "which annotations here are perf-contract markers."@SuppressPerfContract— a generic exemption mechanism for perf-contract marker findings, modeled on@SuppressWarningsbut with a mandatoryreason(). Names the marker(s) being suppressed by class reference (value(): Class<? extends Annotation>[]), not string, so a rename is caught at compile time. Can also be used as a meta-annotation on another annotation type to define a named, "canned" exception (e.g. a future@Borrowedfor@NoEscape) that carries its own defaultreason.Also updates the
perf-reviewskill's@NoEscapefield-storage check (#8 inchecks.md) to recognize@SuppressPerfContractand canned-exception annotations as compliant, alongside the existing comment convention.Motivation
Perf-contract markers were accumulating their own bespoke, one-off exemption channels —
@NoEscape's comment-only convention,@Strategy's nested@Strategy.DynamicDispatchannotation (removed in #12475 now that this exists) — each reinventing the same "deliberate, reviewed exception" idea.@SuppressPerfContractgives every current and future marker one shared mechanism instead.Additional Notes
Documentation-and-tooling only; changes no behavior. Both annotations use
RetentionPolicy.CLASSso a classfile-only checker in a dependent module can still see them.Jira ticket: APMLP-1874