HiramKHackenbacker commited on
Commit
cb38966
·
verified ·
1 Parent(s): 9f5ec84

README: ring bundles

Browse files
Files changed (1) hide show
  1. README.md +66 -0
README.md CHANGED
@@ -302,3 +302,69 @@ bit-identical in fp32. On-device behavior is unmeasured until host support lands
302
  | Bundle | Bytes | Context | Functions | Producer | Created |
303
  |---|---:|---|---|---|---|
304
  | `ring-smoke/gpu-pipelined/gemma4_e2b_qat_decode_int4lin_tbl_pf64_ring_c16384_l5` | 1,171,301,346 | 16384 | main+prefill | coreai-core 1.0.0b2 | 20260818T085021Z |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  | Bundle | Bytes | Context | Functions | Producer | Created |
303
  |---|---:|---|---|---|---|
304
  | `ring-smoke/gpu-pipelined/gemma4_e2b_qat_decode_int4lin_tbl_pf64_ring_c16384_l5` | 1,171,301,346 | 16384 | main+prefill | coreai-core 1.0.0b2 | 20260818T085021Z |
305
+
306
+
307
+ ## `ring/` — shape-stable decode, ring sliding caches
308
+
309
+ > ⚠️ **EXPERIMENTAL — built and gated in torch, on-device measurements pending.** A
310
+ > re-export of the same weights and the same quantization as `stable/`, onto the same
311
+ > host contract, with the KV layout reworked. No throughput or footprint numbers have
312
+ > been taken on a Mac yet; the structural facts below are read off the converted program,
313
+ > not inferred.
314
+
315
+ | Bundle | Bytes | Context | Functions | Producer | Created |
316
+ |---|---:|---|---|---|---|
317
+ | `ring/gpu-pipelined/gemma4_e2b_qat_decode_int4lin_tbl_pf64_ring_c16384` | 2,122,101,099 | 16384 | main+prefill | coreai-core 1.0.0b2 | 20260818T085141Z |
318
+
319
+ **What this is.** `stable/` removed the per-generated-token memory growth by making every
320
+ input shape a literal, and it worked — but it gave every layer a full 16,384-slot KV cache
321
+ and read all of it every step. `ring/` keeps that contract byte-for-byte and changes what
322
+ sits behind it:
323
+
324
+ * **sliding layers read a ring buffer**, 576 slots (the model's own 512-token sliding
325
+ window plus one 64-token prefill chunk) instead of 16,384. Ring slot `r` holds the
326
+ newest written position with `pos % 576 == r`, and the mask that selects the written,
327
+ causal, in-window slots is derived inside the graph from the absolute positions.
328
+ * **the grouped-query head expansion is folded into the query** rather than materialised.
329
+ The stock lowering broadcasts an index tensor to the full `[1, heads, K, head_dim]` and
330
+ gathers K and V through it; reshaping the query so the head counts already match
331
+ produces the same dot products with no index tensor and no gathered copies.
332
+ * **both regions are packed into the same two states**, so the host still binds exactly
333
+ two KV states, positionally, at whatever literal extent the descriptor declares.
334
+
335
+ **Contract — unchanged from `stable/`.** Both entrypoints take four inputs and two states,
336
+ all statically shaped:
337
+
338
+ ```
339
+ main IN input_ids Int32 1x1 | position_ids Int32 1x1 | ple_table Int8 V x (L*ld) | ple_scale Float32 V
340
+ prefill IN input_ids Int32 1x64 | position_ids Int32 1x64 | (same statics)
341
+ ST keyCache / valueCache Float16 [1, 1, n_kv, TOTAL, 512]
342
+ OUT logits Float16 1 x S x 262144
343
+ ```
344
+
345
+ `position_ids` carries the absolute position of each of the S tokens in the call, and
346
+ `position_ids[0,0]` is the write position. The mask is derived in the graph, so there is
347
+ no mask input to bind. The KV states have literal extents, so a host that resolves its
348
+ cache strategy from the state descriptor allocates them up front rather than growing them.
349
+
350
+ **Structural facts** (dumped from the converted program):
351
+
352
+ | | E2B | E4B |
353
+ |---|---|---|
354
+ | KV state shape | `[1, 1, 1, 56064, 512]` x2 | `[1, 1, 2, 77056, 512]` x2 |
355
+ | KV bytes, both states | 114.8 MB | 315.6 MB |
356
+ | same for `stable/` | 503.3 MB | 1.61 GB |
357
+ | cache slots read per decode step | 56,064 | 77,056 |
358
+ | same for `stable/` | 245,760 | 393,216 |
359
+ | sliding / full layers | 12 x 576 + 3 x 16,384 | 20 x 576 + 4 x 16,384 |
360
+ | dynamic dimensions anywhere | none | none |
361
+
362
+ **One new host precondition.** A `prefill` call's first position must be a multiple of 64.
363
+ The ring write is a fixed-width store at `p0 % 576`, and 576 is nine 64-token chunks, so a
364
+ 64-aligned chunk can never straddle the wrap; an unaligned one would write past the end of
365
+ its own ring region. Feeding whole 64-token chunks from a 64-aligned position — and the
366
+ remainder one token at a time through `main` — was already what the contract asked for.
367
+ `stable/` tolerated an unaligned chunk; `ring/` does not.
368
+
369
+ Unlike the `ctx*/` folders, the context ceiling is **encoded in the graph**: a different
370
+ window needs a different export, not a manifest edit.