-
Notifications
You must be signed in to change notification settings - Fork 314
Reuse SpanBuilder within a Thread #9537
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Initial performance experiment The idea is to store a CoreSpanBuilder per thread, since usually only SpanBuilder is in use at a given time per thread -- and CoreSpanBuilder isn't thread safe This simple change provides a giant boost in small heaps Improving Spring petclinic throughput from -39% to -19% with 80m heap
Hi! 👋 Thanks for your pull request! 🎉 To help us review it, please make sure to:
If you need help, please check our contributing guidelines. |
🎯 Code Coverage 🔗 Commit SHA: 054485a | Docs | Was this helpful? Give us feedback! |
BenchmarksStartupParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 59 metrics, 6 unstable metrics. Startup time reports for insecure-bankgantt
title insecure-bank - global startup overhead: candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.031 s) : 0, 1030894
Total [baseline] (8.791 s) : 0, 8791101
Agent [candidate] (1.021 s) : 0, 1020594
Total [candidate] (8.677 s) : 0, 8677273
section iast
Agent [baseline] (1.157 s) : 0, 1156686
Total [baseline] (9.278 s) : 0, 9277857
Agent [candidate] (1.151 s) : 0, 1150976
Total [candidate] (9.355 s) : 0, 9354802
gantt
title insecure-bank - break down per module: candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.498 ms) : 0, 1498
crashtracking [candidate] (1.46 ms) : 0, 1460
BytebuddyAgent [baseline] (701.501 ms) : 0, 701501
BytebuddyAgent [candidate] (694.373 ms) : 0, 694373
GlobalTracer [baseline] (245.755 ms) : 0, 245755
GlobalTracer [candidate] (243.386 ms) : 0, 243386
AppSec [baseline] (33.293 ms) : 0, 33293
AppSec [candidate] (32.435 ms) : 0, 32435
Debugger [baseline] (6.688 ms) : 0, 6688
Debugger [candidate] (6.481 ms) : 0, 6481
Remote Config [baseline] (713.347 µs) : 0, 713
Remote Config [candidate] (694.441 µs) : 0, 694
Telemetry [baseline] (9.513 ms) : 0, 9513
Telemetry [candidate] (9.338 ms) : 0, 9338
Flare Poller [baseline] (10.502 ms) : 0, 10502
Flare Poller [candidate] (11.201 ms) : 0, 11201
section iast
crashtracking [baseline] (1.505 ms) : 0, 1505
crashtracking [candidate] (1.487 ms) : 0, 1487
BytebuddyAgent [baseline] (819.315 ms) : 0, 819315
BytebuddyAgent [candidate] (815.201 ms) : 0, 815201
GlobalTracer [baseline] (232.404 ms) : 0, 232404
GlobalTracer [candidate] (232.207 ms) : 0, 232207
AppSec [baseline] (35.481 ms) : 0, 35481
AppSec [candidate] (33.793 ms) : 0, 33793
Debugger [baseline] (6.205 ms) : 0, 6205
Debugger [candidate] (6.097 ms) : 0, 6097
Remote Config [baseline] (606.02 µs) : 0, 606
Remote Config [candidate] (598.719 µs) : 0, 599
Telemetry [baseline] (8.764 ms) : 0, 8764
Telemetry [candidate] (8.677 ms) : 0, 8677
Flare Poller [baseline] (4.171 ms) : 0, 4171
Flare Poller [candidate] (4.132 ms) : 0, 4132
IAST [baseline] (26.737 ms) : 0, 26737
IAST [candidate] (27.236 ms) : 0, 27236
Startup time reports for petclinicgantt
title petclinic - global startup overhead: candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.017 s) : 0, 1016578
Total [baseline] (10.765 s) : 0, 10764670
Agent [candidate] (1.023 s) : 0, 1023285
Total [candidate] (10.705 s) : 0, 10704667
section appsec
Agent [baseline] (1.194 s) : 0, 1194228
Total [baseline] (11.031 s) : 0, 11031390
Agent [candidate] (1.193 s) : 0, 1193237
Total [candidate] (10.988 s) : 0, 10988333
section iast
Agent [baseline] (1.151 s) : 0, 1151288
Total [baseline] (11.006 s) : 0, 11006240
Agent [candidate] (1.152 s) : 0, 1152385
Total [candidate] (11.054 s) : 0, 11053612
section profiling
Agent [baseline] (1.169 s) : 0, 1169030
Total [baseline] (11.111 s) : 0, 11110782
Agent [candidate] (1.161 s) : 0, 1161237
Total [candidate] (10.974 s) : 0, 10974114
gantt
title petclinic - break down per module: candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.459 ms) : 0, 1459
crashtracking [candidate] (1.459 ms) : 0, 1459
BytebuddyAgent [baseline] (692.726 ms) : 0, 692726
BytebuddyAgent [candidate] (696.627 ms) : 0, 696627
GlobalTracer [baseline] (242.043 ms) : 0, 242043
GlobalTracer [candidate] (244.102 ms) : 0, 244102
AppSec [baseline] (32.457 ms) : 0, 32457
AppSec [candidate] (32.499 ms) : 0, 32499
Debugger [baseline] (6.447 ms) : 0, 6447
Debugger [candidate] (6.531 ms) : 0, 6531
Remote Config [baseline] (701.827 µs) : 0, 702
Remote Config [candidate] (696.033 µs) : 0, 696
Telemetry [baseline] (9.404 ms) : 0, 9404
Telemetry [candidate] (9.443 ms) : 0, 9443
Flare Poller [baseline] (10.127 ms) : 0, 10127
Flare Poller [candidate] (10.709 ms) : 0, 10709
section appsec
crashtracking [baseline] (1.467 ms) : 0, 1467
crashtracking [candidate] (1.456 ms) : 0, 1456
BytebuddyAgent [baseline] (717.369 ms) : 0, 717369
BytebuddyAgent [candidate] (715.159 ms) : 0, 715159
GlobalTracer [baseline] (234.627 ms) : 0, 234627
GlobalTracer [candidate] (236.148 ms) : 0, 236148
AppSec [baseline] (175.708 ms) : 0, 175708
AppSec [candidate] (175.338 ms) : 0, 175338
Debugger [baseline] (6.107 ms) : 0, 6107
Debugger [candidate] (6.118 ms) : 0, 6118
Remote Config [baseline] (635.232 µs) : 0, 635
Remote Config [candidate] (634.52 µs) : 0, 635
Telemetry [baseline] (8.422 ms) : 0, 8422
Telemetry [candidate] (8.48 ms) : 0, 8480
Flare Poller [baseline] (3.927 ms) : 0, 3927
Flare Poller [candidate] (3.979 ms) : 0, 3979
IAST [baseline] (24.832 ms) : 0, 24832
IAST [candidate] (24.833 ms) : 0, 24833
section iast
crashtracking [baseline] (1.474 ms) : 0, 1474
crashtracking [candidate] (1.453 ms) : 0, 1453
BytebuddyAgent [baseline] (815.653 ms) : 0, 815653
BytebuddyAgent [candidate] (815.825 ms) : 0, 815825
GlobalTracer [baseline] (231.427 ms) : 0, 231427
GlobalTracer [candidate] (232.401 ms) : 0, 232401
AppSec [baseline] (35.165 ms) : 0, 35165
AppSec [candidate] (34.851 ms) : 0, 34851
Debugger [baseline] (6.143 ms) : 0, 6143
Debugger [candidate] (6.214 ms) : 0, 6214
Remote Config [baseline] (618.049 µs) : 0, 618
Remote Config [candidate] (616.482 µs) : 0, 616
Telemetry [baseline] (8.705 ms) : 0, 8705
Telemetry [candidate] (8.795 ms) : 0, 8795
Flare Poller [baseline] (4.267 ms) : 0, 4267
Flare Poller [candidate] (4.237 ms) : 0, 4237
IAST [baseline] (26.291 ms) : 0, 26291
IAST [candidate] (26.435 ms) : 0, 26435
section profiling
crashtracking [baseline] (1.447 ms) : 0, 1447
crashtracking [candidate] (1.412 ms) : 0, 1412
BytebuddyAgent [baseline] (727.133 ms) : 0, 727133
BytebuddyAgent [candidate] (719.352 ms) : 0, 719352
GlobalTracer [baseline] (219.028 ms) : 0, 219028
GlobalTracer [candidate] (218.629 ms) : 0, 218629
AppSec [baseline] (32.574 ms) : 0, 32574
AppSec [candidate] (32.253 ms) : 0, 32253
Debugger [baseline] (6.491 ms) : 0, 6491
Debugger [candidate] (6.48 ms) : 0, 6480
Remote Config [baseline] (791.872 µs) : 0, 792
Remote Config [candidate] (757.151 µs) : 0, 757
Telemetry [baseline] (16.069 ms) : 0, 16069
Telemetry [candidate] (16.145 ms) : 0, 16145
Flare Poller [baseline] (4.152 ms) : 0, 4152
Flare Poller [candidate] (4.176 ms) : 0, 4176
ProfilingAgent [baseline] (107.698 ms) : 0, 107698
ProfilingAgent [candidate] (108.613 ms) : 0, 108613
Profiling [baseline] (108.968 ms) : 0, 108968
Profiling [candidate] (109.891 ms) : 0, 109891
LoadParameters
See matching parameters
SummaryFound 4 performance improvements and 2 performance regressions! Performance is the same for 6 metrics, 12 unstable metrics.
Request duration reports for insecure-bankgantt
title insecure-bank - request duration [CI 0.99] : candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section baseline
no_agent (4.267 ms) : 4211, 4324
. : milestone, 4267,
iast (9.973 ms) : 9801, 10145
. : milestone, 9973,
iast_FULL (14.411 ms) : 14121, 14701
. : milestone, 14411,
iast_GLOBAL (10.717 ms) : 10525, 10908
. : milestone, 10717,
profiling (9.212 ms) : 9042, 9382
. : milestone, 9212,
tracing (7.87 ms) : 7757, 7984
. : milestone, 7870,
section candidate
no_agent (4.359 ms) : 4311, 4407
. : milestone, 4359,
iast (9.551 ms) : 9388, 9714
. : milestone, 9551,
iast_FULL (14.186 ms) : 13908, 14464
. : milestone, 14186,
iast_GLOBAL (11.314 ms) : 11103, 11526
. : milestone, 11314,
profiling (8.498 ms) : 8370, 8627
. : milestone, 8498,
tracing (8.22 ms) : 8100, 8340
. : milestone, 8220,
Request duration reports for petclinicgantt
title petclinic - request duration [CI 0.99] : candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section baseline
no_agent (36.621 ms) : 36322, 36920
. : milestone, 36621,
appsec (48.344 ms) : 47913, 48776
. : milestone, 48344,
code_origins (45.164 ms) : 44765, 45562
. : milestone, 45164,
iast (45.342 ms) : 44956, 45728
. : milestone, 45342,
profiling (51.182 ms) : 50702, 51662
. : milestone, 51182,
tracing (45.659 ms) : 45268, 46049
. : milestone, 45659,
section candidate
no_agent (36.505 ms) : 36217, 36793
. : milestone, 36505,
appsec (49.345 ms) : 48909, 49780
. : milestone, 49345,
code_origins (44.866 ms) : 44486, 45245
. : milestone, 44866,
iast (45.015 ms) : 44624, 45405
. : milestone, 45015,
profiling (49.374 ms) : 48935, 49812
. : milestone, 49374,
tracing (43.529 ms) : 43152, 43906
. : milestone, 43529,
DacapoParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 11 metrics, 1 unstable metrics. Execution time for biojavagantt
title biojava - execution time [CI 0.99] : candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section baseline
no_agent (15.532 s) : 15532000, 15532000
. : milestone, 15532000,
appsec (14.99 s) : 14990000, 14990000
. : milestone, 14990000,
iast (18.618 s) : 18618000, 18618000
. : milestone, 18618000,
iast_GLOBAL (18.016 s) : 18016000, 18016000
. : milestone, 18016000,
profiling (15.035 s) : 15035000, 15035000
. : milestone, 15035000,
tracing (15.372 s) : 15372000, 15372000
. : milestone, 15372000,
section candidate
no_agent (15.292 s) : 15292000, 15292000
. : milestone, 15292000,
appsec (15.281 s) : 15281000, 15281000
. : milestone, 15281000,
iast (18.43 s) : 18430000, 18430000
. : milestone, 18430000,
iast_GLOBAL (17.597 s) : 17597000, 17597000
. : milestone, 17597000,
profiling (15.615 s) : 15615000, 15615000
. : milestone, 15615000,
tracing (15.283 s) : 15283000, 15283000
. : milestone, 15283000,
Execution time for tomcatgantt
title tomcat - execution time [CI 0.99] : candidate=1.54.0-SNAPSHOT~054485ac66, baseline=1.55.0-SNAPSHOT~4737935c38
dateFormat X
axisFormat %s
section baseline
no_agent (1.48 ms) : 1468, 1491
. : milestone, 1480,
appsec (3.744 ms) : 3525, 3963
. : milestone, 3744,
iast (2.214 ms) : 2151, 2277
. : milestone, 2214,
iast_GLOBAL (2.255 ms) : 2190, 2319
. : milestone, 2255,
profiling (2.085 ms) : 2032, 2138
. : milestone, 2085,
tracing (2.036 ms) : 1986, 2086
. : milestone, 2036,
section candidate
no_agent (1.483 ms) : 1472, 1495
. : milestone, 1483,
appsec (3.773 ms) : 3549, 3997
. : milestone, 3773,
iast (2.211 ms) : 2147, 2275
. : milestone, 2211,
iast_GLOBAL (2.261 ms) : 2197, 2325
. : milestone, 2261,
profiling (2.063 ms) : 2011, 2114
. : milestone, 2063,
tracing (2.047 ms) : 1997, 2097
. : milestone, 2047,
|
public static final String OPTIMIZED_MAP_ENABLED = "optimized.map.enabled"; | ||
public static final String TAG_NAME_UTF8_CACHE_SIZE = "tag.name.utf8.cache.size"; | ||
public static final String TAG_VALUE_UTF8_CACHE_SIZE = "tag.value.utf8.cache.size"; | ||
public static final String SPAN_BUILDER_REUSE_ENABLED = "span.builder.reuse.enabled"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this is best class to be placing these in. Or if this is the proper namespace. dd.trace... might be better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree dd.trace
prefix fits better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❔ question: Quick question for my understanding: how is that supposed to work with manual tracing API? (DD or OTel)
Let’s say:
var spanBuilder = tracer.spanBuilder("span1");
// …
var span = tracer.spanBuilder("span2").startSpan();
// …
spanBuilder.setAttribute("key", "value").startSpan();
The second startSpan()
call will start the span with the wrong name ("span2" instead of "span1") and there is nothing we can do on the API to prevent such use case.
The solution that I put in place yesterday was that I track whether or not the SpanBuilder is "in-use". A SpanBuilder is considered "in -use" from the point that it is So So the 'in-use' check solves the case mentioned in the original comment. You'll still get two distinct SpanBuilders. But there are still other cases that worry me, specifically, I'm worried that you can actually call build on the SpanBuilder multiple times. That's not idiomatic, but it would probably work today. My solution doesn't handle that. I don't believe our own instrumentation produces multiple Spans per builder today, so we could solve the problem by having two slightly different sets of rules: one for automatic and one for manual. We can accomplish that by having two sets of methods: one set that will reuse SpanBuilders that we use in automatic instrumentation, and another set that always creates a new SpanBuilder that we use in manual instrumentation (and the OTel bridge). UPDATE: buildSpan can maintain the existing semantics including allowing building multiple spans. That does mean that we have to update some instrumentation to get the full benefit, but at least, we know the change is safe. |
Refactored code, so tests work regardless of Config
…ace-java into dougqh/spanbuilder-pooling
To avoid breaking any potential code that builds multiple spans from the same SpanBuilder, updated the SpanBuilder pooling approach Introduced a new method singleSpanBuilder which can build one and only one span, this method can be used by automatic instrumentation as an optimization. singleSpanBuilder is now used inside the startSpan convenience methods, since we know they only build and return one span. Any automatic instrumentation using startSpan gets the optimization for free. buildSpan maintains its original semantics, so all existing continues to work as is.
…ace-java into dougqh/spanbuilder-pooling
In a microbenchmark, buildSpan was performing worse than previously. To address, that shortcoming and to clean-up the code... Made CoreSpanBuilder abstract and introduced two child classes: MultiSpanBuilder and ReusableSingleSpanBuilder MultiSpanBuilder is used by buildSpan ReusableSingleSpanBuilder is used by singleSpanBuilder / startSpan (indirectly)
static final class ReusableSingleSpanBuilderThreadLocalCache | ||
extends ThreadLocal<ReusableSingleSpanBuilder> { | ||
private final CoreTracer tracer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious if it will be OK on latest JDKs with virtual threads?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ThreadLocal will still work with virtual threads but the main issue is the related memory leak as we never remove entries. And CoreSpanBuilder
isn't a small object:
https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-68216B85-7B43-423E-91BA-11489B1ACA61:~:text=the%20connection%20pool.-,Don%27t%20Cache%20Expensive%20Reusable%20Objects%20in%20Thread%2DLocal%20Variables,-Virtual%20threads%20support
Added an init instead of calling reset when creating a new ReusableSingleSpanBuilder Added some asserts to catch misuse of the API
Adding ThreadUtils class that enables checking if Threads are virtual threads
internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java
Show resolved
Hide resolved
internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java
Show resolved
Hide resolved
internal-api/src/main/java/datadog/trace/bootstrap/instrumentation/api/AgentTracer.java
Outdated
Show resolved
Hide resolved
} | ||
} | ||
|
||
static final class MultiSpanBuilder extends CoreSpanBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Some javadoc
/**
* A span builder that creates a new instance for each span.
*
* <p>This builder is used when span builder reuse is disabled or when building spans that may
* have multiple children. Each call to {@link #buildSpan()} creates a fresh span instance
* without any state reuse.
*/
static final class MultiSpanBuilder extends CoreSpanBuilder {
} | ||
} | ||
|
||
static final class ReusableSingleSpanBuilder extends CoreSpanBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Some javadoc suggestions
static final class ReusableSingleSpanBuilder extends CoreSpanBuilder { | |
/** | |
* A reusable span builder optimized for building single spans with no children. | |
* | |
* <p>This builder is pooled in a thread-local cache to reduce allocation overhead for | |
* high-frequency span creation. | |
* | |
* <p><b>Virtual thread handling:</b> Virtual threads do not use thread-local caching because | |
* they are created and destroyed frequently. Instead, a new builder instance is allocated for | |
* each span created on a virtual thread. | |
* | |
* @see CoreTracer#singleSpanBuilder(String, CharSequence) | |
* @see ReusableSingleSpanBuilderThreadLocalCache | |
*/ | |
static final class ReusableSingleSpanBuilder extends CoreSpanBuilder { |
|
||
@Override | ||
public CoreSpanBuilder ignoreActiveSpan() { | ||
public final CoreSpanBuilder ignoreActiveSpan() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: Just noted that some method are private
, and may not need to be final
, but I understand your perspective on anticipating changes here since the class is not final
. Also it aligns with other methods. So feel free to dismiss :)
this.instrumentationName = instrumentationName; | ||
this.operationName = operationName; | ||
|
||
if (this.tagLedger != null) this.tagLedger.reset(); | ||
this.timestampMicro = 0L; | ||
this.parent = null; | ||
this.serviceName = null; | ||
this.resourceName = null; | ||
this.errorFlag = false; | ||
this.spanType = null; | ||
this.ignoreScope = false; | ||
this.builderRequestContextDataAppSec = null; | ||
this.builderRequestContextDataIast = null; | ||
this.builderCiVisibilityContextData = null; | ||
this.links = null; | ||
this.spanId = 0L; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thought: Is there way to test nothing go forbidden here if CoreSpanBuilder
gets a new field ? Maybe via some tests ?
Co-authored-by: Brice Dutheil <[email protected]>
…tion/api/AgentTracer.java Co-authored-by: Brice Dutheil <[email protected]>
Co-authored-by: Brice Dutheil <[email protected]>
Fixing assertion with blackhole test Moved the inUse tracking to start (rather than buildSpan)
- exposed bug with not setting inUse in init
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just left several minor comments.
|
||
@Test | ||
public void isVirtualThread_true() throws InterruptedException { | ||
if (!ThreadUtils.supportsVirtualThreads()) return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to use JUnit assume
here? Test will be marked as skipped.
MethodHandle h_startVThread; | ||
try { | ||
h_startVThread = | ||
MethodHandles.lookup() | ||
.findStatic( | ||
Thread.class, | ||
"startVirtualThread", | ||
MethodType.methodType(Thread.class, Runnable.class)); | ||
} catch (NoSuchMethodException | IllegalAccessException e) { | ||
throw new IllegalStateException(e); | ||
} | ||
|
||
try { | ||
return (Thread) h_startVThread.invoke(runnable); | ||
} catch (Throwable e) { | ||
throw new IllegalStateException(e); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a very minor nitpick: I guess we can simplify code by removing try/catch
?
We already checking for V-threads before calling this function.
|
||
@Override | ||
public CoreSpanBuilder withTag(final String tag, final Number number) { | ||
public final CoreSpanBuilder withTag(final String tag, final Number number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still curious why we are using final
so often? It will force Java compiler to produce more optimal code?
Also noticed in build logs on CI:
|
What Does This Do
This changes reuses a SpanBuilder within a thread.
Motivation
SpanBuilders are one of the major causes of allocation within the client library, but typically only one SpanBuilder is needed at a time in a thread. By reseting and reusing the same SpanBuilder, tracing allocation can be reduced significantly.
By reducing allocation, the garbage collector needs to run less frequently improving the maximum sustainable throughput of the host application. In local tests with Spring Petclinic, this reduces the throughput penalty with tiny heaps (<= 80m) significantly from -40% to -20%. On larger heaps, the gain is more modest, since garbage collector has less of an impact on the application.
In this initial version, the thread local cache isn't used in virtual threads. This restriction exists to avoid creating more memory churn than we save, since virtual threads are created more often than regular threads.