Skip to content

Replace quadratic string concatenation in qualified struct type names - #1607

Merged
dmitriplotnikov merged 3 commits into
cel-expr:masterfrom
dmitriplotnikov:parser-struct-name-builder
Nov 5, 2026
Merged

dmitriplotnikov merged 3 commits into
cel-expr:masterfrom
dmitriplotnikov:parser-struct-name-builder

Conversation

@dmitriplotnikov

@dmitriplotnikov dmitriplotnikov commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator
  • Build qualified message type names with a pre-sized strings.Builder in antlrVisitor.VisitCreateMessage instead of repeated += string concatenation.
  • Assemble qualified struct type names in a single strings.Builder pass in prattParserWorker.extractStructName instead of name = "." + sel.FieldName() + name, and delete intermediate Select/Ident IDs inline.
  • Add TestParseDeepQualifiedStructName and BenchmarkParseLargePathological.

Benchmarks (go test -bench='^BenchmarkParseLargePathological/.*/deep_struct_name$' -benchmem)

goos: linux · goarch: amd64 · pkg: cel.dev/cel-go/parser · cpu: AMD EPYC 7B13

Benchmark before.txt (sec/op) after.txt (sec/op) vs base
ParseLargePathological/antlr/deep_struct_name-64 739.35m ± 25% 45.11m ± 9% -93.90% (p=0.002 n=6)
ParseLargePathological/pratt/deep_struct_name-64 316.84m ± 6% 26.88m ± 2% -91.52% (p=0.002 n=6)
geomean 484.0m 34.82m -92.81%
Benchmark before.txt (B/op) after.txt (B/op) vs base
ParseLargePathological/antlr/deep_struct_name-64 5100.91Mi ± 0% 37.72Mi ± 0% -99.26% (p=0.002 n=6)
ParseLargePathological/pratt/deep_struct_name-64 2539.39Mi ± 0% 11.94Mi ± 0% -99.53% (p=0.002 n=6)
geomean 3.515Gi 21.22Mi -99.41%
Benchmark before.txt (allocs/op) after.txt (allocs/op) vs base
ParseLargePathological/antlr/deep_struct_name-64 300.2k ± 0% 200.2k ± 0% -33.31% (p=0.002 n=6)
ParseLargePathological/pratt/deep_struct_name-64 300.0k ± 0% 250.1k ± 0% -16.66% (p=0.002 n=6)
geomean 300.1k 223.7k -25.45%

TristonianJones
TristonianJones previously approved these changes Nov 3, 2026
Comment thread parser/pratt_parser.go Resolved
Comment thread parser/helper.go Resolved
- Build qualified message type names with a pre-sized `strings.Builder` in `antlrVisitor.VisitCreateMessage` instead of repeated `+=` string concatenation.
- Assemble qualified struct type names in a single `strings.Builder` pass in `prattParserWorker.extractStructName` instead of `name = "." + sel.FieldName() + name`, and delete intermediate `Select`/`Ident` IDs outermost-to-innermost only after confirming an `ast.IdentKind` root.
- Add `TestParseDeepQualifiedStructName` and `BenchmarkParseLargePathological`.

Benchmarks (`go test -bench='^BenchmarkParseLargePathological/.*/deep_struct_name$' -benchmem`):

goos: linux
goarch: amd64
pkg: cel.dev/cel-go/parser
cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
                                                │   before.txt    │              after.txt              │
                                                │     sec/op      │    sec/op     vs base               │
ParseLargePathological/antlr/deep_struct_name-8   1508.25m ±   4%   79.91m ±  4%  -94.70% (p=0.002 n=6)
ParseLargePathological/pratt/deep_struct_name-8    654.89m ± 111%   39.74m ± 24%  -93.93% (p=0.002 n=6)
geomean                                             993.9m          56.35m        -94.33%

                                                │   before.txt   │              after.txt              │
                                                │      B/op      │     B/op      vs base               │
ParseLargePathological/antlr/deep_struct_name-8   5100.91Mi ± 0%   37.72Mi ± 0%  -99.26% (p=0.002 n=6)
ParseLargePathological/pratt/deep_struct_name-8   2537.86Mi ± 0%   12.28Mi ± 0%  -99.52% (p=0.002 n=6)
geomean                                             3.514Gi        21.52Mi       -99.40%

                                                │ before.txt  │             after.txt              │
                                                │  allocs/op  │  allocs/op   vs base               │
ParseLargePathological/antlr/deep_struct_name-8   300.2k ± 2%   200.2k ± 0%  -33.32% (p=0.002 n=6)
ParseLargePathological/pratt/deep_struct_name-8   200.0k ± 0%   150.1k ± 0%  -24.97% (p=0.002 n=6)
geomean                                           245.1k        173.3k       -29.27%
Collect qualified struct name segments in a pre-allocated slice while deleting intermediate `Select`/`Ident` IDs inline, then reverse and join with `strings.Join` instead of tracking a separate `ids` slice and pre-computing length for `strings.Builder`.
@dmitriplotnikov
dmitriplotnikov force-pushed the parser-struct-name-builder branch from b2cf5e0 to ba2f0a9 Compare November 5, 2026 21:25
@dmitriplotnikov
dmitriplotnikov merged commit af76933 into cel-expr:master Nov 5, 2026
8 checks passed
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.

2 participants