sweep.py 4.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. """Real streaming inference, emitted token IDs, common-window speed evidence."""
  2. import concurrent.futures
  3. import json
  4. import os
  5. import hashlib
  6. from pathlib import Path
  7. import sys
  8. import time
  9. import urllib.request
  10. import uuid
  11. sys.path.insert(0, str(Path(os.environ.get('MODEL_PATH','/models/DeepSeek-V4.1-Flash'))/'encoding'))
  12. from encoding import encode_messages
  13. work = Path(os.environ.get('STATE_PATH','/state'))
  14. output = work/os.environ.get('SWEEP_OUTPUT', 'speed-sweep.jsonl')
  15. manifest_hash = hashlib.sha256((work/'launch.json').read_bytes()).hexdigest()
  16. headers = {'Content-Type':'application/json',
  17. 'Authorization':'Bearer '+(work/'api-key').read_text().strip()}
  18. def run_one(index, concurrency):
  19. nonce = uuid.uuid4().hex
  20. instruction = ('Write a complete Python module implementing an LRU cache with a doubly '
  21. 'linked list and dictionary. Include get, put, delete, iteration, resize, clear, '
  22. 'invariant validation and detailed docstrings. Then provide ten usage examples. '
  23. 'Return code only. Implement all methods fully.')
  24. prompt = encode_messages([{'role':'user', 'content':nonce+'\n'+instruction}], thinking_mode='chat')
  25. payload = {'text':prompt, 'stream':True, 'sampling_params':{'temperature':0,
  26. 'max_new_tokens':4096}, 'return_logprob':False}
  27. record = dict(index=index, concurrency=concurrency, nonce=nonce, manifest_sha256=manifest_hash,
  28. prompt=prompt, output_budget=4096, stream_events=[])
  29. start = time.monotonic()
  30. try:
  31. request = urllib.request.Request('http://127.0.0.1:8010/generate',
  32. data=json.dumps(payload).encode(), headers=headers)
  33. with urllib.request.urlopen(request, timeout=900) as response:
  34. for line in response:
  35. if not line.startswith(b'data: '):
  36. continue
  37. data = line[6:].strip()
  38. if data == b'[DONE]':
  39. break
  40. event = json.loads(data)
  41. record['stream_events'].append({'seconds':time.monotonic()-start, **event})
  42. events = record['stream_events']
  43. record['elapsed_s'] = time.monotonic()-start
  44. assert events, 'No generated events'
  45. final = events[-1]
  46. record['meta_info'] = final.get('meta_info', {})
  47. # Pinned runtime uses cumulative output_ids by default. Refuse to
  48. # compute a window if the actual stream does not have this contract.
  49. previous = []
  50. for event in events:
  51. ids = event.get('output_ids', [])
  52. assert ids[:len(previous)] == previous, 'Stream is not cumulative'
  53. previous = ids
  54. record['emitted_tokens'] = len(previous)
  55. def at(token):
  56. return next((e['seconds'] for e in events if len(e.get('output_ids', [])) >= token), None)
  57. record['ttft_s'] = at(1)
  58. left, right = at(129), at(641)
  59. if left is not None and right is not None and right > left:
  60. record['window_129_641_tps'] = 512/(right-left)
  61. record['finish_reason'] = record['meta_info'].get('finish_reason')
  62. except Exception as error:
  63. record['error'] = str(error)
  64. if hasattr(error, 'read'):
  65. record['error_body'] = error.read().decode()
  66. return record
  67. for concurrency in (1, 2, 4, 8):
  68. wave_start = time.monotonic()
  69. with concurrent.futures.ThreadPoolExecutor(max_workers=concurrency) as pool:
  70. records = list(pool.map(lambda i: run_one(i, concurrency), range(concurrency)))
  71. elapsed = time.monotonic()-wave_start
  72. with output.open('a') as handle:
  73. for record in records:
  74. handle.write(json.dumps(record)+'\n')
  75. summary = dict(concurrency=concurrency, elapsed_s=elapsed,
  76. errors=[r.get('error') for r in records if r.get('error')],
  77. tokens=[r.get('emitted_tokens') for r in records],
  78. ttft_s=[r.get('ttft_s') for r in records],
  79. matched_window_tps=[r.get('window_129_641_tps') for r in records],
  80. finish_reasons=[r.get('finish_reason') for r in records])
  81. print(json.dumps(summary), flush=True)
  82. if summary['errors']:
  83. raise RuntimeError('Failed wave; inspect before increasing concurrency')