Topic: Measurements

FIELD REPORT / 10 OCT 2026

Qwen3-8B on WSL2: My Context Test Stopped at the Host RAM Guard

Six single-sample Qwen3-8B scouts on an 8GB RTX 5060 Ti, followed by an incomplete primary batch stopped below 2 GiB of available host RAM.

My Qwen3-8B context experiment stopped during the first 8K/18 primary startup. Windows available RAM crossed the guard’s 2 GiB floor. The planned eighteen-run batch has zero final eligible primary results because its post-run input and runtime binding is missing.

Before that batch, six separately validated scouts completed. I report those six individual observations below, n=1 per condition. They are exploratory samples, not substitutes for the unfinished repetitions.

Measured on: 2026-10-07 · RTX 5060 Ti 8 GB · Ryzen 7 7800X3D · Windows 11 Home / Ubuntu 24.04.4 WSL2 · Qwen3-8B Q4_K_M · llama.cpp e5a8d439cef3 · F16 K/V · six validated scouts, n=1 each · primary contract NOT_MET.

What stopped, and what remains usable

These are separate evidence groups. I preserved their original states.

GroupActual outcomePerformance eligibility
Six current-cohort scouts: 2K/4K/8K × all/18Original raw checks passed; pre/post binding matched; both guards exited 0One descriptive observation per condition
Earlier 16K/18 scoutHost floor abort during startup; original post-binding absentUnavailable
16K/all scoutNOT_RUNUnavailable
Bounded primary: 18 planned trialsSix calls; five provisional checks; stopped at 8K/18 R1Zero final eligible trials
Separate fresh-build reader: 2K/allRaw checks and pre/post binding passed; both request guards exited 0One separate replay; never a primary repetition

The primary host guard’s terminal record was:

{
  "exit_code": 124,
  "abort": "host_ram_below_2gib",
  "elapsed_seconds": 900.5779999999795
}

That is elapsed whole-batch guard time, not the failed trial’s startup time or completion latency. The observed guest child exit was -9; the driver’s signal-handler receipt declared 143. These record different processes. Cleanup was attempted; that flag alone does not prove process absence.

The batch’s stale running string does not mean it survived the terminal guard record. The abort stayed latched after RAM recovered. Earlier prechecks stayed trial_checks_passed_batch_post_pending; I did not promote them, copy in a later closure snapshot, or retry the batch.

The previous 16K/18 scout stopped after 82.344 guard seconds, also during startup. Its original result remained started, without runtime-after or final binding. 16K/all was not launched. Neither record establishes CUDA OOM, a maximum context, or 16K generation speed. Built-in startup warmup is not the evaluated long completion request.

The saved host safety trace

Available host RAM crossed the 2 GiB floor; the device-wide VRAM counter is shown on a separate axis.

Open the full-size figure.

The figure shows 114 saved observations in the final 120-second window of the 852-row host trace. Lines connect samples; they do not capture shorter spikes. The VRAM panel uses the device-wide counter and does not identify the server’s allocation or establish a GPU memory limit.

Saved observationHost available bytesHost available, GiBDevice-wide VRAM, MiBAbort field
Last sample without abort2,795,352,0642.6033,961null
First sample with abort2,106,507,2641.9624,585host_ram_below_2gib
Last saved sample2,849,406,9762.6541,467host_ram_below_2gib

The floor was 2,147,483,648 bytes. Later recovery did not clear the abort. The numeric trace is in the evidence download below.

Environment and locked inputs

Ordinary host applications remained open. The test used a dedicated WSL guest.

ItemRecorded value
Measurement date2026-10-07
HostWindows 11 Home; WSL reported build 10.0.26200.9457
CPUAMD Ryzen 7 7800X3D
Windows visible physical memory15,603,676 KiB, approximately 14.88 GiB
GPU counterRTX 5060 Ti; 8,151 MiB total
NVIDIA driver610.88
WSL package / packaged kernel2.7.12.0 / 6.18.33.2-2
Actual guest kernel6.18.33.2-microsoft-standard-WSL2
GuestUbuntu 24.04.4 LTS, x86-64
Recorded GNU C++ / CMake13.3.0 / 3.28.3, Ninja
CUDA compiler13.2, V13.2.86
BuildRelease; GGML_CUDA=ON; GGML_NATIVE=ON; 120-real
llama.cpp commite5a8d439cef31f27fad6938233da10dae1ba5631
Model repositoryQwen/Qwen3-8B-GGUF
Model revision7c41481f57cb95916b40956ab2f0b139b296d974
FileQwen3-8B-Q4_K_M.gguf
File bytes5,027,783,488
Model SHA-256d98cdcbd03e17ce47681435b5150e34c1417f50b5c0019dd560e4882c5745785

