Repository navigation
perf(parse): give each thread its own regex cache pool - #13
Merged
Merged
Conversation
`regex!` handed every caller the same global `Regex`. regex-automata gives only the first thread to use a `Regex` the lock-free cache fast path; every other thread goes through mutex-protected cache stacks. Under a parallel caller that contention dominated date parsing: `qsv stats --infer-dates` on 16 threads spent ~10% of busy CPU in pthread_mutex / Pool::get_slow / Pool::put_value, and date inference cost +1.41 s CPU in parallel vs +0.75 s single-threaded. `regex!` now returns a `&'static LocalKey<Regex>` holding a per-thread clone of the once-compiled regex. `Regex::clone` shares the compiled program but builds a fresh cache pool, so each thread owns its own pool. Thread-local rather than a leaked per-thread clone, so long-lived processes that churn threads don't accumulate caches. Call sites change mechanically from `re.is_match(input)` to `re.with(|r| r.is_match(input))`. qsv stats on NYC 311 (1M rows, 16 jobs, M4 Max), outputs byte-identical: - --infer-dates: 266 ms -> 225 ms (1.18x) - --infer-dates --dates-whitelist all: 193 ms -> 155 ms (1.25x) - --jobs 1 --infer-dates: 1.70 s -> 1.71 s (unchanged) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
regex!returned one globalRegexper pattern. regex-automata gives only the first thread that uses aRegexthe lock-free cache fast path; every other thread goes through mutex-protected cache stacks (util/pool.rs,MAX_POOL_STACKS = 8). Under a parallel caller likeqsv stats --infer-dates, that contention ate ~10% of busy CPU (pthread_mutex_*,Pool::get_slow,Pool::put_valuein a samply profile), and date inference cost +1.41 s CPU on 16 threads vs +0.75 s single-threaded.regex!now returns a&'static LocalKey<Regex>holding a per-thread clone of the once-compiled regex.Regex::cloneshares the compiled program (Arc) but builds a fresh cache pool (meta/regex.rsimpl Clone for Regex), so each thread owns its pool. It's thread-local rather than a leaked&'staticclone, so long-lived processes that churn threads don't accumulate lazy-DFA caches. The 23 call sites change mechanically:re.is_match(input)becomesre.with(|r| r.is_match(input)), and likewise forfind/captures, whose results borrow only the haystack.Benchmarks
qsv statson NYC 311 (1M rows, 539 MB), 16 jobs, M4 Max, release build. Outputs are byte-identical before/after across--infer-dates,--everything --infer-dates,--prefer-dmy --jobs 1and--dates-whitelist all:--infer-dates--infer-dates --dates-whitelist all--jobs 1 --infer-datesTesting
cargo test,cargo fmt --check,cargo clippy --workspace --tests --all-features -D warnings: all pass🤖 Generated with Claude Code