Commit Graph

402 Commits

Author SHA1 Message Date
BM Cho 721bfcb325 docs: add Traditional Chinese README 2026-07-17 17:03:49 +08:00
Tonu Samuel 81a56777df glm.c: detect 9p by statfs f_type, not the "/mnt/" path prefix
The slow-filesystem warning fired for any model path under /mnt/, which
false-positives on native-Linux mounts (ZFS/ext4/xfs/NFS) that commonly
live there. Check the actual filesystem type via statfs() against the 9p
superblock magic (0x01021997) instead, so it only warns for a genuine
WSL 9p mount. Linux-only (statfs); no behavior change on other platforms.
2026-07-17 08:00:26 +03:00
Nicholas Beerbower ed8dab4da4 test_st_pread: Windows-compatible — relative tmpdir, fork subtest gated POSIX
Same fix pattern as test_stops: mkdtemp with a CWD-relative template
(MinGW resolves Windows paths; /tmp is not one), and the fork/pipe/
truncate-based truncation subtest compiles only where those exist —
Windows still runs the cross-platform chunk-loop content check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:32:43 -04:00
Nicholas Beerbower 6507817d9f st: chunked pread with EINTR retry and honest short-read errors
Two latent bugs in every st.h reader, both hit in the field:

 - a single pread caps at ~2^31 bytes on Linux, so any tensor past
   2.1 GB (bf16 embed/unembed tensors of large models qualify) came
   back silently truncated with perror printing '... : Success'
   (errno untouched by a short read) — the same misleading-error
   symptom glm.c fixed for its own reads in #236;
 - no EINTR retry.

st_pread_full loops in ST_PREAD_CHUNK pieces (1 GB default, override
for tests), retries EINTR, and reports offset + progress on failure.
All five read sites converted; behavior on well-formed files is
byte-identical (GLM oracle re-verified on this branch: 32/32).

