Skip to content

Commit d992fcd

Browse files
bm1549claude
andcommitted
Move thread-ownership optimization into OptimizedTagMap
Per review feedback, move the lock-skipping optimization from DDSpanContext into OptimizedTagMap itself. This keeps the optimization invisible to callers — DDSpanContext no longer needs synchronized blocks around tag operations, and developers adding new tag operations don't need to think about locking. OptimizedTagMap now has a volatile Thread ownerThread field. Core methods (getAndSet, getAndRemove, getEntry, putAll, forEach, copy, etc.) check ownership: owner thread skips the lock, non-owner threads synchronize and permanently transition to shared mode. DDSpanContext changes: removed all 27 synchronized(unsafeTags) blocks, added setOwnerThread(current) in constructor, transitionToShared() delegates to TagMap. Also adds @threads(8) JMH benchmark variants and 5 new concurrency tests (mixed read/write, fuzz, value consistency, finish race, concurrent metrics). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d664ab2 commit d992fcd

File tree

7 files changed

+650
-298
lines changed

7 files changed

+650
-298
lines changed

dd-trace-core/src/jmh/java/datadog/trace/core/SpanTagBenchmark.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,43 @@ public AgentSpan setStringTag_crossThread(SharedSpan state) {
8686
return state.span;
8787
}
8888

89+
// Multi-threaded owner-thread benchmarks: 8 threads each working on their own span.
90+
// Measures the macro impact of the optimization when many threads tag spans concurrently,
91+
// the realistic web-server scenario.
92+
93+
@Benchmark
94+
@Threads(8)
95+
@OutputTimeUnit(NANOSECONDS)
96+
public AgentSpan setStringTag_ownerThread_8T(SpanPerThread state) {
97+
state.span.setTag("key", "value");
98+
return state.span;
99+
}
100+
101+
@Benchmark
102+
@Threads(8)
103+
@OutputTimeUnit(NANOSECONDS)
104+
public AgentSpan setIntTag_ownerThread_8T(SpanPerThread state) {
105+
state.span.setTag("key", 42);
106+
return state.span;
107+
}
108+
109+
@Benchmark
110+
@Threads(8)
111+
@OutputTimeUnit(NANOSECONDS)
112+
public AgentSpan setTenTags_ownerThread_8T(SpanPerThread state) {
113+
state.span.setTag("k0", "v0");
114+
state.span.setTag("k1", "v1");
115+
state.span.setTag("k2", "v2");
116+
state.span.setTag("k3", "v3");
117+
state.span.setTag("k4", "v4");
118+
state.span.setTag("k5", 5);
119+
state.span.setTag("k6", 6L);
120+
state.span.setTag("k7", 7.0);
121+
state.span.setTag("k8", true);
122+
state.span.setTag("k9", "v9");
123+
return state.span;
124+
}
125+
89126
@Benchmark
90127
@Threads(1)
91128
@OutputTimeUnit(MICROSECONDS)
@@ -103,4 +140,22 @@ public AgentSpan fullLifecycle_tenTags(SpanPerThread state) {
103140
state.span.finish();
104141
return state.span;
105142
}
143+
144+
@Benchmark
145+
@Threads(8)
146+
@OutputTimeUnit(MICROSECONDS)
147+
public AgentSpan fullLifecycle_tenTags_8T(SpanPerThread state) {
148+
state.span.setTag("k0", "v0");
149+
state.span.setTag("k1", "v1");
150+
state.span.setTag("k2", "v2");
151+
state.span.setTag("k3", "v3");
152+
state.span.setTag("k4", "v4");
153+
state.span.setTag("k5", 5);
154+
state.span.setTag("k6", 6L);
155+
state.span.setTag("k7", 7.0);
156+
state.span.setTag("k8", true);
157+
state.span.setTag("k9", "v9");
158+
state.span.finish();
159+
return state.span;
160+
}
106161
}

0 commit comments

Comments
 (0)