bankml / testing /decode_ab.py
Gregory-L's picture
bankML: the whole source (github.com/cryptoAGI/bankml @ 12ae409) and its page, with the bankML persona; the live engine (Dockerfile, hf/start.sh) ready for Docker hardware
28c70af verified
Raw History Blame Contribute Delete
4.71 kB
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT OR Apache-2.0
"""0.3.9: bankML against llama-server b11192, decode speed, in pairs. Each round starts a fresh llama-server and a
fresh `bankml serve --native` (alternating which goes first), sends both the same greedy request with the prompt
cache off, and reads each side's own `timings` (prompt and predicted tokens per second, llama-server's fields, which
bankML reports since 0.3.7). The answers must be token-identical, or the speeds are not comparable and the round is
refused. Run it on a quiet machine, pinned, so both get the same cores and memory:
BANKML_GGML_LIB=<b11192 release dir> BANKML_PIN_CPUS=1,2,3 BANKML_PIN_MEM=3000M \\
testing/pinned.sh python3 testing/decode_ab.py Bonsai-8B-Q1_0 [rounds] [threads]
Prints every round and the medians; the ratio is bankML ÷ llama-server (above 1: bankML faster)."""
import json, os, statistics, subprocess, sys, time, urllib.request
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from json_oracle import SAVANTE, wait # noqa: E402
root = Path(__file__).resolve().parents[1]
PROMPT = "Explain in a short paragraph why the sky is blue, and what changes at sunset."
def ask(base, max_tokens):
body = {"messages": [{"role": "system", "content": SAVANTE}, {"role": "user", "content": PROMPT}], "max_tokens": max_tokens,
"temperature": 0, "cache_prompt": False}
req = urllib.request.Request(base + "/v1/chat/completions", json.dumps(body).encode(), {"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=3600) as r:
d = json.loads(r.read())
t = d["timings"]
return d["choices"][0]["message"]["content"], t["prompt_per_second"], t["predicted_per_second"], t["predicted_n"]
def llama(stem, threads, max_tokens):
lib = Path(os.environ["BANKML_GGML_LIB"])
base = "http://127.0.0.1:18321"
p = subprocess.Popen([str(lib / "llama-server"), "-m", str(root / ".models" / f"{stem}.gguf"), "--host", "127.0.0.1", "--port", "18321",
"-t", str(threads), "-c", "2048", "-np", "1", "--jinja", "--reasoning", "off", "--no-webui"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
try:
wait(base, p)
ask(base, 4) # warm the pages: both sides read a memory-mapped file
return ask(base, max_tokens)
finally:
p.terminate()
p.wait(timeout=60)
def bankml(stem, threads, max_tokens):
fork = Path(os.environ.get("BANKML_FORKS", Path.home() / ".local/share/bankml/forks")) / f"{stem}.gguf.FORK.json"
base = "http://127.0.0.1:18323"
env = {**os.environ, "BANKML_THREADS": str(threads), "BANKML_GPU": os.environ.get("BANKML_GPU", "off")}
p = subprocess.Popen([str(root / "target" / "release" / "bankml"), "serve", str(root / ".models" / f"{stem}.gguf"), "--fork", str(fork),
"--native", "--listen", "127.0.0.1:18323", "--upstream", "127.0.0.1:18324", "--ctx", "2048"],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, env=env)
try:
wait(base, p)
ask(base, 4)
return ask(base, max_tokens)
finally:
p.terminate()
p.wait(timeout=60)
def main():
stem = sys.argv[1] if len(sys.argv) > 1 else "Bonsai-8B-Q1_0"
rounds = int(sys.argv[2]) if len(sys.argv) > 2 else 3
threads = int(sys.argv[3]) if len(sys.argv) > 3 else 3
max_tokens = 64
print(f"# {stem}, {rounds} rounds, {threads} threads, {max_tokens} tokens greedy; load {open('/proc/loadavg').read().split()[:3]}")
rows = []
for r in range(rounds):
order = [("llama-server", llama), ("bankML", bankml)] if r % 2 == 0 else [("bankML", bankml), ("llama-server", llama)]
got = {}
for name, run in order:
got[name] = run(stem, threads, max_tokens)
time.sleep(2)
(lt, lp, ld, ln), (bt, bp, bd, bn) = got["llama-server"], got["bankML"]
if (lt, ln) != (bt, bn):
sys.exit(f"round {r + 1}: the answers differ, the speeds are not comparable\n bankML {bt!r}\n llama {lt!r}")
rows.append((bp, bd, lp, ld))
print(f"round {r + 1} ({order[0][0]} first): decode bankML {bd:.2f} tok/s, llama-server {ld:.2f} ({bd / ld:.3f}×); "
f"prompt {bp:.1f} against {lp:.1f} tok/s; {bn} tokens, identical", flush=True)
med = lambda i: statistics.median(x[i] for x in rows)
print(f"median: decode bankML {med(1):.2f} tok/s, llama-server {med(3):.2f} ({med(1) / med(3):.3f}×); "
f"prompt {med(0):.1f} against {med(2):.1f} tok/s ({med(0) / med(2):.3f}×)")
if __name__ == "__main__":
main()