perf: fix double regex pass in UnquoteYAMLKey causing ~2x compile slowdown#22459
perf: fix double regex pass in UnquoteYAMLKey causing ~2x compile slowdown#22459
Conversation
…-pass regex replacement
The UnquoteYAMLKey function was using ReplaceAllStringFunc with a callback
that called re.FindStringSubmatch inside - performing two regex passes per
match. This caused a ~103% performance regression in BenchmarkCompileMemoryUsage.
Replace with ReplaceAllString using capture group references (${1}${2}key:)
for a single-pass O(n) replacement, restoring performance from ~13ms back
to ~7.6ms (near historical average of ~6.4ms).
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/892822a4-0baa-4043-a447-cb4ead4ac131
|
@copilot add tests |
…regression Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/82ab5ebf-b66a-483e-8ec9-4ab0426ce7bf
Added |
There was a problem hiding this comment.
Pull request overview
Improves workflow compilation performance by eliminating a redundant second regex pass in UnquoteYAMLKey, and adds a benchmark to track the regression going forward.
Changes:
- Refactor
UnquoteYAMLKeyto useReplaceAllStringwith capture group references (single regex pass). - Add
BenchmarkUnquoteYAMLKeyto measure/trackUnquoteYAMLKeyperformance over realistic input.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pkg/workflow/yaml.go | Switches UnquoteYAMLKey to a single-pass ReplaceAllString implementation to reduce compile-time overhead. |
| pkg/workflow/yaml_test.go | Adds a benchmark covering the UnquoteYAMLKey hot path to help detect future performance regressions. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Use ReplaceAllString with capture group references for a single-pass replacement. | ||
| // ${1} = line start (^ or \n), ${2} = optional whitespace | ||
| return re.ReplaceAllString(yamlStr, "${1}${2}"+key+":") |
There was a problem hiding this comment.
regexp.Regexp.ReplaceAllString treats $ in the replacement string as a capture-group expansion. Since key is concatenated directly into the replacement, keys containing $ (e.g. user-provided frontmatter keys) would be corrupted by unintended backref expansion. Escape $ in key before building the replacement (e.g. replace $ with $$), or use an API that performs literal insertion for the dynamic portion.
| // Use ReplaceAllString with capture group references for a single-pass replacement. | |
| // ${1} = line start (^ or \n), ${2} = optional whitespace | |
| return re.ReplaceAllString(yamlStr, "${1}${2}"+key+":") | |
| // Escape '$' in the key so it is treated literally in the replacement string, | |
| // not as a backreference marker by regexp.ReplaceAllString. | |
| escapedKey := strings.ReplaceAll(key, "$", "$$") | |
| // Use ReplaceAllString with capture group references for a single-pass replacement. | |
| // ${1} = line start (^ or \n), ${2} = optional whitespace | |
| return re.ReplaceAllString(yamlStr, "${1}${2}"+escapedKey+":") |
BenchmarkCompileMemoryUsageregressed +103.7% (6.4ms → 13.1ms) due toUnquoteYAMLKeyperforming two regex operations per match:ReplaceAllStringFuncto iterate matches, thenFindStringSubmatchinside the callback to retrieve capture groups. This function is called 10+ times per compilation viaextractTopLevelYAMLSection.Change
Replace the two-pass approach with
ReplaceAllStringusing capture group references — a single-pass operation:Benchmark after fix: ~7.6ms (restored to near historical baseline of ~6.4ms).
Testing
Added
BenchmarkUnquoteYAMLKeytopkg/workflow/yaml_test.goto guard against future regressions of the double regex pass pattern. The benchmark uses a realistic workflow YAML string and confirms the single-pass implementation performance.⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.