Skip to content

Adding lighter String processing methods to Strings - #10640

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 22 commits into
masterfrom
dougqh/strings-improvements
Jun 24, 2026
Merged

Adding lighter String processing methods to Strings#10640
gh-worker-dd-mergequeue-cf854d[bot] merged 22 commits into
masterfrom
dougqh/strings-improvements

Conversation

@dougqh

@dougqhdougqh commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

What Does This Do

Adds lighter String-processing helpers to Strings:

  • SubSequence — a zero-copy CharSequence view into a String (no extra String/char[]/byte[]). The differentiated win: lets parsing slice a string into many pieces without allocating a String per slice.
  • Strings.splitIterable<SubSequence> — allocation-free, regex-free lightweight parsing built on SubSequence.
  • Strings.replaceAll — fast literal (non-regex) replaceAll: ~3× the regex methods (String.replaceAll / Matcher.replaceAll). Honest caveat: the JDK's own String.replace(CharSequence, CharSequence) is also literal/regex-free and already captures most of that — Strings.replaceAll is only ~1.2× over it (plus a clearer name). So its incremental value over String.replace is modest. See StringReplaceAllBenchmark (which includes a string_replace row).

Motivation

Reduce allocation from String processing on hot paths. The original target was QueryObfuscator, but that proved less compelling than hoped: obfuscation is inherently regex/pattern work (literal Strings.replaceAll doesn't fit it), and the regex path is better served by reusing a compiled Pattern (see #10630). The more promising use for these helpers is allocation-free parsing — propagation headers / PTags, tag lists, SQLCommenter, query strings — where per-piece substring allocation adds up. The value is realized once a real hot path adopts SubSequence/split.

Additional Notes

Contributor Checklist

Jira ticket: [PROJ-IDENT]

Note:Once your PR is ready to merge, add it to the merge queue by commenting /merge./merge -c cancels the queue request. /merge -f --reason "reason" skips all merge queue checks; please use this judiciously, as some checks do not run at the PR-level. For more information, see this doc.

- fast replaceAll for a fixed string & replacement, 3x throughput compared to regex based solutions, 1/2x allocation compared to regex solutions
- added SubSequence which provides a view into a subsequence of a String without incurring extra allocation
- Strings.spliit returns an Iterable<SubSequence> can be used to do light weight processing of a String
@dougqh
dougqh requested a review from a team as a code ownerFebruary 19, 2026 15:38
@dougqhdougqh added type: feature Enhancements and improvements comp: core Tracer core tag: performance Performance related changes labels Feb 19, 2026
@dougqhdougqh changed the title Adding lighter String processing methods to StringUtiilsAdding lighter String processing methods to StringsFeb 19, 2026
@pr-commenter

pr-commenterBot commented Feb 19, 2026

Copy link
Copy Markdown

Benchmarks

Startup

Parameters

BaselineCandidate
baseline_or_candidatebaselinecandidate
git_branchmasterdougqh/strings-improvements
git_commit_date17722005791772204328
git_commit_shac6896b780b454c
release_version1.60.0-SNAPSHOT~c6896b7cf71.60.0-SNAPSHOT~80b454c348
See matching parameters
BaselineCandidate
applicationinsecure-bankinsecure-bank
ci_job_date17722061891772206189
ci_job_id14628435321462843532
ci_pipeline_id9943655499436554
cpu_modelIntel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHzIntel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
kernel_versionLinux runner-zfyrx7zua-project-304-concurrent-0-ork9da58 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/LinuxLinux runner-zfyrx7zua-project-304-concurrent-0-ork9da58 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
moduleAgentAgent
parentNoneNone

Summary

Found 1 performance improvements and 1 performance regressions! Performance is the same for 59 metrics, 10 unstable metrics.

scenarioΔ mean execution_timecandidate mean execution_timebaseline mean execution_time
scenario:startup:insecure-bank:tracing:Debuggerworse
[+2.157ms; +7.291ms] or [+3.536%; +11.950%]
65.733ms61.009ms
scenario:startup:insecure-bank:tracing:Remote Configbetter
[-66.900µs; -25.301µs] or [-10.350%; -3.914%]
600.278µs646.378µs
Startup time reports for insecure-bank
gantt
title insecure-bank - global startup overhead: candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.066 s) : 0, 1065574
Total [baseline] (8.764 s) : 0, 8763519
Agent [candidate] (1.067 s) : 0, 1066788
Total [candidate] (8.757 s) : 0, 8757483
section iast
Agent [baseline] (1.245 s) : 0, 1244697
Total [baseline] (9.368 s) : 0, 9368390
Agent [candidate] (1.229 s) : 0, 1229311
Total [candidate] (9.379 s) : 0, 9378595
Loading
  • baseline results
ModuleVariantDurationΔ tracing
Agenttracing1.066 s-
Agentiast1.245 s179.123 ms (16.8%)
Totaltracing8.764 s-
Totaliast9.368 s604.871 ms (6.9%)
  • candidate results
