Commit or version
v1.11.0 — main at a8f2ca6. The code path is unchanged on dev (b5968eb, c/coli line 579).
Environment
Ubuntu 26.04.1, i7-11700K (8C/16T), 62 GB RAM, RTX 4060 Ti 8 GB (driver 595.91.07), CUDA Toolkit 12.4 (Ubuntu package, NVCC=/usr/bin/nvcc NVCC_CCBIN=g++-13), gcc 15.2, Samsung 980 PRO NVMe. Model: Kreuzzelg/qwen36-35b-a3b-colibri-i4-gs64.
Reproduction steps
make -C c qwen36 CUDA=1 CUDA_ARCH=native NVCC=/usr/bin/nvcc NVCC_CCBIN=g++-13
make -C c colibri CUDA=1 CUDA_ARCH=native NVCC=/usr/bin/nvcc NVCC_CCBIN=g++-13 # so cuda_binary() passes on main
# 1. the planner and the doctor both advertise a VRAM tier, no flag needed
python3 c/coli plan --model <qwen36_i4_gs64>
python3 c/coli doctor --model <qwen36_i4_gs64>
# 2. apply the plan
COLI_MODEL=<qwen36_i4_gs64> python3 c/coli serve --auto-tier --model-id qwen36
# ... one chat completion over the API, nvidia-smi during decode
# 3. same, with --gpu auto
COLI_MODEL=<qwen36_i4_gs64> python3 c/coli serve --auto-tier --gpu auto --model-id qwen36
Expected behavior
--auto-tier is documented as "automatically apply the RAM/VRAM plan". The plan it applies is the one coli plan prints, which on this box includes a VRAM tier:
VRAM 5.2 GB hot tier · ~2963 experts · 0:NVIDIA GeForce RTX 4060 Ti
limit CPU expert tail and GPU compute
and coli doctor reports [ ok] accelerator.gpu GPU engine and devices are available (doctor checks the qwen36 binary itself). I expected step 2 to start the tier, or at least to say that it was not going to.
Actual behavior and logs
Step 2 starts CPU-only, silently. The engine banner has no [CUDA] / [qtier] line, VRAM stays at the desktop's 897 MiB during decode, and the serve log has no [PLAN] line at all (the sibling-engine path prints none), so nothing tells the user the VRAM part of the plan was dropped:
== qwen36 Phase-2 engine | cache=256/layer bits=4 ctx=8192 pilot=0 wide=1 hot=0 smooth=0.30 conf=0.92 ==
resident weights loaded in 6.7s | RSS after load: 9.23 GB
OpenAI-compatible API listening on http://127.0.0.1:8000/v1
Step 3 works as intended:
[CUDA] device 0: NVIDIA GeForce RTX 4060 Ti, 8.2 GB VRAM, sm_89
[place] auto: dev 0 holds 1207.4 MB of trunk (lmhead yes, 30 dnproj layers), 4.05 GB left for experts
[qtier] CUDA VRAM expert tier active: 1 device(s), 1.80 MB/expert
Same 115-token completion, temperature=0, identical output text:
| launch |
request (warm) |
tools/datapoint.py rotating median |
TTFT |
--auto-tier |
11.5 s |
11.8 tok/s |
2.4–3.4 s |
--auto-tier --gpu auto |
5.9 s |
21.0 tok/s |
1.0 s |
So a Linux user of a sibling engine who does what coli plan suggests gets half the throughput and no hint why. I only found it because I was watching nvidia-smi.
Where it comes from
In env_for() the two paths disagree:
- GLM (
c/coli ~line 767 on main): has_cuda=cuda_binary(); e=environment_for_plan(plan,e,has_cuda) — --auto-tier alone enables the tier when the binary is a CUDA build.
- sibling engines (~line 572 on main, 579 on dev):
environment_for_plan(plan,env,cuda_enabled=env.get("COLI_CUDA") == "1"), with the comment "merely asking for auto-tier must not turn a CPU-only sibling binary into an attempted CUDA launch".
That concern was legitimate when cuda_binary() could only inspect the GLM binary. Since #1533 / #1537 dev has cuda_binary(engine) and engine_for_gpu_check(a), so the sibling path can now make the same decision as the GLM path, from the right binary. (On main v1.11.0, --gpu auto additionally refuses with "the engine binary is CPU-only" unless c/colibri is also a CUDA build — that is #1533, already fixed on dev, not re-reporting it.)
The bare-coli chat auto-enable block is Windows-only on purpose (#363, "Linux already has working detection + the explicit-flag UX"); this report is not about bare chat, it is about --auto-tier dropping part of the plan it claims to apply.
Suggested fix
Either of:
- In the sibling-engine path,
cuda_enabled = env.get("COLI_CUDA") != "0" and cuda_binary(engine_for_gpu_check(a)) — apply the plan's VRAM tier when the family engine is a CUDA build, keep --gpu none / COLI_CUDA=0 as the off-switch, same contract as the GLM path.
- If the explicit-flag contract is to stay for sibling engines: print the
[PLAN] RAM … · CPU line on that path too, and have coli plan / coli doctor say that the VRAM tier needs --gpu auto on Linux, so the printed plan and the applied plan cannot silently differ.
Happy to test a patch on this box (single 8 GB card, qwen36 and deepseek_v4 CUDA builds available).
Commit or version
v1.11.0 —
mainat a8f2ca6. The code path is unchanged ondev(b5968eb,c/coliline 579).Environment
Ubuntu 26.04.1, i7-11700K (8C/16T), 62 GB RAM, RTX 4060 Ti 8 GB (driver 595.91.07), CUDA Toolkit 12.4 (Ubuntu package,
NVCC=/usr/bin/nvcc NVCC_CCBIN=g++-13), gcc 15.2, Samsung 980 PRO NVMe. Model:Kreuzzelg/qwen36-35b-a3b-colibri-i4-gs64.Reproduction steps
Expected behavior
--auto-tieris documented as "automatically apply the RAM/VRAM plan". The plan it applies is the onecoli planprints, which on this box includes a VRAM tier:and
coli doctorreports[ ok] accelerator.gpu GPU engine and devices are available(doctor checks the qwen36 binary itself). I expected step 2 to start the tier, or at least to say that it was not going to.Actual behavior and logs
Step 2 starts CPU-only, silently. The engine banner has no
[CUDA]/[qtier]line, VRAM stays at the desktop's 897 MiB during decode, and the serve log has no[PLAN]line at all (the sibling-engine path prints none), so nothing tells the user the VRAM part of the plan was dropped:Step 3 works as intended:
Same 115-token completion,
temperature=0, identical output text:tools/datapoint.pyrotating median--auto-tier--auto-tier --gpu autoSo a Linux user of a sibling engine who does what
coli plansuggests gets half the throughput and no hint why. I only found it because I was watchingnvidia-smi.Where it comes from
In
env_for()the two paths disagree:c/coli~line 767 on main):has_cuda=cuda_binary(); e=environment_for_plan(plan,e,has_cuda)—--auto-tieralone enables the tier when the binary is a CUDA build.environment_for_plan(plan,env,cuda_enabled=env.get("COLI_CUDA") == "1"), with the comment "merely asking for auto-tier must not turn a CPU-only sibling binary into an attempted CUDA launch".That concern was legitimate when
cuda_binary()could only inspect the GLM binary. Since #1533 / #1537devhascuda_binary(engine)andengine_for_gpu_check(a), so the sibling path can now make the same decision as the GLM path, from the right binary. (Onmainv1.11.0,--gpu autoadditionally refuses with "the engine binary is CPU-only" unlessc/colibriis also a CUDA build — that is #1533, already fixed ondev, not re-reporting it.)The bare-
coli chatauto-enable block is Windows-only on purpose (#363, "Linux already has working detection + the explicit-flag UX"); this report is not about bare chat, it is about--auto-tierdropping part of the plan it claims to apply.Suggested fix
Either of:
cuda_enabled = env.get("COLI_CUDA") != "0" and cuda_binary(engine_for_gpu_check(a))— apply the plan's VRAM tier when the family engine is a CUDA build, keep--gpu none/COLI_CUDA=0as the off-switch, same contract as the GLM path.[PLAN] RAM … · CPUline on that path too, and havecoli plan/coli doctorsay that the VRAM tier needs--gpu autoon Linux, so the printed plan and the applied plan cannot silently differ.Happy to test a patch on this box (single 8 GB card, qwen36 and deepseek_v4 CUDA builds available).