Reduce per-query allocations in SQLCommenter.inject()#11154
Reduce per-query allocations in SQLCommenter.inject()#11154
Conversation
Optimize the hot path of SQLCommenter.inject() which runs on every JDBC statement execution when DBM is enabled: - Avoid getFirstWord() substring allocation by using index-based firstWordStartsWith() and firstWordEqualsIgnoreCase() that check the first word in-place via String.regionMatches() - Eliminate hasDDComment() substring allocation by adding a range-based containsTraceComment(sql, fromIndex, toIndex) overload that searches for trace comment markers directly in the SQL string without extracting a substring - Pre-compute marker strings (e.g. "ddps=", "dddbs=") as static finals instead of concatenating them on every containsTraceComment() call - Cache the static comment string (everything except traceParent and peerService) per (dbService, hostname, dbName, Config) in a ConcurrentHashMap inside SharedDBCommenter, so repeated calls in DBM "static" mode skip URLEncoder.encode() and StringBuilder work Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
BenchmarksStartupParameters
See matching parameters
SummaryFound 0 performance improvements and 0 performance regressions! Performance is the same for 60 metrics, 11 unstable metrics. Startup time reports for insecure-bankgantt
title insecure-bank - global startup overhead: candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.057 s) : 0, 1056613
Total [baseline] (8.862 s) : 0, 8861946
Agent [candidate] (1.052 s) : 0, 1052044
Total [candidate] (8.822 s) : 0, 8821744
section iast
Agent [baseline] (1.219 s) : 0, 1219338
Total [baseline] (9.556 s) : 0, 9555672
Agent [candidate] (1.222 s) : 0, 1222115
Total [candidate] (9.531 s) : 0, 9531333
gantt
title insecure-bank - break down per module: candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.233 ms) : 0, 1233
crashtracking [candidate] (1.225 ms) : 0, 1225
BytebuddyAgent [baseline] (634.41 ms) : 0, 634410
BytebuddyAgent [candidate] (631.202 ms) : 0, 631202
AgentMeter [baseline] (29.475 ms) : 0, 29475
AgentMeter [candidate] (29.404 ms) : 0, 29404
GlobalTracer [baseline] (247.455 ms) : 0, 247455
GlobalTracer [candidate] (247.531 ms) : 0, 247531
AppSec [baseline] (32.362 ms) : 0, 32362
AppSec [candidate] (32.416 ms) : 0, 32416
Debugger [baseline] (58.728 ms) : 0, 58728
Debugger [candidate] (58.993 ms) : 0, 58993
Remote Config [baseline] (588.956 µs) : 0, 589
Remote Config [candidate] (587.518 µs) : 0, 588
Telemetry [baseline] (7.929 ms) : 0, 7929
Telemetry [candidate] (8.707 ms) : 0, 8707
Flare Poller [baseline] (8.256 ms) : 0, 8256
Flare Poller [candidate] (5.891 ms) : 0, 5891
section iast
crashtracking [baseline] (1.235 ms) : 0, 1235
crashtracking [candidate] (1.22 ms) : 0, 1220
BytebuddyAgent [baseline] (797.18 ms) : 0, 797180
BytebuddyAgent [candidate] (800.57 ms) : 0, 800570
AgentMeter [baseline] (11.526 ms) : 0, 11526
AgentMeter [candidate] (11.545 ms) : 0, 11545
GlobalTracer [baseline] (238.226 ms) : 0, 238226
GlobalTracer [candidate] (238.681 ms) : 0, 238681
IAST [baseline] (25.796 ms) : 0, 25796
IAST [candidate] (25.795 ms) : 0, 25795
AppSec [baseline] (32.084 ms) : 0, 32084
AppSec [candidate] (31.873 ms) : 0, 31873
Debugger [baseline] (63.429 ms) : 0, 63429
Debugger [candidate] (63.061 ms) : 0, 63061
Remote Config [baseline] (541.18 µs) : 0, 541
Remote Config [candidate] (530.288 µs) : 0, 530
Telemetry [baseline] (9.565 ms) : 0, 9565
Telemetry [candidate] (9.157 ms) : 0, 9157
Flare Poller [baseline] (3.616 ms) : 0, 3616
Flare Poller [candidate] (3.566 ms) : 0, 3566
Startup time reports for petclinicgantt
title petclinic - global startup overhead: candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.073 s) : 0, 1073421
Total [baseline] (11.075 s) : 0, 11074963
Agent [candidate] (1.055 s) : 0, 1054654
Total [candidate] (10.987 s) : 0, 10986795
section appsec
Agent [baseline] (1.255 s) : 0, 1254779
Total [baseline] (10.968 s) : 0, 10967756
Agent [candidate] (1.247 s) : 0, 1246505
Total [candidate] (11.028 s) : 0, 11027630
section iast
Agent [baseline] (1.224 s) : 0, 1224051
Total [baseline] (11.287 s) : 0, 11286855
Agent [candidate] (1.234 s) : 0, 1233781
Total [candidate] (11.334 s) : 0, 11334330
section profiling
Agent [baseline] (1.2 s) : 0, 1200026
Total [baseline] (11.228 s) : 0, 11227600
Agent [candidate] (1.186 s) : 0, 1185506
Total [candidate] (10.939 s) : 0, 10939178
gantt
title petclinic - break down per module: candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.24 ms) : 0, 1240
crashtracking [candidate] (1.215 ms) : 0, 1215
BytebuddyAgent [baseline] (642.341 ms) : 0, 642341
BytebuddyAgent [candidate] (631.317 ms) : 0, 631317
AgentMeter [baseline] (30.058 ms) : 0, 30058
AgentMeter [candidate] (29.475 ms) : 0, 29475
GlobalTracer [baseline] (251.852 ms) : 0, 251852
GlobalTracer [candidate] (248.27 ms) : 0, 248270
AppSec [baseline] (32.886 ms) : 0, 32886
AppSec [candidate] (32.351 ms) : 0, 32351
Debugger [baseline] (60.661 ms) : 0, 60661
Debugger [candidate] (59.888 ms) : 0, 59888
Remote Config [baseline] (598.97 µs) : 0, 599
Remote Config [candidate] (588.789 µs) : 0, 589
Telemetry [baseline] (8.919 ms) : 0, 8919
Telemetry [candidate] (8.019 ms) : 0, 8019
Flare Poller [baseline] (8.368 ms) : 0, 8368
Flare Poller [candidate] (7.467 ms) : 0, 7467
section appsec
crashtracking [baseline] (1.233 ms) : 0, 1233
crashtracking [candidate] (1.216 ms) : 0, 1216
BytebuddyAgent [baseline] (666.147 ms) : 0, 666147
BytebuddyAgent [candidate] (660.931 ms) : 0, 660931
AgentMeter [baseline] (12.325 ms) : 0, 12325
AgentMeter [candidate] (12.26 ms) : 0, 12260
GlobalTracer [baseline] (250.058 ms) : 0, 250058
GlobalTracer [candidate] (248.318 ms) : 0, 248318
AppSec [baseline] (185.471 ms) : 0, 185471
AppSec [candidate] (184.606 ms) : 0, 184606
Debugger [baseline] (66.044 ms) : 0, 66044
Debugger [candidate] (65.802 ms) : 0, 65802
Remote Config [baseline] (593.482 µs) : 0, 593
Remote Config [candidate] (606.027 µs) : 0, 606
Telemetry [baseline] (8.319 ms) : 0, 8319
Telemetry [candidate] (8.451 ms) : 0, 8451
Flare Poller [baseline] (3.496 ms) : 0, 3496
Flare Poller [candidate] (3.518 ms) : 0, 3518
IAST [baseline] (24.669 ms) : 0, 24669
IAST [candidate] (24.505 ms) : 0, 24505
section iast
crashtracking [baseline] (1.214 ms) : 0, 1214
crashtracking [candidate] (1.231 ms) : 0, 1231
BytebuddyAgent [baseline] (799.741 ms) : 0, 799741
BytebuddyAgent [candidate] (807.162 ms) : 0, 807162
AgentMeter [baseline] (11.605 ms) : 0, 11605
AgentMeter [candidate] (11.735 ms) : 0, 11735
GlobalTracer [baseline] (238.446 ms) : 0, 238446
GlobalTracer [candidate] (240.9 ms) : 0, 240900
AppSec [baseline] (30.72 ms) : 0, 30720
AppSec [candidate] (31.899 ms) : 0, 31899
Debugger [baseline] (66.776 ms) : 0, 66776
Debugger [candidate] (64.527 ms) : 0, 64527
Remote Config [baseline] (560.554 µs) : 0, 561
Remote Config [candidate] (526.965 µs) : 0, 527
Telemetry [baseline] (9.429 ms) : 0, 9429
Telemetry [candidate] (9.668 ms) : 0, 9668
Flare Poller [baseline] (3.626 ms) : 0, 3626
Flare Poller [candidate] (3.649 ms) : 0, 3649
IAST [baseline] (25.849 ms) : 0, 25849
IAST [candidate] (25.981 ms) : 0, 25981
section profiling
ProfilingAgent [baseline] (95.017 ms) : 0, 95017
ProfilingAgent [candidate] (93.619 ms) : 0, 93619
crashtracking [baseline] (1.198 ms) : 0, 1198
crashtracking [candidate] (1.173 ms) : 0, 1173
BytebuddyAgent [baseline] (701.016 ms) : 0, 701016
BytebuddyAgent [candidate] (692.362 ms) : 0, 692362
AgentMeter [baseline] (9.319 ms) : 0, 9319
AgentMeter [candidate] (9.191 ms) : 0, 9191
GlobalTracer [baseline] (209.811 ms) : 0, 209811
GlobalTracer [candidate] (207.641 ms) : 0, 207641
AppSec [baseline] (33.197 ms) : 0, 33197
AppSec [candidate] (32.739 ms) : 0, 32739
Debugger [baseline] (66.432 ms) : 0, 66432
Debugger [candidate] (65.698 ms) : 0, 65698
Remote Config [baseline] (590.299 µs) : 0, 590
Remote Config [candidate] (576.764 µs) : 0, 577
Telemetry [baseline] (7.861 ms) : 0, 7861
Telemetry [candidate] (7.768 ms) : 0, 7768
Flare Poller [baseline] (3.593 ms) : 0, 3593
Flare Poller [candidate] (3.552 ms) : 0, 3552
Profiling [baseline] (95.586 ms) : 0, 95586
Profiling [candidate] (94.181 ms) : 0, 94181
LoadParameters
See matching parameters
SummaryFound 2 performance improvements and 1 performance regressions! Performance is the same for 16 metrics, 17 unstable metrics.
Request duration reports for insecure-bankgantt
title insecure-bank - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section baseline
no_agent (1.227 ms) : 1216, 1239
. : milestone, 1227,
iast (3.292 ms) : 3244, 3341
. : milestone, 3292,
iast_FULL (6.093 ms) : 6031, 6155
. : milestone, 6093,
iast_GLOBAL (3.557 ms) : 3497, 3617
. : milestone, 3557,
profiling (2.036 ms) : 2019, 2053
. : milestone, 2036,
tracing (1.949 ms) : 1931, 1966
. : milestone, 1949,
section candidate
no_agent (1.238 ms) : 1227, 1250
. : milestone, 1238,
iast (3.396 ms) : 3348, 3444
. : milestone, 3396,
iast_FULL (6.042 ms) : 5979, 6105
. : milestone, 6042,
iast_GLOBAL (3.735 ms) : 3668, 3802
. : milestone, 3735,
profiling (2.283 ms) : 2260, 2306
. : milestone, 2283,
tracing (2.079 ms) : 2058, 2100
. : milestone, 2079,
Request duration reports for petclinicgantt
title petclinic - request duration [CI 0.99] : candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section baseline
no_agent (18.136 ms) : 17954, 18318
. : milestone, 18136,
appsec (18.802 ms) : 18613, 18990
. : milestone, 18802,
code_origins (18.146 ms) : 17964, 18328
. : milestone, 18146,
iast (18.068 ms) : 17888, 18248
. : milestone, 18068,
profiling (19.233 ms) : 19036, 19430
. : milestone, 19233,
tracing (17.746 ms) : 17570, 17922
. : milestone, 17746,
section candidate
no_agent (17.325 ms) : 17153, 17496
. : milestone, 17325,
appsec (19.041 ms) : 18850, 19232
. : milestone, 19041,
code_origins (17.944 ms) : 17770, 18117
. : milestone, 17944,
iast (17.889 ms) : 17713, 18065
. : milestone, 17889,
profiling (18.244 ms) : 18064, 18424
. : milestone, 18244,
tracing (17.871 ms) : 17694, 18047
. : milestone, 17871,
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 tomcatgantt
title tomcat - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section baseline
no_agent (1.487 ms) : 1475, 1498
. : milestone, 1487,
appsec (3.827 ms) : 3604, 4050
. : milestone, 3827,
iast (2.274 ms) : 2206, 2343
. : milestone, 2274,
iast_GLOBAL (2.318 ms) : 2249, 2388
. : milestone, 2318,
profiling (2.114 ms) : 2058, 2169
. : milestone, 2114,
tracing (2.076 ms) : 2023, 2130
. : milestone, 2076,
section candidate
no_agent (1.494 ms) : 1482, 1505
. : milestone, 1494,
appsec (3.759 ms) : 3541, 3977
. : milestone, 3759,
iast (2.271 ms) : 2202, 2340
. : milestone, 2271,
iast_GLOBAL (2.312 ms) : 2243, 2381
. : milestone, 2312,
profiling (2.1 ms) : 2045, 2155
. : milestone, 2100,
tracing (2.084 ms) : 2031, 2138
. : milestone, 2084,
Execution time for biojavagantt
title biojava - execution time [CI 0.99] : candidate=1.62.0-SNAPSHOT~1aa7bacec5, baseline=1.62.0-SNAPSHOT~c13e82148e
dateFormat X
axisFormat %s
section baseline
no_agent (15.284 s) : 15284000, 15284000
. : milestone, 15284000,
appsec (14.698 s) : 14698000, 14698000
. : milestone, 14698000,
iast (18.261 s) : 18261000, 18261000
. : milestone, 18261000,
iast_GLOBAL (18.07 s) : 18070000, 18070000
. : milestone, 18070000,
profiling (14.808 s) : 14808000, 14808000
. : milestone, 14808000,
tracing (14.908 s) : 14908000, 14908000
. : milestone, 14908000,
section candidate
no_agent (15.661 s) : 15661000, 15661000
. : milestone, 15661000,
appsec (14.875 s) : 14875000, 14875000
. : milestone, 14875000,
iast (18.34 s) : 18340000, 18340000
. : milestone, 18340000,
iast_GLOBAL (17.941 s) : 17941000, 17941000
. : milestone, 17941000,
profiling (14.802 s) : 14802000, 14802000
. : milestone, 14802000,
tracing (15.097 s) : 15097000, 15097000
. : milestone, 15097000,
|
| * Cache for static comment strings (those without traceParent or peerService). The key combines | ||
| * dbService, hostname, dbName, and Config identity to ensure correctness if Config is replaced. | ||
| */ | ||
| private static final ConcurrentHashMap<StaticCommentKey, String> staticCommentCache = |
There was a problem hiding this comment.
Cache doesn't seem worth the trouble given that statements in Java are usually prepared
Let's remove the cache for this initial pull request
| new ConcurrentHashMap<>(); | ||
|
|
||
| // Pre-computed marker strings for trace comment detection | ||
| private static final String PARENT_SERVICE_EQ = PARENT_SERVICE + "="; |
There was a problem hiding this comment.
These constants are obviously a good idea, keep them
| * | ||
| * @return the static comment prefix, or null if no static fields are set | ||
| */ | ||
| public static String buildStaticComment(String dbService, String hostname, String dbName) { |
There was a problem hiding this comment.
Remove this caching and the associated StaticCommentKey class for this initial PR
Remove the ConcurrentHashMap-based static comment cache and StaticCommentKey class from SharedDBCommenter. Always use the existing buildComment() path. Keep the pre-computed marker constants and allocation-free containsTraceComment overload. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Benchmarks baseline (substring + String.contains) vs optimized (range-based regionMatches) for trace comment detection and first-word extraction. Includes 1-thread and 8-thread variants with prepended, appended, and no-comment SQL scenarios. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| String commentContent; // Pre-extracted for baseline comparison | ||
|
|
||
| @Setup | ||
| public void setup() { |
There was a problem hiding this comment.
I cannot decide how I feel about this benchmark.
This definitely less readable than if I wrote it by hand, but I also feel this is more comprehensive.
Summary
getFirstWord()substring allocation withfirstWordStartsWith()/firstWordEqualsIgnoreCase()usingString.regionMatches()— zero allocationextractCommentContent()substring allocation fromhasDDComment()— uses range-basedcontainsTraceComment()withregionMatches()insteadPARENT_SERVICE_EQ,DATABASE_SERVICE_EQ, etc.) as static finalsSQLCommenterBenchmarkJMH benchmark demonstrating the gainsMotivation:
SQLCommenter.inject()performed multiple substring allocations on every statement execution:getFirstWord(sql)scanned and allocated a substring,hasDDComment()calledextractCommentContent()which allocated another substring. These happened on every DBM-instrumented query.Benchmark results
containsTraceComment: substring + String.contains vs range-based regionMatches (ops/ns, higher is better):firstWord: substring + startsWith vs regionMatches (ops/ns, higher is better):The
prependedcase (SQL starting with/*comment*/ SELECT...) shows the largest firstWord gain becausegetFirstWordhad to scan through the entire comment, whilefirstWordStartsWithshort-circuits immediately.Test plan
tag: no release note
tag: ai generated
🤖 Generated with Claude Code