ModuleVariantDurationΔ tracing
Agenttracing1.067 s-
Agentiast1.229 s162.523 ms (15.2%)
Totaltracing8.757 s-
Totaliast9.379 s621.112 ms (7.1%)
gantt
title insecure-bank - break down per module: candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.206 ms) : 0, 1206
crashtracking [candidate] (1.197 ms) : 0, 1197
BytebuddyAgent [baseline] (627.517 ms) : 0, 627517
BytebuddyAgent [candidate] (628.677 ms) : 0, 628677
AgentMeter [baseline] (29.248 ms) : 0, 29248
AgentMeter [candidate] (29.072 ms) : 0, 29072
GlobalTracer [baseline] (258.78 ms) : 0, 258780
GlobalTracer [candidate] (257.763 ms) : 0, 257763
AppSec [baseline] (33.328 ms) : 0, 33328
AppSec [candidate] (32.966 ms) : 0, 32966
Debugger [baseline] (61.009 ms) : 0, 61009
Debugger [candidate] (65.733 ms) : 0, 65733
Remote Config [baseline] (646.378 µs) : 0, 646
Remote Config [candidate] (600.278 µs) : 0, 600
Telemetry [baseline] (12.258 ms) : 0, 12258
Telemetry [candidate] (9.979 ms) : 0, 9979
Flare Poller [baseline] (5.398 ms) : 0, 5398
Flare Poller [candidate] (4.595 ms) : 0, 4595
section iast
crashtracking [baseline] (1.229 ms) : 0, 1229
crashtracking [candidate] (1.192 ms) : 0, 1192
BytebuddyAgent [baseline] (807.466 ms) : 0, 807466
BytebuddyAgent [candidate] (794.468 ms) : 0, 794468
AgentMeter [baseline] (11.527 ms) : 0, 11527
AgentMeter [candidate] (11.319 ms) : 0, 11319
GlobalTracer [baseline] (248.466 ms) : 0, 248466
GlobalTracer [candidate] (246.98 ms) : 0, 246980
IAST [baseline] (27.189 ms) : 0, 27189
IAST [candidate] (27.138 ms) : 0, 27138
AppSec [baseline] (33.537 ms) : 0, 33537
AppSec [candidate] (34.206 ms) : 0, 34206
Debugger [baseline] (66.221 ms) : 0, 66221
Debugger [candidate] (65.342 ms) : 0, 65342
Remote Config [baseline] (535.424 µs) : 0, 535
Remote Config [candidate] (535.886 µs) : 0, 536
Telemetry [baseline] (8.687 ms) : 0, 8687
Telemetry [candidate] (8.624 ms) : 0, 8624
Flare Poller [baseline] (3.448 ms) : 0, 3448
Flare Poller [candidate] (3.454 ms) : 0, 3454
Loading
Startup time reports for petclinic
gantt
title petclinic - global startup overhead: candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section tracing
Agent [baseline] (1.064 s) : 0, 1063550
Total [baseline] (10.782 s) : 0, 10782453
Agent [candidate] (1.073 s) : 0, 1073422
Total [candidate] (11.01 s) : 0, 11010175
section appsec
Agent [baseline] (1.241 s) : 0, 1240843
Total [baseline] (11.076 s) : 0, 11075730
Agent [candidate] (1.253 s) : 0, 1253056
Total [candidate] (11.099 s) : 0, 11098613
section iast
Agent [baseline] (1.231 s) : 0, 1230908
Total [baseline] (11.209 s) : 0, 11209226
Agent [candidate] (1.23 s) : 0, 1230030
Total [candidate] (11.19 s) : 0, 11190242
section profiling
Agent [baseline] (1.193 s) : 0, 1193105
Total [baseline] (11.023 s) : 0, 11023235
Agent [candidate] (1.198 s) : 0, 1198030
Total [candidate] (10.948 s) : 0, 10947792
Loading
  • baseline results
ModuleVariantDurationΔ tracing
Agenttracing1.064 s-
Agentappsec1.241 s177.293 ms (16.7%)
Agentiast1.231 s167.358 ms (15.7%)
Agentprofiling1.193 s129.555 ms (12.2%)
Totaltracing10.782 s-
Totalappsec11.076 s293.277 ms (2.7%)
Totaliast11.209 s426.773 ms (4.0%)
Totalprofiling11.023 s240.782 ms (2.2%)
  • candidate results
