analyze.py 2.3 KB

123456789101112131415161718192021222324252627
  1. import json, pathlib, subprocess, statistics
  2. root=pathlib.Path(__file__).resolve().parent;out=root
  3. network=[json.loads(s) for s in (out/'network.jsonl').read_text().splitlines()]
  4. rows=[]
  5. for product,bundle in [('yaoyao','cn.samien.yaoyao.hermes'),('openmausbot','cn.samien.hermes.bot')]:
  6. for f in sorted(out.glob(f'{product}-latency-series-*.jsonl')):
  7. events=[json.loads(s) for s in f.read_text().splitlines()]
  8. starts=[e for e in events if e['name']=='send_start']
  9. for i,start in enumerate(starts):
  10. t=start['time'];end=starts[i+1]['time'] if i+1<len(starts) else t+60
  11. e=[x for x in events if t<=x['time']<end]
  12. n=[x for x in network if x.get('app')==product and t<=x['time']<end]
  13. send=next((x for x in n if x.get('event')=='request' and x.get('method')=='POST' and x['path'].endswith('/messages')),None)
  14. if not send:continue
  15. run=send['run'];n=[x for x in n if x.get('run')==run]; first=lambda name:next((x['time'] for x in e if x['name']==name),None)
  16. views=[x for x in e if x['name']=='view_text' and x['detail'].startswith('assistant|') and int(x['detail'].split('|')[-1])>0]
  17. source=[x for x in n if x.get('event')=='upstream_text' and x.get('chars',0)>0]
  18. ms=lambda value:round((value-t)*1000,2) if value else None
  19. gaps=[(b['time']-a['time'])*1000 for a,b in zip(views,views[1:]) if b['time']-a['time']<2]
  20. row=dict(product=product,run=run,traceFile=f.name.removeprefix(product+'-'),sample=i+1,postAckMs=ms(first('post_ack')),sendReadyMs=ms(first('send_ready')),firstViewMs=ms(views[0]['time']) if views else None,firstUpstreamMs=ms(source[0]['time']) if source else None,viewUpdates=len(views),upstreamTextEvents=len(source),medianViewGapMs=round(statistics.median(gaps),2) if gaps else None,largestViewGapMs=round(max(gaps),2) if gaps else None)
  21. if views and source:row['firstDeliveryToViewMs']=round((views[0]['time']-source[0]['time'])*1000,2)
  22. row['upstreamTextFrameBytes']=sum(x.get('bytes',0) for x in source)
  23. row['lastViewChars']=int(views[-1]['detail'].split('|')[-1]) if views else None
  24. row['requestsAfterSend']=[x['path'] for x in n if x.get('event')=='request' and x['time']<t+5]
  25. rows.append(row)
  26. (out/'measurements.json').write_text(json.dumps(rows,ensure_ascii=False,indent=2))
  27. for r in rows:print(json.dumps({k:v for k,v in r.items() if k!='requestsAfterSend'},ensure_ascii=False))