Skip to content

Instrument LambdaMetafactory and preserve Runnable lambda identity during context propagation - #12346

Draft
amarziali wants to merge 18 commits into
masterfrom
andrea.marziali/lambda
Draft

Instrument LambdaMetafactory and preserve Runnable lambda identity during context propagation#12346
amarziali wants to merge 18 commits into
masterfrom
andrea.marziali/lambda

Conversation

@amarziali

Copy link
Copy Markdown
Contributor

What Does This Do

Instrument Runnable lambda classes when they are generated by LambdaMetafactory, allowing executor context propagation to attach state directly to the lambda instead of creating a RunnableWrapper.

This is primarily a functional improvement: avoiding the wrapper preserves the submitted task’s identity while retaining the existing context-propagation behavior.

Notable changes

  • Pass eligible lambda classes through the existing instrumentation pipeline before class definition.
  • Use the ignored-class trie to select exact supported lambda interfaces efficiently.
  • Initially allowlist java.lang.Runnable; the mechanism can later be extended to interfaces such as Callable.
  • Apply the existing Runnable field injection and execution advice to eligible lambda classes.
  • Support both JDK 8 and the module-aware transformation path used by newer JDKs.
  • Bypass the matcher memoizer only for lambda transformations because hidden lambda classes may share the same symbolic name.
  • Preserve the existing fallback behavior if transformation fails or becomes reentrant.
  • Skip agent-owned lambda classes.
  • Enable lambda instrumentation by default, with dd.trace.lambda.enabled=false available as an opt-out.

Known limitation

Concurrent submissions of the same Runnable lambda instance share a single continuation slot. As with other field-injected Runnable implementations, only one pending context can be retained, so overlapping submissions may lose or misassociate context propagation.

Previously, wrapped lambdas had per-submission state. This limitation is most relevant to reusable singleton or stateless lambdas submitted concurrently; lambdas created per operation are unlikely to encounter it.

Benchmarks

Benchmarks were run with dd.benchmark.enabled=true.

Spring Boot startup

A Spring Boot 3.3 Petclinic-style application was measured on Temurin 17 across 15 interleaved runs:

Configuration Mean Median
Lambda instrumentation disabled 1665.8 ms 1656 ms
Lambda instrumentation enabled 1676.7 ms 1670 ms
Paired difference +10.9 ms

The 95% confidence interval for the paired difference was ±43.9 ms, so the measured startup difference was indistinguishable from run-to-run noise.

The application generated approximately 1,600 lambda classes. Of those, 22 exact-Runnable candidates entered the transformer and 8 were modified.

JMH results

Benchmark Disabled Enabled Difference
New Runnable call-site linkage ~14 µs / 27 KB ~126 µs / 295 KB +112 µs / 268 KB
New Supplier call-site linkage ~14–15 µs / 27 KB ~14–15 µs / 27 KB No change
Capturing Runnable allocation 16 B/op 24 B/op +8 B/op
Traced executor submission ~0.009 ms ~0.009 ms No material change
Direct untraced run(), JDK 17 0.723 ns/op 0.817 ns/op +0.094 ns/op
Direct untraced run(), JDK 25 0.776 ns/op 0.815 ns/op +0.039 ns/op

The linkage cost is paid once when a matching lambda call site is created. Unrelated lambda interfaces take the fast trie-rejection path. The direct-run benchmark intentionally uses a nearly empty Runnable, making the relative percentage appear larger than the very small absolute overhead.

GC profiling confirms an 8-byte increase for instrumented capturing Runnable lambda instances due to the injected state field. This is the expected heap tradeoff and may be more visible in applications that retain large numbers of Runnable objects.

Motivation

Additional Notes

Contributor Checklist

Jira ticket: [PROJ-IDENT]

@amarziali

Copy link
Copy Markdown
Contributor Author

@DataDog review

@datadog-prod-us1-6

datadog-prod-us1-6 Bot commented Aug 31, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 0.00%
Overall Coverage: 58.74% (-0.07%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: a721063 | Docs | View more details | Give us feedback!

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Datadog Autotest: FAIL

On JDK 8 and JDK 11, the new structure matcher requires a field that does not exist. The lambda transformer does not run, and Runnable lambdas still use wrappers.

Open Bits AI session

🤖 Datadog Autotest · Commit 054841c · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@amarziali
amarziali force-pushed the andrea.marziali/lambda branch from 054841c to 5742c20 Compare August 31, 2026 12:41
@amarziali

Copy link
Copy Markdown
Contributor Author

@DataDog review

@amarziali
amarziali requested a review from mcculls August 31, 2026 13:04

@datadog-prod-us1-6 datadog-prod-us1-6 Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Datadog Autotest: PASS

More details

The PR instruments generated Runnable lambdas so executor propagation keeps task identity, with supported JDK paths and a Graal build guard. This update fixes the earlier JDK 8 and 11 samBase mismatch and adds no new finding; the documented concurrent-reuse limitation remains, and no review finding is open.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Datadog Autotest · Commit 5655a6f · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@amarziali

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-31T13:17:19.502908Z 5655a6f Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@amarziali
amarziali requested a review from bric3 August 31, 2026 13:09
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 5655a6ff32

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@dd-octo-sts

dd-octo-sts Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.01 s 13.96 s [-0.4%; +1.0%] (no difference)
startup:insecure-bank:tracing:Agent 12.94 s 13.10 s [-2.2%; -0.4%] (maybe better)
startup:petclinic:appsec:Agent 16.70 s 17.23 s [-7.5%; +1.3%] (no difference)
startup:petclinic:iast:Agent 17.28 s 17.43 s [-1.7%; -0.1%] (maybe better)
startup:petclinic:profiling:Agent 17.26 s 17.40 s [-1.9%; +0.3%] (no difference)
startup:petclinic:sca:Agent 17.48 s 17.26 s [+0.3%; +2.2%] (maybe worse)
startup:petclinic:tracing:Agent 16.51 s 16.63 s [-1.9%; +0.5%] (no difference)

Commit: a721063d · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant