Prima.cpp: heterogeneous home-cluster inference¶
Scope: how to run a 30-70B model across a handful of ordinary, unequal devices (laptops, a desktop with a consumer GPU, a Mac, a phone) whose combined RAM and VRAM is less than the model needs, without out-of-memory failures and without the disk-loading stalls that sink a naive offload. Prima.cpp (arXiv 2504.08791) is the worked example: piped-ring parallelism overlaps memory-mapped weight loading with computation, and the Halda scheduler assigns layers to devices under each one's RAM and VRAM limits. This is the low-resource, cross-device counterpart to the datacenter techniques in disaggregated inference and cross-WAN model-parallel inference, and the multi-device extension of running small models on a single consumer GPU; the pipeline-parallel base it builds on is pipeline parallelism.
The paper was submitted as v1 in April 2025 under the title "Speeding Up 70B-Scale LLM Inference on Low-Resource Everyday Home Clusters" and revised to v3 in 2026 ("Fast 30-70B LLM Inference on Heterogeneous and Low-Resource Home Clusters"). Numbers and quotes below are from the v1 PDF the source URL points to, with v1 tables cited exactly; two figures (a consolidated "5-17x" and a "26 tokens/s speculative decoding" result) were introduced in v3, recurring throughout its abstract, introduction, and results discussion, and are absent from v1 entirely. Verify current claims against the repository (as of 2026-07). The
prima.cppinvocation is a reference template; the Python model of the prefetch-release conflict is executed and asserted (stdlib only).
flowchart TB
subgraph HALDA["Halda scheduler (offline): layer-to-device assignment"]
PROF["Device + model profiler:<br/>compute, memory, disk, comms, OS behavior"] --> ILP["Enumerate rounds k -> ILPs (HiGHS)<br/>solve window w_m and GPU layers n_m<br/>under RAM/VRAM limits"]
end
ILP --> RING
subgraph RING["Piped-ring parallelism (runtime): a ring of unequal devices"]
D1["Mac M1 (head)<br/>window w1, prefetch next"] --> D2["Laptop i9 + RTX 3070<br/>window w2"]
D2 --> D3["Desktop i9 + RTX 2080Ti<br/>window w3"]
D3 --> D4["Phone (Kirin 9000)<br/>window w4"]
D4 -->|"next round (multiple rounds per token)"| D1
end
RING --> OUT["Head device emits the token<br/>disk load hidden behind other devices' compute"]
What it is¶
Prima.cpp is a distributed inference system, built on llama.cpp, that runs a model too big for any one device by splitting its layers across a ring of heterogeneous machines and streaming weights from disk with memory mapping. The paper's target is deliberately modest hardware: its default cluster is four everyday devices (a Mac M1, an Intel i9 laptop with an RTX 3070, an i9 desktop with an RTX 2080 Ti, and a Kirin 9000 phone) whose total available RAM plus VRAM is 37 GiB, "not enough for a Q4K-quantized 70B model."1 It reports serving Llama 3-70B at 674 ms per token with a time-to-first-token under two seconds on that cluster, while keeping per-device memory pressure below 6%.5
Two ideas make that possible. Piped-ring parallelism (PRP) is pipeline parallelism arranged as a ring, run over multiple rounds per token, with each device handling a small window of layers per round so that memory-mapped prefetching of the next window overlaps the other devices' computation instead of stalling on disk. Halda is the scheduler that decides, for each device, how many layers it handles per round and how many of those run on its GPU, under that device's RAM and VRAM limits, by solving what the paper frames as a layer-to-device assignment problem.23
The hard problem underneath is offloading. When a model does not fit in RAM, llama.cpp uses mmap to load weights lazily and lets the OS reclaim inactive pages, but under memory pressure that reclaim reloads pages from disk repeatedly. The paper measures this cliff: at 45B "only a few pages are released, so efficiency loss is small," but at 60B "more active mmap-ed pages are labeled as inactive earlier and then released, leading to a sharp increase in token latency and TTFT."4 Prima.cpp's job is to hide that disk latency rather than pay it.
Why use it¶
- It runs models everyday hardware otherwise cannot. The paper's motivating number is that user devices "struggle to run anything beyond 10B, even with 4-bit quantization," and running Qwen 2.5-14B (Q4K) on a Mac M1 with 8 GiB RAM "takes a staggering 10 seconds per token."4 Prima.cpp brings 70B into the same home cluster at sub-second per-token latency.
- It is fast against the alternatives, and it does not OOM where they do. On the four-device cluster, prima.cpp improves token latency by up to 17x and TTFT by up to 8x over llama.cpp, and by 5-8x latency and 12-24x TTFT over exo and dllama; at 70B both exo and dllama run out of memory entirely while prima.cpp serves it.5
- It keeps devices usable. Because it respects each device's available (not total) memory, per-device memory pressure stays below 6%, versus request schedulers that grab enough RAM to freeze the machine; the paper measures exo and dllama pushing a device into critical pressure (over 50%) even on an 8B model.5
- It is genuinely cross-platform. The same system spans macOS (both unified-memory and NUMA), Linux, and Android or HarmonyOS phones (via a Termux-simulated Linux), mixing CPU and GPU and RAM and VRAM across those devices simultaneously.1
When to use it (and when not)¶
Use it when:
- You have several ordinary devices and want to run a model larger than any one of them holds, and you value privacy or cost enough to keep inference local rather than calling a hosted API.
- The devices are unequal (a fast desktop, a slow laptop, a phone) and a uniform split would bottleneck on the weakest link; Halda's whole point is assigning more work to stronger devices under each one's memory limit.
- The model does not fit in aggregate RAM, so disk offloading is unavoidable and hiding its latency is the deciding factor. PRP's benefit is largest exactly here: the paper reports it "reduces latency by nearly half" when total available RAM is insufficient (models above 60B).2
Do not reach for it when:
- The model fits comfortably in one device's memory. The paper is explicit that with sufficient RAM,
k=1(a single round, the whole model as one window) is best, and splitting into more rounds with a smaller window per round "slightly raises latency" from fragmentation, so multi-device ring parallelism adds coordination cost for no gain.2 - You need cloud-grade latency. The authors state plainly that "70B models remain much slower than those on the cloud"; this is for when local execution is the constraint, not when throughput is the goal.6
- The cluster is low-RAM with no SSD and no GPU. The paper warns that in that regime "larger models will be extremely slow," because there is nothing to hide the disk latency behind.6
Architecture¶
Piped-ring parallelism starts from ordinary pipeline parallelism (split the model into layer segments along a chain of devices) and closes the chain into a ring so I/O and the emitted token stay on the head device, which matters for privacy. The departure from prior ring systems is that a token is predicted over multiple rounds, and each device processes only a small layer window per round. The paper's example: six devices, a 36-layer model, window size two, gives eighteen segments so each device does three rounds per token.2 The window size is the load-bearing knob: "By setting the layer window size small, we ensure the model layers stays within memory limits, avoiding prefetch-release during prefetching," so a device can mark its next window's layers WILLNEED and the OS loads them from disk in the background while the other devices compute, fully overlapping disk with compute on a fast disk.2
The failure this avoids is the prefetch-release conflict. Vanilla prefetching marks a whole set of upcoming layers WILLNEED; if that set exceeds available memory, the later prefetched layers evict the earlier ones, so when computation finally reaches those earlier layers they fault back in from disk, and "all layers being loaded twice, adding unnecessary disk overhead without any benefit from prefetching."2 A small window guarantees the prefetched layers fit; k=1 (the whole model as a single window, one round) is the most extreme case where they do not, which is why on a model too large for RAM, k=1 "offers no benefit due to the prefetch-release effect": the single giant window still exceeds the device's resident capacity, so it pays the same doubled-load tax as any oversized window, just at the largest possible scale.2
Halda solves the assignment. For each device it chooses a per-round window w_m and how many of those layers run on the GPU n_m, minimizing token latency subject to RAM and VRAM constraints, given a profiler's measurements of each device's compute, memory-access, disk-loading, and communication latency plus its OS memory-management behavior. The raw problem is NP-hard because the total window size appears in both the objective and the constraints, so Halda breaks it into tractable pieces: since the layer count L is under 100 in typical LLMs, the number of rounds k has few valid values ("at most 11 valid factors for any k <= 100"), so Halda enumerates k, which turns each case into a standard integer linear program solved by HiGHS, then iterates a device-set assignment (which devices must overload their RAM versus which must not) until stable, with a calibration step that reassigns layers to a GPU sitting idle while another device is overloaded. The result "find[s] the optimal solution in polynomial time," O(T(M + K(2M)^3.5)).3
How to use it¶
Prima.cpp is built on llama.cpp, so operation is familiar: build it, point each device at the others over the LAN, and run the model with a quantization the cluster can hold. Reference template (verify flags against the repository, which has moved to the OpenCPIL organization):
# Reference template. Build on each device, then launch the ring; Halda profiles
# the devices and assigns layers automatically. Q4K is the default quantization;
# IQ1 is supported for the tightest memory budgets.
git clone https://github.com/OpenCPIL/prima.cpp && cd prima.cpp && make
# On each participating device, start the worker pointing at the head node;
# the head runs the scheduler and emits tokens (see the repo README for the
# current worker/rank flags and the model path).
./llama-cli -m models/llama3-70b-Q4_K.gguf --prompt "..." # head device
The practical inputs you control are the model and its quantization (which sets the total memory footprint the cluster must cover), the set of devices and their reachability over Wi-Fi or Ethernet, and how much RAM each device is allowed to use. Halda takes it from there; you do not hand-assign layers.
How to develop with it¶
The mechanism worth understanding before trusting a cross-device offload is why a small layer window turns a doubled disk cost into a hidden one. This executed model implements the prefetch-release conflict as an LRU page-reclaim simulation (Part A) and the resulting per-token latency with and without overlap (Part B), reproducing the paper's Appendix A.1 example (six layers, three fit, loaded twice) and its finding that k=1 gives no benefit:
# prima_ring.py -- validated: the two mechanisms that let prima.cpp keep a
# 70B model's disk loading overlapped instead of paying it twice. Pure stdlib.
#
# Part A models the "prefetch-release" conflict (paper Appendix A.1): a device
# can hold only `capacity` layers resident (mem_available), and mmap prefetch
# marks a whole window WILLNEED. If the window exceeds capacity, later prefetched
# layers evict earlier ones, so computation page-faults on the evicted layers and
# every layer is loaded TWICE. A small layer window keeps the window within
# capacity, so each layer is loaded exactly once.
#
# Part B models piped-ring overlap: with each layer loaded once, the next round's
# prefetch overlaps this round's compute, so per-round latency collapses from
# (compute + disk) to max(compute, disk). With prefetch-release it cannot overlap.
from collections import OrderedDict
def disk_loads_per_pass(num_layers: int, capacity: int, window: int) -> int:
"""Count disk loads to prefetch-then-compute one window of `window` layers on
a device that can hold `capacity` layers resident. LRU page reclaim models
the OS freeing inactive mmap-ed pages. Prefetch loads the window in order;
compute then walks the same layers in order, reloading any the prefetch phase
evicted. Returns total loads (prefetch + compute) for one window."""
assert 1 <= window <= num_layers and capacity >= 1
cache: "OrderedDict[int, bool]" = OrderedDict()
loads = 0
def touch(layer: int) -> None:
nonlocal loads
if layer in cache:
cache.move_to_end(layer)
return
loads += 1 # disk load (page fault or prefetch miss)
cache[layer] = True
cache.move_to_end(layer)
while len(cache) > capacity:
cache.popitem(last=False) # OS reclaims the least-recently-used page
for layer in range(window): # prefetch phase: mark window WILLNEED
touch(layer)
for layer in range(window): # compute phase: walk layers in order
touch(layer)
return loads
# --- Part A: prefetch-release is exactly a 2x disk tax when window > capacity ---
CAP = 3 # a device that can hold 3 layers resident (the A.1 example)
# Small window that fits: prefetch 3, compute 3 all resident -> 3 loads, loaded ONCE.
assert disk_loads_per_pass(num_layers=6, capacity=CAP, window=3) == 3
# The paper's A.1 case: window 6 > capacity 3. Prefetch loads 6 (only the last 3
# survive), compute reloads all 6 -> 12 loads = every layer loaded TWICE.
assert disk_loads_per_pass(num_layers=6, capacity=CAP, window=6) == 12
# General rule this exposes: any window strictly above capacity pays 2x; any
# window at or below capacity pays 1x. Checked across a sweep.
for w in range(1, 13):
loads = disk_loads_per_pass(num_layers=12, capacity=CAP, window=w)
expected = w if w <= CAP else 2 * w
assert loads == expected, (w, loads, expected)
# Boundary: window == capacity is the largest window that still loads once.
assert disk_loads_per_pass(12, CAP, CAP) == CAP
assert disk_loads_per_pass(12, CAP, CAP + 1) == 2 * (CAP + 1)
# --- Part B: with layers loaded once, ring prefetch overlaps disk with compute ---
def per_token_latency(num_layers, capacity, window, t_compute_layer, t_disk_layer):
"""Latency to predict one token across a ring, one device's view. A token needs
num_layers/window rounds; each round computes `window` layers. When the window
fits (loaded once), the next round's prefetch overlaps this round's compute, so
a round costs max(compute, disk). When it does not fit, prefetch-release forces
a synchronous reload, so a round costs compute + the reload disk time."""
assert num_layers % window == 0
rounds = num_layers // window
compute = window * t_compute_layer
if window <= capacity: # overlapped
disk = window * t_disk_layer # prefetch the same count, hidden
return rounds * max(compute, disk)
reload_disk = window * t_disk_layer # the extra (2nd) load is NOT hidden
return rounds * (compute + reload_disk)
# A device where disk load per layer dominates compute (the >60B regime, where the
# model does not fit in RAM). t_disk > t_compute, so hiding disk is the whole game.
tc, td = 1.0, 4.0
N = 12
fits = per_token_latency(N, capacity=3, window=3, t_compute_layer=tc, t_disk_layer=td)
release = per_token_latency(N, capacity=3, window=6, t_compute_layer=tc, t_disk_layer=td)
# Overlapped: 4 rounds * max(3*1, 3*4)=12 -> 48. Prefetch-release: 2 rounds *
# (6*1 + 6*4)=30 -> 60. The small window is faster AND the paper's own finding
# that k=1 (one round, whole model at once) "offers no benefit" falls out: a
# single round of the full model cannot overlap anything.
assert fits == 48 and release == 60
# k=1 means window == num_layers: one giant round, no overlap possible, and here
# it also busts capacity so it pays the reload tax too -- worst of both.
k1 = per_token_latency(N, capacity=3, window=N, t_compute_layer=tc, t_disk_layer=td)
assert k1 == (N * tc + N * td) # 12 + 48 = 60, no rounds to overlap across
assert fits < k1, "a small layer window must beat the single-round (k=1) layout"
# Sanity: when the model DOES fit in RAM (capacity >= num_layers), there is no
# disk to hide, so a bigger window (fewer rounds, less ring overhead) is fine --
# matching the paper's note that k=1 is best when memory is sufficient.
resident = per_token_latency(N, capacity=N, window=N, t_compute_layer=tc, t_disk_layer=0.0)
assert resident == N * tc # pure compute, 12
print(f"OK Part A: window<=cap loads each layer once (3); window>cap loads twice "
f"(A.1: 6 layers, cap 3 -> 12 loads). "
f"OK Part B: small-window ring={fits} < prefetch-release={release} < "
f"k=1 single round={k1}; fully-resident={resident} (no disk to hide).")
Run output:
OK Part A: window<=cap loads each layer once (3); window>cap loads twice (A.1: 6 layers, cap 3 -> 12 loads). OK Part B: small-window ring=48.0 < prefetch-release=60.0 < k=1 single round=60.0; fully-resident=12.0 (no disk to hide).
The model makes the design rule concrete: the window must stay at or below a device's resident-layer capacity, and the win only exists when disk time is comparable to or larger than compute time (the offloaded regime). When the model fits in RAM there is no disk to hide, and a small window just adds ring rounds, which is why Halda picks the window per device rather than using a fixed value.
How to maintain it¶
- Re-profile when the cluster changes. Halda's assignment is only as good as the profiler's latency measurements; adding a device, swapping a disk, or changing which processes compete for RAM shifts the optimal window and GPU-layer split, so re-run profiling rather than reusing an old assignment.
- Expect OS-specific disk behavior. The paper notes macOS with Metal "reclaims memory more aggressively than Linux, causing more reloads, while Linux optimizes sequential reads, making reloading faster," which makes disk latency hard to estimate; a mixed-OS cluster needs the per-OS device cases Halda models, not a single disk-latency constant.4
- Pin the quantization to the memory budget. Q4K is the default; IQ1 exists for the tightest budgets. Moving quantization changes the total footprint the cluster must cover and therefore the whole assignment, so treat it as a re-planning event.
Running it in production¶
The realistic deployment is a home or small-office cluster serving latency-tolerant local inference (the paper's framing is voice-assistant-style use), not a throughput-oriented service. Two operational cautions from the paper carry over directly. First, more devices is not always faster, and fitting in aggregate RAM is not the deciding factor: the authors' own device-count study found a 3-device cluster (38 GiB, which does not fit the 40 GiB Llama-3-70B Q4K model) beat a 6-device cluster (50 GiB, which does fit it) on token latency, because fast SSDs on the 3-device cluster let mmap swap layers in fast enough to win anyway, while two of the six devices had weak CPUs and slow disks that bottlenecked the larger cluster despite its memory headroom; add devices to hold a bigger model, not by default to speed up one that already fits, and check the specific devices you add, not just the aggregate memory total.5 Second, latency is sensitive to memory competition: because prima.cpp respects available memory, other processes grabbing RAM force it to slow down to free space, so the paper reports "a stable value from multiple runs instead of an error bound," meaning a device doing other work will degrade inference in a way a single benchmark number hides.6
Failure modes¶
- Prefetch-release from too large a window. If a device's window exceeds its resident capacity (a mis-profiled memory limit, or another process shrinking available RAM), prefetched layers evict each other and every layer loads twice, erasing the overlap; the executed model above quantifies the exact 2x tax. This is why the window must be sized against available, not total, memory.
- A single-round (k=1) layout under memory pressure. Running the whole model in one round cannot overlap disk with anything and, when it overflows RAM, also pays the reload tax; PRP's benefit requires multiple rounds with a fitting window.
- Idle GPUs from a bad assignment. Without Halda's calibration step, a GPU can sit with free VRAM while another device is overloaded; the scheduler must reassign lagging-disk devices to use that GPU, or the cluster underperforms its hardware.
- Cloud-latency expectations. A 70B model at 674 ms per token is usable for local, latency-tolerant interaction, not for a service with strict SLOs; the authors say so directly.6
- Unfiltered content on user devices. The paper flags a safety caveat: running larger open-source models locally means "malicious content may not be filtered," a deployment concern for any home-served model.6
References¶
- Li, Li, Feng, Guizani, and Yu, "Prima.cpp: Speeding Up 70B-Scale LLM Inference on Low-Resource Everyday Home Clusters" (arXiv 2504.08791, v1): https://arxiv.org/abs/2504.08791
- Prima.cpp v1 PDF (the version this page cites for exact tables): https://arxiv.org/pdf/2504.08791v1
- Prima.cpp repository (official, MBZUAI CPIL; MIT): https://github.com/OpenCPIL/prima.cpp
- llama.cpp (the base engine prima.cpp extends, mmap weight loading): https://github.com/ggml-org/llama.cpp
- HiGHS (the linear/integer programming solver Halda uses): https://github.com/ERGO-Code/HiGHS
- exo (a distributed home-cluster inference baseline): https://github.com/exo-explore/exo
Related: Disaggregated inference · Cross-WAN model-parallel inference · Non-colocated inference: which pattern? · vLLM: small models on consumer GPUs · DwarfStar (ds4): DeepSeek V4 local · Pipeline parallelism · Quantization for inference · Local coding agents · Inference serving and optimization · Glossary
-
Prima.cpp (arXiv 2504.08791, v1), Section 4 and Table 2. Default cluster D1-D4: Mac M1 (macOS, unified memory, 2.4 GiB available RAM, Apple Metal); Intel i9 laptop (Linux, 4.1 GiB RAM, RTX 3070, 8 GiB VRAM); Intel i9 desktop (Linux, 9.7 GiB RAM, RTX 2080 Ti, 11 GiB VRAM); Mate40Pro phone (Kirin 9000, Linux on HarmonyOS via Termux, 1.9 GiB RAM). Total available RAM plus VRAM 37 GiB, "not enough for a Q4K-quantized 70B model." Table 1 marks prima.cpp as uniquely using CPU and GPU plus RAM and VRAM simultaneously across macOS (unified and NUMA), Linux, and Android, at Low memory pressure. ↩↩
-
Prima.cpp v1, Section 3.1 and Appendix A.1-A.2. Piped-ring parallelism arranges pipeline parallelism as a ring (last device links back to the head so I/O and output stay local for privacy) and predicts one token over multiple rounds; a small per-device layer window keeps prefetched layers within available memory. "By setting the layer window size small, we ensure the model layers stays within memory limits, avoiding prefetch-release during prefetching." Vanilla prefetching over a too-large window causes later layers to overwrite earlier prefetches, "which results in all layers being loaded twice, adding unnecessary disk overhead without any benefit from prefetching." Section 4.2: PRP "reduces latency by nearly half" when total available RAM is insufficient (above 60B) but "at k = 1, it offers no benefit due to the prefetch-release effect." With sufficient RAM (below 45B),
k=1(the largest window, one round) is the best setting, and increasingkto split the model into more, smaller-windowed rounds slightly raises latency from fragmentation and reduced computational parallelism. ↩↩↩↩↩↩↩ -
Prima.cpp v1, Sections 3.2-3.3. Halda solves the layer-to-device assignment: per device, a window
w_mand GPU-layer countn_mminimizing token latency (objective Eqs. 1-5) subject to RAM and VRAM constraints, using a device profiler (compute, memory access, disk loading, communication, OS memory behavior) and a model profiler (FLOPs per layer). NP-hard because the total window appears in objective and constraints; Halda enumerates the roundsk("at most 11 valid factors for any k <= 100"), reducing each case to an integer linear program solved by HiGHS, iterates a device-set assignment (device cases M1-M4 by OS and memory sufficiency), and calibrates GPU underutilization. "Halda breaks the NP-hard problem into a set of simple ILPs, so we can find the optimal solution in polynomial time," complexityO(T(M + K(2M)^3.5)). ↩↩ -
Prima.cpp v1, Sections 1-2 and 4.1. User devices "struggle to run anything beyond 10B, even with 4-bit quantization"; running Qwen 2.5-14B (Q4K) on a Mac M1 with 8 GiB RAM "takes a staggering 10 seconds per token." High-memory alternatives (an Apple M2 Ultra with 192 GiB, or kTransformers needing about 75 GiB for a 70B) are inaccessible to most users. llama.cpp uses mmap for lazy loading; under memory pressure the OS reclaims inactive pages and reloads them, so at 45B "only a few pages are released" but at 60B pages are "released, leading to a sharp increase in token latency and TTFT." OS heterogeneity: macOS with Metal "reclaims memory more aggressively than Linux ... while Linux optimizes sequential reads," making disk latency hard to estimate. ↩↩↩
-
Prima.cpp v1, Tables 3-4 and Sections 1, 4.1-4.2. Llama 3-70B at 674 ms/token and 1793 ms TTFT (Q4K, D1-D4), versus llama.cpp at 10120 ms/token; exo and dllama OOM at 70B. Contribution: "prima.cpp is 15x faster than llama.cpp on 70B models, with memory pressure below 6% per device." Section 4.1: "compared to llama.cpp, prima.cpp improves token latency by up to 17x and TTFT by up to 8x. Against exo and dllama, it speeds up token latency by 5-8x and TTFT by 12-24x." Ablations (Section 4.2): Halda gives up to 30x for 70B-scale versus no-Halda; prefetching lowers token latency 9-17%; PRP roughly halves latency when RAM is insufficient. Per-device memory pressure stays below 6% (max 6.3% at 60B). Device-count study (Appendix A.5): a 3-device cluster (38 GiB, insufficient for the 40 GiB Llama-3-70B Q4K model) beat a 6-device cluster (50 GiB, sufficient) on token latency, via fast SSDs on the 3-device cluster enabling effective mmap swapping, while two of the six devices had weak CPUs and slow disks that bottlenecked the larger cluster; "more devices do not always result in faster inference." The current version (v3) introduced a "32B model with speculative decoding achieves 26 tokens/s" figure and a consolidated "5-17x" speedup figure, recurring throughout its abstract, introduction, and results discussion; neither appears anywhere in v1. ↩↩↩↩
-
Prima.cpp v1, Section 5. Stated limitations: limited device types and quantity restrict the exploration; "70B models remain much slower than those on the cloud"; in low-RAM clusters without SSDs or GPUs "larger models will be extremely slow"; token latency "is heavily affected by memory competition," so the paper reports "a stable value from multiple runs instead of an error bound" (no error bars) because other processes force prima.cpp to slow down to free RAM; and a safety caveat that larger open-source models on user devices run "where malicious content may not be filtered." A design caveat: the current implementation assigns every device at least one layer, which the authors plan to relax so idle devices drop out. ↩↩↩↩↩