Skip to content

Share parent's PropagationTags for local child spans#11701

Open
dougqh wants to merge 8 commits into
masterfrom
dougqh/ptags-per-segment
Open

Share parent's PropagationTags for local child spans#11701
dougqh wants to merge 8 commits into
masterfrom
dougqh/ptags-per-segment

Conversation

@dougqh

@dougqh dougqh commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

What This Does

Local child spans now share the parent's (trace-level) PropagationTags instead of each allocating a fresh empty(). Collapses N+1 → 1 PropagationTags per N-span trace.

Motivation

CoreTracer span-build allocated propagationTagsFactory.empty() for every local child span (the common in-process case); only the distributed ExtractedContext path reused the parent's. A non-root child's own PropagationTags, however, is never readDDSpanContext.getPropagationTags() routes to the root (getRootSpanContextOrThis().propagationTags). So the per-span empty() was pure allocation waste.

Additional Notes

50s petclinic run under JMeter multi-endpoint load (Zulu 17, alloc JFR):

  • 5,481 DDSpanContext allocations, 311 PTags allocations — 1 PTags per ~17.6 spans (vs 1:1 before)
  • The 311 are all root spans (expected — no parent to share from); child spans share the root's instance
  • PTagsFactory$PTags no longer appears in the top 30 allocating classes (below 0.5% of sampled allocation)

Correctness — gated by a characterization test

First commit adds PropagationTagsChildSpanTest, which pins the load-bearing behavior: a non-root (local child) span still carries the inbound distributed _dd.p.* tags on injection. Both tests pass, confirming this is pure allocation waste, not a latent correctness bug. The test is the gate + safety net for the change.

Safety

  • The ctor's updateTraceIdHighOrderBits stamp is guard-idempotent (if (traceIdHighOrderBits != highOrderBits)) and a no-op on the already-stamped shared root instance (same trace ⇒ same high-order bits).
  • The full dd-trace-core propagation + span-build suite passes (W3C/Datadog extractors+injectors, W3CPropagationTags, OPM round-trip, OrgGuard, CoreSpanBuilderTest, DDSpanContextTest) — 0 failures.

The lastParentId/OPM inject-time mutation race (a transient per-injection value parked in the shared object) is pre-existing — injection already routes to the root's shared instance via getPropagationTags() — so it is a separate concurrency concern, not introduced or worsened by this change. Tracked in #11702.

tag: no release note
tag: ai generated

🤖 Generated with Claude Code

dougqh and others added 2 commits June 22, 2026 17:22
CoreTracer span-build allocates a fresh propagationTagsFactory.empty()
per local child span; only the distributed ExtractedContext path reuses
the parent's. Before optimizing that per-span allocation away, this test
pins the load-bearing behavior: that a non-root (local child) span still
carries the inbound distributed _dd.p.* tags when it injects.

Verdict (both tests pass): it does. DDSpanContext.getPropagationTags()
routes to the root (getRootSpanContextOrThis), so a non-root child's own
propagationTags field is never read for injection. The per-span empty()
is pure allocation waste, not a latent correctness bug.

This test is the gate + safety net for the planned "share the parent's
PropagationTags for local children" allocation fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CoreTracer span-build allocated a fresh propagationTagsFactory.empty()
for every local child span, reused from the parent only on the
distributed ExtractedContext path — N+1 PropagationTags per N-span
trace, N of them needless empties.

A non-root child's own PropagationTags is never read for injection:
DDSpanContext.getPropagationTags() routes to the root
(getRootSpanContextOrThis), confirmed by PropagationTagsChildSpanTest
(inbound _dd.p.* survive child injection). So local children can share
the parent's (trace-level) instance instead of allocating their own,
collapsing N+1 -> 1 per trace.

Safe: the ctor's updateTraceIdHighOrderBits stamp is guard-idempotent
and a no-op on the already-stamped shared root instance (same trace =>
same high-order bits). Full dd-trace-core propagation + span-build
suite passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dougqh dougqh changed the title Characterize non-root span _dd.p.* propagation (gate for PTags per-span alloc fix) Share parent's PropagationTags for local child spans Jun 22, 2026
@datadog-prod-us1-4

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Jun 22, 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.06 s 13.97 s [-0.1%; +1.4%] (no difference)
startup:insecure-bank:tracing:Agent 13.00 s 13.11 s [-1.7%; -0.1%] (maybe better)
startup:petclinic:appsec:Agent 16.91 s 16.78 s [-0.2%; +1.7%] (no difference)
startup:petclinic:iast:Agent 16.93 s 16.97 s [-1.2%; +0.7%] (no difference)
startup:petclinic:profiling:Agent 16.83 s 16.99 s [-2.1%; +0.3%] (no difference)
startup:petclinic:sca:Agent 16.98 s 16.57 s [+1.5%; +3.4%] (significantly worse)
startup:petclinic:tracing:Agent 16.06 s 16.05 s [-0.8%; +0.9%] (no difference)

Commit: e4542743 · 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.

Comment thread dd-trace-core/src/main/java/datadog/trace/core/CoreTracer.java Outdated
@dougqh dougqh marked this pull request as ready for review June 24, 2026 15:30
@dougqh dougqh requested a review from a team as a code owner June 24, 2026 15:30
@dougqh dougqh requested a review from amarziali June 24, 2026 15:30
@dd-octo-sts

dd-octo-sts Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Hi! 👋 Thanks for your pull request! 🎉

To help us review it, please make sure to:

  • Add at least one type, and one component or instrumentation label to the pull request

If you need help, please check our contributing guidelines.

@dd-octo-sts dd-octo-sts Bot added the tag: ai generated Largely based on code generated by an AI or LLM label Jun 24, 2026

@amarziali amarziali left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Doug the intent is ok to me. It looks some tests are still failing

The change landed, so drop the pre-implementation 'open question / planned fix'
framing, the scratch-doc reference (ptags-allocation-findings.md), and the
brittle CoreTracer line numbers. State what it guards: local children share the
root's PropagationTags, and reads route to the root, so a non-root span still
injects the inbound _dd.p.* tags.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dougqh dougqh added tag: performance Performance related changes type: enhancement Enhancements and improvements comp: context propagation Trace context propagation labels Jun 29, 2026
The master merge renamed AgentSpan.context() to spanContext(); update the
two call sites so :dd-trace-core:compileTestJava passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dougqh

dougqh commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Doug the intent is ok to me. It looks some tests are still failing

@amarziali Thanks. It looks like a rename got merged in last week that broke the tests that I ported from Groovy. It should be better now.

@dougqh dougqh added this to the 1.64.0 milestone Jun 30, 2026
@dougqh dougqh requested a review from amarziali June 30, 2026 17:44
@dougqh

dougqh commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Synced with master (the branch was ~57 commits behind) and confirmed :dd-trace-core compiles + PropagationTags* tests pass locally on the merge. The reds you saw were the flaky parametric/system-tests jobs, not this change — a fresh run is underway. Targeted at the 1.64.0 milestone. 🙏

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

Labels

comp: context propagation Trace context propagation tag: ai generated Largely based on code generated by an AI or LLM tag: performance Performance related changes type: enhancement Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants