{{ message }}
Repository navigation
Request carrier-scoped ddprof context storage on JDK 21+ - #11826
Merged
Merged
Conversation
…PROF-15271) The ddprof profiler exposes its OTEL context ThreadContext as a DirectByteBuffer over the carrier thread's native record. When that storage is keyed by the virtual thread (the pre-fix default), a mounted vthread pins to its first carrier: writes land on the wrong carrier after migration, and become a use-after-free once that carrier's OS thread exits. The java-profiler fix (PROF-15271) adds carrier-scoped storage via jdk.internal.misc.CarrierThreadLocal, selected by the ddprof.context.storage.mode system property. Before the profiler is loaded, on JDK 21+ (profiler enabled, non-Windows): - export java.base/jdk.internal.misc to the classloader that loads com.datadoghq.profiler.* so CarrierThreadLocal is reachable, and - set ddprof.context.storage.mode=carrier (only if unset), which requests carrier scoping and makes the profiler fail fast if it cannot honor it. Both actions are inert against ddprof builds that predate carrier support (the property is ignored; the export goes unused), so this is safe to ship ahead of the ddprof version bump — it activates automatically when that lands. Operators opt out with -Dddprof.context.storage.mode=thread (or =auto); we only set the property when unset, so an explicit choice always wins. No separate dd.* config key: the profiler's own system property is the single kill-switch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
🟡 Java Benchmark SLOs — Performance SLO warning (near threshold)
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. |
…dogTracer Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
rkennke
marked this pull request as ready for review
July 1, 2026 12:18
…ROF-15271) The java-profiler side renamed the selector to ddprof.debug.context.storage.mode (ddprof.debug.*, signalling an internal knob). Match the property name we export and set here so the carrier request still takes effect. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jbachorik
reviewed
Jul 6, 2026
jbachorik
reviewed
Jul 6, 2026
jbachorik
reviewed
Jul 6, 2026
jbachorik
reviewed
Jul 6, 2026
jbachorik
requested changes
Jul 6, 2026
jbachorik
left a comment
Contributor
There was a problem hiding this comment.
In general, looking good.
My only concerns are about not entangling the generic Agent with profiler specific configs and quirks.
…he export Per review, don't set the profiler's internal ddprof.debug.context.storage.mode property from tracer code -- it's an implementation detail that may change and the profiler bump activating carrier mode is already in the merge queue. The remaining change is exporting java.base/jdk.internal.misc so java-profiler can reach CarrierThreadLocal.
jbachorik
approved these changes
Jul 6, 2026
Contributor
Author
|
/merge |
kaahos
pushed a commit
that referenced
this pull request
Jul 8, 2026
…11826) profiling: request carrier-scoped ddprof context storage on JDK 21+ (PROF-15271) The ddprof profiler exposes its OTEL context ThreadContext as a DirectByteBuffer over the carrier thread's native record. When that storage is keyed by the virtual thread (the pre-fix default), a mounted vthread pins to its first carrier: writes land on the wrong carrier after migration, and become a use-after-free once that carrier's OS thread exits. The java-profiler fix (PROF-15271) adds carrier-scoped storage via jdk.internal.misc.CarrierThreadLocal, selected by the ddprof.context.storage.mode system property. Before the profiler is loaded, on JDK 21+ (profiler enabled, non-Windows): - export java.base/jdk.internal.misc to the classloader that loads com.datadoghq.profiler.* so CarrierThreadLocal is reachable, and - set ddprof.context.storage.mode=carrier (only if unset), which requests carrier scoping and makes the profiler fail fast if it cannot honor it. Both actions are inert against ddprof builds that predate carrier support (the property is ignored; the export goes unused), so this is safe to ship ahead of the ddprof version bump — it activates automatically when that lands. Operators opt out with -Dddprof.context.storage.mode=thread (or =auto); we only set the property when unset, so an explicit choice always wins. No separate dd.* config key: the profiler's own system property is the single kill-switch. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> docs: clarify profiler context-storage helper runs before installDatadogTracer Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> profiling: align ddprof context-storage property to ddprof.debug.* (PROF-15271) The java-profiler side renamed the selector to ddprof.debug.context.storage.mode (ddprof.debug.*, signalling an internal knob). Match the property name we export and set here so the carrier request still takes effect. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Merge branch 'master' into rkennke/PROF-15271 profiling: drop internal ddprof context-storage property, keep only the export Per review, don't set the profiler's internal ddprof.debug.context.storage.mode property from tracer code -- it's an implementation detail that may change and the profiler bump activating carrier mode is already in the merge queue. The remaining change is exporting java.base/jdk.internal.misc so java-profiler can reach CarrierThreadLocal. [ci: NON_DEFAULT_JVMS] trigger graalvm smoke tests Merge branch 'master' into rkennke/PROF-15271 Merge branch 'master' into rkennke/PROF-15271 Co-authored-by: jbachorik <jaroslav.bachorik@datadoghq.com> Co-authored-by: roman.kennke <roman.kennke@datadoghq.com>
3 tasks done
gh-worker-dd-mergequeue-cf854d Bot
pushed a commit
that referenced
this pull request
Aug 31, 2026
Revert carrier-scoped ddprof context storage export (#11826) java-profiler PR #696 (Phase 3, merged 2026-07-31) deleted the legacy DirectByteBuffer-based context storage entirely (ThreadContext, OtelContextStorage, CarrierThreadLocal usage, etc.), now that dd-trace-java has migrated onto the all-native context API (#11899). The jdk.internal.misc export this PR added exists only to make CarrierThreadLocal reachable, and that type is gone from java-profiler, so the export is now dead weight. ddprof is bundled at 1.49.0, which already includes PR #696. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Merge branch 'master' into rkennke/revert-11826-carrier-context-export Merge branch 'master' into rkennke/revert-11826-carrier-context-export Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What Does This Do
On JDK 21+, before the ddprof profiler is loaded, this exports
java.base/jdk.internal.miscto the classloader that loadscom.datadoghq.profiler.*.Implemented as a small
prepareDatadogProfilerContextStorage(Instrumentation)helper inAgent, invoked inInstallDatadogTracerCallbackright beforeinstallDatadogTracer(which triggers the profiler load, so the export is in place beforeJavaProfileris constructed).Motivation
The profiler exposes its OTEL context
ThreadContextas aDirectByteBufferover the carrier thread's native record — the record the (carrier-bound) sampler reads. When that storage is keyed by the virtual thread (the current default), a mounted vthread pins to whichever carrier it first ran on:ThreadsSMRSupport::free_listunder a Loom workload).The java-profiler fix (PROF-15271) adds carrier-scoped storage via
CarrierThreadLocal, so a mounted vthread always resolves to its current carrier's live record.CarrierThreadLocalis in a non-exported package, hence the export.Additional Notes
ddprof.debug.context.storage.modesystem property from tracer code. Per review, that's an internal ddprof knob that may still change and shouldn't be entangled with the genericAgentclass; the profiler's own version bump (already queued) is what activates carrier mode. This PR is now scoped to just the export, which is harmless to ship regardless of which ddprof version is bundled.isProfilingEnabled() && isDatadogProfilerEnabled() && !isWindows() && isJavaVersionAtLeast(21).JDK9ModuleAccess(internal-api-9) is only referenced under the 21+ guard, so it never loads on Java 8.jdk.internal.miscviaredefineModulefollows existing precedent (AdvancedAgentChecksdoes the same for CDS detection).Contributor Checklist
type:/comp:labelsclose/fixlinking keywords usedJira ticket: PROF-15271
🤖 Generated with Claude Code