Skip to content

contrib: GPU serving via llama.cpp (13-19x latency, 89% decision agreement) - #43

Open
PLNech wants to merge 1 commit into
feder-cr:mainfrom
PLNech:gpu-llama
Open

PLNech wants to merge 1 commit into
feder-cr:mainfrom
PLNech:gpu-llama

Conversation

@PLNech

@PLNech PLNech commented Oct 14, 2026

Copy link
Copy Markdown

From #40 (and as discussed): an optional GPU backend for jev serve.

What. contrib/gpu-llama/ — a ~260-line C++ proxy that speaks the same /v1/systemone wire format and computes answers with llama.cpp decoding a quantized GGUF instead of the OpenVINO graph. It reuses jev's own wire/prompt/vocab/choice/score/request_tokens sources unchanged (-I src), so the wire semantics, prompt rendering and answer math are literally the upstream code. The only new logic: one llama.cpp decode per question on top of the shared state prefix, with the KV cache rolled back in between (every question sees the state alone, the way jev's attention mask does), and P(yes) read from raw logits: sigmoid(logit("1") - logit("0")).

Why. In a real-time consumer of jev (a browser game loop judging 10-15x/s), CPU OpenVINO latency is the bottleneck. This lane makes batched 5-question judgments ~19x faster, which turns a 0.9B classifier into a genuinely real-time decision engine.

Receipts (RTX 4080 Laptop GPU, q4_k_m, llama.cpp b11541):

metric CPU jev serve GPU lane ratio
1-question p50 292 ms 22 ms 13x
~300-token state, 5 questions, p50 1372 ms 73 ms 19x
tokenizer parity (usage.input_tokens) — exact match, every request checked —
decision agreement vs jev serve — 89% overall, 100% danger/dodge, 95-100% fire/spatial, mean |dP| 0.02-0.16 —

validate.py reproduces the agreement + latency study against a running jev serve (seeded scenarios, results.example.json included). Makefile builds against any llama.cpp CUDA prefix (pin b11541). Full runbook and caveats in contrib/gpu-llama/README.md; serving notes also on the wiki (serving jev via llama.cpp).

Caveats (documented in the README): single client at a time (requests serialize; a second client turns 42 ms p50 into ~487 ms — matches jev's NUM_STREAMS=1), no KV snapshots across requests, and cold-vs-warm GPU clocks (idle 210 MHz, warm 1.6 GHz — a 68 -> 43 ms p50 swing in benchmarks).

Happy to adjust structure (e.g. gpu/ instead of contrib/), swap httplib for whatever the project prefers, or split docs out of the code — whatever fits the repo best.

Optional backend: a ~260-line proxy speaking jev's /v1/systemone wire
format, answers computed by llama.cpp decoding a quantized GGUF instead
of the OpenVINO graph. Reuses jev's own wire/prompt/vocab/choice/score
sources unchanged; one decode per question on the shared state prefix
with KV rolled back in between; P(yes) from raw logits.

Receipts (RTX 4080 Laptop, q4_k_m, llama.cpp b11541):
- 1-question p50 22 ms vs 292 ms CPU (13x)
- ~300-token state, 5 questions: 73 ms vs 1372 ms (19x)
- tokenizer parity exact (usage.input_tokens match on every request)
- 89% overall decision agreement vs jev serve (100% danger/dodge,
  95-100% fire/spatial, mean |dP| 0.02-0.16); results.example.json

Includes validate.py (seeded agreement + latency vs jev serve) and a
Makefile pinning llama.cpp b11541. Caveats in README: single client,
no KV snapshots across requests, cold-vs-warm GPU clocks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant