fix: default distributions to automatic GPU support with CPU fallback

This commit is contained in:
karl committed 2026-10-12 21:42:31 +02:00
1 parent d9336db1d5
commit 0fcc8ec21c
9 files changed
+43 -15

No files matched your search

+4
View File
@@ -9,6 +9,10 @@ readiness without completed release gates and recorded evidence.
- All tests in the Windows VM must use CPU only. Never enable GPU providers here.
- Production uses available GPU/hardware acceleration with reliable CPU fallback;
the CPU-only rule is a VM testing constraint, not a product restriction.
Ship one normal hardware-detecting runtime per OS/architecture. Default
builds/staging use auto (Metal on macOS, Vulkan on Windows/Linux plus CPU).
Missing acceleration build SDKs must fail release preparation, never silently
produce CPU-only distributions. Explicit CPU builds remain internal VM tools.
- Keep the Rust engine independent of the desktop shell; CLI and UI share its API.
- Prefer established Rust crates and proven retrieval algorithms over custom
implementations. Keep platform adapters small, bound allocations and queues,
@@ -10,12 +10,12 @@ endif()
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Static local worker runtime" FORCE)
set(GGML_OPENMP OFF CACHE BOOL "Use bounded native llama thread pools without external OpenMP runtime" FORCE)
set(GGML_NATIVE OFF CACHE BOOL "Portable CPU kernels")
# GPU backends are explicit production build options. The Windows VM builds
# with all of these OFF; runtime device selection always retains CPU fallback.
# Normal distribution builds include GPU support and CPU fallback. CPU-only
# configuration is explicitly reserved for development/testing in the VM.
set(GGML_CUDA OFF CACHE BOOL "Production CUDA backend")
set(GGML_VULKAN OFF CACHE BOOL "Production Vulkan backend")
set(GGML_METAL OFF CACHE BOOL "Production Metal backend")
set(SEARCHI_ACCELERATION "cpu" CACHE STRING "cpu, auto, metal, vulkan, or cuda")
set(SEARCHI_ACCELERATION "auto" CACHE STRING "auto; explicit developer overrides: cpu, metal, vulkan, cuda")
if(SEARCHI_ACCELERATION STREQUAL "cpu")
set(GGML_CUDA OFF CACHE BOOL "CPU test build" FORCE)
set(GGML_VULKAN OFF CACHE BOOL "CPU test build" FORCE)
@@ -27,12 +27,10 @@ elseif(SEARCHI_ACCELERATION STREQUAL "cuda")
elseif(SEARCHI_ACCELERATION STREQUAL "vulkan")
set(GGML_VULKAN ON CACHE BOOL "Production Vulkan backend" FORCE)
elseif(SEARCHI_ACCELERATION STREQUAL "auto")
find_package(Vulkan QUIET)
if(Vulkan_FOUND)
set(GGML_VULKAN ON CACHE BOOL "Available production Vulkan backend" FORCE)
else()
message(STATUS "No production acceleration SDK detected; retaining CPU backend")
endif()
# A missing build SDK must not silently turn a normal release into a
# CPU-only artifact. End users need drivers, not this compilation SDK.
find_package(Vulkan COMPONENTS glslc REQUIRED)
set(GGML_VULKAN ON CACHE BOOL "Production GPU support with runtime CPU fallback" FORCE)
else()
message(FATAL_ERROR "Unknown SEARCHI_ACCELERATION=${SEARCHI_ACCELERATION}")
endif()
+8
View File
@@ -86,6 +86,14 @@ search starts a model process; the desktop retains a prewarmed query worker.
## Cross-compilation and native release matrix
Normal distribution worker builds and staging default to `auto`: Metal on
macOS, Vulkan on Windows/Linux, with CPU fallback in the same application.
Users do not choose a CPU/GPU edition or rebuild for their graphics card.
Windows/Linux build machines need the Vulkan SDK including `glslc`; absence
fails release preparation instead of quietly generating a CPU-only runtime.
The compilation SDK is not an end-user requirement. Explicit `--backend cpu`
commands in the VM development sections are internal test configurations.
The shared Rust engine/service has no GUI dependency. Install a destination
Rust target with `rustup target add TARGET`, then build using
`cargo build -p searchi-cli --target TARGET --locked`. This also requires the
+4
View File
@@ -49,6 +49,10 @@ Status: implementation started; no production release yet. Windows VM tests use
- [ ] Isolated extraction workers with timeouts and resource ceilings.
## 5. Release gates
- [x] Normal worker build/staging defaults to hardware-detecting auto with CPU
fallback; missing Vulkan/glslc fails configuration rather than hiding GPU loss.
- [ ] Provision release-build GPU SDKs and verify one hardware-detecting package
per OS/architecture, including missing-driver fallback and dependency closure.
- [x] Windows desktop archive packager includes explicit runtime/helper files
and notices, checks architecture and records per-file checksums; excludes
model caches and user data. Controlled packaging regression tests pass.
+8 -1
View File
@@ -33,6 +33,13 @@ an external OpenMP runtime. Production CMake supports cpu, auto, metal, vulkan,
and cuda; CPU builds force GPU flags off. Runtime/provider parity and packaging
on other operating systems remain independent release checks.
The normal build/staging default is `auto`, shipping GPU support together with
CPU fallback: Metal on macOS, Vulkan on Windows/Linux. Runtime detection chooses
the usable device; users do not need hardware-specific builds. Release builders
must have the relevant compilation SDK. Missing Vulkan/glslc now fails the
normal build rather than silently omitting acceleration. Actual GPU parity,
loader/dependency packaging and no-driver CPU fallback still require evidence.
| Artifact | Bytes | SHA256 |
| --- | ---: | --- |
| embeddinggemma-2-Q8_0.gguf | 309,855,456 | 2188ac1deca4b77dffefd603c2776a9d76d9d74ec01841392982ebb840b09135 |
@@ -264,4 +271,4 @@ point-localization failures and unsuppressed no-answer results. Strong file
recall is insufficient for accurate spoken-topic navigation. A ten-second audio
experiment reduces some distances but does not close that gate; it is not a
new default. Quality policies must be validated on held-out data rather than
inventing thresholds from the evaluation corpus.
inventing thresholds from the evaluation corpus.
+9 -2
View File
@@ -11,8 +11,15 @@ The Windows archive packager has two controlled Python regressions: complete
required file collection with checksum verification and user-settings exclusion,
and mismatched worker architecture preserving the previous archive. Both pass.
An actual CPU-only Tauri embedded-frontend Release build has been started;
archive creation, native launch outside the source tree and clean-machine
installation remain unverified until its completion and separate checks.
the embedded-frontend Release application build completed in 7m 25s. CPU-only
describes its VM test context, not a supported end-user edition. The normal
worker build/staging defaults are now auto and require GPU compilation support
alongside CPU fallback. The previously staged CPU worker remains an internal
test artifact; archive creation, automatic-runtime dependency packaging, native
launch outside the source tree and clean-machine installation remain unverified.
Actual `auto` configuration correctly rejected this VM's missing Vulkan library,
headers and `glslc`; no GPU-capable worker/package is claimed. Both staging
regressions still pass using explicit internal CPU test configuration.
Offline staging now verifies the native license and every bundled Google asset
before modifying resources. Two Python regressions verify missing-model rejection
+1 -1
View File
@@ -17,7 +17,7 @@ def run(arguments, cwd=None):
def main():
parser = argparse.ArgumentParser(description="Build Searchi's pinned Google embedding worker")
parser.add_argument("--backend", choices=["cpu", "auto", "metal", "vulkan", "cuda"], default="cpu")
parser.add_argument("--backend", choices=["cpu", "auto", "metal", "vulkan", "cuda"], default="auto")
parser.add_argument("--jobs", type=int, default=2)
args = parser.parse_args()
if not 1 <= args.jobs <= 16:
+1 -1
View File
@@ -25,7 +25,7 @@ def verify_bundle(root, manifest):
def main():
parser = argparse.ArgumentParser(description="Stage Searchi runtime resources")
parser.add_argument("--backend", choices=["cpu", "auto", "metal", "vulkan", "cuda"], default="cpu")
parser.add_argument("--backend", choices=["cpu", "auto", "metal", "vulkan", "cuda"], default="auto")
parser.add_argument("--bundle-model", action="store_true")
args = parser.parse_args()
name = "searchi-gemma-worker.exe" if os.name == "nt" else "searchi-gemma-worker"
+1 -1
View File
@@ -32,7 +32,7 @@ class StagingTests(unittest.TestCase):
(models / filename).write_bytes(content)
specs.append({"path": filename, "bytes": len(content), "sha256": hashlib.sha256(content).hexdigest()})
(models / "projector.gguf").write_bytes(b"corrupt!")
with patch.object(stage_runtime, "ROOT", root), patch("sys.argv", ["stage_runtime", "--bundle-model"]), patch.object(stage_runtime.json, "loads", return_value={"files": specs}):
with patch.object(stage_runtime, "ROOT", root), patch("sys.argv", ["stage_runtime", "--backend", "cpu", "--bundle-model"]), patch.object(stage_runtime.json, "loads", return_value={"files": specs}):
with self.assertRaisesRegex(RuntimeError, "checksum mismatch"):
stage_runtime.main()
self.assertEqual((destination / name).read_bytes(), b"previous worker")