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>
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
Stadio 0 - Cost model + benchmark del disco per lo streaming degli expert MoE.
|
||||
|
||||
Domanda: e' FISICAMENTE possibile fare streaming degli expert da disco
|
||||
e generare a velocita' usabile, su QUESTA macchina?
|
||||
|
||||
Due numeri che servono:
|
||||
1. Banda effettiva del disco in lettura RANDOM, a blocchi grossi quanto un expert.
|
||||
2. Quanti byte/token dobbiamo leggere -> da cui il tetto di token/sec.
|
||||
|
||||
Nessun modello richiesto. Gira in secondi.
|
||||
"""
|
||||
import os, sys, time, mmap, random, argparse
|
||||
|
||||
MB = 1024 * 1024
|
||||
GB = 1024 * MB
|
||||
|
||||
|
||||
def bench_disk(path_dir, expert_mb=12.0, total_mb=2048, n_reads=200):
|
||||
"""Crea un file, poi misura lettura sequenziale e random a chunk = un expert."""
|
||||
os.makedirs(path_dir, exist_ok=True)
|
||||
fpath = os.path.join(path_dir, "_bench.bin")
|
||||
chunk = int(expert_mb * MB)
|
||||
total = int(total_mb * MB)
|
||||
total = (total // chunk) * chunk
|
||||
n_chunks = total // chunk
|
||||
|
||||
# scrittura
|
||||
t = time.time()
|
||||
with open(fpath, "wb") as f:
|
||||
buf = os.urandom(chunk)
|
||||
for _ in range(n_chunks):
|
||||
f.write(buf)
|
||||
f.flush(); os.fsync(f.fileno())
|
||||
write_bw = total / (time.time() - t) / GB
|
||||
|
||||
# prova a buttare via la page cache (best effort, serve permessi su Linux nativo)
|
||||
try:
|
||||
os.system("sync")
|
||||
with open("/proc/sys/vm/drop_caches", "w") as c:
|
||||
c.write("3")
|
||||
except Exception:
|
||||
pass # su /mnt/c o senza root non si puo': il numero sara' ottimistico
|
||||
|
||||
f = open(fpath, "rb")
|
||||
mm = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ)
|
||||
|
||||
# random reads a chunk di un expert
|
||||
idxs = [random.randrange(n_chunks) for _ in range(n_reads)]
|
||||
s = 0
|
||||
t = time.time()
|
||||
for i in idxs:
|
||||
off = i * chunk
|
||||
s += mm[off] # tocca la prima pagina
|
||||
s += mm[off + chunk - 1] # e l'ultima -> forza il caricamento del range
|
||||
_ = bytes(mm[off:off + chunk]) # legge davvero l'intero expert
|
||||
rand_bw = (n_reads * chunk) / (time.time() - t) / GB
|
||||
|
||||
mm.close(); f.close()
|
||||
os.remove(fpath)
|
||||
return write_bw, rand_bw
|
||||
|
||||
|
||||
def cost_model(name, n_layers, n_active, expert_mb, disk_bw_gbs, ram_resident_gb):
|
||||
"""Stampa il tetto di token/sec in funzione dell'hit-rate della cache."""
|
||||
bytes_cold = n_layers * n_active * expert_mb / 1024 # GB letti per token se 0 cache
|
||||
print(f"\n--- {name} ---")
|
||||
print(f" layer={n_layers} expert_attivi/layer={n_active} expert={expert_mb:.1f} MB")
|
||||
print(f" parte densa residente in RAM stimata: ~{ram_resident_gb:.1f} GB")
|
||||
print(f" byte da streammare per token (cache fredda): {bytes_cold*1024:.0f} MB")
|
||||
print(f" tetto token/sec @ banda {disk_bw_gbs:.2f} GB/s, al variare dell'hit-rate cache:")
|
||||
for hit in (0.0, 0.5, 0.8, 0.9, 0.95, 0.99):
|
||||
eff = bytes_cold * (1 - hit)
|
||||
tps = disk_bw_gbs / eff if eff > 0 else float("inf")
|
||||
print(f" hit {hit*100:5.1f}% -> {tps:6.2f} tok/s")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--dir", default=".", help="cartella su cui benchmarkare il disco")
|
||||
ap.add_argument("--expert-mb", type=float, default=12.0)
|
||||
args = ap.parse_args()
|
||||
|
||||
print(f"Benchmark disco su: {os.path.abspath(args.dir)} (chunk={args.expert_mb} MB)")
|
||||
wbw, rbw = bench_disk(args.dir, expert_mb=args.expert_mb)
|
||||
print(f" scrittura seq : {wbw:.2f} GB/s")
|
||||
print(f" lettura random: {rbw:.2f} GB/s <-- numero che conta per lo streaming")
|
||||
|
||||
# Scenari. expert_mb a Q4 ~ (hidden*inter*3)*0.5B.
|
||||
# OLMoE 1B-7B: 16 layer, 8 attivi, hidden 2048 inter 1024 -> ~3 MB Q4
|
||||
cost_model("OLMoE 1B-7B (piccolo, lo useremo allo Stadio 1)",
|
||||
n_layers=16, n_active=8, expert_mb=3.0,
|
||||
disk_bw_gbs=rbw, ram_resident_gb=1.0)
|
||||
# DeepSeek-V3/V4 class: ~60 layer MoE, 8 attivi, expert ~6 MB Q2
|
||||
cost_model("DeepSeek/GLM class @ Q2 (il sogno finale)",
|
||||
n_layers=60, n_active=8, expert_mb=6.0,
|
||||
disk_bw_gbs=rbw, ram_resident_gb=10.0)
|
||||
Reference in New Issue
Block a user