feat(wheels): publish lancedb-compat for pre-Haswell x86_64 hosts#3327
Conversation
5bee0e4 to
778c15a
Compare
The default lancedb wheel targets target-cpu=haswell (AVX2 + FMA + F16C) and SIGILLs at import on pre-Haswell silicon (Sandy Bridge / Ivy Bridge / Westmere on Intel; Bulldozer / Piledriver / Steamroller on AMD). Per westonpace's review on lancedb#3324 (fast by default, extra steps to work on legacy), the default wheel baseline stays fast for modern users; pre-Haswell users get a separately-published 'lancedb-compat' wheel. Adds a 'lancedb-compat' matrix entry to pypi-publish.yml that builds with RUSTFLAGS=-C target-cpu=x86-64-v2 (Nehalem-class baseline). The compat wheel relies on runtime SIMD dispatch in the embedded lance crate (landing via lance-format/lance#6630) to pick the appropriate kernel tier at load time, so it still goes fast on modern hardware. Generalizes build_linux_wheel and upload_wheel composites with optional package-name and rustflags inputs (defaults preserve current behavior for the existing 4 lancedb matrix entries). Documents the choice in python/README.md: pip install lancedb-compat for pre-Haswell hosts; same import lancedb API. Maintainer setup required before this can ship: register lancedb-compat on PyPI and configure trusted publishing. Blocked on lance-format/lance#6630.
778c15a to
e5d005a
Compare
…re-haswell-build # Conflicts: # .github/workflows/build_linux_wheel/action.yml
|
friendly bump @wjones127 @westonpace — lance-format/lance#6630 has been merged so this is now ready for review and I'm taking it out of draft. I updated the PR description to now have the benchmarks from the lance work as well |
| # / AVX-512) at load time. Same import as `lancedb` -- conflicts | ||
| # at install time, so users pick one. | ||
| - platform: x86_64 | ||
| manylinux: "2_17" |
There was a problem hiding this comment.
suggestion: we dropped support for 2_17, as have most projects. Can we use 2_28 instead? (Might need to change the name of the job too to prevent collisions.) The purposes of this is to support outdated hardware, not software, right?
There was a problem hiding this comment.
that's right, I'll update it now.
There was a problem hiding this comment.
Also, this exposed a bug.
I updated the compat wheel artifact name. it was wheels-linux-{platform}-{manylinux}, which collides with the default.
It now includes the package name, same as the job name.
Also found an issue where beta tags would have built the compat wheel but skipped publishing it.
The compat wheel targeted manylinux 2_17, which lancedb no longer supports. The variant exists to support outdated hardware, not outdated glibc, so it now builds on 2_28 like the other wheels. Since all three linux matrix entries are now x86_64/aarch64 on 2_28, the job name and wheel artifact name no longer uniquely identify an entry. Both now include the package name. Also widen the Fury upload glob, which matched lancedb-*.whl and so would have skipped the compat wheel -- its distribution filename normalizes to lancedb_compat-*.whl.
The rustflags input was interpolated unconditionally into docker-options, which broke both wheels. For the default lancedb builds the input is empty, so the container got '-e RUSTFLAGS='. Cargo treats RUSTFLAGS as an override whenever it is set -- even to the empty string -- so it discarded the per-target rustflags in .cargo/config.toml and silently dropped -Ctarget-cpu=haswell and +avx2,+fma,+f16c from the released x86_64 wheel. The same input default made this true of the CI wheel built by python.yml. For the compat build the value contained a space. maturin-action argv-splits docker-options (string-argv), so '-e RUSTFLAGS=-C target-cpu=x86-64-v2' tore into 'RUSTFLAGS=-C' plus a stray 'target-cpu=x86-64-v2' argument to docker run. The '-e RUSTFLAGS=...' argument is now emitted only when the input is non-empty, and the value is a single whitespace-free token.
|
One thing here needs maintainer setup: Without it the tag publishes the I also fixed a bug of my own in 7277917: the empty |
|
Docs PR opened: lancedb/docs#311 Added a Quickstart section explaining when and how to install the new lancedb-compat wheel on pre-Haswell x86_64 CPUs. |
Tracks #3324. On x86_64 CPUs without AVX2 (Sandy Bridge / Ivy Bridge / Westmere on Intel; Bulldozer / Piledriver / Steamroller on AMD),
import lancedbSIGILLs because the wheel bakes AVX2 + FMA into every compiled function. Per westonpace's review, the defaultlancedbwheel stays fast; pre-Haswell users get a separately-publishedlancedb-compatwheel.Summary
lancedb-compatmatrix entry topypi-publish.ymlthat builds withRUSTFLAGS="-C target-cpu=x86-64-v2"(Nehalem-class baseline). Same Python API (import lancedbworks) — files install to the same namespace, so the two wheels conflict at install time and users pick one. Same pattern aspsycopg2/psycopg2-binaryandtensorflow/tensorflow-cpu.build_linux_wheelandupload_wheelcomposites with optionalpackage-nameandrustflagsinputs (defaults preserve the existing 4lancedbmatrix entries verbatim).python/README.md:pip install lancedb-compatfor pre-Haswell hosts.The default
.cargo/config.tomlbaseline is unchanged.Sequencing
feat(lance-linalg): runtime SIMD dispatch for pre-Haswell x86_64 from-source builds lance-format/lance#6630 merges → runtime SIMD dispatch lands in lance.Done — merged.lancedb-compatwheel build path starts producing a wheel that runs on pre-Haswell hardware. Maintainer setup: registerlancedb-compaton PyPI and configure trusted publishing.Verified end-to-end on Sandy Bridge Xeon E5-2609
Verification was done locally against a fork-pinned lance dep that includes the runtime dispatch implementation, using the same
RUSTFLAGS="-C target-cpu=x86-64-v2"flags this PR uses in CI:Pre-fix on the same CPU (default
pip install lancedb):Illegal instruction (core dumped). Full reproducer (deps + clone + build + verification): https://gist.github.com/tobocop2/2e341358b55c143527416edfdb1e37df. Fork-internal verification PR with the dep bump and full logs:tobocop2/lancedb#2.Benchmarks — no regressions on modern CPUs from the lance-side change
These are the numbers I ran for the lance PR, confirming the runtime dispatch doesn't slow down the default (
target-cpu=haswell) wheel that existing users install. Criterion, one machine, one session, base → PR, noRUSTFLAGSoverride. Full methodology, null experiments, and logs: lance-format/lance#6630 benchmark comment and the logs gist.avx2,fma, noavx512f)avx512f)Cosine(f32, scalar)(control)Cosine(f64, scalar)Cosine(u8, SIMD)Dot(f16, SIMD)Dot(f32, SIMD)Dot(f32, arrow_arity)L2(f32, scalar)L2(f32, simd)(dim 1024)L2(simd,f32x8)(dim 8)L2(u8, SIMD)NormL2(f32, SIMD)NormL2(f64, SIMD)Nothing regresses beyond the noise floor. Dim 8 — the PQ sub-vector width — improves 25–46%.
To be transparent: this isn't my domain of expertise and the lance-side implementation is AI-generated. I verified it works end-to-end on the failing hardware. Happy to roll in feedback.