perf: skip non-candidate bytes when backtracking in strings::like - #3
Open
felipeblazing wants to merge 1 commit into
Open
perf: skip non-candidate bytes when backtracking in strings::like#3felipeblazing wants to merge 1 commit into
felipeblazing wants to merge 1 commit into
Conversation
The thread-per-row like_fn backtracks one target character at a time after a
multi-wildcard. Each retry decodes a full UTF-8 character from the target,
decodes a character from the pattern, and runs the escape/single-wildcard
branch chain -- roughly 20-25 instructions to reject one byte. For the very
common '%literal%' shapes almost every retry fails on the first character, so
nearly all of the kernel time goes into proving that a byte is not the first
byte of the literal.
On backtrack, first skip over target bytes that differ from the first byte of
the literal being resumed. Such bytes provably cannot begin a match, so this is
semantics-preserving.
The test is on the raw pattern byte rather than the decoded character. That is
cheaper (no UTF-8 decode on the backtrack path) and still safe: '_', '%' and a
single-byte escape are all ASCII, so a decoded character can equal one of them
only if its first byte does; and requiring a lead byte means a byte-wise search
can only land on a character boundary. Anything the test rejects simply falls
back to the previous unskipped walk.
Measured on GB300 / CUDA 13.2 over a TPC-H o_comment-shaped column (16M rows,
lengths uniform in [19,78], mean 48.5 bytes), pattern '%special%requests%':
7.380 ms -> 2.940 ms, 2.51x. Across mean lengths 24-200 bytes the gain is
2.29x-2.67x, and 2.8x-3.5x for other multi-wildcard patterns. Patterns with no
leading wildcard never backtrack and are unchanged (0.99x). The one regression
is a literal starting with '_' directly after a wildcard ('%_pecial%', 0.90x),
where the skip can never fire but its guard is still evaluated per backtrack.
Validated against the current implementation over 428 patterns (including
escapes, consecutive wildcards and multi-byte UTF-8) x 2 escape settings x
20000 random strings: identical results on every row.
Co-Authored-By: Claude Opus 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.
The thread-per-row like_fn backtracks one target character at a time after a
multi-wildcard. Each retry decodes a full UTF-8 character from the target,
decodes a character from the pattern, and runs the escape/single-wildcard
branch chain -- roughly 20-25 instructions to reject one byte. For the very
common '%literal%' shapes almost every retry fails on the first character, so
nearly all of the kernel time goes into proving that a byte is not the first
byte of the literal.
On backtrack, first skip over target bytes that differ from the first byte of
the literal being resumed. Such bytes provably cannot begin a match, so this is
semantics-preserving.
The test is on the raw pattern byte rather than the decoded character. That is
cheaper (no UTF-8 decode on the backtrack path) and still safe: '_', '%' and a
single-byte escape are all ASCII, so a decoded character can equal one of them
only if its first byte does; and requiring a lead byte means a byte-wise search
can only land on a character boundary. Anything the test rejects simply falls
back to the previous unskipped walk.
Measured on GB300 / CUDA 13.2 over a TPC-H o_comment-shaped column (16M rows,
lengths uniform in [19,78], mean 48.5 bytes), pattern '%special%requests%':
7.380 ms -> 2.940 ms, 2.51x. Across mean lengths 24-200 bytes the gain is
2.29x-2.67x, and 2.8x-3.5x for other multi-wildcard patterns. Patterns with no
leading wildcard never backtrack and are unchanged (0.99x). The one regression
is a literal starting with '_' directly after a wildcard ('%_pecial%', 0.90x),
where the skip can never fire but its guard is still evaluated per backtrack.
Validated against the current implementation over 428 patterns (including
escapes, consecutive wildcards and multi-byte UTF-8) x 2 escape settings x
20000 random strings: identical results on every row.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com