tests/test_st_pread builds with -DST_PREAD_CHUNK=7 so a 96-byte tensor
exercises the multi-chunk loop, and forks a child against a shard
truncated after st_init (init's static bounds check means the pread
path only fires when a file shrinks under a live handle) asserting
exit(1) with a 'short read' message and no 'Success'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 15:20:43 -04:00
JustVugg d45cfa268a Merge branch 't321' into trial321b
# Conflicts:
#	README.md
2026-07-16 21:11:23 +02:00
Mohamed Mastouri 69284facb8 docs: Windows 11 native install walkthrough - toolchain, SAC, CUDA DLL, failure index (#198) 2026-07-16 21:59:20 +03:00
Mohamed Mastouri 80f886cd22 convert_olmoe.py: wire --ebits through to quantization (#323) 2026-07-16 21:59:16 +03:00
Vincenzo cead3d8bf3 Merge pull request #324 from dawnfield-institute/feat/olmoe-ppl-mode
olmoe: PPL=1 teacher-forced perplexity mode (loss meter for throughput experiments)
2026-07-16 20:47:37 +02:00
Vincenzo 57030ab231 Merge pull request #327 from lEWFkRAD/ci/windows-cuda-build
ci: build the Windows CUDA path (nvcc + MSVC host) — the one toolchain no job covers
2026-07-16 20:47:33 +02:00
lEWFkRAD b75422d605 ci: build the Windows CUDA path (nvcc + MSVC host) — the one toolchain no job covers
engine-cuda-syntax compiles backend_cuda.cu with nvcc's GCC host on Linux, and
check.yml's windows job is MinGW/UCRT64 CPU-only by design (#140). Neither
exercises nvcc's MSVC host — the only host compiler nvcc accepts on Windows — so
`make cuda-dll` and `make glm CUDA_DLL=1` are currently built by nothing.

The gap has already cost real bugs, all compile-time, all catchable without a GPU:

  - #158: MSVC rejects the GCC-style -Xcompiler=-Wall,-Wextra ("D8021 invalid
    numeric argument '/Wextra'"), CUDA_HOME/NVCC defaults were unresolvable, and
    the kernel test used POSIX setenv. `make cuda-dll` was unbuildable as shipped.
  - #314: CUDA_HOME containing spaces — the CUDA installer's default layout. This
    job installs to exactly that path, so it reproduces the condition by default.

Two Windows-specific facts the job encodes, both verified by making it fail first:

  - sub-packages needs "cudart", not just "nvcc": cuda-dll *links* the runtime, and
    on Windows the headers/import lib are a separate installer component. With
    '["nvcc"]' alone it dies at `#include <cuda_runtime.h>` — the Linux syntax job
    never notices because it only compiles.
  - runs-on is pinned to windows-2022: windows-latest now ships Visual Studio 18
    (MSVC 14.5x) and CUDA's crt/host_config.h hard-errors on any host newer than
    VS 2022. That is a real constraint on every Windows CUDA user today, so the pin
    tracks what the toolkit supports rather than papering over it with
    -allow-unsupported-compiler.

Build-only on purpose: hosted runners have no NVIDIA device, so this proves the
Windows+MSVC CUDA build stays buildable, not that the kernels or the DLL loader
behave on real silicon — that still needs hardware (#157). A check that overclaims
buys the false confidence the engine-cuda-syntax comment already warns about.

Verified green on a fork before proposing:
https://github.com/lEWFkRAD/colibri/actions/runs/29524302993

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 14:35:30 -04:00
JustVugg e7188df16a tests: test_stops must not assume /tmp exists (fixes the windows job)
My test_stops.c called mkdtemp("/tmp/coli_stops_XXXXXX"). These binaries are
built by MinGW into NATIVE Windows .exe files, which resolve Windows paths —
"/tmp" is not one, so mkdtemp failed ENOENT and `make check` went red on the
windows job the moment #143 gave us cross-platform CI.

Now a relative template in the CWD, which is what test_compat_direct.c already
does (`#define TMPF "test_direct.tmp"`). test_uring.c uses /tmp but is
Linux-only by construction (Makefile guards it behind $(LINUX)); I copied the
wrong neighbour.

Worth being precise about what this was, because the red job looked scarier
than it was: Windows is fine. `make check` built the engine, ran the whole C
suite, and passed everything else — test_i4_grouped, kv_alloc, compat_direct —
before tripping on my temp path. The CI caught a bug in the test, not in the
port. That is #143 earning its keep on day one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 20:08:02 +02:00
Vincenzo ee5d273cd4 Merge pull request #232 from nbeerbower/profiling-upstream
Profiling: PROF=1 opt-in performance profile + live per-turn Profiling page in the web dashboard
2026-07-16 19:58:31 +02:00
JustVugg 98f7c88ca9 numa: parenthesise the page-align arithmetic (#313)
`(uintptr_t)p+n+4095 & ~(uintptr_t)4095` is CORRECT — `+` binds tighter than
`&` in C, so the rounding happens before the mask, which is what was meant.
But gcc -Wall warns (`suggest parentheses around '+' in operand of '&'`), and
this repo builds clean at -Wall -Wextra. Warning-free is a property worth more
than the two characters it costs to keep: it is what makes a NEW warning
visible instead of scrolling past in a wall of noise.

No behaviour change; the emitted code is identical.

Co-Authored-By: ZacharyZcR <#313>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 19:50:20 +02:00
Vincenzo 3cec90cd45 Merge pull request #313 from ZacharyZcR/feat/numa-expert-interleave
glm: COLI_NUMA=1 — interleave resident weights across NUMA nodes (+13% decode on 2-socket, raw mbind, zero deps) (#82)
2026-07-16 19:49:17 +02:00
Vincenzo 2dca36a8a0 Merge pull request #314 from mohamedmastouri2000-boop/fix/windows-cuda-dll-build
Add build-config stamp: flag changes (e.g. CUDA_DLL=1) force a relink instead of a silent stale binary
2026-07-16 19:49:14 +02:00
Vincenzo 644e0d16c6 Merge pull request #302 from alekseysorokin68/main
Fix: set stdout to O_BINARY on Windows to fix READY sentinel
2026-07-16 19:49:11 +02:00
Vincenzo 59988c41c8 Merge pull request #143 from lEWFkRAD/ci/make-check-matrix
ci: make check on ubuntu / windows (MSYS2 UCRT64) / macos — and it already caught a Windows test bug (#140)
2026-07-16 19:46:27 +02:00
Vincenzo 545d9d0ab5 Merge pull request #317 from ZacharyZcR/docs/serve-protocol
docs: serve protocol reference — the engine⇄server wire format (#310)
2026-07-16 19:46:24 +02:00
Vincenzo b04c2ca50e Merge pull request #322 from woolcoxm/fix/oracle-transformers-pin
oracle: hard-fail on transformers < 5.11.0 (interleaved-RoPE floor, #281)
2026-07-16 19:46:20 +02:00
Vincenzo c686f6bd51 Merge pull request #320 from Magnet-js/docs/winget-python-readme
docs: add winget python one-liner to Windows install block (#310)
2026-07-16 19:46:17 +02:00
Vincenzo 95b059b15b Merge pull request #318 from tt1203/fix/oracle-mkdir-glm-tiny
fix: make_glm_oracle.py creates glm_tiny/ before saving (fresh-checkout failure)
2026-07-16 19:46:13 +02:00
JustVugg 72d3d37231 ci: run the checks on main too (#144)
@ZacharyZcR's workflow, already green on dev (78c77bf): engine + C suite,
web build + vitest, python suite, and a real CUDA syntax check.

Only the workflow file is cherry-picked here — main's engine code stays at
54cfe56 and nothing else from dev comes along. main is where the checks are
worth the most and where they were missing entirely.

Includes the two fixes the first run exposed: the pinned action's version
table stops at 12.6.2 (12.6.3 failed the install), and `nvcc ... | head -40`
took its exit status from head, so the job could never fail.

Co-Authored-By: ZacharyZcR <#144>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 19:39:40 +02:00
JustVugg 78c77bf6c8 ci: make the CUDA job able to fail, and able to run (#144)
Two independent defects in the CUDA syntax job, both caught on its first run.

1. `cuda: '12.6.3'` — Jimver/cuda-toolkit@v0.2.19's version table stops at
   12.6.2, so the install step died with "Version not available: 12.6.3"
   before nvcc was ever invoked. One digit.

2. `nvcc ... 2>&1 | head -40` — a pipeline exits with the status of its LAST
   command, so head's 0 masked every nvcc error. The job printed "CUDA syntax
   check passed" unconditionally: it could not fail. Defect 1 is why we found
   out, since it broke the step *before* the pipe.

The second one is the one that matters. backend_cuda.cu is compiled by nothing
else in this repo — no local build, no test — so this job is the only thing
standing between a CUDA change and a user's GPU. A check that cannot fail is
worse than no check: it buys false confidence in exactly the file that most
needs the real thing. #298 spent a night debugging CUDA against no oracle at
all; this job is supposed to be that oracle.

It is also, precisely, the disease of the week in YAML form: a signal that
measures its own intention rather than the thing it claims to measure. See the
`~335 GB I/O saved` counter that counted dropped experts instead of bytes not
read (#303), and `route_agree: 95.3%` cited as "quality preserved" when it
only measures which experts coincide.

The other three jobs (engine, web, python) passed on the first run.

Co-Authored-By: ZacharyZcR <#144>

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 19:36:31 +02:00
Vincenzo 5272d19abc Merge pull request #144 from ZacharyZcR/ci/github-actions
ci: GitHub Actions — engine, web, Python, CUDA syntax (free for public repos)
2026-07-16 19:32:18 +02:00
ZacharyZcR 7bc9f6e2e9 docs/media: refreshed dashboard shots (full-residency 4 tok/s, disk 0), new Atlas galaxy, phone + sidebar shots 2026-07-17 00:29:50 +08:00
Peter Groom c5f2027fa1 olmoe: PPL=1 teacher-forced perplexity mode (loss meter for throughput experiments)
Feeds reference tokens through the normal step() decode path and reports
NLL/ppl + hit rate + tok/s + RSS. Inert unless PPL=1; default path
untouched (12/12 vs ref.json verified with patch applied). Cross-checked
vs HF transformers bf16 on identical token ids: 12.11 vs 12.25 ppl (#108).
2026-07-16 13:10:50 -03:00
mohamedmastouri2000-boop c70d94368e Merge branch 'main' into fix/windows-cuda-dll-build 2026-07-16 19:05:43 +03:00
woolcoxm fa821a15a2 oracle: hard-fail on transformers < 5.11.0 (interleaved-RoPE floor, #281)
GLM-5.2 MLA uses interleaved (DeepSeek-style) RoPE, which the C engine
implements. transformers < 5.11.0 applied split-half (Llama-style) RoPE in
GlmMoeDsa* instead; an oracle built on those versions silently drifts and the
engine scores 25/32 instead of the documented 32/32 (#281). Weights come out
identical across versions -- only the forward pass differs -- so a too-old
transformers produces an invalid ref_glm.json with no warning.

Add a version gate at the top of make_glm_oracle.py: hard sys.exit with an
actionable message citing the issue and the upgrade command. Reads the version
from importlib.metadata (authoritative installed-dist version) rather than the
mutable transformers.__version__ attribute -- the latter gets reset by the lazy
model-class import (from transformers import GlmMoeDsaForCausalLM), so reading
it after that import is unreliable. The gate runs before the heavy import and
falls back to the attribute only if the dist metadata lookup fails (editable/
src installs).

Validated end-to-end on transformers 5.13.1: script runs, ref_glm.json and
model.safetensors are byte-identical to the shipped versions, engine scores
32/32. With the floor raised to (5,14) the gate blocks with the expected
message.
2026-07-16 12:03:15 -04:00
JustVugg 6de32c55f6 Don't trust a converted checkpoint's config for the stop set
The engine armed its stop tokens from config.json's eos_token_id and nothing
else. That trusts metadata written by third-party conversion tooling, which is
a thing we already know goes wrong: the README documents a mirror shipping
int4 MTP heads that silently give 0% draft acceptance. GLM-5.2 declares THREE
eos ids (<|endoftext|>, <|user|>, <|observation|>); a converter that rewrites
config.json with a reduced list leaves the engine stopping on fewer tokens
than the model emits, and the missed ones get detokenized and printed into the
chat as literal text while generation runs past the end of the turn.

Two independent defenses:

  - eos_token_id is now unioned with generation_config.json, which is
    HuggingFace's authority for generation (config.json often carries a
    partial legacy copy). An extra stop is harmless; a missing one is not.

  - every added-token the TOKENIZER marks "special":true is armed as a stop,
    whatever the configs say. Those are control tokens (<|user|>, <|assistant|>,
    <sop>, [gMASK], the image/video/audio markers) and are never legitimate
    content in a reply -- GLM itself lists three of them as official eos.
    <think>/<tool_call>/<arg_key> are "special":false and are deliberately NOT
    swept up: they are real output. tok.h was parsing added_tokens but throwing
    the "special" flag away, so the distinction wasn't available to anyone.

On the real per-row checkpoint this takes the armed set from 3 to 18:
  [stop] 18 stop tokens: 154820 154827 154829 154821 ... (15 from the
  tokenizer's special set)

Honesty about scope: this is hygiene for a class of bug, NOT a fix for the
trailing-junk report on #298 that prompted it. I hypothesised @woolcoxm's g64
checkpoint had lost eos ids in conversion; he checked, and it hadn't -- his
config arms all three correctly. The emit path is also innocent: is_stop() is
checked BEFORE emit() at every one of the four call sites (4215, 4256, 4908,
4987), so a correctly-armed stop cannot be printed. His trailing junk is still
unexplained and is more likely quantization noise. What this commit buys is
that a checkpoint we don't control cannot leak control tokens into a reply,
which was true before and is not now.

tests/test_stops.c covers both defenses: the union, a missing
generation_config.json, BOTH configs mutilated (the tokenizer still stops all
five control tokens while leaving <think> alone), and T=NULL (the validation
path keeps config-only behaviour).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 17:59:34 +02:00
JustVugg ac7103fe9c tests: extend the fmt=4 oracle to the fused gate+up kernel (#298)
@woolcoxm's matmul_i4_grouped_pair reads x once instead of twice for the
gate+up pair. Verified here against his branch (86e91b1 merged onto dev):
correct to ~2e-8 relative vs the double reference, and BIT-EXACT against two
separate matmul_i4_grouped calls on aligned shapes -- which is the shape the
real g64 checkpoints have (I = 2048 / 6144, gs = 64). His kernel is good.

Guarded behind COLI_HAVE_GROUPED_PAIR since the function only exists on that
branch; add -DCOLI_HAVE_GROUPED_PAIR to the test's Makefile rule when #298
lands and the pair cases activate.

The checks are deliberately asymmetric, and the reason is worth recording.
Bit-exactness is asserted ONLY when I % gs == 0: there every group is covered
by the AVX2 body, whose accumulation order matches the unfused kernel, so any
difference is a real bug. With a partial last group the tail falls to scalar
code and the compiler may contract/reassociate the fused body differently,
producing ~1e-7 differences -- rounding, not logic. My first version demanded
bit-exactness everywhere and duly "found" a bug in his kernel that did not
exist; the tell was that only `up` differed and never `gate`, which is FP luck
rather than a code path. Correctness is checked everywhere against the double
reference; identity only where identity is actually implied.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 17:27:06 +02:00
ZacharyZcR 64291238da README: restructure around the technical path — parameters and full results move to docs/, four new figures 2026-07-16 23:24:37 +08:00
Elias 05f9bd4b77 docs: add winget python one-liner to Windows install block (#310)
The coli CLI and openai_server.py need a real python3 interpreter, but a
fresh Windows resolves 'python' to the Microsoft Store alias stub (#198).
Document the winget one-liner as the interim fix suggested in #310 until
the CLI port lands.
2026-07-16 16:43:32 +02:00
JustVugg 2a5961a01b tests: exactness oracle for the grouped-int4 kernel (fmt=4)
matmul_i4_grouped is the reference the CUDA fmt=4 port (#298) is expected to
reproduce, and it had no test of its own. @woolcoxm is currently debugging a
CUDA backend against an oracle nobody had verified, which is two moving
targets at once -- and he can't cross-check on CPU, since a 5-prompt run
takes 8 hours on the 744B model.

This checks matmul_i4_grouped against a plain-C reference that dequantizes
nibble -> (v-8)*scale[i/gs] and accumulates in double, over 11 shapes: I a
clean multiple of gs, a partial last group (the glen clamp), odd I (the
scalar nibble tail), gs > I, gs=16/64/128, S>1, and the nibble extremes
0x00/0xFF -- which decode to -8/+7 because the format is offset-encoded, not
two's complement. Reading that backwards turns 15 into -1 and looks like
data-dependent noise rather than a bug.

All 11 shapes match to ~1e-8 relative, so the CPU kernel is exact and can be
trusted as the reference.

One note on the tolerance, because the first draft of this test got it wrong
and "found" a bug that wasn't there: the error is compared against the sum of
|terms|, not against |result|. A dot product of signed terms can land near
zero through cancellation, and then a 1e-6 absolute error -- ordinary f32
accumulator precision -- reads as a 1e-3 relative one. A wrong scale index or
a wrong group boundary shifts the result by a fraction of the terms, so it is
still caught at 1e-6.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 16:37:39 +02:00
Egon Ruiter c769e04d13 fix(prefetch): address fourth round of copilot review comments
- Fix queue flush race: clear is_queued under mutex only; never move
  pilot_w backwards (would break r<=w ring-buffer invariant). Worker
  skips stale entries via new is_queued guard at start of pilot_realload
- Add early-exit in pilot_realload when is_queued==0 (entry flushed
  between enqueue and worker pickup), preventing unnecessary loads
- Fix misleading EMA struct comment: momentum_logits is used only by
  the PILOT prefetcher, not blended into actual MoE routing decisions
- Fix Slot pinned comment: 'never evicted' was too strong; clarify that
  pinned slots may be displaced under extreme all-pinned cache pressure
- Use st_read_f32() for scale tensor (.qs) instead of st_read_raw() to
  handle potential future BF16/F16 dtype changes robustly
2026-07-16 15:58:38 +02:00
tt1203 a3e942516c fix(oracle): create glm_tiny/ before saving so a fresh checkout works
make_glm_oracle.py wrote glm_tiny/model.safetensors and glm_tiny/config.json
without creating the directory first. safetensors.save_file writes a temp file
inside the target dir before the atomic rename, so on a clean checkout (no
pre-existing glm_tiny/) it aborts with an opaque error:

    SafetensorError: Error while serializing: I/O error:
    The system cannot find the path specified. (os error 3)
    at path ".../glm_tiny/.tmpXXXXXX"

The directory only ever existed because it was left over from a previous run,
so the first-ever `python tools/make_glm_oracle.py` fails for every new user
following the README's verify step.

Create glm_tiny/ with Path.mkdir(parents=True, exist_ok=True) before the save
branch — covers the fp8 path, the bf16 path, and config.json. Path is already
imported; no new dependency, no change to the CPU build.
2026-07-16 14:52:16 +01:00
Egon Ruiter b6bae91b66 fix(prefetch): address third round of copilot review comments
- Fix LRU fallback: when all evictable slots are in-flight, find oldest
  non-in-flight slot (pinned ok) before falling back to slot 0
- Fix pin_hot_experts: guard enqueue behind g_pilot>0, call
  ensure_pilot_worker_started(), and set is_queued flag to prevent
  duplicate in-flight loads from pilot_prefetch()
- Fix token counting: increment token_count/freq_token_count by S (batch
  size) instead of 1 so prefill tokens are counted accurately and warmup
  threshold triggers at the right time
2026-07-16 15:46:26 +02:00
Egon Ruiter 2d8d2951ee fix(prefetch): address second round of copilot review comments
- Fix ENV VARS header: document PILOT=0-3, SMOOTH, CONF_LIMIT; remove stale REBAL entry
- Fix per-layer EMA: apply routing momentum to all layers (not just layer 0) with correct offset
- Fix in-flight slot race in expert_get: LRU eviction now skips slots with eid==-1 (being loaded)
- Fix in-flight slot race in pilot_realload: same fix, prevents concurrent writes into active slot
- Fix idx[] buffer overflow: clamp max_cand to 128 before E in pilot_prefetch
2026-07-16 15:37:20 +02:00
ZacharyZcR deafa72b95 docs: serve protocol reference — mux wire format, telemetry lines, HTTP surface (#310) 2026-07-16 21:25:45 +08:00
Claude 36394bc317 Profiling: fix the phase accounting so 'Other' stops swallowing the disk stall
The dashboard's wall-time stack assumed ewait = felt I/O stall and
edisk = overlapped read service, but the engine measured neither:
t_ewait was declared and reported yet never incremented (the blue
'I/O wait' segment always read 0.00s), while t_edisk accumulated on
the COMPUTE thread — blocking OMP loads, PIPE dispatch, pipe_wait
spins — i.e. exactly the felt stall. The UI excluded it from the
stack as 'overlapped', so the whole disk stall landed in 'Other'
(e.g. 46.9s Other vs 45.3s disk on a 54.1s turn).

Now the semantics match the contract:
- t_ewait accumulates the compute-thread stall (blocking loads,
  PIPE dispatch, pipe_wait spins) and feeds the in-stack I/O wait.
- Disk service is real: expert_load is timed on whichever thread
  runs the read (PIPE workers, OMP loaders, pilot) into an atomic
  ns counter (g_edisk_ns) — thread-seconds, overlapped with compute.
- prof_report's I/O share and verdict use the felt wait only, and
  the expert I/O line prints 'read service / felt wait' so the
  wait:service gap shows how well PIPE is hiding the reads.

PROF wire format, /profile JSON and the web UI are unchanged —
the dashboard's existing assumptions are simply true now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dd4hHD2Dsvgr7VAwEVFqWK
2026-07-16 09:00:31 -04:00
Claude 6afffbcbf2 Profiling page: per-turn phase timings, live in the web dashboard
The engine already tracks where each turn's wall time goes (expert-disk
service, I/O wait, expert matmul, attention, lm_head) — it just only spoke
at exit or under PROF=1. Stream it instead:

- glm.c: mux serve emits a per-turn "PROF" protocol line next to TIERS/HITS
  (window deltas per request, same convention as the STAT hit%); the phase
  window base is now always captured (a few loads per request).
- openai_server.py: parses PROF into a 120-turn rolling window and serves it
  at /profile (read-only, same trust level as /health).
- web: new Profiling tab — stat tiles (tok/s, wall, tokens/forward, disk
  service), wall-time composition bars for the last turn and the window,
  per-turn throughput and stacked phase columns with hover readouts, and a
  table of recent turns. Disk service is shown apart from the stack: it
  overlaps with compute, so only the I/O wait the compute thread felt counts
  inside wall time. Phase colours are a CVD-validated set with gaps + legend
  + table so identity never rides on colour alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WhTmF8yvEBgSkUKSVfZF7P
2026-07-16 08:56:12 -04:00
Claude 63a6824881 PROF=1: per-request reports in mux serve mode too (the web-dashboard path)
run_serve_mux (SERVE_BATCH, used by openai_server.py / coli web) completes
requests in mux_done, so the run_serve per-turn hook never fired there.
Snapshot the window where hits0 is taken, record batched-forward latency
around step_decode_batch, report on stderr at DONE. With KV_SLOTS>1 the
window shares batched forwards across slots — same convention as the
existing STAT hit%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCBNCciBaHea41QmidLUMn
2026-07-16 08:56:12 -04:00
Claude 09bf17f001 PROF=1: opt-in performance profile (latency percentiles, expert I/O, tuning verdict)
Answers 'where does it slow down on THIS machine with THIS config' so users
can tune RAM_GB/PIPE/DIRECT/PIN for their hardware without folklore:

- startup header: CPU/cores/RAM/backend + effective knobs (cache cap, pin,
  DRAFT/PIPE/DIRECT/MMAP/IDOT/DSA/PILOT/CACHE_ROUTE) — every saved log is
  self-describing when comparing runs across configs or machines
- per-forward decode latency ring (32k) -> p50/p90/p99/max, plus a tail
  diagnosis when p99 >> p50 (cold-cache expert loads)
- expert I/O accounting at the pread/mmap-touch sites: GB fetched, MB/token,
  GB/s, hit rate, loads/token, pinned/LRU tier fill
- phase shares of wall time and a plain-language verdict naming the knob
  most likely to move tok/s (I/O-bound vs compute-bound vs attention-bound)
- reports after REPLAY / PROMPT / oracle runs (stdout) and per turn in serve
  mode (stderr; stdout stays the framed protocol)

Additive only: with PROF unset every mode's output is byte-identical.
hwinfo_emit's /proc probe is factored into hw_probe() and shared.
Validated end-to-end on a tiny-random unquantized fixture (REPLAY, PROF on/
off, RAM_GB squeeze flips hit 96.9%->26.6% and the verdict follows);
make check clean, 0 warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCBNCciBaHea41QmidLUMn
2026-07-16 08:56:12 -04:00
Egon Ruiter 1ac2e7b487 fix(prefetch): address copilot code quality reviews on safety and concurrency 2026-07-16 14:36:53 +02:00
ZacharyZcR 2b182ae7f6 glm: COLI_NUMA=1 interleaves resident weights across NUMA nodes — +13% decode on 2S, raw mbind, no libnuma (#82) 2026-07-16 20:32:03 +08:00
Mohamed Mastouri 9cf97a4f0c Fix Windows cuda-dll build: quote NVCC, gate MSVC warnings, add config stamp (#306) 2026-07-16 15:27:08 +03:00
Egon Ruiter 6ade4093de refactor(prefetch): clean up unused variables, dead functions, and hardcoded paths 2026-07-16 14:22:04 +02:00
aleks 6728029555 fix: set stdout to O_BINARY on Windows to prevent READY sentinel corruption
Both sentinels in c/coli (READY and END) end with \n. Under CRT text
mode on Windows, printf() translates \n to \r\n, so the engine emits
\x01\x01READY\x01\x01\r\n. The Python coli wrapper checks
endswith(SENTINEL) which expects bare \n — the match never fires and
chat hangs forever.

_setmode(fileno(stdout), O_BINARY) at engine startup switches stdout
to binary mode so \n passes through unchanged. This matches the
belt-and-braces reasoning already in compat.h:88 (O_BINARY for file
I/O). The fix is defense-in-depth: on the documented w64devkit/MinGW
build path, CRT text mode may or may not apply depending on how the
terminal is attached, so this ensures correctness regardless.

Note: I was unable to compile-test this on the full codebase because
glm.c uses POSIX-only symbols (mmap, madvise, select, fd_set, struct
stat/fstat) that are unavailable on Windows without platform guards.
The codebase compiles on Linux (Ubuntu 24.04, GCC 13) and macOS
(Apple clang). Windows compilation requires wrapping those POSIX calls
in #if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__)
guards — I opened this as a separate concern for the maintainer.
2026-07-16 14:10:27 +03:00
JustVugg 54cfe56324 Merge remote-tracking branch 'origin/main' into dev 2026-07-16 12:38:42 +02:00
Vincenzo 16b253ae43 Merge pull request #308 from fermionoid/fix-metal-clang16-std
Fix METAL=1 build on Apple clang 16: add -std=gnu++17 to METALXX
2026-07-16 12:38:12 +02:00
Vincenzo 0d297ee85b Merge pull request #301 from NeuralNotwerk/pr/pin-auto
PIN=auto: seed the pin from the live usage history
2026-07-16 12:38:09 +02:00