Repository navigation
npu: hardware-gate NPU phase + closed, encrypted kernel delivery - #503
Conversation
Make the NPU engine shippable with the runtime and kernels closed, as compiled binaries only: - scripts/hw-gate.sh: a neutral `npu` phase (not in the default phases; add with --phases npu) that auto-skips with no NPU (/dev/accel/accel0) or no checker, and otherwise runs a private checker ($HW_GATE_NPU_CHECK) inside the gate's GPU claim and under ~/npu.lock, reads its neutral result lines (oracle vs an fp64 reference, greedy64, prefill, reproducibility) and applies a tok/s floor (HW_GATE_NPU_FLOOR). The checker and kernels are private; the gate carries no method. - config/npu-kernels.config: the private NPU-kernels pin the release fetches (ONEBIT_NPU_PRIVATE), same shape as config/gpu-kernels.config. - docs/npu.md, docs/releases.md: the NPU kernels ship as compiled, encrypted artifacts that `1bit` verifies and decrypts in memory at load (fails clean on a wrong key, no network callback); no source or method is public. Proven on Strix Halo (private npu-kernels npu/ship-sealed-kernels): the sealed dx kernel set decodes BYTE-IDENTICAL logits to the plain set (Qwen3-0.6B, 24/24 vs fp64, md5 9a405cf6...), 64/64 greedy at ~90 tok/s, a foreign-key set refused cleanly, a plain ELF refused under REQUIRE_SEALED, 0 amdxdna/IOMMU faults. The on-device gate `npu` phase run and wiring the kernels into the weekly package are the remaining steps (strixhalo was under a maintenance freeze). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PR Reviewer Guide 🔍(Review updated until commit 73c18dc)Here are some key observations to aid the review process:
|
Moves the NPU-kernels pin to 1bit-MONSTER/npu-kernels npu/ship-sealed-kernels HEAD (neutral sealed metadata). The pin moves to the merge commit when PR #13 lands. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Persistent review updated to latest commit 4e03ad6 |
…e npu gate passes) The release side of shipping the NPU kernels closed, compiled and encrypted only: - scripts/weekly.sh build: with WEEKLY_NPU_KERNELS=1, fetch config/npu-kernels.config and call the private checkout's one entry point (addons/release-kernels.sh <out> <key dir>), which installs the kernel key for the runtime build and writes the sealed sets to $BUILD/npu/kernels; build with ONEBIT_NPU_PRIVATE and ONEBIT_NPU_RELEASE=ON, so the packed 1bit loads sealed kernels only. The policy lives in the binary: the package has no launcher wrapper (Lemonade execs 1bit directly), so an environment variable could be unset. Default off until the hardware gate's npu phase passes on Strix Halo. - scripts/package-linux.sh: packs $BUILD/npu/kernels beside 1bit (npu/kernels), where the route looks for it. - package_checks (npu): every file under npu/kernels but layout.json is sealed, never a plaintext ELF; every ELF in the tarball is for the host (x86-64); the packed 1bit has no symbol table and its strings name no private source file and no build-machine home. Private-source file names now include the NPU-kernels checkout. - config/npu-kernels.config: pin the private branch head that has the entry point; neutral require= list. The pin moves to the merge commit when npu-kernels #13 lands. - docs/releases.md: the switch, the checks, the key directory (ONEBIT_NPU_KEY_DIR). Checked on ryzen: bash -n; package_checks on a synthetic good package passes all four new checks, and on a bad one fails each (plaintext kernel ELF, an EM 264 ELF, an unstripped 1bit with 25 symbols, a private source name, a /home/ path). Not run on Strix Halo yet (maintenance freeze): no weekly build with the switch on has been made. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… gate needs no llama.cpp - Pin 1bit-MONSTER/npu-kernels at dfe511236d03, the npu-dx merge of #13 (sealed kernel loading, release entry point, sealed-only release switch). fetch-private.sh fetches it and finds every require= file. - scripts/hw-gate.sh: the llama.cpp binary check applies to the HRX phases only, so --phases npu runs on a box with no HRX build. Dry run on ryzen (no NPU): npu SKIP, exit 0. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Persistent review updated to latest commit c2a5592 |
…arries the kernels Neutral: "the 1bit NPU engine runs the model on the XDNA 2 NPU", the serve command for a Qwen3 NPU model directory (0.6B, 1.7B, 4B), Lemonade's onebit npu backend, and that the kernels ship inside the package. README.txt gains the NPU serve line only when the package has npu/kernels. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Persistent review updated to latest commit 949029b |
|
Persistent review updated to latest commit 2c418be |
The first on-device run of the npu phase passed with an empty tok_s (a checker bug, npu-kernels #14): the floor check only ran when a number was present. Require a number; unit-checked on three checker outputs (90.50 PASS, empty FAIL, 41.2 below a 60 floor FAIL). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Persistent review updated to latest commit 7d0738a |
npu-kernels #14 fixes the awk printf redirection that left tok_s empty, so the gate npu phase speed floor now has a number to check (11.05 ms/step -> 90.50 tok/s on both gawk and mawk). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Persistent review updated to latest commit 73c18dc |
…e paths
package_checks refuses a package whose 1bit names a build-machine home, and that
rule is what the NPU delivery tripped: of the four /home/ strings the e2e
package carried, two came from the NPU defines themselves
(ONEBIT_NPU_REPACK_SCRIPT / ONEBIT_NPU_LANE_PACK_SCRIPT = ${CMAKE_SOURCE_DIR}/...)
and the other two from ONEBIT_BUILD_DIR = ${CMAKE_BINARY_DIR}. So the package
gate failed on #503's own NPU path.
Every backend path is now embedded relative to the build dir via
file(RELATIVE_PATH ...) (a new onebit_build_relative() helper) and
app/built_path.h resolves it from the executable's own directory
(/proc/self/exe). That is the same file a 1bit in the build tree has always
found, because the binary lives in the build dir; the package keeps that layout
beside the binary (scripts/package-linux.sh, pack_localize). Nothing
machine-specific is compiled in any more.
Sites: ONEBIT_HRX_SERVER, ONEBIT_DS4_SERVER, ONEBIT_ONNX_SERVER,
ONEBIT_LAYA_GGML_BIN, the two NPU python tools. ONEBIT_BUILD_DIR is removed and
has no remaining references. Absolute paths still work if a caller passes one
(an older build), and the env overrides (ONEBIT_LLAMA_SERVER etc.) are
unchanged and still win.
…patchelf abort) (#505) * package: ship only the sealed NPU artifact surface The release package carried the NPU kernel build tree. package-linux.sh did `cp -a "$build/npu/kernels"`, and a sealed set directory still holds its layer1.work/ next to the sealed kernels: ~340 object files, ~250 intermediate AIE ELFs, 10 design.mlir.prj dirs and ~20 plaintext .mlir per set (measured on strixhalo 2026-10-22, all three sets). Two consequences: 1. The kernel method travels in the clear. Sealing only rewrites layer1_*/layer1.elf; everything in layer1.work/ stays plaintext, so the MLIR and objects would have shipped in a public artifact. 2. Packaging could not finish. pack_localize treats every staged ELF as dynamically linked and runs `patchelf --set-rpath` on it; an AIE object is static, so the run died with "patchelf: cannot find section '.dynamic'. The input file is most likely statically linked" - the 06:04 e2e run, engine-pkg/ empty, no PR. Staging now copies the artifact surface explicitly: <set>/layout.json and <set>/layer1_*/layer1.elf, nothing else. package_checks asserts that allowlist on the tarball and names a leaked path, and .mlir/.mlirbc count as source files in the source scan. pack_localize only rewrites ELFs that actually have a .dynamic section (new pack_is_dynelf), so a static ELF is skipped instead of aborting the package. Verified on strixhalo against the e2e build (main cfa197b scripts, existing build tree): package-linux.sh rc=0, 1bit-e2e-linux-x86_64.tar.zst 16 MB, and the package now holds exactly 33 files under npu/kernels - 3 layout.json and 30 layer1.elf, every one sealed (1BPKCRYP magic), zero .mlir, .o, layer1.work or design.mlir.prj. package_checks: "ok NPU kernels: 33 files under npu/kernels, all sealed". pack_is_dynelf returns yes on the real 1bit, no on an AIE object and no on a sealed kernel. The two remaining package_checks failures on that build are properties of the build, not of this change: its 1bit binary carries four /home/ build-machine paths baked in at compile time, and the tree has no onnx/ because it was configured without -DONEBIT_ONNX=ON. * build: embed backend paths relative to the build, not as build-machine paths package_checks refuses a package whose 1bit names a build-machine home, and that rule is what the NPU delivery tripped: of the four /home/ strings the e2e package carried, two came from the NPU defines themselves (ONEBIT_NPU_REPACK_SCRIPT / ONEBIT_NPU_LANE_PACK_SCRIPT = ${CMAKE_SOURCE_DIR}/...) and the other two from ONEBIT_BUILD_DIR = ${CMAKE_BINARY_DIR}. So the package gate failed on #503's own NPU path. Every backend path is now embedded relative to the build dir via file(RELATIVE_PATH ...) (a new onebit_build_relative() helper) and app/built_path.h resolves it from the executable's own directory (/proc/self/exe). That is the same file a 1bit in the build tree has always found, because the binary lives in the build dir; the package keeps that layout beside the binary (scripts/package-linux.sh, pack_localize). Nothing machine-specific is compiled in any more. Sites: ONEBIT_HRX_SERVER, ONEBIT_DS4_SERVER, ONEBIT_ONNX_SERVER, ONEBIT_LAYA_GGML_BIN, the two NPU python tools. ONEBIT_BUILD_DIR is removed and has no remaining references. Absolute paths still work if a caller passes one (an older build), and the env overrides (ONEBIT_LLAMA_SERVER etc.) are unchanged and still win. --------- Co-authored-by: agent <agent@local>
Make the NPU engine shippable with the runtime and kernels closed, compiled binaries only.
What this adds (public, neutral)
scripts/hw-gate.sh— anpuphase. Not in the default phases (--phases npu). Auto-skips when there is no NPU (/dev/accel/accel0) or no checker configured. Otherwise it runs a private checker ($HW_GATE_NPU_CHECK) inside the gate's GPU claim and under~/npu.lock(NPU through the fair queue; not wrapped in thermal-run, whose freeze can abort an NPU dispatch), reads its neutral result lines —oracle(dense Qwen3-0.6B decode vs an fp64 reference),greedy64,prefill,reproducible— and applies atok/sfloor (HW_GATE_NPU_FLOOR). The checker and the kernels are private; this script carries no method.config/npu-kernels.config— the private NPU-kernels pin the release fetches (ONEBIT_NPU_PRIVATE), same shape asconfig/gpu-kernels.config.docs/npu.md,docs/releases.md— the NPU kernels ship as compiled, encrypted artifacts that1bitverifies and decrypts in memory at load (fails cleanly on a wrong key, no network callback of any kind; a lifted kernel file is ciphertext and does not run). No source or method is public.Proven on Strix Halo
The private delivery mechanism (sealed kernel container, in
1bit-MONSTER/npu-kernelsnpu/ship-sealed-kernels) was proven on device: the sealed dx kernel set decodes byte-identical logits to the plain set (Qwen3-0.6B, 24/24 vs fp64, logits md59a405cf6…), 64/64 greedy at ~90 tok/s, a set sealed with a foreign key is refused cleanly (signature verification failed, no NPU dispatch), a plain ELF is refused underREQUIRE_SEALED, with 0 amdxdna/IOMMU faults.Remaining (needs a post-freeze Strix Halo build)
npuphase end to end on the box.scripts/weekly.shso a release package carries them.Pin PR — please review; not auto-merging, do not merge without the hardware gate.
🤖 Generated with Claude Code