Skip to content

qwen36 tier: QT_MAX_ROWS, placement pin, ownership-based int8 free (follow-up to #1344) - #1388

Merged
JustVugg merged 3 commits into
JustVugg:devfrom
crichalchemist:qwen36-tier-review-followup
Sep 12, 2026
Merged

JustVugg merged 3 commits into
JustVugg:devfrom
crichalchemist:qwen36-tier-review-followup

Conversation

@crichalchemist

@crichalchemist crichalchemist commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Follow-up to #1344, addressing the review there from @kreuzzelg and @JustVugg. Three commits on current dev.

1. Review response (original implementation by @mfethe1, crichalchemist#1)

The shutdown-test watchdog from the original follow-up is already on dev via fa8142d, so this PR does not touch test_qwen36_tier_shutdown.c.

2. The #1341 free keys on ownership, not on format

@JustVugg's suggestion from the review. if (!keep8 && expert_is_int4 && e->g) encoded today's correspondence between weight format and memory ownership; a third format that also aliases e->g would reintroduce the use-after-free without anyone reading a format flag as an ownership statement. Now:

if (!keep8 && e->g && wg != (const uint8_t *)e->g) { free(e->g); ... }

Do not free what was just handed over. Same behaviour on both current containers (test_qwen36_tier_int8_engine covers both), correct by construction for the next one.

3. One warning

cnt in the placement pricing loop (ff13134) was set and never read; -Wunused-but-set-variable flagged it in every test build that includes qwen36_tier.c. Removed.

Verified

macOS 13 x86_64 (2017 iMac, i7-7700K), Apple clang, fake CUDA backend: make qwen36 and all seven tests/test_qwen36_tier_* binaries with 0 warnings, all passing (autoplace, fp8, int8, int8_engine, invariants, multidev, shutdown). Not built on MinGW/UCRT64 locally; the Windows job here is the proof for that.

mfethe1 and others added 3 commits September 7, 2026 14:54
…ainer docs

Review response for JustVugg#1344, rebased onto dev after the auto-placer (ff13134)
moved the is_x allocation below the placement pass.

- QT_MAX_ROWS replaces the bare 32 in all seven sites that must agree
  (is_k width, K clamp, tg/tu/td, rows[], topk message, is_x_floats,
  qt_issue stride). JustVugg#1339 was three of these disagreeing.
- multidev test gains the sizeof consistency check and a placement pin.
  These catch different drift directions: widening is_k to 64 while the
  stride stays 32 is caught ONLY by the sizeof check (placement,
  in-bounds and disjointness all pass); shrinking the stride below the
  row capacity is caught by the placement pin where in-bounds is not
  sufficient. Both kept.
- warmstart log line and docs no longer promise an RSS saving that does
  not exist on an int8 container (since JustVugg#1341 the free is int4-only).

The shutdown-test watchdog from the original follow-up is already on dev
(fa8142d), so that file is untouched here.
The JustVugg#1341 free keyed on expert_is_int4, which encodes today's
correspondence between weight format and memory ownership. A third
format that also aliases e->g would have no reason to read a format flag
as an ownership statement and would reintroduce the use-after-free.

State the invariant directly: do not free what was just handed to the
tier. int4 handed g4, so the int8 copy is spare and goes; int8 handed
e->g itself, so it stays. Same behaviour on both current containers
(test_qwen36_tier_int8_engine covers both), correct by construction for
the next one. Suggested by JustVugg in the JustVugg#1344 review.
cnt was incremented and never read, and -Wunused-but-set-variable
flagged it in every test build that includes qwen36_tier.c. The engine
build must stay at zero warnings; now the test builds do too.
Copilot AI lite review requested due to automatic review settings September 7, 2026 20:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@kreuzzelg kreuzzelg left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking all three points from the #1344 review; this closes them.

QT_MAX_ROWS. All seven sites now read the one constant, and the sizeof-based check in the multidev test ties is_k's row capacity to the replica stride, which is exactly the pair #1339 let drift. The two placement pins (records[dev0].x == G.is_x, records[dev1].x == G.is_x + QT_MAX_ROWS*D) are the assertion the original test lacked: in-bounds and disjoint both pass on a single-row issue under the old 8*D stride, these do not. One literal is left in the test itself, float val[32] and its loop just below the new pins; harmless, but since the point of the PR is that the number lives in one place, QT_MAX_ROWS there too.

Ownership free. !keep8 && e->g && wg != (const uint8_t *)e->g is the right predicate: int4 hands g4 (spare int8 copy, free it), int8 hands e->g itself (keep it), and a third format that aliases e->g is safe without a format check. The wg == NULL case still leaves via the continue above it, so qt_note_planned has always staged before anything is freed. Correct by construction, as the description says.

Log line and docs. Both now say which container they describe; the 40 → 29 GB row is labelled as int4-only. Good.

On real hardware, two cards (RTX 3070 + Quadro RTX 4000, driver 580.173, CUDA 12.0), this PR plus #1390 applied on dev 6f9117f: the CI qwen36_tiny fixture as an int8 container (--ebits 8, ./qwen36 8 8), COLI_CUDA=1, default warmstart: 40/40 runs, 16/16 tokens, uploads 64 / miss(CPU) 0 / VRAM hit rate 100 %, banner int8 container: all experts keep their weights in RAM. Same fixture as int4 (--ebits 4, ./qwen36 8 4): 20/20, 16/16, banner int8 copy dropped for residents, kept for non-residents, resident 64/64. All seven tests/test_qwen36_tier_* pass. (Caveat as in #1390: dev's warmstart has an unrelated one-in-twelve segfault in ehit_mark's lazy allocation, see #1331; the runs above carry a local lock for it.)

Approve. My open qwen38 tier branch adds to qwen36_tier.c too (fp8 mode, dense residents) but not to qt_issue or the is_x sizing, so rebasing onto this is mechanical; I will do it once it lands.

@JustVugg
JustVugg merged commit d9d773b into JustVugg:dev Sep 12, 2026
25 checks passed
crichalchemist added a commit to crichalchemist/colibri that referenced this pull request Sep 17, 2026
Second forward-merge of this branch. Four files conflicted; the rest of dev
merged clean.

c/qwen36_tier.c, c/qwen36_tier.h: JustVugg#1390 landed upstream with reworded
comments, so the branch's copy of the qt_fill_wait fix is dropped in favour
of dev's. JustVugg#1388's QT_MAX_ROWS replaces the literal 32 in the issue path and
the per-device row arrays; the backend-neutral QtTensor stays, since dev's
side of those lines still spells ColiCudaTensor.

The dense-trunk block dev added for the Qwen3.8 trunk (qt_dense_init,
qt_dense_matmul, dense_free_all) called coli_cuda_* directly and would not
compile without CUDA. It now goes through the same be_trunk_upload /
be_trunk_matmul / be_free shim as lm_head and the DeltaNet projections, so
on Vulkan it refuses and the matrices stay on the CPU path.
coli_cuda_group_stats is left alone: it is already inside #ifdef COLI_CUDA.

G.ybuf was the one remaining literal 32 in the file and is now sized by
QT_MAX_ROWS. Not a live overflow at the current value, but it is the fourth
spelling of the constant JustVugg#1339 was filed to unify.

c/Makefile: dev's new prerequisites (expert_ffn.h, omp_tune.h, kv_prefix.h)
with this branch's $(VK_OBJ)/$(VK_SPV) re-applied, and the tier condition is
dev's ifneq over CUDA/CUDA_DLL/HIP/HIP_DLL with the VK=1 branch kept after
it. The three tests/test_qwen36_tier_vk* rules are unchanged.

docs/qwen36.md: dev's expert-kernel section and the ROCm paragraph, with the
VK=1 sentence and the qwen36-tier.md link restored.
@crichalchemist
crichalchemist deleted the qwen36-tier-review-followup branch September 23, 2026 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants