from ops import *
import sys,statistics
phase=sys.argv[1];d=json.loads((HERE/(phase+'.json')).read_text());dt=d['seconds']
first={r['camera']:r for r in d['samples'][0]['channels']};channels=[];durations={}
for b in d['samples'][-1]['channels']:
    a=first[b['camera']];am=a['metadata_path'];bm=b['metadata_path'];ap=am['performance'];bp=bm['performance'];ad=ap['pipeline_diagnostic'];bd=bp['pipeline_diagnostic']
    counts={k:v-ad['counts'].get(k,0) for k,v in bd['counts'].items()}
    rows={}
    for k,v in bd['durations'].items():
        old=ad['durations'].get(k,{});n=v['count']-old.get('count',0);ns=v['sum_ns']-old.get('sum_ns',0)
        rows[k]=dict(count=n,mean_ms=round(ns/n/1e6,3) if n else None,over100=v['over_100ms']-old.get('over_100ms',0))
        r=durations.setdefault(k,{'count':0,'ns':0});r['count']+=n;r['ns']+=ns
    accepted=(bm.get('accepted_result',0)-am.get('accepted_result',0)) if 'accepted_result' in bm else counts.get('submitted',0)
    channels.append(dict(camera=b['camera'],selected_fps=round(counts.get('selected',0)/dt,2),
        completed_fps=round(counts.get('copied',0)/dt,2),accepted_fps=round(accepted/dt,2),
        rejection_pct=(round(100*(bm['providers']['medium']['late']-am['providers']['medium']['late'])/
                             (bm['providers']['medium']['responses']-am['providers']['medium']['responses']),2)
                       if 'providers' in bm and bm['providers']['medium']['responses']>am['providers']['medium']['responses'] else None),
        legacy_stale=bm.get('stale',0)-am.get('stale',0),legacy_queue_drop=bm.get('queue_drop',0)-am.get('queue_drop',0),
        result_fps=round((bm.get('processed',bm.get('finalized',0))-am.get('processed',am.get('finalized',0)))/dt,2),
        counts=counts,rejected={k:v-am.get(k,0) for k,v in bm.items() if k.startswith('rejected_')},
        durations=rows,missed=bd['missed']-ad['missed']))
m='RFDETRMedium';ta=d['triton_before'][m];tb=d['triton_after'][m]
assert ta['config']==tb['config']
a=ta['stats'];b=tb['stats'];stats={}
for k,v in b['inference_stats'].items():
    n=int(v['count'])-int(a['inference_stats'][k]['count']);ns=int(v['ns'])-int(a['inference_stats'][k]['ns']);stats[k]=dict(count=n,ms=round(ns/n/1e6,2) if n else None)
batch=[];old={x['batch_size']:x for x in a['batch_stats']}
for v in b['batch_stats']:
    n=v['compute_infer']['count']-old.get(v['batch_size'],{}).get('compute_infer',{}).get('count',0);batch.append([v['batch_size'],n])
ex=int(b['execution_count'])-int(a['execution_count']);inf=int(b['inference_count'])-int(a['inference_count'])
cpu={}
for k,v in d['cpu_after'].items():
    if k not in d['cpu_before']:continue
    old=d['cpu_before'][k];r=cpu.setdefault(v['channel'],dict(cpu_s=0.,runnable_wait_s=0.))
    r['cpu_s']+=(v['values'][0]-old['values'][0])/1e9;r['runnable_wait_s']+=(v['values'][1]-old['values'][1])/1e9
for r in cpu.values():
    for k in r:r[k]=round(r[k],3)
c0=[int(x) for x in d['samples'][0]['cpu'].split()[1:9]];c1=[int(x) for x in d['samples'][-1]['cpu'].split()[1:9]];dc=[b-a for a,b in zip(c0,c1)]
summary=dict(phase=phase,seconds=round(dt,3),channels=channels,
    mean_ms={k:round(v['ns']/v['count']/1e6,3) if v['count'] else None for k,v in durations.items()},
    triton=stats,batches=batch,mean_batch=round(inf/ex,3) if ex else None,model_config=ta['config'],cpu=cpu,
    host_cpu_busy_pct=round(100*(sum(dc)-dc[3]-dc[4])/sum(dc),1),
    gpu_mean_pct=round(statistics.mean(float(s['gpu'].split(',')[0]) for s in d['samples']),1))
save(phase+'-summary-r02.json',summary)
print(json.dumps(dict(phase=phase,channels=[{k:v for k,v in c.items() if k not in ('durations','counts')} for c in channels],mean_ms=summary['mean_ms'],triton=stats,batches=batch,mean_batch=summary['mean_batch'],cpu_busy=summary['host_cpu_busy_pct'],gpu=summary['gpu_mean_pct'])))
