Skip to content

Pre-merge immutable tag sources to reduce span creation overhead#11118

Closed
dougqh wants to merge 1 commit intomasterfrom
dougqh/pre-merge-tag-templates
Closed

Pre-merge immutable tag sources to reduce span creation overhead#11118
dougqh wants to merge 1 commit intomasterfrom
dougqh/pre-merge-tag-templates

Conversation

@dougqh
Copy link
Copy Markdown
Contributor

@dougqh dougqh commented Apr 15, 2026

Summary

  • Pre-merges mergedTracerTags + localRootSpanTags into a frozen preMergedRootSpanBase template at ConfigSnapshot creation time (once at init / remote config update, not per-span)
  • Initializes each span's TagMap via tagBase.copy() from the template instead of TagMap.create() + 5 separate setAllTags() calls
  • Root spans: 5 setAllTags + removeTag(VERSION) reduced to 3 setAllTags
  • Child spans: 2 effective setAllTags reduced to 1
  • Strips Tags.VERSION at merge time instead of per-span
  • Includes TagMergeBenchmark JMH benchmark

Motivation: CoreTracer.buildSpanContext() consumed ~7% of foreground CPU in a 16-thread span creation stress test (6% in buildSpanContext itself + 1% in BucketGroup._cloneEntries). Two of the five setAllTags() calls used frozen/immutable tag maps that never change between spans — redundantly re-merged on every span.

Benchmark results (8 threads, throughput)

TagMergeBenchmark:

Benchmark Score Units
rootSpan 0.073 ± 0.001 ops/us
childSpan 0.040 ± 0.001 ops/us

CoreTracerBenchmark (end-to-end):

Benchmark Score Units
startSpan 0.078 ± 0.001 ops/us
buildSpan 0.079 ± 0.001 ops/us
singleSpanBuilder 0.071 ± 0.001 ops/us

Test plan

  • All *CoreTracer* tests pass (52/52)
  • All *DDSpanContext* tests pass
  • All *DDSpan*, *SpanTag*, *TagInterceptor*, *DynamicConfig* tests pass
  • Run full CI suite
  • Verify with span creation stress test profiling

🤖 Generated with Claude Code

…creation

buildSpanContext() called setAllTags() 5 times per span, with two of
those sources (mergedTracerTags, localRootSpanTags) being immutable
across all spans. Every span redundantly re-merged them plus ran a
per-span removeTag(Tags.VERSION).

This change pre-merges those frozen tag sources into a
preMergedRootSpanBase template at ConfigSnapshot creation time and
initializes each span's TagMap via copy from the template. Root spans
go from 5 setAllTags + removeTag to 3 setAllTags; child spans go from
2 effective setAllTags to 1.

tag: no release note
tag: ai generated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@dougqh
Copy link
Copy Markdown
Contributor Author

dougqh commented Apr 16, 2026

After running a before / after comparison, this change yields negligible real gains.
I think there is room to significantly improve the performance span creation around tags, but that will be through moving common tags into a TraceSegment and/or introducing a SpanPrototype so up front work can be reused more efficiently.

@dougqh dougqh closed this Apr 16, 2026
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