Repository navigation
Conversation
…nchronous reads) Niko1221#286's unbuffered file tier existed on Windows alone: on Linux the experts outside the RAM copy were always read through the page cache, as page faults of the mapped GGUF - small requests on the critical path, and pages that a 32 GB PC cannot keep beside a 16 GiB RAM copy anyway, so they were read again and again. - open_direct opens the files with O_DIRECT; read_direct queues every 4 KiB-aligned window of a batch with one io_submit (linux/aio_abi.h, no library; allowed by Docker's default seccomp profile, unlike io_uring) and waits for all of them, each thread with its own context and aligned buffer. Windows merges windows up to 1 MiB apart for NTFS; here only windows that touch are merged. A refused submit or a failed read falls back to the mapping, as on Windows. - The same decision as Windows' `cache_counts = false` arm: unbuffered when the file cache could not keep the expert bytes outside the RAM copy (platform::file_cache_keeps, from MemAvailable and the tightest cgroup limit), re-checked once the copy is built (Niko1221#577). STRATA_UNBUFFERED_LOAD=1 / 0 forces it either way. A pack's experts.bin works too (its Linux open now records the path). - direct_fallbacks() counts the blobs an unbuffered read could not deliver. - Tests: file_expert_source_test reads a synthetic pack unbuffered - one blob at a time, a batch of adjacent experts, copy_blob - and requires the file's bytes and no fallback (a mutation that fails every read is caught). ctest: 63 of 66 pass; the three others need a Q2_0 pack, a higher `ulimit -l` and AVX-512, as before. Measured on an RTX 3080 Ti Laptop 16 GB, i9-12900H, 30 GB RAM, KIOXIA PCIe 4 NVMe, Linux 7.0, ext4: Qwen3.8-Flash-Next Abliterated Q4_K_M in place (--native), --resident-budget-gib 16, --expert-cache auto, 8K context, greedy; three prompts (code, Russian prose, a 7.8K-token summary), each with and without MTP, two rounds of buffered (STRATA_UNBUFFERED_LOAD=0) against unbuffered, the same binary. Decode 4.38 -> 7.90 tok/s on average (x1.80; x1.49-x2.01 per prompt and mode), the 7.8K prompt read at 154/172 -> 184/290 tok/s, startup 36 -> 18-21 s. The code prompt's answer is the same text in all 16 runs; the other two differ between runs of either arm (the adaptive GPU cache changes which experts the CPU computes), as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reply to PR #773 (cakescats) — posted via gh as q8atnightMeasured on a low-RAM layer-split rig where the failure mode this PR cures is NOT the one that
So the Linux arm wants a second condition besides |
Review of Niko1221#773 (2 x RTX 5060 Ti 16 GB, 32 GB RAM, --mmap-experts, no --resident-budget-gib): with no RAM copy the file cache is the expert tier, and forcing unbuffered reads there re-read 163-629 GB from the drive and halved the speed. The automatic decision never armed in that mode; now the forced one does not either, and the log says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for measuring this — agreed, forcing it with no RAM copy should not be possible: 2bdcf37 ignores |
Review of #773 (2 x RTX 5060 Ti 16 GB, 32 GB RAM, --mmap-experts, no --resident-budget-gib): with no RAM copy the file cache is the expert tier, and forcing unbuffered reads there re-read 163-629 GB from the drive and halved the speed. The automatic decision never armed in that mode; now the forced one does not either, and the log says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged in 0.1.40: the unbuffered file tier on Linux (O_DIRECT + io_submit), chosen by the same rule as Windows; STRATA_UNBUFFERED_LOAD=1/0 forces it either way. |
…es the keep set Upstream (v0.1.40, expert_source.cpp file_tier_unbuffered and platform::file_cache_keeps, Niko1221#286 / Niko1221#577 / Niko1221#773): the hottest experts get a RAM copy (our RAM tier); the rest are read through the file cache, or with O_DIRECT when the cache could not keep them (available RAM less 4 GiB below their bytes). It never drops pages after a buffered read (its notes: POSIX_FADV_DONTNEED made decode re-read from the disk). This replaces 7bd95ad's keep set and per-expert DONTNEED. The O_DIRECT reader covers each expert with its 4 KiB-aligned window. expert_stream_test runs both modes on a fake pack whose experts do not start on 4 KiB boundaries: 600 of 600 slots correct each (RTX 3060). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review of #773 (2 x RTX 5060 Ti 16 GB, 32 GB RAM, --mmap-experts, no --resident-budget-gib): with no RAM copy the file cache is the expert tier, and forcing unbuffered reads there re-read 163-629 GB from the drive and halved the speed. The automatic decision never armed in that mode; now the forced one does not either, and the log says so.
Review of Niko1221#773 (2 x RTX 5060 Ti 16 GB, 32 GB RAM, --mmap-experts, no --resident-budget-gib): with no RAM copy the file cache is the expert tier, and forcing unbuffered reads there re-read 163-629 GB from the drive and halved the speed. The automatic decision never armed in that mode; now the forced one does not either, and the log says so.
Review of Niko1221#773 (2 x RTX 5060 Ti 16 GB, 32 GB RAM, --mmap-experts, no --resident-budget-gib): with no RAM copy the file cache is the expert tier, and forcing unbuffered reads there re-read 163-629 GB from the drive and halved the speed. The automatic decision never armed in that mode; now the forced one does not either, and the log says so.
#286's unbuffered file tier exists on Windows only. On Linux the experts outside the RAM copy are always read through the page cache, as page faults of the mapped GGUF: small requests on the critical path, and pages that a 32 GB PC cannot keep beside a 16 GiB RAM copy anyway, so the same experts are read from the drive again and again.
This adds the Linux side of the same mechanism.
open_directopens the files withO_DIRECT.read_directqueues every 4 KiB-aligned window of a batch with oneio_submitand waits for all of them. That is the kernel's own asynchronous read (linux/aio_abi.h): no library, and Docker's default seccomp profile allows it, unlike io_uring. Each thread has its own context and aligned buffer, so concurrent batches never see each other's completions. Windows merges windows up to 1 MiB apart because of NTFS; here only windows that touch are merged. A refused submit or a failed read falls back to the mapping, as on Windows.The decision is Windows'
cache_counts = falsearm: unbuffered when the file cache could not keep the expert bytes outside the RAM copy (platform::file_cache_keeps, from MemAvailable and the tightest cgroup limit viahost_available_memory). It is re-checked once the copy is built (#577), andSTRATA_UNBUFFERED_LOAD=1/0forces it either way. A machine whose RAM can cache those bytes keeps the buffered path. A pack'sexperts.binworks too: its Linux open now records the path.direct_fallbacks()counts the blobs an unbuffered read could not deliver.The Windows code paths are unchanged; I had no Windows machine to build on. The new
#elif defined(__linux__)branches sit beside them.Measured. RTX 3080 Ti Laptop 16 GB, i9-12900H, 30 GB RAM, KIOXIA PCIe 4 NVMe, Linux 7.0, ext4. Setup:
--native),--resident-budget-gib 16,--expert-cache auto, 8K context, greedy.STRATA_UNBUFFERED_LOAD=0) against unbuffered, with the same binary.Tests.
file_expert_source_testgainstest_unbuffered_reads. It writes a synthetic pack of random bytes and reads it unbuffered three ways: one blob at a time, a batch of adjacent experts, andcopy_blob. It requires the file's bytes anddirect_fallbacks() == 0. A mutation that fails every read is caught. The pack is written in the working directory, not/tmp, so a file system withoutO_DIRECTskips the test with a message instead of failing it.ctest: 63 of 66 pass. The other three fail on this machine before and after the change, for these reasons:ple_parityneeds the Q2_0 pack;platform_memory_testneeds a higherulimit -l;expert_multi_testneeds AVX-512.🤖 Generated with Claude Code