Skip to content

perf: optimize spark_unhex in spark-expr#4876

Open
andygrove wants to merge 3 commits into
apache:mainfrom
andygrove:auto-opt/spark_unhex-2026-07-09-pr1
Open

perf: optimize spark_unhex in spark-expr#4876
andygrove wants to merge 3 commits into
apache:mainfrom
andygrove:auto-opt/spark_unhex-2026-07-09-pr1

Conversation

@andygrove

@andygrove andygrove commented Jul 9, 2026

Copy link
Copy Markdown
Member

This PR was created by an LLM as a draft PR. I will mark it as ready for review after human review.

What changed

Optimizes spark_unhex in the native spark-expr crate.

Replace unhex's per-digit range-match with a compile-time 256-entry hex lookup table and preallocate the BinaryBuilder to its known output size, cutting per-byte branching and repeated buffer reallocations.

Evidence

  • Correctness: unit tests + seeded differential fuzz (bit-identical Arrow output vs main).
  • Benchmark (criterion, Rust-only): baseline (main) vs this branch, across five input shapes (8192-row columns). All changes are statistically significant (p < 0.05).
spark_unhex: long strings:      31.5% faster (365us -> 250us)
spark_unhex: all valid:         23.2% faster (110us ->  85us)
spark_unhex: with nulls:        14.0% faster (105us ->  90us)
spark_unhex: mixed hex column:  12.6% faster (106us ->  93us)
spark_unhex: invalid inputs:     1.9% faster (133us -> 130us)

@andygrove andygrove marked this pull request as ready for review July 10, 2026 03:16
Comment thread native/spark-expr/src/math_funcs/unhex.rs Outdated
@mbutrovich

Copy link
Copy Markdown
Contributor

I can't find all of the benchmarks in the PR description in the code. Were they temporary, hallucinated, or am I missing something?

@andygrove andygrove marked this pull request as draft July 10, 2026 15:27
@andygrove

Copy link
Copy Markdown
Member Author

I can't find all of the benchmarks in the PR description in the code. Were they temporary, hallucinated, or am I missing something?

This was the first live run and there were some glitches. Will update the PR with the full benchmarks.

Cover valid/nulls/long/invalid/mixed columns instead of a single case, and
replace the fully-qualified arrow::array::BinaryBuilder with a use import.
@andygrove

Copy link
Copy Markdown
Member Author

Updated. Two things:

Benchmarks — you were right, the original description listed benchmark IDs that weren't in the code. This was the first live run of an automated tool, and it had a bug: criterion measurements from earlier attempts on this same function accumulated in target/criterion and got scraped into the PR description, even though the committed benchmark only ever had the single mixed hex column case. I've fixed the tooling (it now wipes stale criterion results before measuring) and rewritten the benchmark to genuinely cover five input shapes. Freshly measured, baseline (main) vs this branch, 8192-row columns, all p < 0.05:

  • long strings: 31.5% faster (365µs → 250µs)
  • all valid: 23.2% faster (110µs → 85µs)
  • with nulls: 14.0% faster (105µs → 90µs)
  • mixed hex column: 12.6% faster (106µs → 93µs)
  • invalid inputs: 1.9% faster (133µs → 130µs)

The description now reflects exactly these numbers.

FQN — replaced the fully-qualified arrow::array::BinaryBuilder with a use import. Thanks for the review!

@comphead comphead left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @andygrove I would also port more tests from spark with bad inputs.

unhex('-123')
unhex('\0')

@andygrove andygrove marked this pull request as ready for review July 10, 2026 16:41
@andygrove andygrove requested a review from mbutrovich July 10, 2026 16:41

@mbutrovich mbutrovich left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @andygrove!

@andygrove

Copy link
Copy Markdown
Member Author

Thanks @andygrove I would also port more tests from spark with bad inputs.

unhex('-123')
unhex('\0')

I created a separate PR to add these cases.

#4890

…2026-07-09-pr1

# Conflicts:
#	native/spark-expr/Cargo.toml
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.

3 participants