ngram-mod is draftless (added to the spec config vector unconditionally, while every model-backed drafter needs ctx_dft), so unlike MTP it can share the process with DFlash2. Chained at the fleet's 48/64 window, over three shapes: prose 1k/512 dflash 43.77 | ngram 17.72 (0 drafts) | chain 43.65 echo 1.5k/400 dflash 76.82 | ngram 102.50 | chain 200.58 structured/400 dflash 91.08 | ngram 17.80 (0 drafts) | chain 91.22 identity dflash 70.37 | ngram 17.77 | chain 70.40 On prose the chain is byte-identical to the drafter alone (same 119 drafts/49 accepts) -- that is what makes it a safe default -- and on prompt-echo traffic it is 2.6x. VRAM is unchanged: the matcher is a 64 MiB host-RAM hash table. The window sweep says keep the long one: 48/64 beats 16/32 (161.0) and 8/16 (113.8) on echo, and shortening it costs prose (43.9 -> 36.0) because the matcher then proposes on ordinary fragments and the rejections still have to be verified. That is the 'ngram hurts' result this fleet hit twice before. Two documentation traps recorded with it: ngram-mod prints NO startup banner in this build (its drafts are only visible behaviourally), and the harness's 'structured' shape is a negative control because its lines differ.
372 lines
19 KiB
Markdown
372 lines
19 KiB
Markdown
---
|
||
type: configuration
|
||
title: frank-medium llama.cpp + DFlash2 Runbook
|
||
description: The ACTIVE frank-medium deployment since 2026-09-16 — mainline llama.cpp on Dankserver serving ajgazin/Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP at UD-Q8_K_XL with the z-lab DFlash2 Q8_0 drafter, as ONE layer-split process across both Radeon AI PRO R9700 cards.
|
||
tags:
|
||
- frank-medium
|
||
- dankserver
|
||
- llama-cpp
|
||
- dflash2
|
||
- qwen35
|
||
- gfx1201
|
||
- r9700
|
||
- layer-split
|
||
timestamp: 2026-09-16
|
||
---
|
||
|
||
# frank-medium — llama.cpp + DFlash2
|
||
|
||
The ACTIVE frank-medium deployment since 2026-09-16: **mainline llama.cpp**
|
||
serving `ajgazin/Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP-GGUF` at `UD-Q8_K_XL`
|
||
with the **z-lab DFlash2** block-diffusion drafter, as **one process across
|
||
both Radeon AI PRO R9700 cards**, layer-split.
|
||
|
||
It replaced the vllm-radiance MXFP4 replica pair + routing proxy
|
||
([[frank-medium-radiance-mxfp4]], the record and the PCIe-atomics evidence) in
|
||
the same day the pair went live. It is also the box's **only** LLM runtime: the
|
||
replicas, the proxy and their unit files are retired.
|
||
|
||
## Why one process and layer split
|
||
|
||
The endpoint's whole history is one constraint: **the two cards cannot take
|
||
part in an RCCL collective.** RCCL's kernels declare a hidden hostcall buffer,
|
||
and ROCr refuses to supply it to a device without PCIe atomics; the second
|
||
R9700 hangs off the B650 chipset (`AtomicOpsCap: Routing-`, read-only), so
|
||
every collective that touches it dies with `hipErrorIllegalState`. That rules
|
||
out tensor parallelism — and it rules out **vLLM's pipeline parallelism too**,
|
||
whose stage handoff is a `send`/`recv` of the hidden state on the device
|
||
backend (`vllm/distributed/parallel_state.py`), the very primitive that fails.
|
||
The full matrix is in [[Dual-R9700-Cooperation]].
|
||
|
||
llama.cpp's `--split-mode layer` needs **no collective at all**: layers are
|
||
distributed across the cards in order and the boundary activation is a plain
|
||
per-backend copy, once per forward pass. Measured on this host with the
|
||
predecessor runtime (llama-bench, pp4096 / tg128, f16 KV, flash-attn on):
|
||
|
||
| Split | pp4096 | tg128 |
|
||
|---|---:|---:|
|
||
| one R9700 (`-sm none`) | 1160.9 | 19.42 |
|
||
| **two cards, layer (`-sm layer`)** | **1991.2** | **18.76** |
|
||
| two cards, tensor (`-sm tensor`, no RCCL: butterfly fallback) | 271.8 | 26.26 |
|
||
|
||
Tensor split buys ~40 % decode and loses 7× prefill. The workload here is
|
||
prefill-heavy (agentic, long prompts, reasoning traces), so layer split is the
|
||
shape — prefill nearly doubles and one model serves from both cards.
|
||
|
||
## Hardware
|
||
|
||
| Property | Value |
|
||
|---|---|
|
||
| GPUs | 2x AMD Radeon AI PRO R9700 (DID 0x7551), gfx1201 (Navi 48, RDNA4) |
|
||
| VRAM | 34,208,743,424 B (31.86 GiB) each, as `rocm-smi` reports it |
|
||
| Link | PCIe, no XGMI; card #2 behind the chipset, **no atomic routing** |
|
||
| iGPU | Raphael (gfx1036) enumerates as HIP device 2 — hidden via `HIP_VISIBLE_DEVICES=0,1` |
|
||
| CPU / RAM | Ryzen 7 7700X (8c/16t), 60 GiB RAM, 63 GiB swap |
|
||
|
||
## Runtime
|
||
|
||
Mainline llama.cpp at **`fb27a525`** (2026-09-16), built for **gfx1201 only** by
|
||
`scripts/build-llama-rdna4.sh` against a private ROCm `7.14.0a20260624`
|
||
toolchain (TheRock nightly) that is **bundled next to the binary** —
|
||
`RPATH=$ORIGIN/../lib`, no `LD_LIBRARY_PATH`, nothing from the host's ROCm 7.1
|
||
packages.
|
||
|
||
Two features pin that ref, and neither is in the ROCmFPX fork the endpoint used
|
||
earlier the same day (its tip, `c49ebdb`, predates both):
|
||
|
||
- **DFlash2** (`ggml-org/llama.cpp#27342`): grouped dynamic depthwise
|
||
convolution plus the candidate selector, detected from the draft GGUF
|
||
(`selector_top_k > 0`) and served through the ordinary
|
||
`--spec-type draft-dflash` path.
|
||
- **qwen35 MTP**: the `draft-mtp` implementation covers this architecture's
|
||
single trained head.
|
||
|
||
Build with:
|
||
|
||
```bash
|
||
bash scripts/build-llama-rdna4.sh # ~25 min on this box, JOBS=$(nproc)
|
||
```
|
||
|
||
> **Bundling trap, measured.** rocBLAS and hipBLASLt look for their device code
|
||
> at a fixed depth under the binary's lib dir (`../lib/rocblas/library`,
|
||
> `../lib/hipblaslt/library/<arch>`). `cp -r SRC DST/` with a missing `DST`
|
||
> creates `DST` as a copy of `SRC` and **flattens it one level**, and the
|
||
> failure is invisible at startup: the engine loads 29 GiB of weights, answers
|
||
> `/health`, and dies on the **first request** with
|
||
> `rocBLAS error: Cannot read .../lib/rocblas/library/TensileLibrary.dat: No
|
||
> such file or directory for GPU arch : gfx1201`. The build script now declares
|
||
> the destination and copies contents.
|
||
|
||
## Model and drafter
|
||
|
||
| File | Bytes | Role |
|
||
|---|---:|---|
|
||
| `Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP-UD-Q8_K_XL.gguf` | 31,457,990,112 | target, 29.29 GiB |
|
||
| `Qwen3.8-27B-DFlash2-Q8_0.gguf` | 2,056,414,816 | DFlash2 drafter, 1.92 GiB |
|
||
|
||
Fetched by `scripts/download-frank-medium-gguf.sh` (resumable, byte-verified —
|
||
a truncated 31 GB GGUF is otherwise a load-time crash).
|
||
|
||
The target is Unsloth Dynamic 3.0 (per-tensor types from Unsloth's own quant of
|
||
the same size, on Unsloth's importance matrix) of an abliterated Swift
|
||
fine-tune: orcarouter's single refusal direction projected out of 131 tensors,
|
||
vision tower untouched. **Text only here** (`--no-mmproj`); the fleet's image
|
||
endpoint is frank-small.
|
||
|
||
**The file also carries the model's MTP head** (`blk.64.nextn.*`). With
|
||
`--spec-type draft-dflash` those tensors are deliberately **not** loaded — the
|
||
log says `model has unused tensor blk.64.nextn.eh_proj.weight ... ignoring` —
|
||
because DFlash2 drafts from its own 5-layer drafter. Switching (or chaining)
|
||
`--spec-type draft-mtp,draft-dflash` is a one-line env change that pulls the
|
||
head in; it is not enabled by default because the DFlash2 path is the measured
|
||
one.
|
||
|
||
## Deployment
|
||
|
||
| File | Role |
|
||
|---|---|
|
||
| `scripts/frank-medium.env` | every tunable, with the sizing arithmetic in comments |
|
||
| `scripts/serve-frank-medium.sh` | env-driven llama-server launcher; no arguments |
|
||
| `scripts/frank-medium.service` | ROOT systemd unit, `User=dank`, `WantedBy=multi-user.target` |
|
||
|
||
```bash
|
||
./scripts/deploy.sh dankserver --service frank-medium
|
||
```
|
||
|
||
The handler verifies the runtime and payload exist (and refuses otherwise),
|
||
retires the three vLLM quadlets into `~/.AGENTTRASH/20260916-vllm-radiance-retire/`,
|
||
waits for **port 7770 to be released** (the retired proxy held it on the host
|
||
network), relinks and restarts the unit, and gates on
|
||
`http://127.0.0.1:7770/health`.
|
||
|
||
Deployed flags:
|
||
|
||
| Flag | Value | Why |
|
||
|---|---|---|
|
||
| `--split-mode` / `--device` / `--tensor-split` | `layer` / `ROCm0,ROCm1` / `1,1` | both cards, one model, no collective |
|
||
| `--gpu-layers` / `--fit` | `999` / `off` | everything on the cards; auto-fit must not resize a context we set |
|
||
| `--ctx-size` / `--parallel` | `262144` / `1` | one slot carries the model's whole configured window; `--parallel` **divides** the context |
|
||
| `--flash-attn` / cache types | `on` / `f16` K and V | an agentic checkpoint is the wrong place to spend KV precision |
|
||
| `--spec-type` / `--spec-draft-n-max` | `draft-dflash` / `7` | DFlash2 blocks are 8 tokens, so 7 drafts is the ceiling llama.cpp allows |
|
||
| `--spec-draft-device` | `ROCm1` | the drafter rides the card that ends up holding the target's last layers |
|
||
| `--temp` / `--top-p` / `--top-k` | `0.7` / `0.95` / `20` | the values the vLLM predecessor served on this endpoint |
|
||
| `--reasoning-format` / `--reasoning-budget` | `deepseek` / `-1` | trace into `reasoning_content`, unlimited |
|
||
| `--no-mmproj` | — | text only |
|
||
|
||
## Verified serving behaviour (2026-09-16)
|
||
|
||
- Load: `model loaded` ~29 s after start with a warm page cache, then
|
||
`listening on http://0.0.0.0:7770`. The drafter adds ~2.5 s.
|
||
- Slot shape: `n_slots = 1, n_ctx_slot = 131072`; `/props` reports
|
||
`modalities: {vision: false}`, one slot, and the sampler defaults above.
|
||
- DFlash2 engaged — the init line is the proof, not the flag:
|
||
|
||
```
|
||
common_speculative_impl_draft_dflash: adding speculative implementation 'draft-dflash'
|
||
common_speculative_impl_draft_dflash: - n_max=7, n_min=0, p_min=0.00
|
||
common_speculative_impl_draft_dflash: - block_size=8, mask_token_id=248070, n_extract=5, sample_from_anchor=true
|
||
```
|
||
|
||
`block_size=8` and `n_extract=5` are DFlash2's own metadata; the selector is
|
||
what distinguishes it from DFlash 1.
|
||
- Both cards hold the model: at 262144 context `rocm-smi` reports **24.72 GB on
|
||
GPU 0 and 29.14 GB on GPU 1** of 34.21 GB each — the drafter, the attention
|
||
layers' KV and the compute buffers all sit on the second card, which keeps
|
||
~5.1 GB of headroom. At 131072 the same pair reads 19.89 / 24.30 GB.
|
||
- **140,069 prompt tokens prefilled in 134 s** (1043 tok/s) through the one
|
||
slot: the raised window is real, not just declared, and it is 22 % beyond the
|
||
114688 the vLLM predecessor could offer.
|
||
|
||
- **Nothing is replicated.** The loader does not print a per-device ledger at
|
||
this verbosity, so this is measured instead of read: raising CTX_SIZE from
|
||
131072 to 262144 added **4.83 GB to GPU 0 and 4.84 GB to GPU 1** — both cards
|
||
carry the KV for their own attention layers, about half each — and neither
|
||
card's *total* usage (24.94 / 29.42 GB at 262144) could hold the 31.46 GB
|
||
file, so no card carries a full copy of the weights. Compare the shape this
|
||
replaced: two vLLM replicas, i.e. two complete copies of the model, one per
|
||
card, which is exactly why a 29.8 GB FP8 checkpoint could not be served there
|
||
at any usable context.
|
||
|
||
### Measured throughput (2026-09-16, deployed service, `temperature 0`)
|
||
|
||
Same filler corpus for every shape, so these are shapes rather than a
|
||
benchmark: a large prompt with a tiny budget isolates prefill, a small prompt
|
||
with a long budget isolates decode. `draft`/`acc` are per request; acceptance
|
||
moves with the text (filler prose accepts far worse than code or a real agent
|
||
loop).
|
||
|
||
| Shape | Prefill | Decode | Acceptance |
|
||
|---|---|---|---|
|
||
| 4k prompt / 32 out | 3994 tok in 3.25 s — 1230 tok/s | 59.8 tok/s | 71 % |
|
||
| 1k prompt / 512 out | 998 tok in 1.41 s — 707 tok/s | **43.8 tok/s** | 41 % |
|
||
| 16k prompt / 16 out | 12,528 tok in 8.94 s — **1402 tok/s** | — | 100 % (13/13) |
|
||
| 64k prompt / 16 out | 48,508 tok in 39.8 s — 1219 tok/s | — | 53 % |
|
||
| 140k prompt / 16 out | 140,069 tok in 134.3 s — 1043 tok/s | — | — |
|
||
| same 1k prompt again | **4 tokens prefilled** | 43.8 tok/s | 41 % |
|
||
|
||
The last row is the prefix cache doing its job: the second request of the same
|
||
conversation re-prefilled 4 of 998 tokens. Prefill holds ~1.0-1.4k tok/s from
|
||
4k to 140k, and decode sits at ~44 tok/s on a long generation — against the
|
||
vLLM predecessor's 42.8 tok/s single-stream (two replicas) and the ROCmFPX
|
||
llama.cpp measured here at 35.7-46.2 tok/s. One process, one model, both cards,
|
||
no proxy.
|
||
|
||
### What the drafter is worth — and why MTP is not the alternative
|
||
|
||
Measured 2026-09-16 with `scripts/bench-spec-ab.py`, four configurations of the
|
||
same binary, identical prompts at `temperature 0`, unit stopped between runs
|
||
(one host, one copy of a 29 GiB model). 1k-token prompt, 512-token budget:
|
||
|
||
| Configuration | Decode | Drafting | VRAM (card 1) |
|
||
|---|---:|---|---:|
|
||
| `none` — autoregressive | 17.7 tok/s | — | 26.07 GB |
|
||
| `draft-mtp` n_max 3 (the model's own head) | 32.4 tok/s | 58 % of 72 | 29.35 GB |
|
||
| `draft-mtp` n_max 7 | 26.7 tok/s | 33 % of 147 | 29.65 GB |
|
||
| **`draft-dflash` n_max 7 — deployed** | **43.5 tok/s** | 41 % of 119 | 29.42 GB |
|
||
|
||
- **DFlash2 is worth 2.46× over autoregressive and 34 % over the best MTP.**
|
||
Deeper MTP drafting costs more than it returns: at depth 7 only a third of
|
||
the proposals survive, at depth 3 more than half do.
|
||
- **All four produced identical greedy text** (`2, 3, 5, 7, 11`): speculation
|
||
buys speed, never a different answer. The harness warns loudly if a future
|
||
configuration ever breaks that.
|
||
- **MTP is not the cheaper option.** Selecting it loads `blk.64.nextn.*` from
|
||
the target and adds ~3.3 GB to the card that holds it, against 2.06 GB for
|
||
the drafter's file — which is also why the load log says
|
||
`unused tensor blk.64.nextn... ignoring` under `draft-dflash`: correct
|
||
behaviour, not a truncated download.
|
||
- **They cannot be chained.** `--spec-type draft-mtp,draft-dflash` dies at load
|
||
with `context type MTP requested but model doesn't contain MTP layers`. A
|
||
chain has ONE draft context, and MTP builds against whatever model that
|
||
context holds — here the DFlash2 file. MTP's head is loaded only when MTP *is*
|
||
the draft model (`creating MTP draft context against the target model ...`).
|
||
That is structural, not a tuning question.
|
||
|
||
### Chaining the draftless n-gram matcher (deployed)
|
||
|
||
`ngram-mod` **can** ride beside DFlash2, and it is enabled. The reason is in
|
||
`common/speculative.cpp`: the n-gram types are added to the config vector
|
||
unconditionally while every model-backed drafter is gated on
|
||
`ctx_dft != nullptr` — so n-gram needs no draft context and cannot collide with
|
||
the drafter over one. (MTP is the opposite: it *is* context-backed, which is why
|
||
`draft-mtp,draft-dflash` cannot load.) The vector's fixed order — ngram types
|
||
first, then the drafters — also means CLI order is irrelevant.
|
||
|
||
Measured with `scripts/bench-spec-ab.py`, decode tok/s, three shapes that a
|
||
proposer can and cannot match:
|
||
|
||
| Configuration | prose 1k/512 | echo 1.5k/400 (copy 0.94) | structured/400 | identity |
|
||
|---|---:|---:|---:|---:|
|
||
| `draft-dflash@7` | 43.77 | 76.82 | 91.08 | 70.37 |
|
||
| `ngram-mod` alone | 17.72 *(0 drafts)* | 102.50 | 17.80 *(0 drafts)* | 17.77 |
|
||
| **`draft-dflash,ngram-mod@7`** | **43.65** | **200.58** | 91.22 | 70.40 |
|
||
|
||
- **On prompt-echo traffic the chain is 2.6× the drafter alone** (200.6 vs 76.8)
|
||
and twice `ngram-mod` by itself, at 100 % acceptance.
|
||
- **On prose it is indistinguishable from DFlash2 alone** — the same 119 drafts
|
||
and 49 accepts, the same 43.7 tok/s. That is the property that makes it safe
|
||
as a default: where the matcher cannot match, it costs nothing.
|
||
- `ngram-mod` alone is a *negative control*: zero drafts on prose and identity
|
||
(17.7 tok/s = the autoregressive baseline), 100 % acceptance on echo. Nothing
|
||
else could have proposed those tokens, which is how its drafts are identified
|
||
at all — see the trap below.
|
||
- VRAM is unchanged (29.42 GB on card 1 with or without it): the matcher is a
|
||
64 MiB host-RAM hash table.
|
||
- `structured` (25 records with unique ids) rewards no proposer: its lines
|
||
differ, so there is no long span to match. It is a negative control for
|
||
*self-repetition*, not evidence about it.
|
||
|
||
**The window matters, and shorter is not better.** The chain at three windows:
|
||
|
||
| `SPEC_NGRAM_N_MIN`/`N_MAX` | prose 1k/512 | echo 1.5k/400 |
|
||
|---|---:|---:|
|
||
| **48/64 — deployed** | **43.9** | **200.6** |
|
||
| 16/32 | 36.0 | 161.0 |
|
||
| 8/16 | 36.2 | 113.8 |
|
||
|
||
A short window makes the matcher propose on ordinary prose fragments, where the
|
||
proposals are rejected and the verification is still paid — the "ngram hurts"
|
||
result this fleet measured twice before on other payloads. At 48/64 the chain
|
||
keeps DFlash2's exact numbers on prose and wins on echo.
|
||
|
||
> **Operational trap: `ngram-mod` prints no startup banner in this build.**
|
||
> `journalctl -u frank-medium` shows `adding speculative implementation
|
||
> 'draft-dflash'` and nothing for the matcher — the only evidence it is running
|
||
> is behavioural (`draft_n` > 0 where text repeats) or the per-task line
|
||
> `slot print_timing: ... draft acceptance = 1.00000 (256 accepted / 256
|
||
> generated), mean len = 65.00`. Do not conclude from the load log that the
|
||
> chain is not engaged.
|
||
|
||
### The agent-loop shape (fleet harness, 2 families × 2 turns)
|
||
|
||
`scripts/bench-turn-latency.py http://127.0.0.1:7770 2 2 LAYERSPLIT` — two
|
||
agent loops re-sending a ~30k-token document concurrently:
|
||
|
||
| | turn 1 | turn 2 |
|
||
|---|---:|---:|
|
||
| family 1 | 24,799 ms | 30,697 ms |
|
||
| family 0 | 51,424 ms | 8,015 ms |
|
||
|
||
Read that against the prefill table, not as a latency regression: one slot
|
||
means the second family's first turn waits for the first (25 s of cold 30k
|
||
prefill + the wait ≈ 51 s), and the last number — 8.0 s — is a re-prefill that
|
||
the cache could only partly serve. **The single slot is now the limiting
|
||
resource for concurrent agent loops**, which is the trade this deployment makes
|
||
for giving one conversation the whole 262144-token window instead of splitting
|
||
two. Raising `--parallel` splits the window (and the KV) between slots; it does
|
||
not add throughput.
|
||
|
||
## Observability
|
||
|
||
The endpoint exports Prometheus metrics under the **`llamacpp:`** namespace
|
||
(`--metrics`), which is what the fleet's scrape and dashboard read — the
|
||
`vllm:` series the predecessor exported no longer exist:
|
||
|
||
| Need | Series |
|
||
|---|---|
|
||
| Throughput | `llamacpp:prompt_tokens_seconds`, `llamacpp:predicted_tokens_seconds` |
|
||
| Queue | `llamacpp:requests_processing`, `llamacpp:requests_deferred` |
|
||
| Cache reuse | `llamacpp:prompt_tokens_cached_total` vs `llamacpp:prompt_tokens_total` |
|
||
| **Speculative decoding is live** | `llamacpp:spec_decode_num_drafts_total` and `llamacpp:spec_decode_num_accepted_tokens_total` (their ratio is the acceptance rate) |
|
||
|
||
`spec_decode_num_drafts_total` staying at 0 is the one-line answer to "is the
|
||
drafter actually running": the flags can all be right while the draft model
|
||
failed to load.
|
||
|
||
## Client contract
|
||
|
||
OpenAI-compatible `/v1` on **7770**, alias **`frank-medium`**, streaming and
|
||
`/health`, `/props`, `/metrics` as llama.cpp provides them. Reasoning traces
|
||
are projected into `reasoning_content`. A request that sends no sampler fields
|
||
gets the server defaults above; a client that sends its own wins. Text only.
|
||
|
||
## Troubleshooting
|
||
|
||
- **Loads, then dies on the first request with a rocBLAS Tensile error** — the
|
||
bundled device-library depth (see the bundling trap above); check
|
||
`build-rdna4-rocm714/lib/rocblas/library/` exists and is populated.
|
||
- **`hipErrorNoDevice` / a card missing** — `HIP_VISIBLE_DEVICES` must be
|
||
`0,1`; the iGPU enumerates as device 2 and must stay hidden.
|
||
- **Drafting not engaged** — read the journal for
|
||
`common_speculative_impl_draft_dflash`; a missing drafter file makes the
|
||
serve script exit before llama-server starts, and a non-DFlash2 drafter (or
|
||
an older llama.cpp) fails the load instead.
|
||
- **Why is `blk.64.*` "unused"?** That is the model's own MTP head and it is
|
||
correct for `draft-dflash`. It is not a truncated download:
|
||
`bash scripts/download-frank-medium-gguf.sh --verify-only` proves the bytes.
|
||
- **A rebuild segfaults at load** — the build is gfx1201-only on purpose; a
|
||
gfx1200 sibling binary links, loads the model and then segfaults on these
|
||
cards.
|
||
|
||
## See Also
|
||
|
||
- [[frank-medium-radiance-mxfp4]] — the retired vllm-radiance MXFP4 deployment
|
||
(replicas + proxy) and the PCIe-atomics evidence
|
||
- [[frank-medium-rocmfpx]] — the llama.cpp/ROCmFPX deployment earlier on
|
||
2026-09-15, whose `--split-mode layer` measurements this service reuses
|
||
- [[Dual-R9700-Cooperation]] — why the two cards cannot take part in a
|
||
collective, and every software escape that is closed
|
||
- [[frank-small-qwen38-gsq-rco]] — the fleet's other llama.cpp endpoint (RTX
|
||
3090, MTP, the image path)
|
||
- [[Dankserver System Specs]] — hardware inventory
|