ModuleVariantDurationΔ tracing
Agenttracing1.073 s-
Agentappsec1.253 s179.633 ms (16.7%)
Agentiast1.23 s156.608 ms (14.6%)
Agentprofiling1.198 s124.608 ms (11.6%)
Totaltracing11.01 s-
Totalappsec11.099 s88.438 ms (0.8%)
Totaliast11.19 s180.067 ms (1.6%)
Totalprofiling10.948 s-62.383 ms (-0.6%)
gantt
title petclinic - break down per module: candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section tracing
crashtracking [baseline] (1.181 ms) : 0, 1181
crashtracking [candidate] (1.197 ms) : 0, 1197
BytebuddyAgent [baseline] (626.725 ms) : 0, 626725
BytebuddyAgent [candidate] (631.737 ms) : 0, 631737
AgentMeter [baseline] (29.046 ms) : 0, 29046
AgentMeter [candidate] (29.35 ms) : 0, 29350
GlobalTracer [baseline] (257.328 ms) : 0, 257328
GlobalTracer [candidate] (259.221 ms) : 0, 259221
AppSec [baseline] (32.968 ms) : 0, 32968
AppSec [candidate] (33.329 ms) : 0, 33329
Debugger [baseline] (65.037 ms) : 0, 65037
Debugger [candidate] (66.23 ms) : 0, 66230
Remote Config [baseline] (612.862 µs) : 0, 613
Remote Config [candidate] (607.301 µs) : 0, 607
Telemetry [baseline] (10.755 ms) : 0, 10755
Telemetry [candidate] (10.777 ms) : 0, 10777
Flare Poller [baseline] (3.789 ms) : 0, 3789
Flare Poller [candidate] (4.643 ms) : 0, 4643
section appsec
crashtracking [baseline] (1.195 ms) : 0, 1195
crashtracking [candidate] (1.224 ms) : 0, 1224
BytebuddyAgent [baseline] (658.282 ms) : 0, 658282
BytebuddyAgent [candidate] (666.751 ms) : 0, 666751
AgentMeter [baseline] (12.029 ms) : 0, 12029
AgentMeter [candidate] (12.121 ms) : 0, 12121
GlobalTracer [baseline] (258.706 ms) : 0, 258706
GlobalTracer [candidate] (261.076 ms) : 0, 261076
AppSec [baseline] (168.147 ms) : 0, 168147
AppSec [candidate] (168.941 ms) : 0, 168941
Debugger [baseline] (66.998 ms) : 0, 66998
Debugger [candidate] (67.089 ms) : 0, 67089
Remote Config [baseline] (684.151 µs) : 0, 684
Remote Config [candidate] (710.071 µs) : 0, 710
Telemetry [baseline] (9.475 ms) : 0, 9475
Telemetry [candidate] (9.318 ms) : 0, 9318
Flare Poller [baseline] (3.696 ms) : 0, 3696
Flare Poller [candidate] (3.682 ms) : 0, 3682
IAST [baseline] (25.415 ms) : 0, 25415
IAST [candidate] (25.707 ms) : 0, 25707
section iast
crashtracking [baseline] (1.191 ms) : 0, 1191
crashtracking [candidate] (1.196 ms) : 0, 1196
BytebuddyAgent [baseline] (794.443 ms) : 0, 794443
BytebuddyAgent [candidate] (794.374 ms) : 0, 794374
AgentMeter [baseline] (11.33 ms) : 0, 11330
AgentMeter [candidate] (11.311 ms) : 0, 11311
GlobalTracer [baseline] (247.017 ms) : 0, 247017
GlobalTracer [candidate] (246.942 ms) : 0, 246942
AppSec [baseline] (35.083 ms) : 0, 35083
AppSec [candidate] (34.124 ms) : 0, 34124
Debugger [baseline] (65.78 ms) : 0, 65780
Debugger [candidate] (66.499 ms) : 0, 66499
Remote Config [baseline] (550.831 µs) : 0, 551
Remote Config [candidate] (529.664 µs) : 0, 530
Telemetry [baseline] (8.715 ms) : 0, 8715
Telemetry [candidate] (8.639 ms) : 0, 8639
Flare Poller [baseline] (3.45 ms) : 0, 3450
Flare Poller [candidate] (3.439 ms) : 0, 3439
IAST [baseline] (27.203 ms) : 0, 27203
IAST [candidate] (26.891 ms) : 0, 26891
section profiling
ProfilingAgent [baseline] (99.685 ms) : 0, 99685
ProfilingAgent [candidate] (100.641 ms) : 0, 100641
crashtracking [baseline] (1.21 ms) : 0, 1210
crashtracking [candidate] (1.172 ms) : 0, 1172
BytebuddyAgent [baseline] (683.535 ms) : 0, 683535
BytebuddyAgent [candidate] (685.599 ms) : 0, 685599
AgentMeter [baseline] (8.584 ms) : 0, 8584
AgentMeter [candidate] (8.654 ms) : 0, 8654
GlobalTracer [baseline] (216.035 ms) : 0, 216035
GlobalTracer [candidate] (216.85 ms) : 0, 216850
AppSec [baseline] (32.663 ms) : 0, 32663
AppSec [candidate] (32.702 ms) : 0, 32702
Debugger [baseline] (67.173 ms) : 0, 67173
Debugger [candidate] (66.882 ms) : 0, 66882
Remote Config [baseline] (634.793 µs) : 0, 635
Remote Config [candidate] (639.285 µs) : 0, 639
Telemetry [baseline] (8.944 ms) : 0, 8944
Telemetry [candidate] (9.835 ms) : 0, 9835
Flare Poller [baseline] (3.727 ms) : 0, 3727
Flare Poller [candidate] (3.791 ms) : 0, 3791
Profiling [baseline] (100.276 ms) : 0, 100276
Profiling [candidate] (101.22 ms) : 0, 101220
Loading

Load

Parameters

