Files
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

10 KiB
Raw Permalink Blame History

Per-GPU specs and autotune math — single-GPU llama.cpp tier

Source of truth for the per-GPU JSON configs in this directory (3090.json, 4090.json, 5090.json, h200.json) and for the gpu-autotune.ts helper in packages/app-core/src/services/local-inference/.

Scope: one GPU per host. No tensor parallelism, no NVLink splits, no multi-tenant scheduling. The product target is "one conversation at a time on a single GPU box."

Inference engine: llama.cpp / llama-server (the buun-llama-cpp fork that ships the QJL + Polar KV quant kernels). This file does not cover vLLM / SGLang — those have different memory and parallelism models.

All expected_metrics in the JSON configs are extrapolated, not measured. The _provenance: "extrapolated" field marks that explicitly. A real benchmark on each card replaces these once a runner is wired.

Spec table

Card Arch (CC) VRAM Mem-BW FP16 TFLOPs FP8 TFLOPs FP4 TFLOPs INT4 TFLOPs Max ctx (rec.) Max parallel Target RTF (voice)
RTX 3090 Ampere sm_86 24 GiB GDDR6X 936 GB/s 71 284 65 536 4 0.55
RTX 4090 Ada Lovelace sm_89 24 GiB GDDR6X 1 008 GB/s 165 660 (E4M3/E5M2) 660 131 072 8 0.40
RTX 5090 Blackwell sm_120 32 GiB GDDR7 1 792 GB/s 209 838 1 676 838 262 144 12 0.30
H200 SXM Hopper sm_90 141 GiB HBM3e 4 800 GB/s 989 1 979 1 979 1 048 576 16 0.20

RTF = real-time factor; lower is better. For voice streaming we need RTF < 1 for steady-state and < 0.5 to leave headroom for TTS + ASR.

Citations

  • RTX 3090 — NVIDIA Ampere GA102 whitepaper (2020). 24 GB GDDR6X at 19.5 Gbps × 384-bit = 936 GB/s. No FP8 tensor cores. Compute capability sm_86. flash-attn 2 supported; flash-attn 3 is Hopper-only.
  • RTX 4090 — NVIDIA Ada Lovelace AD102 whitepaper (2022). 24 GB GDDR6X at 21 Gbps × 384-bit = 1 008 GB/s. FP8 E4M3/E5M2 tensor cores (4th gen). Compute capability sm_89. flash-attn 2; flash-attn 3 kernels upstreamed but Hopper-tuned.
  • RTX 5090 — NVIDIA Blackwell GB202 whitepaper / launch deck (2025). 32 GB GDDR7 at 28 Gbps × 512-bit = 1 792 GB/s. 5th-gen tensor cores with FP8 + FP4 (E2M1). Compute capability sm_120. llama.cpp sm_120 kernel coverage is incomplete in early Blackwell builds — buun-llama-cpp records this in CAPABILITIES.json; the runtime probes it before promising QJL/Polar.
  • H200 SXM — NVIDIA H200 datasheet (2024). 141 GB HBM3e at 4.8 TB/s. FP8 transformer engine (4th gen). Compute capability sm_90. Flash-attn 3 first-class.

llama.cpp issues:

Autotune math

Two budgets dominate every choice:

  1. VRAM budget — model weights + per-slot KV must fit.
  2. Memory bandwidth budget — steady-state decode throughput is (weights-per-token) / (mem-bw). RTF ≈ tokens-per-second-audio / tokens-per-second-decode.

KV-cache cost per token

Transformer KV cost: bytes/token = 2 × n_layers × n_kv_heads × head_dim × bytes_per_element (factor of 2 = K and V).

Legacy Eliza-1 KV baseline (retired Qwen-shaped tiers; active Gemma tiers use manifest-declared stock Gemma KV plus MTP):

Bundle n_layers n_kv_heads head_dim FP16 KiB/tok Q8K/Q4V KiB/tok QJL+Polar KiB/tok
2B class 28 8 128 112 88 28
4B 36 8 128 144 113 36
9B 48 8 128 192 150 48
27B 62 8 128 248 194 62
Bundle Ctx KV quant KV per slot
2B 32k Q8K/Q4V 32 768 × 88 KiB = 2.75 GiB
2B 32k QJL+Polar 32 768 × 28 KiB = 0.88 GiB
9B 65k QJL+Polar 65 536 × 48 KiB = 3.0 GiB
27B 32k QJL+Polar 32 768 × 62 KiB = 2.0 GiB
27B 128k QJL+Polar 131 072 × 62 KiB = 8.0 GiB
27B 256k QJL+Polar 262 144 × 62 KiB = 16.0 GiB

Parallel slot derivation

VRAM available for KV ≈ vram - model_weights - reserved_headroom. Reserved headroom (driver + activations + drafter): 3 GiB on 24 GB cards, 4 GiB on 5090, 6 GiB on H200. See reservedHeadroomGb() in packages/shared/src/local-inference/gpu-profiles.ts.

RTX 3090 (24 GiB, no FP8) — uses Q8K / Q4V KV (Ampere has no q4_polar kernel on the Polar fork).

  • 2B (1.5 GiB model): KV budget 19.5 GiB / 2.75 GiB-per-slot = 7 max parallel @ 32k. Config caps at 8 to leave OS-window headroom.
  • 9B (5.4 GiB): KV budget 15.6 GiB / (65 536 × 150 KiB = 9.4 GiB-per-slot @ 64k) = 1 parallel @ 64k; at 32k it's 4.7 GiB-per-slot → 3 parallel. Config picks 4 with kvSpillToCpu opt-in at 64k.
  • 27B (16.8 GiB): KV budget 4.2 GiB / 2 GiB-per-slot @ 32k = 2 parallel.

