Skip to content

Laya GGUF scorer: ggmlc's laya on Vulkan, 24 ms a routing decision - #206

Merged
bong-water-water-bong merged 1 commit into
mainfrom
laya-gguf
Sep 28, 2026
Merged

bong-water-water-bong merged 1 commit into
mainfrom
laya-gguf

Conversation

@bong-water-water-bong

Copy link
Copy Markdown
Collaborator

The Laya GGUFs (mys/laya-GGUF, laya-multilingual-GGUF, laya-typed-decisions-GGUF) are compiled by ggmlc for its own laya runtime on GGML. They aren't llama.cpp GGUFs. This PR makes the typed-decisions one the router's scorer.

  • third_party/ggmlc is pinned at 1519ea42. -DONEBIT_LAYA_GGML=ON builds its laya with GGML Vulkan (cmake/laya-ggml.cmake).
  • config/laya.json pins mys/laya-typed-decisions-GGUF@1e9e8ba1, file laya_typed_decisions_q8_0.gguf. scripts/fetch-laya.sh fetches it into <laya dir>/gguf/ and checks its sha256. Verified on strixhalo: 20 checkpoint files plus the GGUF.
  • serve --laya runs laya daemon <gguf> --family typed-decisions --device vulkan and talks to it over pipes. It doesn't use laya serve, which binds INADDR_ANY with auth off. It asks the same question and applies the same long_doc size gate, and it falls back to the C++ scorer when the binary or GGUF is missing. --laya-model FILE.gguf, ONEBIT_LAYA_GGML and ONEBIT_LAYA_DEVICE override the defaults.
  • tests/laya_gguf_route.sh (ctest, CI) runs 8 checks with a fake daemon.

Measured through 1bit serve --laya on Strix Halo, using tests/laya_route_cases.json (200 cases; 150 are asked of the model):

Scorer Accuracy Decision p50
C++ scorer, safetensors, CPU 95.5% 538 ms
ggmlc laya, typed-decisions Q8_0, Vulkan 95.5% 24 ms

Asked directly: typed-decisions F16 scores 95.5% at 36 ms, the English Q8_0 93.0% at 22 ms, and the English F16 91.5%. Also verified: a build with -DONEBIT_LAYA_GGML=ON runs the compiled-in binary with no environment overrides.

Licence note: ggmlc declares MIT in its pyproject.toml and README, but the repo has no LICENSE file (GitHub shows no license). NOTICE says so. Its vendored ggml carries MIT.

🤖 Generated with Claude Code

`1bit serve --laya` now uses the Laya typed-decisions checkpoint compiled to
a GGUF (mys/laya-typed-decisions-GGUF, Q8_0, pinned in config/laya.json,
fetched and sha256-checked by fetch-laya.sh into <laya dir>/gguf/) through
ggmlc's `laya daemon` (third_party/ggmlc, -DONEBIT_LAYA_GGML=ON, GGML
Vulkan), over stdin/stdout rather than its `serve` (which binds every
interface with no key). Same question and long_doc size gate as the C++
scorer, which stays the fallback.

Through serve on Strix Halo, tests/laya_route_cases.json (200): both 95.5%;
decision p50 538 ms (C++ scorer, CPU) -> 24 ms (GGUF, Vulkan).
tests/laya_gguf_route.sh covers the wiring with a fake daemon (8 checks).
NOTICE credits ggmlc (MIT declared; its repo has no LICENSE file yet) and
the GGUF (Apache-2.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@context7

context7 Bot commented Sep 28, 2026

Copy link
Copy Markdown

Docs7 for 1bit-monster/engine

Result Status Action
Deployment ➖ Not used —
Content review ➖ Did not run. This site has no agent runs available this month. Wait for the monthly reset or check your Docs7 plan. —

Commit e909f0f

@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Potential Resource Leak in LayaDaemon

The LayaDaemon class manages file descriptors for pipes (to_ and from_) and a child process (pid_). While the destructor attempts to close the file descriptors and terminate the child process, there's a potential issue if ::close() or ::kill() fails. Specifically, if ::close() fails, the file descriptor may remain open, leading to a resource leak. Similarly, if ::kill() fails to terminate the child process, it could remain as a zombie process. These scenarios could lead to resource exhaustion or unexpected behavior, especially in long-running server processes.

~LayaDaemon() {
    if (to_ >= 0) ::close(to_);
    if (from_ >= 0) ::close(from_);
    if (pid_ > 0) {
        ::kill(pid_, SIGTERM);
        ::waitpid(pid_, nullptr, 0);
    }
}
Possible SIGPIPE Handling Issue

The code sets std::signal(SIGPIPE, SIG_IGN) to ignore SIGPIPE signals. While this prevents the server from crashing when a pipe write fails, it can mask underlying issues. If the daemon dies unexpectedly, writes to its stdin may fail silently, and the server might not detect that the daemon is no longer functional. This could lead to silent failures or incorrect routing decisions.

std::signal(SIGPIPE, SIG_IGN);  // a daemon that died fails a write, not the server
Insecure Temporary File Usage

The script uses mktemp -d to create a temporary directory for testing, but it doesn't explicitly set permissions or ensure the directory is secure. While mktemp generally creates secure directories, the script should explicitly set permissions to ensure that only the owner can access the temporary files, preventing potential security issues.

@bong-water-water-bong
bong-water-water-bong merged commit be31130 into main Sep 28, 2026
11 checks passed
@bong-water-water-bong
bong-water-water-bong deleted the laya-gguf branch September 28, 2026 19:53
bong-water-water-bong added a commit that referenced this pull request Sep 28, 2026
…208)

* Laya scorer on HRX: ggmlc's laya on AMD's backend instead of Vulkan

The router's GGUF scorer (#206) now runs on HRX0 (HRX + LOOM), not Vulkan:

- third_party/ggmlc -> our fork 1bit-MONSTER/ggmlc 1bit/main (df08d1b0): an
  HRX build against a llama.cpp ggml, and a uid on every graph so HRX's
  graph-program cache and graph replay hit.
- third_party/llama.cpp -> 22ceda3a (fork #31): the LOOM kernels ModernBERT
  needs on HRX (LayerNorm, strided/broadcast arithmetic, clamp, F32->F16 copy,
  per-head attention, odd-K matmuls) and fused RoPE and GEGLU.
- cmake/laya-ggml.cmake builds ggmlc's laya with TheRock's amdclang against
  third_party/llama.cpp's ggml and hrx-system; no Vulkan build for the scorer.
- serve --laya starts `laya daemon ... --device hrx` with the HSA runtime HRX
  needs (IREE_HAL_AMDGPU_LIBHSA_PATH from --hrx-libhsa / TheRock).

Strix Halo, tests/laya_route_cases.json (200): 95.5% (as the CPU scorer and
Vulkan); p50 25 ms a decision, 15-16 ms at a steady 64 tokens (Vulkan 12),
25 ms at 128 (Vulkan 24-31); C++ scorer 538 ms. docs/laya.md also records
that the multilingual checkpoint routes worse than typed-decisions in all six
languages measured (69.1% vs 83.7%), so it is not used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* registry: record the llama.cpp pin 22ceda3a (no architecture changes)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
bong-water-water-bong added a commit that referenced this pull request Sep 29, 2026
…UF on the NPU, 1BP; blog post (#214)

README gets a Direction note (HRX with Loom kernels plus the NPU, as geramyL proposed;
Vulkan stays the default until the RFC #213 gates are met) and current status lines:
six GGUF architectures answer on the NPU (0.006-0.17 tok/s), DwarfStar reads 1BP, and
Laya classifies conversations with its scorer on HRX at 15-16 ms. PORTING's NPU and
Laya rows gain #179/#181/#209 and #187/#206/#208. The blog post covers the same.

Co-authored-by: bong-water-water-bong <bong-water-water-bong@1bit.gg>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant