1ae22a6135
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>
98 lines
3.9 KiB
Python
98 lines
3.9 KiB
Python
"""
|
|
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)
|