conc.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738
  1. # Aggregate and per-stream decode tok/s with N concurrent streams (streamed,
  2. # timed from each stream's first token). Prompts rotate across workloads.
  3. import json, os, statistics, sys, threading, time, urllib.request
  4. BASE = os.environ.get("GATE_URL", "http://127.0.0.1:8002")
  5. MODEL = os.environ.get("GATE_MODEL", "glm53")
  6. PROMPTS = ["Write a red-black tree in Python with insert, delete and rebalancing. Code only.",
  7. "Explain how a hash map works, in flowing prose. No code, no lists.",
  8. "Write a complete Python implementation of a red-black tree with insert, delete and in-order traversal.",
  9. "Explain in detail how a hash map handles collisions, with examples."]
  10. def one(prompt, out, i):
  11. body = json.dumps({"model": MODEL, "max_tokens": 512, "temperature": 0, "stream": True,
  12. "chat_template_kwargs": {"thinking": False, "enable_thinking": False},
  13. "stream_options": {"include_usage": True},
  14. "messages": [{"role": "user", "content": prompt}]}).encode()
  15. r = urllib.request.urlopen(urllib.request.Request(BASE + "/v1/chat/completions", data=body,
  16. headers={"Content-Type": "application/json"}), timeout=900)
  17. first = n = None
  18. for line in r:
  19. if not line.startswith(b"data: {"):
  20. continue
  21. d = json.loads(line[6:])
  22. if first is None and d.get("choices"):
  23. first = time.monotonic()
  24. if d.get("usage"):
  25. n = d["usage"]["completion_tokens"]
  26. out[i] = (n, first, time.monotonic())
  27. for N in [int(a) for a in sys.argv[1:]] or [1, 2, 4, 8]:
  28. out = [None] * N
  29. ts = [threading.Thread(target=one, args=(PROMPTS[i % 4], out, i)) for i in range(N)]
  30. for t in ts: t.start()
  31. for t in ts: t.join()
  32. t0 = min(o[1] for o in out); t1 = max(o[2] for o in out)
  33. per = [o[0] / (o[2] - o[1]) for o in out]
  34. print(f"streams {N:2d}: aggregate {sum(o[0] for o in out) / (t1 - t0):6.1f} tok/s, per stream median {statistics.median(per):6.1f} (min {min(per):.1f})", flush=True)