RTX 4090 (24 GiB, FP8) — QJL + Polar KV available.

  • 2B: KV budget 19.5 GiB / 0.88 GiB-per-slot @ 32k = 16 parallel (we cap at 16 for practical session-count reasons).
  • 9B: 18 GiB / 3 GiB-per-slot @ 64k = 6; spec picks 8 parallel @ 32k (slot KV = 1.5 GiB) for voice; 4 @ 64k for chat.
  • 27B: 4.2 GiB / 2 GiB-per-slot @ 32k = 2 parallel.
  • voice (omnivoice + small LLM): omnivoice runs on CPU/Metal in fused mode; KV is only the small text drafter. Cap 4 parallel at 8k for the voice loop.

RTX 5090 (32 GiB, FP8/FP4) — same KV math, 8 GiB more headroom.

  • 2B: KV budget 27.5 GiB / 0.88 GiB = 31 → 24 parallel (we leave realistic session headroom).
  • 9B: 26.6 GiB / 3 GiB @ 64k = 8 → 12 parallel @ 64k.
  • 27B: 12 GiB / 2 GiB @ 32k = 6 → 6 parallel @ 32k; at 128k it's 8 GiB per slot → 1.5 → 1 parallel @ 128k.

H200 (141 GiB) — the marquee box.

  • 27b: 8 GiB per slot @ 128k → 16 parallel (capped).
  • 9b: ~0.45 GiB per slot @ 8k → 64 parallel.

Batch / ubatch derivation

  • batch_size = logical batch fed to the prefill kernel per server tick. Doubles with VRAM (more headroom for activations) but caps at 4096 — beyond that, llama.cpp scheduler overhead eats the win.
  • ubatch_size = physical micro-batch the GPU launches. Ada / Blackwell / Hopper want ≥ 512 to keep tensor cores saturated; Ampere is happiest at 256-512.
Card batch ubatch Why
3090 2048 512 Ampere; mem-bw-bound past 512 ubatch
4090 2048 512 Same dies as 3090 family; FP8 helps prompt eval not decode
5090 4096 1024 More SMs + GDDR7 bw lets the bigger ubatch land
H200 4096 2048 HBM3e + sm_90 tensor cores; bigger ubatch wins

n_gpu_layers

Always 999 (all layers on GPU). Single-GPU only — we never split across cards in this tier. The literal -1 works equally well in llama.cpp but 999 is unambiguous and survives clamping in older builds.

split_mode / main_gpu

Always "none" / 0. We never multi-GPU.

cache_type_k / cache_type_v

  • Ampere (3090): q8_0 / q4_polar. The q4_polar Polar-quant V kernel exists for sm_86 but the qjl1_256 K kernel does not — fall back to Q8 K.
  • Ada / Blackwell / Hopper (4090 / 5090 / H200): qjl1_256 / q4_polar. Both kernels are pre-built and exposed in CAPABILITIES.json.

ctx_checkpoints / ctx_checkpoint_interval

Used by the voice optimistic-rollback path. Mid-prefill snapshots cost ~per-checkpoint = slot_kv_at_checkpoint. Defaults per ctxCheckpointsForTier() in packages/shared/src/local-inference/catalog.ts:

Bundle ctx_checkpoints interval
2B 4 4 096
4B / 9B 8 8 192
27B (incl. 256k) 16 8 192

MTP draft range

Per-card, picked from mtpDraftMin / mtpDraftMax in gpu-profiles.ts:

Card min max
3090 4 16
4090 4 24
5090 4 24
H200 8 32

Draft window scales with compute throughput, not memory. Bigger cards can verify a longer drafter run per round without latency hit.

p_min / draft_p_min

0.5 everywhere — drafter token accepted only if p ≥ 0.5. This is a conservative default for voice latency. Higher values mean fewer accepted drafts; lower values raise rollback waste.

Known limits

  • 3090 has no FP8 — 27B quality drops slightly without FP8 attention; we keep Q8K KV for safety. Don't promise FP8 on sm_86.
  • 5090 sm_120 kernel coverage — early Blackwell llama.cpp builds may not ship qjl1_256 for sm_120. The runtime probes CAPABILITIES.json; missing → fall back to q8_0/q4_0 and surface a structured warning rather than silently. Don't fix in the autotune; fix in the kernel build.
  • flash-attn-3 — Hopper only (sm_90). 4090 / 5090 use flash-attn-2.
  • 24 GiB cards at 27B + ≥64k ctx — fits only with QJL+Polar AND single slot AND --mlock. Beyond 64k, opt-in kvSpillToCpu=true.
  • H200 256k @ 6 parallel — radix cache helps when sessions share a long system prefix; otherwise fresh conversations should be scheduled conservatively to avoid KV pressure.

Override mechanism

The autotune helper merges in this order (later wins):

  1. gpu-profiles.ts static profile defaults
  2. packages/inference/configs/gpu/<id>.json (this directory)
  3. Bundle-specific override block (bundle_recommendations.<bundle>)
  4. Per-call overrides arg to selectGpuConfig() (used by the CLI)
  5. Env vars: ELIZA_LOCAL_* (see ffi-streaming-backend.ts for the full list, e.g. ELIZA_LOCAL_UBATCH_SIZE, ELIZA_LOCAL_N_PARALLEL).

When selectGpuConfig() gets a GPU it doesn't recognize, it falls back on a VRAM bucket:

VRAM (GiB) Bucket Falls back to
< 12 tiny Returns null — use catalog defaults
12 18 small RTX 3090 profile, parallel halved
18 28 mid RTX 3090
28 40 mid-plus RTX 5090 (capped)
40 80 large RTX 5090
≥ 80 huge H200

Bucket fallback is "best effort" — if the user has an unsupported card, log the fallback choice loudly so they know they're not on a tuned profile.