BaselineCandidate
baseline_or_candidatebaselinecandidate
git_branchmasterdougqh/strings-improvements
git_commit_date17722005791772204328
git_commit_shac6896b780b454c
release_version1.60.0-SNAPSHOT~c6896b7cf71.60.0-SNAPSHOT~80b454c348
See matching parameters
BaselineCandidate
applicationinsecure-bankinsecure-bank
ci_job_date17722068551772206855
ci_job_id14628435331462843533
ci_pipeline_id9943655499436554
cpu_modelIntel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHzIntel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz
kernel_versionLinux runner-zfyrx7zua-project-304-concurrent-1-tk6xra9w 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/LinuxLinux runner-zfyrx7zua-project-304-concurrent-1-tk6xra9w 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

Summary

Found 1 performance improvements and 2 performance regressions! Performance is the same for 16 metrics, 17 unstable metrics.

scenarioΔ mean agg_http_req_duration_p50Δ mean agg_http_req_duration_p95Δ mean throughputcandidate mean agg_http_req_duration_p50candidate mean agg_http_req_duration_p95candidate mean throughputbaseline mean agg_http_req_duration_p50baseline mean agg_http_req_duration_p95baseline mean throughput
scenario:load:insecure-bank:iast_GLOBAL:high_loadworse
[+200.395µs; +308.764µs] or [+7.492%; +11.544%]
worse
[+239.615µs; +600.482µs] or [+3.122%; +7.825%]
unstable
[-253.765op/s; +42.265op/s] or [-18.809%; +3.133%]
2.929ms8.094ms1243.406op/s2.675ms7.674ms1349.156op/s
scenario:load:petclinic:appsec:high_loadbetter
[-1119.043µs; -385.336µs] or [-5.866%; -2.020%]
unsure
[-1.874ms; -0.582ms] or [-6.089%; -1.890%]
unstable
[-18.374op/s; +36.999op/s] or [-7.636%; +15.376%]
18.324ms29.547ms249.938op/s19.076ms30.774ms240.625op/s
Request duration reports for petclinic
gantt
title petclinic - request duration [CI 0.99] : candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section baseline
no_agent (18.174 ms) : 17986, 18363
. : milestone, 18174,
appsec (19.402 ms) : 19203, 19601
. : milestone, 19402,
code_origins (17.579 ms) : 17402, 17755
. : milestone, 17579,
iast (18.89 ms) : 18699, 19082
. : milestone, 18890,
profiling (18.746 ms) : 18560, 18931
. : milestone, 18746,
tracing (17.616 ms) : 17445, 17787
. : milestone, 17616,
section candidate
no_agent (18.898 ms) : 18703, 19093
. : milestone, 18898,
appsec (18.674 ms) : 18488, 18859
. : milestone, 18674,
code_origins (17.35 ms) : 17179, 17521
. : milestone, 17350,
iast (18.025 ms) : 17846, 18204
. : milestone, 18025,
profiling (18.718 ms) : 18530, 18906
. : milestone, 18718,
tracing (17.701 ms) : 17523, 17879
. : milestone, 17701,
Loading
  • baseline results
VariantRequest duration [CI 0.99]Δ no_agent
no_agent18.174 ms [17.986 ms, 18.363 ms]-
appsec19.402 ms [19.203 ms, 19.601 ms]1.227 ms (6.8%)
code_origins17.579 ms [17.402 ms, 17.755 ms]-595.449 µs (-3.3%)
iast18.89 ms [18.699 ms, 19.082 ms]715.897 µs (3.9%)
profiling18.746 ms [18.56 ms, 18.931 ms]571.178 µs (3.1%)
tracing17.616 ms [17.445 ms, 17.787 ms]-558.451 µs (-3.1%)
  • candidate results
VariantRequest duration [CI 0.99]Δ no_agent
no_agent18.898 ms [18.703 ms, 19.093 ms]-
appsec18.674 ms [18.488 ms, 18.859 ms]-224.381 µs (-1.2%)
code_origins17.35 ms [17.179 ms, 17.521 ms]-1.548 ms (-8.2%)
iast18.025 ms [17.846 ms, 18.204 ms]-873.367 µs (-4.6%)
profiling18.718 ms [18.53 ms, 18.906 ms]-180.135 µs (-1.0%)
tracing17.701 ms [17.523 ms, 17.879 ms]-1.197 ms (-6.3%)
Request duration reports for insecure-bank
gantt
title insecure-bank - request duration [CI 0.99] : candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section baseline
no_agent (1.174 ms) : 1162, 1185
. : milestone, 1174,
iast (3.214 ms) : 3173, 3256
. : milestone, 3214,
iast_FULL (5.892 ms) : 5832, 5952
. : milestone, 5892,
iast_GLOBAL (3.396 ms) : 3354, 3438
. : milestone, 3396,
profiling (2.114 ms) : 2095, 2133
. : milestone, 2114,
tracing (1.819 ms) : 1804, 1835
. : milestone, 1819,
section candidate
no_agent (1.165 ms) : 1154, 1177
. : milestone, 1165,
iast (3.217 ms) : 3174, 3259
. : milestone, 3217,
iast_FULL (5.848 ms) : 5789, 5907
. : milestone, 5848,
iast_GLOBAL (3.691 ms) : 3630, 3752
. : milestone, 3691,
profiling (2.332 ms) : 2310, 2353
. : milestone, 2332,
tracing (1.812 ms) : 1797, 1827
. : milestone, 1812,
Loading
  • baseline results
VariantRequest duration [CI 0.99]Δ no_agent
no_agent1.174 ms [1.162 ms, 1.185 ms]-
iast3.214 ms [3.173 ms, 3.256 ms]2.041 ms (173.9%)
iast_FULL5.892 ms [5.832 ms, 5.952 ms]4.718 ms (402.0%)
iast_GLOBAL3.396 ms [3.354 ms, 3.438 ms]2.222 ms (189.3%)
profiling2.114 ms [2.095 ms, 2.133 ms]939.779 µs (80.1%)
tracing1.819 ms [1.804 ms, 1.835 ms]645.583 µs (55.0%)
  • candidate results
VariantRequest duration [CI 0.99]Δ no_agent
no_agent1.165 ms [1.154 ms, 1.177 ms]-
iast3.217 ms [3.174 ms, 3.259 ms]2.051 ms (176.0%)
iast_FULL5.848 ms [5.789 ms, 5.907 ms]4.683 ms (401.9%)
iast_GLOBAL3.691 ms [3.63 ms, 3.752 ms]2.526 ms (216.8%)
profiling2.332 ms [2.31 ms, 2.353 ms]1.167 ms (100.1%)
tracing1.812 ms [1.797 ms, 1.827 ms]646.838 µs (55.5%)

Dacapo

Parameters

BaselineCandidate
baseline_or_candidatebaselinecandidate
git_branchmasterdougqh/strings-improvements
git_commit_date17722005791772204328
git_commit_shac6896b780b454c
release_version1.60.0-SNAPSHOT~c6896b7cf71.60.0-SNAPSHOT~80b454c348
See matching parameters
BaselineCandidate
applicationbiojavabiojava
ci_job_date17722065321772206532
ci_job_id14628435351462843535
ci_pipeline_id9943655499436554
cpu_modelIntel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHzIntel(R) Xeon(R) Platinum 8175M CPU @ 2.50GHz
kernel_versionLinux runner-zfyrx7zua-project-304-concurrent-3-wey4o12n 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/LinuxLinux runner-zfyrx7zua-project-304-concurrent-3-wey4o12n 6.8.0-1031-aws #33~22.04.1-Ubuntu SMP Thu Jun 26 14:22:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux

Summary

Found 0 performance improvements and 0 performance regressions! Performance is the same for 11 metrics, 1 unstable metrics.

Execution time for tomcat
gantt
title tomcat - execution time [CI 0.99] : candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section baseline
no_agent (1.482 ms) : 1470, 1493
. : milestone, 1482,
appsec (4.274 ms) : 4018, 4530
. : milestone, 4274,
iast (2.653 ms) : 2543, 2762
. : milestone, 2653,
iast_GLOBAL (2.706 ms) : 2596, 2816
. : milestone, 2706,
profiling (2.46 ms) : 2368, 2553
. : milestone, 2460,
tracing (2.406 ms) : 2318, 2494
. : milestone, 2406,
section candidate
no_agent (1.485 ms) : 1473, 1497
. : milestone, 1485,
appsec (4.188 ms) : 3934, 4442
. : milestone, 4188,
iast (2.658 ms) : 2548, 2768
. : milestone, 2658,
iast_GLOBAL (2.71 ms) : 2600, 2821
. : milestone, 2710,
profiling (2.434 ms) : 2344, 2524
. : milestone, 2434,
tracing (2.42 ms) : 2331, 2509
. : milestone, 2420,
Loading
  • baseline results
VariantExecution Time [CI 0.99]Δ no_agent
no_agent1.482 ms [1.47 ms, 1.493 ms]-
appsec4.274 ms [4.018 ms, 4.53 ms]2.793 ms (188.5%)
iast2.653 ms [2.543 ms, 2.762 ms]1.171 ms (79.0%)
iast_GLOBAL2.706 ms [2.596 ms, 2.816 ms]1.224 ms (82.6%)
profiling2.46 ms [2.368 ms, 2.553 ms]978.929 µs (66.1%)
tracing2.406 ms [2.318 ms, 2.494 ms]924.645 µs (62.4%)
  • candidate results
VariantExecution Time [CI 0.99]Δ no_agent
no_agent1.485 ms [1.473 ms, 1.497 ms]-
appsec4.188 ms [3.934 ms, 4.442 ms]2.704 ms (182.1%)
iast2.658 ms [2.548 ms, 2.768 ms]1.173 ms (79.0%)
iast_GLOBAL2.71 ms [2.6 ms, 2.821 ms]1.226 ms (82.5%)
profiling2.434 ms [2.344 ms, 2.524 ms]949.0 µs (63.9%)
tracing2.42 ms [2.331 ms, 2.509 ms]934.754 µs (63.0%)
Execution time for biojava
gantt
title biojava - execution time [CI 0.99] : candidate=1.60.0-SNAPSHOT~80b454c348, baseline=1.60.0-SNAPSHOT~c6896b7cf7
dateFormat X
axisFormat %s
section baseline
no_agent (14.499 s) : 14499000, 14499000
. : milestone, 14499000,
appsec (14.336 s) : 14336000, 14336000
. : milestone, 14336000,
iast (17.162 s) : 17162000, 17162000
. : milestone, 17162000,
iast_GLOBAL (17.085 s) : 17085000, 17085000
. : milestone, 17085000,
profiling (14.214 s) : 14214000, 14214000
. : milestone, 14214000,
tracing (14.23 s) : 14230000, 14230000
. : milestone, 14230000,
section candidate
no_agent (15.08 s) : 15080000, 15080000
. : milestone, 15080000,
appsec (14.228 s) : 14228000, 14228000
. : milestone, 14228000,
iast (17.366 s) : 17366000, 17366000
. : milestone, 17366000,
iast_GLOBAL (17.148 s) : 17148000, 17148000
. : milestone, 17148000,
profiling (14.412 s) : 14412000, 14412000
. : milestone, 14412000,
tracing (14.298 s) : 14298000, 14298000
. : milestone, 14298000,
Loading
  • baseline results
VariantExecution Time [CI 0.99]Δ no_agent
no_agent14.499 s [14.499 s, 14.499 s]-
appsec14.336 s [14.336 s, 14.336 s]-163.0 ms (-1.1%)
iast17.162 s [17.162 s, 17.162 s]2.663 s (18.4%)
iast_GLOBAL17.085 s [17.085 s, 17.085 s]2.586 s (17.8%)
profiling14.214 s [14.214 s, 14.214 s]-285.0 ms (-2.0%)
tracing14.23 s [14.23 s, 14.23 s]-269.0 ms (-1.9%)
  • candidate results
VariantExecution Time [CI 0.99]Δ no_agent
no_agent15.08 s [15.08 s, 15.08 s]-
appsec14.228 s [14.228 s, 14.228 s]-852.0 ms (-5.6%)
iast17.366 s [17.366 s, 17.366 s]2.286 s (15.2%)
iast_GLOBAL17.148 s [17.148 s, 17.148 s]2.068 s (13.7%)
profiling14.412 s [14.412 s, 14.412 s]-668.0 ms (-4.4%)
tracing14.298 s [14.298 s, 14.298 s]-782.0 ms (-5.2%)

Comment on lines +23 to +25
* StringReplacementBenchmark.string_replaceAll thrpt 6 14611046.391 ± 4865682.875 ops/s
* StringReplacementBenchmark.string_replaceAll:gc.alloc.rate thrpt 6 11391.346 ± 3790.917 MB/sec
*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add also String.replace(CharSequence, CharSequence) for completeness?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I'd overlooked that replace actually does a replace all, so I didn't realize it was equivalent.

@dougqhdougqhFeb 24, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my surprise, the Strings.replaceAll that I implemented is actually still 20% faster than String.replace.

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been marked as stale because it has not had activity over the past quarter. It will be closed in 7 days if no further activity occurs. Feel free to reopen the PR if you are still working on it.

@github-actionsgithub-actionsBot added the tag: stale Stale pull requests label Jun 1, 2026

@bric3bric3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice tweak. However, I think some tiny javdoc improvement would be worth it.

Approving nonetheless.

Comment on lines +4 to +7
* A <code>CharSequence</code> that is view into a sub-sequencce of a <code>String</code> Unlike
* <code>String.subSequence</code>, this class doesn't allocate an additional <code>String</code>,
* <code>char[]</code>, or <code>byte[]</code>
*/

@bric3bric3Jun 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: I believe this worth adding a motivation over why not creating a new String is important vs allocating a SubSequence anyway, and when the benefit "disappears" e.g with suSeq.hashCode(), etc.

String.subSequence(start, end), creates a String object, that has a backing array object, and copies the characters over there (that said array copy should be pretty fast). Not sure about that, but I think it's possible that SubSequence can benefit from scalr replacement in loops, if that's the case that's something worthy to put in the javadoc.

IIRC String.subSequence(start, end) creates a new String instance so that the bigger original String had more chance to get GCed, while in this case the SubSequence keeps the original String, so that might be something to take into account.

…tion)
Per bric3 review: the doc said what SubSequence avoids allocating but not why it
matters. Explain the use case — allocation-free lightweight parsing: substring/
subSequence copy per call, so splitting a string into many pieces on a hot path
allocates O(pieces) Strings; SubSequence is a zero-copy view. Also fixes a typo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dd-octo-stsdd-octo-stsBot added the tag: ai generated Largely based on code generated by an AI or LLM label Jun 24, 2026
@dd-octo-sts

dd-octo-stsBot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

