Skip to content

Move rarely read span context fields onto the trace - #13032

Draft
dougqh wants to merge 3 commits into
dougqh/uncached-unique-tag-valuesfrom
dougqh/cold-span-fields-off-context
Draft

dougqh wants to merge 3 commits into
dougqh/uncached-unique-tag-valuesfrom
dougqh/cold-span-fields-off-context

Conversation

@dougqh

@dougqh dougqh commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

What Does This Do

Moves four rarely read fields off DDSpanContext, which exists once per span:

field now read from read when
injectBaggageAsTags the tracer, through the collector serialization
injectLinksAsTags the tracer, through the collector serialization
disableSamplingMechanismValidation the tracer, through the collector a sampling decision fails validation
w3cBaggage the trace collector, set by the local root serialization, for the local root only (as before)

The three settings were always the tracer's own final fields, copied into every span. The DDSpanContext constructors lose those three parameters. The 21-argument variant became identical to the 19-argument one, so it is removed.

Motivation

TraceSegment work (APMLP-2049): per-trace and per-tracer state moves off the per-span object.

JOL shallow sizes (JDK 17, compressed oops):

class before after
DDSpanContext 128 B 120 B
PendingTrace 128 B 128 B
StreamingTraceCollector 72 B 72 B

DDSpanContext was full: 128 B with a 1-byte gap. Removing any single 4-byte reference would have saved nothing. These four fields free 7 bytes, which together with the gap reaches the next 8-byte boundary down. w3cBaggage fits in the collectors' existing padding, so this is −8 B per span with no per-trace cost.

Hops. No field read on span creation, tagging or activation moves:

  • tagInterceptor, profilingContextIntegration and the trace id stay on the span context.
  • The moved fields are read only on the serializer thread, or when a decision fails validation.

That was deliberate, because an extra dependent load on a hot path could cost more than the 8 bytes save. The trace id can move later, together with a primitive trace-id view, where its hop can be measured on its own.

Additional Notes

  • Behavior is unchanged in production, where every span already carried its tracer's values.
  • DDSpanSerializationTest's baggage cases set injectBaggageAsTags on the tracer instead of on each context. The other direct constructions passed the tracer defaults.
  • CompoundExtractionGoldenTest passes.
  • Tests: the full dd-trace-core suite passes locally, except for 2 Docker-dependent TracerConnectionReliabilityTest cases and the order-dependent PendingTraceBufferTest.testingTracerFlareDumpWithMultipleTraces. The OpenTracing and OpenTelemetry TypeConverterTests pass.

Stacked: master ← #13008 ← #13000 ← #13009 ← #13010 ← #13015 ← #13028 ← #13029 ← this PR.

🤖 Generated with Claude Code

@dougqh dougqh added comp: core Tracer core tag: performance Performance related changes tag: no release notes Changes to exclude from release notes type: refactoring tag: ai generated Largely based on code generated by an AI or LLM labels Oct 23, 2026
@datadog-datadog-prod-us1-2

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Oct 23, 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 13.95 s 13.84 s [+0.0%; +1.5%] (maybe worse)
startup:insecure-bank:tracing:Agent 12.94 s 12.90 s [-0.4%; +1.0%] (no difference)
startup:petclinic:appsec:Agent 17.16 s 17.10 s [-0.7%; +1.3%] (no difference)
startup:petclinic:iast:Agent 17.01 s 17.02 s [-0.9%; +0.8%] (no difference)
startup:petclinic:profiling:Agent 16.78 s 16.80 s [-1.2%; +0.9%] (no difference)
startup:petclinic:sca:Agent 17.08 s 16.86 s [+0.6%; +2.0%] (maybe worse)
startup:petclinic:tracing:Agent 16.27 s 16.12 s [-0.0%; +1.9%] (no difference)

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

dougqh and others added 3 commits October 23, 2026 16:17
Every DDSpanContext held three tracer settings, read only at
serialization or when a sampling decision fails validation, and the W3C
baggage extracted for the local root. The settings are now read from
the tracer and the baggage from the trace collector, taking
DDSpanContext from 128 to 120 bytes. The trace collectors keep their
size, and no field read on span creation, tagging or activation moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dougqh
dougqh force-pushed the dougqh/uncached-unique-tag-values branch from 1173ac0 to 90533c3 Compare October 23, 2026 20:26
@dougqh
dougqh force-pushed the dougqh/cold-span-fields-off-context branch from 4e4da0d to 55176e3 Compare October 23, 2026 20:26

This branch has not been deployed

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

Labels

comp: core Tracer core tag: ai generated Largely based on code generated by an AI or LLM tag: no release notes Changes to exclude from release notes tag: performance Performance related changes type: refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant