Repository navigation
hrx: a Q4_K/Q6_K weight in the file mapping is read in the packed layout by default, so it has one device copy (engine #2137) - #313
Conversation
…out by default, so it has one device copy (engine ggml-org#2137) llama.cpp #308 and #310 let prefill read the packed rows decode reads, behind GGML_HRX_Q4K_PACKED_TAIL=1 and GGML_HRX_Q6K_PACKED_ROWS=1. The packed layout saves a copy exactly when the stored one costs a copy, which is when the weight is in the loader's file mapping (#304); for an uploaded weight the stored layout is already on the device and the packed one would be the extra copy. So the default now follows the weight's own buffer: packed for a weight in the file mapping, stored otherwise. The switches still force either: =1 packed for every weight, =0 stored for every weight. Test (device-free): hrx-backend-test packed_layout_follows_weight.{q4_k,q6_k}.{file_mapped,uploaded}. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
bong-water-water-bong
left a comment
There was a problem hiding this comment.
VERDICT at e02f3ba: READY
This is the last step on ggml-org#2137's "done when" list — the default — and the ordering of the series is what makes it safe: #308 (Q4_K opt-in), #310 (Q6_K opt-in, which also fixed a fault in the first opt-in), and now the default path reading a Q4_K/Q6_K weight from the file mapping.
Two things are right about finishing here rather than earlier:
- the opt-in path ran twice with its own flag before anything became default, so the second opt-in (#310) had a chance to find the first one's fault before it was on by default;
- each step was validated on a real model's shapes (Qwen3-4B's 216 q4_K / 37 q6_K) rather than on a synthetic pair.
Reaches engine main with a later pin bump, which is the chain ggml-org#2141's submodule-pin checker guards — so the default cannot land here and sit unreached in the fork.
|
The device before/after the body said was queued (cl-hrxmem). Head
The model is 2,375.9 MiB, so the default holds exactly one device copy per weight after a long prompt with a reply; the stored arm reproduces the issue's own figure (647 copies, 4,400.6 MiB). Copies are counted from Prefill is not slower with the default. The two arms ran back to back in one ticket, not interleaved, and the Still not done, as in the body: a dense 27B row, a routed-expert row, and the whole suites at this head. ready for review at e02f3ba. |
Refs 1bit-MONSTER/engine#2137 (the step after #308 and #310 on its "done when" list: the default). Reaches engine main with a later pin bump, not in this PR.
What changes
#308 and #310 let prefill read a Q4_K / Q6_K weight in the packed rows decode reads, behind
GGML_HRX_Q4K_PACKED_TAIL=1andGGML_HRX_Q6K_PACKED_ROWS=1. Both say why they stayed opt-in: the packed layout saves a device copy only when the stored one costs a copy, i.e. when the weight is in the loader's file mapping (#304); for an uploaded weight the stored layout is already on the device and the packed one is the extra copy.That condition is a property of each weight's buffer, so the default now reads it there:
GGML_HRX_MODEL_BUFFER_COPY=1, a host-weight limit, a load without mmap, a test tensor): stored, as before.=1still forces packed for every weight and=0forces stored for every weight. The once-per-process log line says which of the three is in effect.buffer_is_file_mapped()(new, inmodel-buffer-from-mmap) identifies the mapped buffer type by its interface, not by name.This also composes with #311 (open, engine ggml-org#2163), which would upload models above a size limit: those weights are not file-mapped, so they stay stored without either PR knowing about the other. I have not run the two together.
Test (device-free)
hrx-backend-test packed_layout_follows_weight.{q4_k,q6_k}.{file_mapped,uploaded}: oneMUL_MATat 100 tokens (off both aligned grids), the weight allocated either in a buffer made bymodel_buffer_from_mmap()or in a plain weights buffer; the scheduledggml.mul_mat.weight_formatmust be 44 / 46 for the file-mapped weight and 4 / 6 for the uploaded one.(strixhalo, amdclang Release, fork
2b7960b+ this change, run host-only.) Before this change the twofile_mappedrows cannot pass: the default was stored for every weight. I did not run them against the old code, because the rows use the newbuffer_is_file_mapped().Not measured yet
The device before/after is queued, not done: Qwen3-4B Q4_K_M, device copies after a 1,700-token prompt with a reply, default against
=0, with perplexity at a 300-token batch and prefill tok/s in both arms. I will post it here when the ticket has run; please do not treat this as verified on a device until then. cl-hrxkern's numbers on #308/#310 are for the switches forced on, which is the same kernel path this default selects for a file-mapped model.Also not done: a dense 27B row and a routed-expert row (the box has not had the memory), and the whole
hrx-backend-test/test-backend-opssuites at this change (intest-backend-opsno weight is file-mapped, so the default there is unchanged by construction).🤖 Generated with Claude Code