Commit Graph

35 Commits

Author SHA1 Message Date
John Balis 342ceaf368 attention: heap per-thread score buffers — fix stack overflow past 8192 ctx on non-DSA snapshots (both absorb + dense paths, oracle-exact) (#110)
Both attention score buffers were fixed stack arrays (float sc[8192]).
The score count nt is only capped at index_topk when DSA selection
covers the layer; without indexer weights in the snapshot (has_dsa=0),
with DSA=0, or on the MTP layer, nt spans the full context. Past
position 8192 every OMP worker wrote beyond sc[] on its own stack:
silent corruption up to the guard page (~9400), then segfault.

Reproduced on a GLM-5.2 int4 snapshot without indexer tensors:
14.7k-token prompt crashed seconds into [prefill] layer 1/78, three
workers faulting simultaneously in attention._omp_fn.2 on the
sc[jj]=a*attn_scale store.

Fix: allocate the scratch once per attention call on the heap, sized
omp_get_max_threads() x (Tk - kv_start) — the true nt upper bound for
both the dense range and the DSA top-k list — and slice per thread.
Non-OpenMP builds get inline fallbacks, preserving the dependency-free
CPU path.

Validated: make check clean; short greedy output token-identical to the
previous binary; 10,232-token prefill segfaults on the old binary and
runs clean on the fixed one (layers 1-9+ verified, remainder is
expert-streaming disk time).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 08:52:58 +02:00
AutoJanitor bc6bc9c250 VSX integer-dot kernels for POWER8 (12.8x int8 / 7.6x int4 over scalar, #ifdef-gated, x86 path untouched) (#98)
* Makefile: support Linux PowerPC (ppc64le) builds

PowerPC GCC uses -mcpu instead of -march, so the Linux branch failed
with unrecognized option -march=native on ppc64le. Detect ppc64le and
ppc64 via uname -m and use -mcpu=$(ARCH) there. The x86-64 path is
unchanged.

Validated on an IBM POWER8 S824 (Ubuntu 20.04, gcc 9.4): make test-c
passes, teacher forcing 32/32 positions and greedy 20/20 tokens against
the transformers oracle, engine reports the scalar idot fallback.

Signed-off-by: Scott <scottbphone12@gmail.com>

* VSX integer-dot kernels for POWER8 (12.8x int8, 7.6x int4 over scalar)

Adds a VSX path to dot_i8i8 and dot_i4i8 using vec_msum, which sums
byte products directly into s32 lanes, so the 16-bit saturation bound
of the AVX2 maddubs trick does not apply. abs(w) is built with a
modulo-subtract select instead of vec_abs so w=-128 wraps to 128
unsigned instead of saturating to 127. Nibble unpack uses
vec_mergeh/vec_mergel, which interleave like x86 unpacklo/unpackhi on
ppc64le (verified on hardware). g_i4s=1 on VSX since the f32 fallback
is plain scalar there: measured 5.5x for int4 IDOT at S=1.

Measured on an IBM POWER8 S824 (gcc 9.4, Ubuntu 20.04 ppc64le),
single thread, 1536x6144:
  dot_i8i8  1.48 -> 18.99 Gops/s (12.8x)
  dot_i4i8  2.33 -> 17.72 Gops/s (7.6x)
  S=1 int4 matmul path: 3.925 -> 0.505 ms/call (7.8x vs scalar build)

Adds tests/test_idot.c: exactness test of the compiled idot kernels
(any arch) against a plain-C reference, covering odd tails and the
w=-128 edge. Passes on avx512-vnni (x86) and vsx (POWER8). The tiny
oracle stays token-exact on the VSX build: TF 32/32, greedy 20/20.

Signed-off-by: Scott <scottbphone12@gmail.com>

---------

Signed-off-by: Scott <scottbphone12@gmail.com>
Co-authored-by: Scott <scottbphone12@gmail.com>
2026-07-12 22:44:56 +02:00
Rodolfo Hansen 9bba681ae2 perf(pilot): PILOT_REAL real cross-layer expert loads, independent from PIPE pool (data-driven: two pools beat layered/unified on both disk- and matmul-bound hosts) (#78)
The existing PILOT prefetcher predicts the next layer's routed experts
from the router logits and issues advisory readahead (posix_fadvise
WILLNEED / expert_prefetch) so the page cache is warm when the main
thread reaches that layer. That only warms the OS cache; the main thread
still pays the dequant/slab-build cost of expert_load on the critical
path.

PILOT_REAL=1 upgrades the prefetcher to perform the *actual* expert_load
into the next layer's LRU cache (ecache[L+1]) from the pilot I/O thread,
overlapped with the current layer's compute, so on a hit the main thread
finds the expert already resident and skips the load entirely.

Safety invariant (value-identical output vs OFF):
  - MATMUL path: the pilot writes ONLY ecache[layer] for layer >
    g_cur_moe_layer; the matmul in moe() reads ONLY ecache[layer]==
    g_cur_moe_layer. A barrier at the top of moe() claims the current
    layer and waits out any in-flight pilot load already targeting it,
    after which the pilot drops every new load <= that layer. So the
    matmul and the pilot never touch the same layer concurrently and no
    half-loaded slot is ever matmul-ed.
  - SCAN path (review fix — Option A): pilot_prefetch also runs on the
    main thread and its residency scan reads ecache[lnext]/ecn[lnext] for
    the FUTURE layer lnext = current+1 — exactly the layer the pilot
    worker is writing. That scan previously ran off-lock (a real, benign
    data race) and a stale comment falsely claimed the two threads never
    touch the same layer's ecache. Fixed: the scan now takes g_pilot_mx
    (the same lock the worker uses), decides under the lock, and enqueues
    AFTER unlocking into the lock-free pilot_q ring (no re-entrant double
    lock). The comment is rewritten to describe the real two-part
    invariant honestly.
  - The loading slot is published (eid set, ecn grown) only after the
    pread completes; while loading it is hidden (eid=-1) from cache scans.
  - The slow pread runs outside the handshake lock; the lock only guards
    slot selection/publication. The shared LRU clock (m->eclock) is bumped
    with an unconditional relaxed atomic add so the main thread and pilot
    can't lose an increment; this is value-identical to the plain ++ with
    only a negligible relaxed-atomic cost (no runtime branch for the OFF
    case — not worth it).

Reliability (review fix — non-fatal speculative load):
  expert_load() aborted the whole process (exit(1)) on any missing tensor,
  OOM, short read or pread error. That is correct for the main / on-demand
  / REPIN / pin paths but fatal for a ~28%-mispredicted speculative pilot
  load — a wrong guess could kill the server. expert_load now takes a
  `fatal` flag: all main callers pass fatal=1 and keep today's exit-on-
  error behavior byte-for-byte; the pilot passes fatal=0, so on error it
  abandons the load, leaves the slot hidden (never published), bumps
  g_pilot_drops, and logs a one-line stderr warning (never a silent
  swallow). The main load path is behaviorally unchanged.

  Residual gap closed (re-review): the fslab scale-buffer allocation still
  went through falloc(), which exit(1)s on OOM regardless of `fatal`, so a
  fatal=0 pilot load could still abort the process on a scale-buffer OOM.
  expert_load now branches: fatal=1 keeps falloc() (byte-identical exit-on-
  OOM for the main path), fatal=0 uses a checked malloc replicating falloc's
  anti-wrap guard and, on failure, does the same non-fatal cleanup as the
  slab-OOM branch (frees/NULLs s->slab and s->fslab, zeroes their caps,
  returns -1) leaving a clean hidden slot (eid stays -1). The qt_from_disk
  f32 fallback path is unquantized-only (GLM always has .qs) and is left
  as-is, now with a comment noting it's unreachable for the pilot.

Tuning (review fix — PILOT_K default):
  Real loads create LRU eviction pressure that hint-only WILLNEED does
  not, so a large K thrashes at 28% mispredict. When PILOT_REAL is on and
  the user did not set PILOT_K explicitly, K now defaults to 6 (best
  measured this session) instead of 8; hint-only PILOT keeps the 8
  default.

Default OFF (PILOT_REAL=0); PILOT_REAL=1 opts in and implies PILOT=1. A
per-run stats line reports real cross-layer loads completed vs dropped.
No Makefile change: pure C (stdatomic.h + sched.h).


Claude-Session: https://claude.ai/code/session_01DS7oc65c5RdA9V99otRCwt

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 22:39:20 +02:00
Rodolfo Hansen 03d9a23fe4 perf(moe): overlap NVMe expert loads with matmul via opt-in PIPE I/O pool (default off, oracle-exact) (#79)
For streamed (non-resident) experts the MoE forward is disk-bound: each
64-expert block first blocks on a parallel pread of every miss, then runs
the matmuls serially. Those two phases don't overlap, so the compute
cores idle while the block's weights are still coming off NVMe.

PIPE=1 hands the misses' expert_load() to a small persistent pool of I/O
worker pthreads and lets the main thread start matmul immediately. The
main thread walks the block's experts in routing order and waits on a
per-slot ready flag only for the expert it needs right now, so loads of
later experts in the block hide behind matmul of earlier ones. All
matmul_qt stays on the main thread (it parallelises internally via
OpenMP and gates GPU dispatch on !omp_in_parallel()), so the I/O pool
never competes with the compute team for the matmul itself.

Cross-generation correctness: generation-tagged lock-free cursor
--------------------------------------------------------------------
The batch state (njobs/eids[]/layer/ready[]) is reused in place across
64-blocks, so a straggler or late-woken worker could touch the NEXT
batch's state. Two prior fixes (a drain barrier, then an _Atomic active
counter) each still left a cross-generation window. Both are now removed
and replaced with a single generation-tagged cursor:

    _Atomic uint64_t cur = (gen << 8) | index;   // gen main-only, index 0..njobs

  - dispatch writes njobs/layer/eids[]/ready-reset with RELAXED stores,
    then RELEASE-stores cur (bumping gen); that release publishes all
    batch state to any worker whose ACQUIRE-load of cur sees the new gen.
  - a worker grabs a job by CAS-advancing the index; it reads eids[i]/
    layer only AFTER the winning CAS. The CAS comparand carries the
    generation, so if a new batch was published the stale CAS fails and
    the worker re-reads — it can never grab a wrong-generation job or
    read torn state, no matter where it was preempted (wake gap,
    post-cursor, anywhere).
  - gen is bumped only by the main thread and is monotonic ⇒ no ABA.
  - the per-expert pipe_wait(ready[q]) in the matmul loop (kept) makes
    every grabbed job complete before the block ends, so no grab
    outlives its generation. That is what makes the old `active`
    counter and the end-of-block drain barrier unnecessary — both are
    removed. ready[] is reset before the publishing release, so no stale
    flag survives into the new generation.
  - the mutex/condvar now exist ONLY to park and wake idle workers, not
    for correctness.

This only reorders I/O, never the computation: greedy decode output is
byte-identical to the blocking path.

Default OFF (PIPE=0) so upstream behaviour is unchanged; PIPE=1 opts in
and PIPE_WORKERS=n sizes the pool (default 8). No Makefile change: pure C
(stdatomic.h + sched.h), builds with the default toolchain.


Claude-Session: https://claude.ai/code/session_01DS7oc65c5RdA9V99otRCwt

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 13:44:34 +02:00
Rodolfo Hansen 704ed49c16 perf(omp): keep OpenMP worker team hot across tiny per-expert matmul regions (seed + re-exec once, fully overridable) (#77)
The MoE forward does many tiny, back-to-back per-expert matmul regions.
Under libgomp's default passive wait policy the worker team is parked
between regions, and the thread re-wake latency dominates the actual
compute. Switching the team to an active wait policy (with a bounded spin
count so long NVMe expert-load stalls still yield instead of burning a
core) keeps the threads hot across those regions.

Measured on the Zen5 build: expert-matmul wall time 66.9s -> 20.9s
(~3.2x on that phase). Output is numerically unchanged — this only
affects thread scheduling, not the computation.

Mechanism: libgomp parses OMP_/GOMP_ vars in a constructor that runs
before main(), so setenv() from main() and continuing is too late
(verified: the already-initialised runtime ignores it). Instead we seed
the winning defaults on first entry with overwrite=0 (so any value the
user already set wins), set a COLI_OMP_TUNED sentinel, and execv() self
once so a fresh libgomp constructor reads them. The sentinel guards the
exec, so we re-exec at most once. The block is the first statement in
main() so argv is passed verbatim to execv().

Discoverability / observability (review follow-up):
  - COLI_NO_OMP_TUNE=1 is a documented kill-switch that disables the
    whole re-exec + tuning path in one shot (distinct from the internal
    COLI_OMP_TUNED re-exec sentinel);
  - a one-line stderr breadcrumb is printed before the re-exec
    ("[OMP] hot-thread tuning: re-exec once (COLI_NO_OMP_TUNE=1 to skip)")
    so the self-re-exec is self-documenting;
  - execv only returns on failure, so a perror() now follows it
    ("execv self-reexec failed, running untuned") — a container without
    /proc or a deleted inode falls back visibly instead of silently
    losing the ~3.2x.

Fully opt-out / overridable and lossless:
  - explicit OMP_WAIT_POLICY / GOMP_SPINCOUNT / OMP_PROC_BIND / OMP_DYNAMIC
    in the environment win (overwrite=0);
  - pre-setting COLI_OMP_TUNED=1 skips the re-exec entirely;
  - COLI_NO_OMP_TUNE=1 disables the tuning path entirely;
  - guarded by __linux__ (no-op re-exec elsewhere; the setenv defaults
    still apply for any later-initialising runtime).


Claude-Session: https://claude.ai/code/session_01DS7oc65c5RdA9V99otRCwt

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 13:40:29 +02:00
Sidd 2416bc9079 Translate user-facing runtime output to English, machine prefixes preserved, + CLI output test (#67, #85)
* feat: standardize runtime output in English

* test: cover English CLI output
2026-07-12 13:38:40 +02:00
JustVugg 6e7aa6f92e Guard against running the tiny oracle against a real model (#76)
The default ./glm mode validates against ref_glm.json, which is generated
from glm_tiny (a random tiny model). Pointed at the 744B GLM-5.2 it feeds
the model tiny-vocab prompt tokens and compares against tiny references —
0/20 and a degenerate loop, guaranteed on EVERY platform (x86/ARM/Metal),
which reads as an engine bug (it isn't). Detect the mismatch (real vocab +
tiny-range oracle ids) and print the correct commands instead. REF_FORCE=1
overrides. The engine self-test (SNAP=./glm_tiny TF=1) is unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 13:35:15 +02:00
Fabio Rovai cec7d6b648 Grammar-forced speculative drafts: GBNF grammar as a third draft source, guaranteed-accepted forced spans, lossless + opt-in (#48, #70)
New byte-level GBNF-subset engine (c/grammar.h: parser + set-of-stacks PDA
walker) wired into spec_decode as a third draft source ("metodo F"), tried
before MTP/n-gram. Wherever the grammar admits exactly one legal byte, the
forced span is tokenized and injected as drafts; the existing batch-union
verification confirms them, so a wrong or out-of-sync grammar can never
change the output. Lazy arming skips preambles; adaptive guard (same
pattern as MTP) disables the source below 50% acceptance; grammar-accepted
tokens no longer pollute the MTP acceptance counter.

GRAMMAR=file.gbnf enables it in run and serve modes (also with DRAFT=0 and
with the int4 MTP head from #8); GRAMMAR_DRAFT=n caps the span (default 24).

Measured on M3 Max / int8-MTP container, greedy, MTP=0 DRAFT=0, NDJSON
classification: 0.37 -> 0.50 tok/s (1.60 tok/forward, 81 fw per 130 tok),
100% acceptance (48/48), output byte-identical to baseline.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 01:35:39 +02:00
nalepy 89d95fc73b Windows 11 native port, phase 1: MinGW-w64 static build, compat shims, setup + docs (#40)
* fix: Windows port audit fixes — _FILE_OFFSET_BITS guard, O_BINARY st.h, getrusage peak, oracle diagnostic, setup.sh wmic

Audit remediation (all MEDIUM issues fixed):
- compat.h: compile-time #error if _FILE_OFFSET_BITS < 64 on _WIN32
- compat.h: COMPAT_O_RDONLY macro (O_RDONLY|O_BINARY on Windows, belt-and-braces)
- st.h: use COMPAT_O_RDONLY in both open() call sites (plan §1 row 1)
- compat.h: getrusage shim now uses PeakWorkingSetSize (ru_maxrss = peak, not current)
- glm.c: oracle mismatch diagnostic — prints position/expected/got on TF failures
- setup.sh: replace deprecated wmic with /proc/meminfo (MSYS2 provides it)
- .gitignore: *.exe, glm_tiny/, olmoe_hf/, olmoe_i4/

LOW issues addressed:
- _FILE_OFFSET_BITS guard prevents silent 32-bit off_t wrap at >4GB offsets
- coli Windows venv path (Scripts/python.exe) fixed earlier
- posix_fadvise do{}while(0) kept intentionally — no caller checks return code

Verification: oracle 32/32, 27/27 Python tests, rename EEXIST, >4GB pread offset.

* docs: add Windows 11 native port section to README

- Toolchain: MinGW-w64 (winlibs or MSYS2), GCC 16.1 tested
- Build instructions: make glm.exe, tiny oracle verification
- Runtime: SNAP=..., coli chat, coli serve all work
- Status: Phase 1 complete (compiles, correct, static-linked)
- Update platform requirements to include Windows 11 natively
2026-07-11 12:59:49 +02:00
0xhis 7d8d5f3109 Reduce allocation overhead in quantized matmul and MoE routing (thread-local scratch, trimmed temporaries) (#43)
* Reuse quantization scratch buffers

* Trim MoE routing temporaries

---------

Co-authored-by: 0xhis <0xhis@users.noreply.github.com>
2026-07-11 12:59:01 +02:00
ZacharyZcR 9e6e1ac327 Isolated sequence KV contexts: KVState extraction, KV_SLOTS serve contexts with per-slot persistence, budget-aware pool accounting (#29)
* Add isolated sequence KV contexts

* Log projected multi-slot KV footprint
2026-07-10 16:19:43 +02:00
ZacharyZcR 1453dab7ae REPIN follows live session heat (decaying heat map; .coli_usage stays the persistent signal) + disk→RAM→VRAM promotion (#26) 2026-07-10 12:48:53 +02:00
ZacharyZcR 3e4d08b6bf OpenAI-compatible HTTP API: stdlib-only gateway over SERVE with KV prefix reuse across stateless requests (#21)
* Add OpenAI-compatible HTTP API

* Support browser API clients

* Handle missing KV cache during rewind
2026-07-10 11:04:56 +02:00
JustVugg ea5f6fb914 Harden against hostile model files: config dim validation at parse + overflow-safe falloc (PR #25 report, done right)
Model files come from untrusted mirrors. One choke point in load_cfg bounds
every dimension (hostile config.json now dies with a clear message instead
of reaching allocation sites); falloc guards the n*sizeof(float) wrap.
No hot-path calloc churn — the report's patch was declined in review, the
valid kernel of the idea is taken here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:53:04 +02:00
ZacharyZcR 13e8f09ffc Organize project tools and local workflows: c/tools, c/scripts, c/tests, root Makefile (flat C core untouched) (#22) 2026-07-10 10:08:39 +02:00
JustVugg 8f99e12b5e KV-to-disk: conversations reopen WARM across engine restarts (.coli_kv, KVSAVE=0 opts out)
serve mode persists the compressed MLA KV-cache incrementally after every
turn (~182 KB/token appended, header count written last = crash-safe) and
resumes it at startup: the model remembers the whole conversation and zero
re-prefill happens. :reset and context-full restarts truncate the file.
The MTP layer's KV row is not saved; kv_start=-1 re-arms its decode window.

Validated: split-session answer byte-identical to an uninterrupted session
(tiny oracle, TEMP=0), and on the real 744B model a restarted chat resumed
58 tokens in 0.0s and recalled a fact from the previous session while
prefilling only the new question.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:00:19 +02:00
JustVugg 077894210e LOOKA: routing predictability counters; PILOT: router-lookahead disk prefetch (async I/O thread); cap auto-raise to RAM budget (#12)
Measured on GLM-5.2 (48 tok, greedy): next-layer routing is 71.6% predictable
one full layer ahead (79.4% skipping attention only; 41.3% previous-token).
PILOT=1 issues next-layer expert WILLNEED from a dedicated I/O thread while
the current layer computes — inline fadvise BLOCKS ~0.5ms/call on a saturated
disk queue (+92s/48 tok, measured), hence the lock-free ring + worker.
Neutral-in-noise on this dev box (disk already ~80% duty); expected to pay on
balanced machines (#12: 43% disk / 46% matmul) — opt-in, default off.

cap_for_ram now RAISES the LRU cap up to the RAM budget (ceiling n_experts,
CAP_RAISE=0 opt-out): big-RAM machines were silently running with cap=8
(#12: 128GB box using 22GB of a 110GB budget; #13: 92GB box, same).

DRAFT=3 on cold cache measured locally: 1399s vs 880s baseline for the same
48 tokens (acceptance 16%, experts/token 1809 vs 800) — confirms #8; DRAFT
re-evaluation belongs to warm-cache serve sessions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 07:44:26 +02:00
ZacharyZcR 57706a0200 Tiered CUDA acceleration for routed experts (opt-in, CPU default untouched) + REPLAY fixture harness (#16)
* feat: add experimental CUDA backend for resident tensors

* feat: promote pinned experts to a bounded VRAM tier

* feat: preload the GPU expert tier at startup

* fix: harden CUDA backend failure handling

* feat: add deterministic multi-GPU tensor placement

* test: add deterministic CUDA benchmark fixture

* perf: make routed experts the default CUDA path
2026-07-10 07:41:09 +02:00
RDouglas ab6950876b RFC: live re-pin of the hot-store between turns (REPIN=n, opt-in, default off) (#11) 2026-07-09 12:49:40 +02:00
RDouglas 3daceaf5ec IDOT: NEON single-token int4 gate (g_i4s/I4S) — SDOT makes S=1 decode pay on Apple Silicon (+14%, expert-matmul -16%) (#10) 2026-07-09 12:49:06 +02:00
Dog279 8040dac645 IDOT: AVX-512 VNNI kernel paths + batch-size gate for single-row int4 (+20% decode on Xeon) (#9)
- dot_i8i8/dot_i4i8: guarded __AVX512VNNI__ branches using vpdpbusd
  (64 bytes/iter, s32 accumulation, no 16-bit intermediate). AVX-512 has
  no vpsignb, so the sign trick becomes abs(w) + mask-negate on x.
- dot_i4i8: nibble unpack stays 256-bit; activation blocks are permuted
  to match the per-lane value order instead of re-sorting weights.
- The int4 IDOT gate (was hardcoded S>=2, from AVX2 measurements) becomes
  g_i4s with a VNNI-aware default of 1: single-row decode goes through the
  integer path where it now pays. I4S=n overrides for A/B; I4S=2 restores
  the old behavior exactly. AVX2/NEON/scalar builds are unchanged.
- Startup banner reports the active idot kernel (avx512-vnni/avx2/neon/scalar).

Measured on Xeon 6 (24C, AVX512-VNNI), DDR5-5600, ~19.8 GB/s NVMe RAID0,
gcc 13.3 -march=native: 256-tok greedy decode 1.72 -> 2.08 tok/s (+21%),
expert-matmul -24%; second prompt +20%. Integer-path outputs bit-identical
(associative s32 adds, same no-saturation bounds); S=1 int4 adopts the same
int8-activation tradeoff IDOT already makes for S>=2.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 12:44:40 +02:00
RDouglas cfd16b4c7e PIN: mlock pinned experts into physical RAM (macOS: stop the compressor evicting the hot-store) (#7) 2026-07-09 12:44:11 +02:00
JustVugg 193d2ce92d DSA lightning indexer: full implementation with auto-detection
- Faithful to the official modeling (transformers glm_moe_dsa): q from the
  q_a latent via wq_b (32 heads x 128), k = LayerNorm(wk(h)) shared across
  heads, interleaved RoPE on the first 64 dims, ReLU(q.k/sqrt(128)) weighted
  by weights_proj(h)/sqrt(32), causal top-2048 per query.
- 'full' layers compute the selection (+ maintain the indexer k-cache from
  token 0); 'shared' layers reuse it (IndexShare, index_topk_freq=4).
- Selection restricts both attention paths (absorbed decode + prefill
  reconstruction). MTP row stays dense.
- Auto-detected like MTP: if out-idx-* weights are present for all full
  layers, DSA arms itself; DSA=0 disables; DSA_FORCE/DSA_TOPK for testing.
- Validated on the tiny oracle (which ships indexer weights): selection
  machinery forced on with keep=all keys reproduces dense attention exactly
  (TF 32/32, gen 20/20); sparse smoke runs clean; kill switch verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 22:07:50 +02:00
RDouglas dd8c907800 macOS/Apple Silicon port: NEON kernels + platform shim (PR #1 by RDouglasSharp) 2026-07-06 22:01:12 +02:00
JustVugg 7a5ffd192d async I/O: WILLNEED readahead of the next expert block while computing the current one
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:56:24 +02:00
JustVugg 757b0a8369 MLA weight absorption for decode (S<=4): no per-token k/v reconstruction — score via (W_K^T q)·latent, ctx via W_V(Σ a·latent). Validated exact: f32 TF 32/32, gen 20/20 with ABSORB=1 forced
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:54:51 +02:00
JustVugg 741f49a1ca integer-dot kernels (Q8_0-style activations, AVX2 maddubs): int8 always, int4 when S>=2 — measured 1.4-2.5x
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:50:02 +02:00
JustVugg 2dd6800aea sampling defaults for int4 reality: temp 0.7, nucleus 0.90 (official 1.0/0.95 tuned for full precision; the int4 tail is quantization noise)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 19:30:34 +02:00
JustVugg 1a8d2bcff3 prefill progress: engine reports layer N/78 on stderr, coli spinner shows it live
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 18:18:50 +02:00
JustVugg 3278ea78d0 reserve 2.5 GB for the page cache in the RAM budget: starving it drops buffered reads 800->180 MB/s (measured)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 18:00:35 +02:00
JustVugg e982d2930e autopin: pin share scales with usage-history confidence
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 17:26:08 +02:00
JustVugg afcd71ab1c surface MTP/USAGE status in coli chat banner (stderr)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 17:03:49 +02:00
JustVugg 3e88e37ba2 learning cache + true sampling + DSA indexer extraction mode
- Learning cache: expert usage persists in <SNAP>/.coli_usage across sessions
  (atomic save every turn); at startup the hottest experts are auto-pinned in
  RAM with half the expert budget (AUTOPIN=0 disables). The engine gets faster
  the more you use it.
- Sampling: temperature + nucleus (official 1.0/0.95 defaults in chat; TEMP=0
  = greedy). MTP/n-gram speculation stays lossless via rejection sampling
  (accept draft w.p. p(draft); on reject resample with draft banned).
- coli: --temp flag.
- Converter: --indexer mode extracts DSA lightning-indexer weights
  (resumable; needed for future sparse attention beyond 2048 ctx).
- pin_load/stats include the MTP row; usage histogram covers layer 78.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 12:29:13 +02:00
JustVugg 257c4d0a8b serve: :piu resumes a truncated answer from live KV; ngen default 1024 (stops end turns now)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:54:47 +02:00
JustVugg 1ae22a6135 colibrì: pure-C GLM-5.2 (744B MoE) engine with disk-streamed experts
Engine (c/glm.c): MLA attention with compressed KV, sigmoid noaux_tc router,
int8/int4/int2 quant kernels (AVX2), per-layer LRU expert cache + pinned
hot-store, batch-union MoE, native MTP speculative decoding (lossless),
multi-stop + official chat template, RAM auto-budget from MemAvailable.
Tokenizer: byte-level BPE in C. Tooling: coli CLI, disk-safe FP8→int4
converter, tiny-random oracle validation (TF 32/32, greedy 20/20).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 20:57:25 +02:00