Repository navigation
Closed
Labels
arch: arm64ARM64 specific (NEON, future)ARM64 specific (NEON, future)area: dfaLazy DFA, OnePass DFALazy DFA, OnePass DFAarea: literalLiteral extraction from ASTLiteral extraction from ASTarea: metaStrategy selection, engine orchestrationStrategy selection, engine orchestrationbench: vs-stdlibComparison with Go stdlib regexpComparison with Go stdlib regexpeffort: 8Very large, ~1 weekVery large, ~1 weekplatform: macosmacOS-specificmacOS-specificpriority: criticalRelease blocker, correctness regressionRelease blocker, correctness regressionstatus: confirmedVerified, ready for workVerified, ready for workstrategy: teddyTeddy SIMD multi-pattern prefilterTeddy SIMD multi-pattern prefiltertype: performanceSpeed/memory improvement or regressionSpeed/memory improvement or regression
Description
the benchmark cost 116.923s to finish, there is maybe a issue here:
func BenchmarkMatchStringCache_WithoutCache_coregex(b *testing.B) {
runtime.GOMAXPROCS(4)
var data = strings.Repeat("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36", 8)
var re = coregex.MustCompile(`(?iU)\b(eval|system|exec|execute|passthru|shell_exec|phpinfo)\b`)
b.ReportAllocs()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = re.MatchString(data)
}
})
}result:
goos: darwin
goarch: arm64
pkg: [MY REPOSITORY]/internal/waf/utils
cpu: Apple M2 Max
BenchmarkMatchStringCache_WithoutCache_coregex-12 100 1148587620 ns/op 1737521223 B/op 1445 allocs/op
testing: BenchmarkMatchStringCache_WithoutCache_coregex-12 left GOMAXPROCS set to 4
PASS
ok github.com/[MY REPOSITORY]/internal/waf/utils 116.923s
Reacted by Andrey Kolkov
Metadata
Metadata
Assignees
Labels
arch: arm64ARM64 specific (NEON, future)ARM64 specific (NEON, future)area: dfaLazy DFA, OnePass DFALazy DFA, OnePass DFAarea: literalLiteral extraction from ASTLiteral extraction from ASTarea: metaStrategy selection, engine orchestrationStrategy selection, engine orchestrationbench: vs-stdlibComparison with Go stdlib regexpComparison with Go stdlib regexpeffort: 8Very large, ~1 weekVery large, ~1 weekplatform: macosmacOS-specificmacOS-specificpriority: criticalRelease blocker, correctness regressionRelease blocker, correctness regressionstatus: confirmedVerified, ready for workVerified, ready for workstrategy: teddyTeddy SIMD multi-pattern prefilterTeddy SIMD multi-pattern prefiltertype: performanceSpeed/memory improvement or regressionSpeed/memory improvement or regression
Activity
tjbrains commentedon Mar 17, 2026
and with go stdlib regexp result:
kolkov commentedon Mar 17, 2026
Thank you for the report! This is a confirmed critical performance issue.
Root Cause
The problem is in our literal extractor — it currently rejects ALL case-insensitive patterns entirely (a blanket guard added for #87). Without extracted literals, the meta-engine has no prefilter candidates and falls back to lazy DFA, which suffers from state space explosion on
(?i)patterns (181 NFA states → massive DFA cache thrashing).For comparison, Rust's regex crate handles this pattern by:
eval→EVAL, EVAl, EVaL, ... eval= 16 variants)Our engine should do the same but currently skips step 1, so Teddy is never engaged.
Fix Plan
(?i)alternation literals (like Rust does)Workaround (until fix is released)
You can manually expand the case variations and drop
(?i):If that doesn't help, the fastest workaround is to list lowercase only (if your input is predictable):
This routes to Teddy strategy (~200ns/op) since literals are extracted correctly without
(?i).We'll prioritize the fix. Thank you for the detailed benchmark — the
RunParallelwithGOMAXPROCS(4)test is especially valuable as it exposes DFA cache contention under concurrency.feat: case-insensitive literal extraction with prefilter (Issue #137)
7 remaining items
tjbrains commentedon Mar 19, 2026
Thank you, but sadly on my Apple M2 Max the match case became extremely slow with v0.12.13:
go.mod:
benchmark:
result:
tjbrains commentedon Mar 19, 2026
PS go version: go1.26.1 darwin/arm64
fix: isMatchDFA concurrent safety — prefilter rejection only (#137)
fix: isMatchDFA concurrent safety — prefilter rejection only (#137)
Merge pull request #145 from coregx/hotfix/concurrent-ismatch-safety
kolkov commentedon Mar 19, 2026
Fixed in v0.12.14.
Root cause: the prefilter candidate loop in
isMatchDFAcallede.dfa.SearchAtAnchoredconcurrently — shared lazy DFA is not thread-safe for concurrent state construction. On ARM64 without SIMD prefilters, every candidate triggered DFA lazy state build → cache corruption underRunParallel.Fix: prefilter is now used for fast rejection only (single
Findcall). When a candidate is found, verification uses pooled PikeVM (thread-safe) instead of shared DFA. Also addedTestConcurrentCaseInsensitivePrefilter(8 goroutines × 100 iterations) to catch this class of races.tjbrains commentedon Mar 19, 2026
Thanks to your work, with 0.12.14, coregex performance under match condition is near with go regexp.
kolkov commentedon Mar 19, 2026
@tjbrains Thanks! We'll fix it tomorrow; it should be noticeably closer to the Rust implementation. I'll let you know.
fix: restore FatTeddy for 33-64 patterns, AC only for >64
perf: per-goroutine DFA cache + AC prefilter + integrated loop (#146)
kolkov commentedon Mar 21, 2026
@tjbrains v0.12.15 is released with major improvements for your use case:
Per-goroutine DFA cache (Rust approach) — each goroutine gets its own DFA cache via
sync.Pool, eliminating all concurrent data races. No more shared mutable state.Results on your pattern
(?iU)\b(eval|system|exec|execute|passthru|shell_exec|phpinfo)\b:This was a large release with significant internal changes (DFA architecture split, 7 correctness fixes, integrated prefilter loop, strategy DFA caches). Please validate thoroughly in your environment — we've added a stdlib compatibility test (38/38 patterns match
regexp) and ran full regex-bench CI (Benchmark + LangArena + DNA + Extreme) with no regressions, but with this many changes extra testing on your side would be appreciated.tjbrains commentedon Mar 21, 2026
Amazing! I will do more test on coregex in my projects.
kolkov commentedon Mar 21, 2026
@tjbrains Quick follow-up — v0.12.16 just released with a fix for a multiline pattern regression found on ARM64. If you use
(?m)^patterns, please update:tjbrains commentedon Mar 21, 2026
Got it!