fix(llm): rebuild pgvector without AVX-512 so HNSW builds on Zen2 (closes #580)
Upstream Bitnami vector.so was built -march=native on an AVX-512 host; vector_norm's EVEX AVX-512 (vextractf64x2/vcvtusi2sd) SIGILLs the Ryzen 3950X during hnsw/ivfflat index builds, crashing the shared postgres. infra/images/postgresql.Dockerfile rebuilds pgvector -march=x86-64-v3 FROM the mirror; compose + deploy.sh build fhirworx/postgresql:pgvector. HNSW verified on the 15852-vector pilot (~2s, index scan). Flip [llm].build_ann_index default to true.
This commit is contained in:
@@ -136,8 +136,15 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: ${IMAGE_PREFIX:-fhirworx}/postgresql:latest
|
# Patched pgvector (AVX-512-free) built FROM the upstream mirror — the
|
||||||
|
# stock vector.so SIGILLs this Zen2 host on hnsw/ivfflat index builds (#580).
|
||||||
|
image: ${IMAGE_PREFIX:-fhirworx}/postgresql:pgvector
|
||||||
pull_policy: if_not_present
|
pull_policy: if_not_present
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: infra/images/postgresql.Dockerfile
|
||||||
|
args:
|
||||||
|
BASE: ${IMAGE_PREFIX:-fhirworx}/postgresql:latest
|
||||||
container_name: postgres
|
container_name: postgres
|
||||||
networks:
|
networks:
|
||||||
- storage
|
- storage
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ declare -A BUILDABLE=(
|
|||||||
[zotero]="${PREFIX}/zotero:${HEAVY}"
|
[zotero]="${PREFIX}/zotero:${HEAVY}"
|
||||||
[docs]="${PREFIX}/docs:${SHA}"
|
[docs]="${PREFIX}/docs:${SHA}"
|
||||||
[api]="${PREFIX}/api:${SHA}"
|
[api]="${PREFIX}/api:${SHA}"
|
||||||
|
# Patched pgvector (AVX-512-free) built FROM the postgresql:latest mirror (#580).
|
||||||
|
[postgres]="${PREFIX}/postgresql:pgvector"
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── Pre-flight: check local images ─────────────────────────────────
|
# ── Pre-flight: check local images ─────────────────────────────────
|
||||||
|
|||||||
@@ -91,20 +91,23 @@ minus the task server it feared.
|
|||||||
|
|
||||||
P33 landed on branch `llm-p33`. Two infrastructure findings changed the plan:
|
P33 landed on branch `llm-p33`. Two infrastructure findings changed the plan:
|
||||||
|
|
||||||
**pgvector ANN index build crashes the shared Postgres (AVX-512 SIGILL).** The
|
**pgvector ANN index build crashed the shared Postgres (AVX-512 SIGILL) —
|
||||||
mirrored `fhirworx/postgresql:latest` image (Bitnami PG18, shared by
|
fixed (#580).** The mirrored `fhirworx/postgresql:latest` image (Bitnami PG18,
|
||||||
gitea/nessie/polaris) ships a pgvector 0.8.1 `vector.so` built with AVX-512,
|
shared by gitea/nessie/polaris) shipped a pgvector 0.8.1 `vector.so` built with
|
||||||
but the server host is a Ryzen 9 3950X (Zen 2, no AVX-512). `CREATE INDEX …
|
`-march=native` on an AVX-512 build host, but the server is a Ryzen 9 3950X
|
||||||
USING hnsw` **and** `ivfflat` fault with signal 4 (SIGILL) — even on 3 rows —
|
(Zen 2, no AVX-512). `CREATE INDEX … USING hnsw` **and** `ivfflat` faulted with
|
||||||
and the fault kills every backend, dropping the whole server (and its other
|
signal 4 (SIGILL) — even on 3 rows — because `vector_norm()` executed
|
||||||
databases) into recovery. Index-free **exact search works fine** (query-time
|
EVEX-encoded AVX-512 (`vextractf64x2`, `vcvtusi2sd`); the fault killed every
|
||||||
distance dispatch is correct; only the bulk index-build path faults). Decision:
|
backend and dropped the whole server (and its other databases) into recovery.
|
||||||
ANN index creation is gated behind `[llm].build_ann_index` (**default false**);
|
Query-time distance ops were compiled as legal AVX2, which is why exact search
|
||||||
the module ships on exact search. Restoring HNSW needs the image's pgvector
|
never faulted. **Fixed** by `infra/images/postgresql.Dockerfile`: a patched
|
||||||
rebuilt without AVX-512 (thin image `FROM fhirworx/postgresql:latest` replacing
|
`fhirworx/postgresql:pgvector` image built `FROM` the mirror that rebuilds
|
||||||
`vector.so` with a `-march=x86-64-v2`/`znver2` build) — filed as a P33
|
pgvector with `-march=x86-64-v3` (AVX2/FMA, fully supported by Zen 2) and swaps
|
||||||
follow-up issue. Exact search on the pilot (15,852 vectors) answers in ~1.2 s
|
in the AVX-512-free `vector.so`. Verified: HNSW builds on the 15,852-vector
|
||||||
for two queries, so this is not urgent at pilot scale.
|
pilot in ~2 s with no crash, queries use `Index Scan using ix_embedding_hnsw`,
|
||||||
|
and dependents are unaffected. `[llm].build_ann_index` now **defaults true**;
|
||||||
|
set it false to fall back to exact search. `compose.yml` and `deploy.sh` build
|
||||||
|
the patched image from the mirror base.
|
||||||
|
|
||||||
**Embed model bake-off (#564).** Retrieval-proxy metric (comment abstract as
|
**Embed model bake-off (#564).** Retrieval-proxy metric (comment abstract as
|
||||||
query against its own pooled chunks, 120 pilot comments):
|
query against its own pooled chunks, 120 pilot comments):
|
||||||
|
|||||||
40
infra/images/postgresql.Dockerfile
Normal file
40
infra/images/postgresql.Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# Rebuild pgvector without AVX-512.
|
||||||
|
#
|
||||||
|
# The upstream Bitnami image (fhirworx/postgresql:latest — PostgreSQL 18.1 on
|
||||||
|
# VMware Photon) ships a vector.so built with pgvector's default
|
||||||
|
# OPTFLAGS=-march=native on an AVX-512-capable build host. On this server's
|
||||||
|
# Ryzen 9 3950X (Zen 2, no AVX-512) the hnsw/ivfflat index BUILD path SIGILLs:
|
||||||
|
# vector_norm() executes EVEX-encoded AVX-512 (vextractf64x2 @ 0x1fe11,
|
||||||
|
# vcvtusi2sd @ 0x121d4) that the CPU rejects, which crashes the whole server
|
||||||
|
# (every backend, gitea/nessie/polaris included, drops into recovery).
|
||||||
|
# Query-time distance ops were compiled as legal AVX2, so exact search works —
|
||||||
|
# only the index build faults. Rebuilding pgvector with -march=x86-64-v3
|
||||||
|
# (AVX2/FMA/BMI2, fully supported by Zen 2) keeps SIMD while dropping every
|
||||||
|
# AVX-512 encoding. See issue #580.
|
||||||
|
ARG BASE=fhirworx/postgresql:latest
|
||||||
|
ARG PGVECTOR_VERSION=0.8.1
|
||||||
|
ARG PGVECTOR_SHA256=a9094dfb85ccdde3cbb295f1086d4c71a20db1d26bf1d6c39f07a7d164033eb4
|
||||||
|
|
||||||
|
FROM ${BASE} AS build
|
||||||
|
ARG PGVECTOR_VERSION
|
||||||
|
ARG PGVECTOR_SHA256
|
||||||
|
USER 0
|
||||||
|
# hadolint ignore=DL3041
|
||||||
|
RUN tdnf install -y gcc binutils make glibc-devel linux-api-headers tar gzip curl && \
|
||||||
|
curl -fsSL "https://github.com/pgvector/pgvector/archive/refs/tags/v${PGVECTOR_VERSION}.tar.gz" \
|
||||||
|
-o /tmp/pgvector.tar.gz && \
|
||||||
|
echo "${PGVECTOR_SHA256} /tmp/pgvector.tar.gz" | sha256sum -c - && \
|
||||||
|
tar -xzf /tmp/pgvector.tar.gz -C /tmp && \
|
||||||
|
make -C "/tmp/pgvector-${PGVECTOR_VERSION}" OPTFLAGS="-march=x86-64-v3" with_llvm=no && \
|
||||||
|
make -C "/tmp/pgvector-${PGVECTOR_VERSION}" install
|
||||||
|
|
||||||
|
FROM ${BASE}
|
||||||
|
USER 0
|
||||||
|
# Installing glibc-devel above pulled a glibc update, so the rebuilt vector.so
|
||||||
|
# links against the newer glibc; bump the runtime glibc to match (glibc is
|
||||||
|
# backward-compatible, so the existing postgres binaries keep working). This
|
||||||
|
# installs only glibc — no build tools reach the final image.
|
||||||
|
# hadolint ignore=DL3041
|
||||||
|
RUN tdnf install -y glibc && tdnf clean all
|
||||||
|
COPY --from=build /opt/bitnami/postgresql/lib/vector.so /opt/bitnami/postgresql/lib/vector.so
|
||||||
|
USER 1001
|
||||||
@@ -106,10 +106,10 @@ ollama = "http://127.0.0.1:11434" # host-side default; containers override v
|
|||||||
embed_model = "nomic-embed-text" # 768-dim; bake-off (P33 #564) may revise
|
embed_model = "nomic-embed-text" # 768-dim; bake-off (P33 #564) may revise
|
||||||
instruct_model = "llama3.1:8b" # bake-off may revise
|
instruct_model = "llama3.1:8b" # bake-off may revise
|
||||||
embed_dim = 768
|
embed_dim = 768
|
||||||
# ANN index build (hnsw/ivfflat) SIGILLs on this Zen2 host — the mirrored
|
# HNSW index build. Safe since the postgres image ships an AVX-512-free
|
||||||
# postgres image's pgvector is AVX-512. Leave false until the image is
|
# pgvector rebuild (infra/images/postgresql.Dockerfile, #580); before that it
|
||||||
# rebuilt; exact search works regardless.
|
# SIGILLed this Zen2 host. Set false to fall back to exact search.
|
||||||
build_ann_index = false
|
build_ann_index = true
|
||||||
pg_host = "127.0.0.1" # host-side default; containers set LLM_PG_HOST=postgres
|
pg_host = "127.0.0.1" # host-side default; containers set LLM_PG_HOST=postgres
|
||||||
pg_port = 5432
|
pg_port = 5432
|
||||||
pg_db = "llm"
|
pg_db = "llm"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class TestLoad:
|
|||||||
assert cfg.embed_dim == 768
|
assert cfg.embed_dim == 768
|
||||||
assert cfg.pg_host == "127.0.0.1"
|
assert cfg.pg_host == "127.0.0.1"
|
||||||
assert cfg.pg_db == "llm"
|
assert cfg.pg_db == "llm"
|
||||||
assert cfg.build_ann_index is False
|
assert cfg.build_ann_index is True
|
||||||
|
|
||||||
def test_env_overrides(self, monkeypatch):
|
def test_env_overrides(self, monkeypatch):
|
||||||
monkeypatch.setenv(
|
monkeypatch.setenv(
|
||||||
|
|||||||
Reference in New Issue
Block a user