"""Synthetic streaming benchmark; run inside serving container, writes JSONL to stdout. No external datasets or user prompts. Usage: python3 benchmark.py --label eager TTFT includes reasoning tokens; first_content_s separately measures visible answer. Decode tok/s is an approximation from total completion tokens and streaming time. """ import argparse import concurrent.futures import hashlib import json import random import re import threading import time import urllib.request from pathlib import Path parser = argparse.ArgumentParser() parser.add_argument('--label', required=True) parser.add_argument('--long-max-tokens', type=int, default=1024) parser.add_argument('--phase', choices=['all', 'short', 'long'], default='all') args = parser.parse_args() BASE = 'http://127.0.0.1:8000' KEY = Path('/run/secrets/qwen_api_key').read_text().strip() HEADERS = {'Authorization': 'Bearer ' + KEY, 'Content-Type': 'application/json'} def emit(record): print(json.dumps({'label': args.label, **record}, ensure_ascii=False), flush=True) def metrics(): request = urllib.request.Request(BASE + '/metrics', headers=HEADERS) with urllib.request.urlopen(request, timeout=10) as response: text = response.read().decode() values = {} for line in text.splitlines(): if line.startswith('#') or 'prefix_cache_' not in line: continue name = line.split('{')[0].split()[0] if name.endswith('_total'): values[name] = values.get(name, 0) + float(line.split()[-1]) return values def run(name, prompt, expected=None, barrier=None, max_tokens=512): payload = {'model': 'qwen3.8-flash-next', 'messages': [{'role': 'user', 'content': prompt}], 'temperature': 0, 'seed': 42, 'max_tokens': max_tokens, 'reasoning_effort': 'low', 'stream': True, 'stream_options': {'include_usage': True}} request = urllib.request.Request(BASE + '/v1/chat/completions', data=json.dumps(payload).encode(), headers=HEADERS) if barrier: barrier.wait() start = time.perf_counter() first = first_content = last = None content, reasoning = '', '' usage, finish = {}, None with urllib.request.urlopen(request, timeout=900) as response: for raw in response: line = raw.decode().strip() if not line.startswith('data: ') or line == 'data: [DONE]': continue item = json.loads(line[6:]) if item.get('usage'): usage = item['usage'] for choice in item.get('choices', []): delta = choice.get('delta', {}) answer = delta.get('content') or '' thought = delta.get('reasoning') or delta.get('reasoning_content') or '' if answer or thought: now = time.perf_counter() first = first if first is not None else now last = now if answer: first_content = first_content if first_content is not None else now content += answer reasoning += thought finish = choice.get('finish_reason') or finish elapsed = time.perf_counter() - start count = usage.get('completion_tokens', 0) record = {'test': name, 'max_tokens': max_tokens, 'elapsed_s': round(elapsed, 4), 'ttft_s': round(first-start, 4) if first else None, 'first_content_s': round(first_content-start, 4) if first_content else None, 'decode_tps_approx': round((count-1)/(last-first), 3) if last and first and last>first else None, 'usage': usage, 'finish_reason': finish, 'content': content, 'output_sha256': hashlib.sha256((reasoning+'\0'+content).encode()).hexdigest(), 'prompt_sha256': hashlib.sha256(prompt.encode()).hexdigest(), 'correct': bool(content.strip()) and (expected is None or expected in content)} emit(record) if not record['correct'] or finish != 'stop': emit({'event':'ANSWER_CHECK_FAILED','test':name}) return record emit({'event': 'start', 'phase': args.phase}) if args.phase in ('all', 'short'): run('warmup', '计算17乘19,只输出结果。', '323') prompt = '用中文写一段约150字的说明,解释数据库索引为什么能加快查询,以及它对写入有什么影响。' for i in range(3): run('short_'+str(i), prompt) run('code', '写一个Python函数is_even(n),判断整数是否为偶数,只输出代码。', '%') for concurrency in [2, 4]: barrier = threading.Barrier(concurrency) start = time.perf_counter() with concurrent.futures.ThreadPoolExecutor(max_workers=concurrency) as pool: futures = [pool.submit(run, f'concurrent_{concurrency}_{i}', f'场景编号{i}。'+prompt, None, barrier) for i in range(concurrency)] results = [f.result() for f in futures] seconds = time.perf_counter()-start emit({'test': 'concurrency_summary', 'concurrency': concurrency, 'elapsed_s': round(seconds, 3), 'aggregate_completion_tps': round(sum(r['usage']['completion_tokens'] for r in results)/seconds, 3)}) if args.phase in ('all', 'long'): from transformers import AutoTokenizer snapshot = '/root/.cache/huggingface/hub/models--nvidia--Qwen3.8-Flash-Next-NVFP4/snapshots/fc694b54fb0174e0913e6adf86691ef85a4ead47' tokenizer = AutoTokenizer.from_pretrained(snapshot, local_files_only=True) rng = random.Random(42) filler = '\n'.join(f'Record {i}: item={rng.randrange(100000,999999)}; status=archived; category={i%17}.' for i in range(6000)) ids = tokenizer.encode(filler, add_special_tokens=False) for size in [8192, 32768]: text = tokenizer.decode(ids[:size-150]) pos = len(text)//2 text = text[:pos]+'\n唯一有效的校验口令是:青松739251。\n'+text[pos:] prompt = '从下面的档案里找出唯一有效的校验口令。只输出口令,不要解释。\n<档案>\n'+text+'\n\n请输出校验口令。' before = metrics() a = run(f'long_{size}_cold', prompt, '青松739251', max_tokens=args.long_max_tokens) b = run(f'long_{size}_repeat', prompt, '青松739251', max_tokens=args.long_max_tokens) after = metrics() emit({'test':f'prefix_{size}', 'same_output':a['output_sha256']==b['output_sha256'], 'metrics_delta':{key:after[key]-before.get(key,0) for key in after}}) emit({'event':'BENCHMARK_COMPLETED'})