onw / bench_decode.py
ryugyosoft's picture
v0.8.0: faster SSD streaming without more memory - prompt prefetch into cache slots, predicted next-layer expert prefetch while decoding (helper thread, separate read queue), single-copy reads
ee52468 verified
Raw History Blame Contribute Delete
2.36 kB
"""Decode speed with experts streamed from the SSD, for several prefetch settings: per answer the decode tok/s and the
time the NPU waited for expert reads per token. Each setting in a fresh process (cold cache), settings interleaved.
usage: python bench_decode.py MODEL_DIR GB K1,K2,... [ROUNDS=2]"""
import json, os, subprocess, sys
CHILD = r'''
import json, sys, time
from onw.chat import ChatEngine
e = ChatEngine(sys.argv[1], "NPU", pld=False)
qs = ["NPUとGPUの違いを、身近なたとえを使って説明してください。",
"ある商品を定価の2割引きで買うと960円でした。定価はいくらですか?途中の式も書いてください。",
"Explain the difference between a process and a thread, with a short Python example."]
out = []
for q in qs:
e.checkpoint = None
b0, st = e.model.bank.stats(), None
toks = []
for x in e.stream_chat([{"role": "user", "content": q}], 192):
if isinstance(x, dict):
st = x
else:
toks.append(x)
b1 = e.model.bank.stats()
n = st["completion_tokens"]
out.append({"tok_s": round(st["decode_tok_s"], 2), "wait_ms_per_tok": round((b1["read_s"] - b0["read_s"]) * 1000 / n, 1),
"hit": round(b1["hit_rate"], 3), "text": "".join(toks)[:30]})
print("RESULT " + json.dumps(out, ensure_ascii=False), flush=True)
'''
def main():
d, gb, ks = sys.argv[1], sys.argv[2], sys.argv[3].split(",")
rounds = int(sys.argv[4]) if len(sys.argv) > 4 else 2
for r in range(rounds):
for k in ks:
env = {**os.environ, "PYTHONUTF8": "1", "ONW_EXPERT_GB": gb, "ONW_PREFETCH_K": k}
p = subprocess.run([sys.executable, "-c", CHILD, d], capture_output=True, text=True, encoding="utf8",
errors="replace", env=env)
line = next((l for l in p.stdout.splitlines() if l.startswith("RESULT ")), None)
if not line:
print(f"round {r} K={k}: FAILED {p.stderr[-300:]}", flush=True)
continue
res = json.loads(line[7:])
print(f"round {r} K={k:>2}: " + " | ".join(f"{x['tok_s']:5.2f} tok/s, wait {x['wait_ms_per_tok']:5.1f} ms/tok"
for x in res) + f" | {res[0]['text']!r}", flush=True)
if __name__ == "__main__":
main()