Skip to content

[SPARK-59062][CORE] Word-at-a-time single-byte search for UTF8String.contains - #58354

Open
david-mollitor-db wants to merge 1 commit into
apache:masterfrom
david-mollitor-db:SPARK-contains-swar
Open

[SPARK-59062][CORE] Word-at-a-time single-byte search for UTF8String.contains#58354
david-mollitor-db wants to merge 1 commit into
apache:masterfrom
david-mollitor-db:SPARK-contains-swar

Conversation

@david-mollitor-db

@david-mollitor-db david-mollitor-db commented Aug 27, 2026

Copy link
Copy Markdown

What changes were proposed in this pull request?

UTF8String.contains scans for the needle byte-by-byte. For a single-byte needle --
the common case produced by LIKE '%x%' (which the optimizer rewrites to Contains) with
an ASCII character -- this PR adds a word-at-a-time (SWAR / memchr-style) scan.

  • New ByteArrayMethods.containsByte(Object base, long offset, long length, byte target):
    broadcasts the target byte to all 8 lanes of a word, then for each 8-byte word XORs and
    applies the classic exact "a word contains a zero byte" test
    (w - 0x0101010101010101L) & ~w & 0x8080808080808080L. It reports only existence, not
    position, so it is endianness independent. Alignment handling mirrors arrayEquals.
  • UTF8String.contains takes a numBytes == 1 fast path delegating to it, which also drops
    the redundant per-position matchAt call.

Why are the changes needed?

Contains single-character predicates are common ('%,%', '%@%', '% %', '%/%'). The
current byte-at-a-time scan reads through Platform.getByte (Unsafe), which the JIT cannot
auto-vectorize, so it processes one byte per iteration.

Does this PR introduce any user-facing change?

No.

How was this patch tested?

UTF8StringSuite.contains gains single-byte cases (first byte, past the first word, last
byte, absent, sub-word length); the property-based UTF8StringPropertyCheckSuite also passes.

Local microbenchmark (needle absent, i.e. full scan), nanoseconds per call:

Region size Current (byte-at-a-time) This PR (SWAR) Speedup
16 B 5.2 2.7 1.9x
64 B 14.4 6.0 2.4x
256 B 54.1 17.3 3.1x
1 KB 177.4 62.6 2.8x
16 KB 2691.3 963.5 2.8x
64 KB 10753.5 3974.6 2.7x

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Opus 4.8

…contains

`UTF8String.contains` scans byte-by-byte. For a single-byte needle -- the common
case produced by `LIKE '%x%'` (rewritten to `Contains`) with an ASCII character --
add a word-at-a-time (SWAR / memchr-style) scan that checks 8 bytes per iteration.

Add `ByteArrayMethods.containsByte(base, offset, length, target)`, which XORs each
8-byte word with the broadcast target byte and uses the exact "word contains a zero
byte" test `(w - 0x0101010101010101L) & ~w & 0x8080808080808080L`. It reports only
existence (not position), so it is endianness independent; alignment handling
mirrors `arrayEquals`. `UTF8String.contains` takes a `numBytes == 1` fast path that
delegates to it, which also drops the redundant per-position `matchAt` call.
@david-mollitor-db david-mollitor-db changed the title [SPARK-XXXXX][CORE] Word-at-a-time single-byte search for UTF8String.contains [SPARK-59062][CORE] Word-at-a-time single-byte search for UTF8String.contains Aug 27, 2026
@david-mollitor-db
david-mollitor-db marked this pull request as ready for review August 27, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant