Repository navigation
perf: SIMD accelerate escape routines with memchr (fixes #405) - #1013
dhimasardinata wants to merge 1 commit into
Conversation
|
@dhimasardinata Can you share the impact these changes have on the One thing we need to be careful of is that some escape functions often operate on short strings, where SIMD can actually be slower. Of course it's also very much hardware dependent so results on one system can't be easily generalized. |
|
Thanks @dralley — good point about short strings. This PR uses 2x
I triggered CI after fixing missing_docs lint; will paste |
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1013 +/- ##
==========================================
- Coverage 57.31% 55.19% -2.12%
==========================================
Files 46 51 +5
Lines 18197 18832 +635
==========================================
- Hits 10429 10395 -34
- Misses 7768 8437 +669
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Replace scalar iter.position closure in _escape with memchr SIMD. escape (6 chars <>&'"\r): 2x memchr3 partial (4 chars <>&\r): memchr3 + memchr minimal (3 chars <&\r): memchr3 single pass attribute (8 chars <>&'"\r\n\t): 2x memchr3 + memchr2 Before used iter.position(|&b| matches!(...)) scalar per byte. Now uses memchr crate which uses SSE2/AVX2 runtime dispatch. Verif: cargo test --lib + cargo bench --bench microbenches escape_text Related: tafia#718 stringzilla comparison shows 6x reverse throughput with SIMD _escape now takes Cow<'a, str> directly instead of impl Into<Cow> to avoid monomorphisation per call site
c989f9e to
de26776
Compare
|
I do not see any changes in performance on my hardware. Also note, that some benchmarks has very low threshold for reporting performance changing. From my experiments, if you see numbers <10-15%, this is a noise. The escape benchmarks are not at all indicative -- the results floats ±90% simply from various runs on the same code. It seems that there is currently no point in changing anything, unless there are more convincing benchmarks, possibly on large files (>10Mb at least). I've also checked this in the same manner as in this #1012 (comment), and didn't see any difference. |
Fixes #405
Replace scalar
iter.position(|&b| matches!(b, <>&'"\r))in_escapewith SIMDmemchr(SSE2/AVX2 runtime dispatch viamemchrcrate).Previously
_escapeused generic closureiter.position()scalar per byte.Now
_escape_with(find: fn(&[u8])->Option<usize>)dispatches to SIMD search.Bench
cargo bench --bench microbenches -- escape_text(needs #404 coverage, now available):escape_text/no_chars_to_escape_long" andescaped_chars_long" expected 2-5% win on AVX2, larger on short strings (avoid closure overhead)jetscii(handles 16) but uses existingmemchrdep to avoid new dep; can switch to jetscii later if gains shown inmemchrvsstringzillaperformance comparison #718.Verif:
cargo test --libpass,cargo bench --bench microbenches escape_text --sample-size 10Related: #718 memchr vs stringzilla 6.2x reverse throughput with SIMD