SuiteStatus
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
ScenarioCandidatemasterΔ (95% CI of mean)
startup:insecure-bank:iast:Agent13.93 s13.98 s[-1.0%; +0.2%] (no difference)
startup:insecure-bank:tracing:Agent12.90 s13.00 s[-1.6%; -0.1%] (maybe better)
startup:petclinic:appsec:Agent16.92 s16.74 s[+0.0%; +2.2%] (maybe worse)
startup:petclinic:iast:Agent16.91 s16.94 s[-0.7%; +0.4%] (no difference)
startup:petclinic:profiling:Agent16.89 s17.01 s[-1.8%; +0.4%] (no difference)
startup:petclinic:sca:Agent16.99 s16.65 s[+1.1%; +3.0%] (significantly worse)
startup:petclinic:tracing:Agent16.00 s16.07 s[-1.6%; +0.7%] (no difference)

Commit:7ba45583 · 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
dougqhforce-pushed the dougqh/strings-improvements branch from 79b5a30 to db6ebcdCompareJune 24, 2026 21:30
@dd-octo-sts

Copy link
Copy Markdown
Contributor

/merge

@gh-worker-devflow-routing-ef8351

gh-worker-devflow-routing-ef8351Bot commented Jun 24, 2026

Copy link
Copy Markdown

View all feedbacks in Devflow UI.

2026-06-24 22:31:59 UTC ℹ️ Start processing command /merge


2026-06-24 22:32:04 UTC ℹ️ MergeQueue: pull request added to the queue

The expected merge time in master is approximately 1h (p90).


2026-06-24 23:33:44 UTC ℹ️ MergeQueue: This merge request was merged