The selected environment and protocol records include the saved host version fields, guest version output, selected original build-cache fields, guard terminals and executed Linux-control output. Each selection identifies its original file by size and SHA-256; its transformed bytes have a separate digest. These are saved records, not later live queries.

The host memory counter is not model RSS or a WSL allocation limit. The two kernel labels came from different commands. The model is pinned to this revision; the engine is pinned to this source.

Six scout observations, n=1

Each scout used one fresh server and one raw /completion request. Integer tokens were progressively longer prefixes of an invented notebook, without a chat template. Capacity and actual input length changed together. This cannot isolate the context-size flag with an identical prompt or measure answer quality.

Timing values below are individual observations, rounded to three decimals. Prefill and decode rates are rounded to two decimals. There are no repeat medians, ranges, confidence intervals or stable speed estimates.

ContextGPU argumentInput / output tokensStartup, sFirst content, sComplete, sServer prefill, tokens/sServer decode, steps/s
2,048all1,792 / 12818.0440.6472.4352,803.5471.00
2,048181,792 / 12824.3743.28916.302547.619.75
4,096all3,840 / 12818.1461.3673.2422,825.0767.73
4,096183,840 / 12824.1677.21022.946533.298.07
8,192all7,936 / 12817.9222.9985.0762,661.9560.93
8,192187,936 / 12824.26216.16637.396491.325.98

Client first-content time starts at request submission and ends at the first nonempty content SSE event. Completion ends at the terminal event. Both exclude server startup. Server prefill/decode use the engine’s separate clocks.

The pinned engine times 127 decode steps for 128 outputs: the first output comes from the final prompt logits. For the 2K/all scout, the final event records:

tokens_evaluated = 1792
tokens_predicted = 128
prompt_ms = 639.191
predicted_ms = 1788.781
predicted_per_second = 70.99807075321127
truncated = false
stop_type = limit
decode arithmetic: 127000 / 1788.781

This is not 128 / client completion time. The definition is in the pinned server timing code.

Memory has several scopes

These sampled peaks cover startup, request and shutdown. Baseline is separate. GiB values below are rounded to three decimals; VRAM values are MiB counters. Again, every row is one scout, n=1.

Context / GPU argumentDevice VRAM baseline, MiBDevice sampled peak, MiBPeak minus baseline, MiBProcess RSS peak, GiBHost available minimum, GiBGuest available minimum, GiBGuest swap peak, bytes
2K / all1,6846,6024,9180.7864.9745.9940
2K / 181,6854,4362,7512.9822.5933.7900
4K / all1,6816,8885,2070.7874.9606.0040
4K / 181,6824,5552,8733.1312.6303.6420
8K / all1,6947,1985,5040.7904.8365.9990
8K / 181,6944,8413,1473.4302.2763.3380

Device-wide WDDM usage includes the desktop and other applications. Peak minus baseline is not process VRAM. Linux RSS/HWM, backend buffers and whole-guest memory overlap; I do not add them. RSS is approximate process accounting, not a complete attribution of CUDA or mapped-file memory. See the Linux proc documentation and NVIDIA counter documentation.

Zero sampled guest swap does not establish that Windows avoided paging or WDDM migration. I collected no host paging or GPU-transfer trace. At validated process-exit boundaries, null RSS/HWM stays unavailable, not zero.

Repeated reads of one heartbeat are one GPU observation. These are the six saved coverage records; gap values are rounded to three decimals. Sampled peaks can miss shorter spikes.

ScoutMemory rowsDistinct host heartbeatsLargest memory gap, sLargest heartbeat gap, s
2K / all81771.0001.104
2K / 18102971.0011.109
4K / all82781.0001.064
4K / 181081021.0001.130
8K / all84801.0091.071
8K / 181231161.0001.108

Offload and the attempted protocol

In this pinned model placement, --gpu-layers 18 includes the output layer. Only repeating layers have KV: 17 GPU blocks and 19 CPU blocks, not 18/18. All-offloaded uses 36 GPU KV blocks. The startup logs matched these F16 amounts:

Contextall: GPU KV, MiB18: GPU KV, MiB18: CPU KV, MiB
2,048288136152
4,096576272304
8,1921,152544608

See the pinned placement calculation and KV loop. These are backend buffers, not additional RSS or global VRAM measurements.

The common server settings were:

--fit off --parallel 1
--cache-type-k f16 --cache-type-v f16 --flash-attn on
--batch-size 512 --ubatch-size 128 --threads 4 --threads-batch 4
--no-cache-prompt --cache-ram 0 --no-cache-idle-slots
--no-context-shift --ctx-checkpoints 0
--load-mode none --lazy-mode off --verbosity 4
--perf --warmup --offline --host 127.0.0.1
--cors-origins http://127.0.0.1
{
  "stream": true,
  "cache_prompt": false,
  "n_predict": 128,
  "temperature": 0,
  "seed": 20260910,
  "ignore_eos": true,
  "return_tokens": true
}

Context/offload arguments selected the table’s capacity and all or 18. The six core scripts stayed fixed. After the incomplete 16K scout, I declared a new six-condition primary scope before any primary request. It planned one pass in canonical order, one in reverse order and one in half-rotated order: three trials per condition, eighteen trials total.

The separately bound driver added a complete model size/SHA read, then bounded idle observations before every original trial call. All six attempted calls had that preparation. Scouts did not thereby become identically prepared primary samples. Model reads can warm file caches, sit outside TTFT, and do not guarantee RAM stability. Idle windows are waits, not model retries.

Preserved checkLimit
Whole-model readCooperative 120 s, checked around 8 MiB chunks
Auxiliary idle windows30 s each; at most 10 within 300 s
Original baseline / recovery30 s / 30 s
Baseline RAM / VRAM spread512 MiB / 128 MiB
Baseline GPU median utilizationAt most 10%
Drift from first primary baseline1 GiB host RAM / 256 MiB device VRAM
Startup / first content / total request120 s / 120 s / 180 s
Host RAM / disk floor2 GiB / 5 GiB
Internal primary budget7,920 s
Actual outer guard budget15,480 s

None of these floors was relaxed after the stop. I do not yet know which host memory components caused the floor crossing. The preserved host trace shows the observed stop; it cannot isolate file-cache behavior, another application, or memory migration as its cause.

Evidence and reproduction boundary

The transformed evidence bundle contains six-scout CSV values, numeric event clocks, returned-token counts, memory projections, selected startup log segments, primary safety observations and a manifest. Its archive SHA-256 is:

43ea3feb09a4a065738a21ba4c494304cedd29eec968e8e9cdd975ac10f5c058

The archive READMEs and status fields record the unpublished preparation snapshot from 2026-10-07. They are retained as historical metadata.

The exporter rechecked saved scout bindings, original receipts/guards and raw numeric calculations. It did not claim full primary provenance PASS or rehash live model/binary bytes. Public projections allow selected recomputation; they are redacted transformations with different hashes from originals. Generated content, token IDs/text, personal paths and free-form errors are omitted.

One separate fresh-build replay

I built the pinned source in a new build directory with a new build cache, then ran exactly one 2K/all request. The existing host, guest, source checkout, model file and toolchain were reused. This is a same-lab replay, not a clean OS or a new computer. The fresh process still used startup warmup and existing file caches.

Reader-only observationRecorded value
Context / GPU argument2,048 / all
Input / generated tokens1,792 / 128
Startup19.153 s
Client first content / completion0.664 s / 2.424 s
Server prompt / decode time647.780 ms / 1,768.160 ms
Timed decode steps / rate127 / 71.826 steps/s
Device VRAM baseline / sampled peak1,452 / 6,371 MiB
Process RSS sampled peak843,456,512 bytes
Host / guest available minimum5,147,660,288 / 6,431,133,696 bytes
Guest swap sampled peak0 bytes
Memory rows / distinct host heartbeats82 / 78
Largest memory / heartbeat gap1.001 s / 1.106 s
Request guards, host / guest0 / 0; no abort
Raw request checks / pre-post bindingPASS / PASS

The reader has its own raw numeric projections and validation receipt in the evidence bundle. Its success neither repairs primary post-binding nor supplies a second scout repetition. I do not combine its clocks or memory baseline with the earlier table.

Inspectable source and executed controls

The copied 21-asset source package subsequently ran these no-GPU controls on Windows Python 3.12.14. The 21 source assets stayed unchanged.

Packaged control suiteTests runPassedSkipped
Collector controls29290
Raw-validator controls60600
Setup controls330
Scope-driver controls64631
Total1561551

The skip required unavailable Windows symlink permission. Installed Linux driver controls separately passed 64/64; neither control result is a reader or GPU measurement. The package omits the model, source checkout, toolchain, binaries, guest disk and private handoffs. Exact guest registration and omitted handoff/Prepare CLI dependencies prevent turnkey setup. The inspectable source download contains the exact copied scripts, synthetic fixtures, selected control receipt and setup limitations. It is a prepared-lab scaffold, not a turnkey installer. The model and upstream code retain their respective licenses; this bundle makes no new license grant for the local scripts.