Profiling page: per-turn phase timings, live in the web dashboard
The engine already tracks where each turn's wall time goes (expert-disk service, I/O wait, expert matmul, attention, lm_head) — it just only spoke at exit or under PROF=1. Stream it instead: - glm.c: mux serve emits a per-turn "PROF" protocol line next to TIERS/HITS (window deltas per request, same convention as the STAT hit%); the phase window base is now always captured (a few loads per request). - openai_server.py: parses PROF into a 120-turn rolling window and serves it at /profile (read-only, same trust level as /health). - web: new Profiling tab — stat tiles (tok/s, wall, tokens/forward, disk service), wall-time composition bars for the last turn and the window, per-turn throughput and stacked phase columns with hover readouts, and a table of recent turns. Disk service is shown apart from the stack: it overlaps with compute, so only the I/O wait the compute thread felt counts inside wall time. Phase colours are a CVD-validated set with gaps + legend + table so identity never rides on colour alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WhTmF8yvEBgSkUKSVfZF7P
This commit is contained in:
committed by
Nicholas Beerbower
parent
63a6824881
commit
6afffbcbf2
@@ -380,6 +380,25 @@ class DispatcherTest(unittest.TestCase):
|
||||
engine.close()
|
||||
self.assertEqual(chunks, ["é"])
|
||||
|
||||
def test_records_profile_snapshots_from_prof_lines(self):
|
||||
def respond(process, frame):
|
||||
request_id = frame.split()[1]
|
||||
process.stdout.feed(b"DATA " + request_id + b" 2\nok\n")
|
||||
process.stdout.feed(b"PROF 2.500 7 12 0.400 0.100 0.900 0.600 0.200 15\n")
|
||||
process.stdout.feed(b"DONE " + request_id + b" STAT 12 4.8 0 1.0 7 0\n")
|
||||
|
||||
process = FakeProcess(respond)
|
||||
with patch("openai_server.subprocess.Popen", return_value=process):
|
||||
engine = Engine("glm", "model")
|
||||
engine.generate("hello", 16, 0.7, 0.9, lambda _: None)
|
||||
engine.close()
|
||||
self.assertEqual(engine.profile_seq, 1)
|
||||
self.assertEqual(list(engine.profile), [{
|
||||
"wall_s": 2.5, "prompt_tokens": 7, "completion_tokens": 12,
|
||||
"expert_disk_s": 0.4, "expert_wait_s": 0.1, "expert_matmul_s": 0.9,
|
||||
"attention_s": 0.6, "lm_head_s": 0.2, "forwards": 15,
|
||||
}])
|
||||
|
||||
def test_cancels_generation_after_consumer_disconnects(self):
|
||||
request_id = None
|
||||
|
||||
@@ -443,6 +462,20 @@ class HTTPTest(unittest.TestCase):
|
||||
self.assertIn("queued", scheduler)
|
||||
self.assertEqual(health["kv_slots"], 2)
|
||||
|
||||
def test_profile_reports_recent_turns_without_auth(self):
|
||||
with urlopen(self.base + "/profile", timeout=2) as response:
|
||||
self.assertEqual(json.load(response), {"seq": 0, "turns": []})
|
||||
turn = {"wall_s": 2.5, "prompt_tokens": 7, "completion_tokens": 12,
|
||||
"expert_disk_s": 0.4, "expert_wait_s": 0.1, "expert_matmul_s": 0.9,
|
||||
"attention_s": 0.6, "lm_head_s": 0.2, "forwards": 15}
|
||||
self.engine.profile = [turn]
|
||||
self.engine.profile_seq = 1
|
||||
try:
|
||||
with urlopen(self.base + "/profile", timeout=2) as response:
|
||||
self.assertEqual(json.load(response), {"seq": 1, "turns": [turn]})
|
||||
finally:
|
||||
del self.engine.profile, self.engine.profile_seq
|
||||
|
||||
def test_browser_preflight(self):
|
||||
request = Request(self.base + "/v1/chat/completions", method="OPTIONS", headers={
|
||||
"Origin": "http://localhost:5173",
|
||||
|
||||
Reference in New Issue
Block a user