decode.py 1.7 KB

1234567891011121314151617181920212223242526
  1. # Per-workload decode with DFlash2 acceptance: thinking off, temperature 0,
  2. # 512 tokens, median of 3 after one discarded warm-up. Same prompts as the
  3. # 2026-09-06..26 measurements. usage: decode.py [base-url]
  4. import json, re, statistics, sys, time, urllib.request
  5. BASE = sys.argv[1] if len(sys.argv) > 1 else "http://127.0.0.1:8002" # no /v1
  6. W = [("structured", "Count from 1 to 200, comma separated. No commentary."),
  7. ("code", "Write a red-black tree in Python with insert, delete and rebalancing. Code only."),
  8. ("prose", "Explain how a hash map works, in flowing prose. No code, no lists.")]
  9. def metrics():
  10. raw = urllib.request.urlopen(BASE + "/metrics", timeout=30).read().decode()
  11. get = lambda k: sum(float(v) for v in re.findall(rf"^vllm:{k}\S*\s+([0-9.e+]+)$", raw, re.M))
  12. return get("spec_decode_num_accepted_tokens_total"), get("spec_decode_num_draft_tokens_total")
  13. def run(prompt, n=512):
  14. body = json.dumps({"model": "glm53", "messages": [{"role": "user", "content": prompt}],
  15. "max_tokens": n, "temperature": 0, "chat_template_kwargs": {"thinking": False}}).encode()
  16. r = urllib.request.Request(BASE + "/v1/chat/completions", data=body, headers={"Content-Type": "application/json"})
  17. t = time.time(); d = json.loads(urllib.request.urlopen(r, timeout=600).read()); e = time.time() - t
  18. return d["usage"]["completion_tokens"] / e
  19. print("%-12s %10s %8s %s" % ("workload", "tok/s", "accept", "runs"))
  20. for name, p in W:
  21. run(p, 16)
  22. a0, d0 = metrics()
  23. rates = [run(p) for _ in range(3)]
  24. a1, d1 = metrics()
  25. acc = (a1 - a0) / (d1 - d0) if d1 > d0 else float("nan")
  26. print("%-12s %10.1f %7.1f%% %s" % (name, statistics.median(rates), acc * 100, " ".join("%.1f" % r for r in rates)), flush=True)