@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Jun 24, 2026
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854dBot merged commit 0ac2d54 into masterJun 24, 2026
583 checks passed
@gh-worker-dd-mergequeue-cf854d
gh-worker-dd-mergequeue-cf854dBot deleted the dougqh/strings-improvements branch June 24, 2026 23:33
@github-actionsgithub-actionsBot added this to the 1.64.0 milestone Jun 24, 2026
dougqh added a commit that referenced this pull request Jun 29, 2026
… substring
getFirstWord's result is only consumed by startsWith("{") and
equalsIgnoreCase("call"), so materializing a substring on every inject() was
pure waste. Return a zero-copy SubSequence view instead and use its
startsWith/equalsIgnoreCase. Behavior is unchanged (91 SQLCommenterTest cases
pass); the test compares getFirstWord(sql).toString().
This is the motivating consumer for SubSequence.startsWith/equalsIgnoreCase
(retracted from #10640 and carried here so they land with their use case).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
dougqh added a commit that referenced this pull request Jun 29, 2026
…diom)
Add SubSequence.contains (delegating to the Strings.regionContains primitive)
and rewrite containsTraceComment(sql, from, to) as
SubSequence.of(sql, from, to).contains(...) -- a 1-to-1 substitution for what
you'd idiomatically write on a substring, with no copy. EA elides the view in
the transient consumption; even if it doesn't, the string copy is still avoided.
Couples this branch to the SubSequence base (#10640); regionContains stays as
the allocation-free primitive the view delegates to.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
TophrC-dd pushed a commit that referenced this pull request Jun 29, 2026
Adding to StringUtiils
- fast replaceAll for a fixed string & replacement, 3x throughput compared to regex based solutions, 1/2x allocation compared to regex solutions
- added SubSequence which provides a view into a subsequence of a String without incurring extra allocation
- Strings.spliit returns an Iterable<SubSequence> can be used to do light weight processing of a String
Checking hashCode
Reducing whitespace
Fixing ugly spotless formatting
Fixing ugly spotless formatting
Renaming benchmark method
Clarifying Javadoc
grammar
Allowing forbidden API usage
These benchmarks exist to show why the APIs are forbidden
Merge branch 'master' into dougqh/strings-improvements
Merge branch 'master' into dougqh/strings-improvements
Adding String.replace to the benchmark
grammar
Added comment explaining implementation approach
Clean-up imports
spotless
Merge branch 'master' into dougqh/strings-improvements
Fixing package after moving code from stand-alone reproduction
Merge branch 'dougqh/strings-improvements' of github.com:DataDog/dd-trace-java into dougqh/strings-improvements
Add motivation to SubSequence Javadoc (why avoid the substring allocation)
Per bric3 review: the doc said what SubSequence avoids allocating but not why it
matters. Explain the use case — allocation-free lightweight parsing: substring/
subSequence copy per call, so splitting a string into many pieces on a hot path
allocates O(pieces) Strings; SubSequence is a zero-copy view. Also fixes a typo.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Merge remote-tracking branch 'origin/master' into dougqh/strings-improvements
Merge branch 'master' into dougqh/strings-improvements
Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
dougqh added a commit that referenced this pull request Jun 30, 2026
…diom)
Add SubSequence.contains (delegating to the Strings.regionContains primitive)
and rewrite containsTraceComment(sql, from, to) as
SubSequence.of(sql, from, to).contains(...) -- a 1-to-1 substitution for what
you'd idiomatically write on a substring, with no copy. EA elides the view in
the transient consumption; even if it doesn't, the string copy is still avoided.
Couples this branch to the SubSequence base (#10640); regionContains stays as
the allocation-free primitive the view delegates to.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gh-worker-dd-mergequeue-cf854dBot pushed a commit that referenced this pull request Jun 30, 2026
… substring (#11736)
Add SubSequence.startsWith / equalsIgnoreCase (CharSequence-friendly comparisons)
These are the ops a real classification parse needs but CharSequence lacks —
surfaced by porting SQLCommenter.getFirstWord (firstWord.startsWith("{"),
firstWord.equalsIgnoreCase("call")). Lets transient parse views be compared
without materializing a String. + JUnit 5 tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Return SubSequence from SQLCommenter.getFirstWord to avoid per-inject substring
getFirstWord's result is only consumed by startsWith("{") and
equalsIgnoreCase("call"), so materializing a substring on every inject() was
pure waste. Return a zero-copy SubSequence view instead and use its
startsWith/equalsIgnoreCase. Behavior is unchanged (91 SQLCommenterTest cases
pass); the test compares getFirstWord(sql).toString().
This is the motivating consumer for SubSequence.startsWith/equalsIgnoreCase
(retracted from #10640 and carried here so they land with their use case).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add SQLCommenterGetFirstWordBenchmark (getFirstWord alloc: 48 -> 0 B/op)
Benchmarks the getFirstWord first-word scan, consuming the result via the real
transient pattern (startsWith, returning the boolean) so EA isn't faked away.
@threads(8), @fork(2), -prof gc: the old substring allocated 48 B/op per call;
the SubSequence view is fully EA-elided (~0 B/op), ~1.6x throughput. Numbers in
the class Javadoc.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refresh SQLCommenterGetFirstWordBenchmark results to JDK 17 @fork(5)
zulu-17 @fork(5), -prof gc: 258.1M -> 508.0M ops/s (~2x), 48 -> ~0 B/op.
@fork(5) tightens the earlier bimodal @fork(2) spread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge branch 'master' into dougqh/sqlcommenter-getfirstword-subseq
Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
dougqh added a commit that referenced this pull request Jun 30, 2026
The CharSequence contract treats start/end as offsets in this view's
coordinates, so absolute end is beginIndex+end, not beginIndex+start+end
(which overshoots by start; only correct when start==0). Latent since
#10640 -- no production caller invoked it with start>0. Adds a regression
test including the nested case the bug broke worst.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gh-worker-dd-mergequeue-cf854dBot pushed a commit that referenced this pull request Jul 14, 2026
… substring (#11737)
Check the DBM comment region in place, dropping the extractCommentContent substring
SQLCommenter.hasDDComment materialized sql.substring(commentStart, commentEnd)
on every duplicate-comment check just to feed containsTraceComment. Add a
SharedDBCommenter.containsTraceComment(sql, from, to) range overload that scans
the comment body in place, and a Strings.regionContains primitive it (and the
String delegate) build on -- no per-call substring. The String overload now
delegates to the range form, so Mongo behavior is unchanged.
regionContains is the allocation-free, copy-free primitive; the natural-reading
SubSequence.contains layer can delegate to it later. Boundary semantics unit-
tested on Strings.regionContains; DB needle behavior on the overloads; existing
SQLCommenter/SharedDBCommenter suites unchanged and green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Read the comment-region check as a SubSequence view (the followable idiom)
Add SubSequence.contains (delegating to the Strings.regionContains primitive)
and rewrite containsTraceComment(sql, from, to) as
SubSequence.of(sql, from, to).contains(...) -- a 1-to-1 substitution for what
you'd idiomatically write on a substring, with no copy. EA elides the view in
the transient consumption; even if it doesn't, the string copy is still avoided.
Couples this branch to the SubSequence base (#10640); regionContains stays as
the allocation-free primitive the view delegates to.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add SQLCommenterDuplicateCommentBenchmark (substring 140 -> 0 B/op)
Isolates the duplicate-comment guard (dbType=null skips the first-word scan;
already-DD-commented SQL makes inject return early). The extractCommentContent
substring allocated 140 B/op; the in-place range/view scan is EA-elided (~0).
@threads(8), @fork(2), -prof gc; numbers in the class Javadoc. Throughput is
flat-to-slightly-up but within @fork(2) noise -- this path is scan-CPU-dominated,
so the win is the allocation, not throughput.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refresh SQLCommenterDuplicateCommentBenchmark results to JDK 17 @fork(5)
zulu-17 @fork(5), -prof gc: 23.5M -> 26.2M ops/s (~1.1x), 140 -> ~0 B/op.
Headline win is the allocation; @fork(5) tightens the earlier bimodal spread.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Merge remote-tracking branch 'origin/master' into dougqh/dbcommenter-scan-overload
# Conflicts:
#	internal-api/src/main/java/datadog/trace/util/SubSequence.java
#	internal-api/src/test/java/datadog/trace/util/SubSequenceTest.java
Merge branch 'master' into dougqh/dbcommenter-scan-overload
Merge branch 'master' into dougqh/dbcommenter-scan-overload
Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: coreTracer coretag: ai generatedLargely based on code generated by an AI or LLMtag: performancePerformance related changestag: staleStale pull requeststype: featureEnhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@dougqh@jbachorik@bric3