from ops import *
import csv,statistics
summary=json.loads((HERE/'summary-v2.json').read_text())
configs=json.loads((HERE/'scale/model-configs.json').read_text())
models=[];lanes=[];senders=[]
def d(a,b,k):return b.get(k,0)-a.get(k,0)
def mean_delta(a,b):
    n=d(a,b,'count');return (b.get('sum_ns',0)-a.get('sum_ns',0))/n/1e6 if n else None
for stage_summary in summary:
    level=stage_summary['level'];stage=json.loads((HERE/f'scale/stage-{level}.json').read_text())
    first,last=stage['samples'][0],stage['samples'][-1];dt=last['t']-first['t']
    for model,row in stage_summary['models'].items():
        config=configs[model];batch=row['batch_executions'];maximum=config['max_batch_size']
        total=sum(batch.values());n=batch.get(str(maximum),0);frames=sum(int(k)*v for k,v in batch.items())
        assert total==row['executions']
        models.append(dict(level=level,model=model,max_batch_size=maximum,
            preferred_batch_size=config.get('dynamic_batching',{}).get('preferred_batch_size'),
            max_queue_delay_microseconds=config.get('dynamic_batching',{}).get('max_queue_delay_microseconds'),
            instance_group=config.get('instance_group'),batch_executions=batch,
            max_batch_executions=n,total_executions=total,max_batch_execution_pct=100*n/total if total else None,
            frames_in_max_batch=n*maximum,total_batched_frames=frames,
            max_batch_frame_pct=100*n*maximum/frames if frames else None,
            request_count=row['stats']['success']['count'],inference_count=row['inferences'],
            queue_ms=row['stats']['queue']['mean_ms'],compute_ms=row['stats']['compute_infer']['mean_ms']))
    for camera,bc in last['channels'].items():
        ac=first['channels'][camera];pa=ac['publisher_metrics'];pb=bc['publisher_metrics']
        for p,bp0 in bc['providers'].items():
            ap=ac['providers'][p]['metadata_path'];bp=bp0['metadata_path']
            a=ap['provider_timing'][p]['selected_to_response'];b=bp['provider_timing'][p]['selected_to_response']
            count=d(a,b,'count');an=ap['providers'][p];bn=bp['providers'][p]
            delivery_a=next(iter(pa.get('delivery',{}).values()),{}).get(p,{})
            delivery_b=next(iter(pb.get('delivery',{}).values()),{}).get(p,{})
            interval_n=d(delivery_a,delivery_b,'interval_count')
            samples=[s['channels'][camera]['providers'][p]['metadata_path'] for s in stage['samples']]
            lanes.append(dict(level=level,camera=int(camera),provider=p,seconds=dt,
                requests=d(an,bn,'requests'),request_fps=d(an,bn,'requests')/dt,
                finalized=d(ap,bp,'finalized'),finalized_fps=d(ap,bp,'finalized')/dt,
                completed_queue_drop=d(ap,bp,'completed_queue_drop'),completed_queue_expired=d(ap,bp,'completed_queue_expired'),
                completed_queue_depth_peak=max(s['queued'] for s in samples),
                completed_queue_age_peak_s=max(s['completed_queue_age_s'] for s in samples),
                requests_minus_responses_peak=max(s['providers'][p].get('requests',0)-s['providers'][p]['responses'] for s in samples),
                selected_to_response_mean_ms=d(a,b,'sum_ms')/count if count else None,
                over100_count=d(a,b,'over_100ms'),response_timing_count=count,
                over100_pct=100*d(a,b,'over_100ms')/count if count else None,
                redis_interval_mean_ms=d(delivery_a,delivery_b,'interval_sum_ns')/interval_n/1e6 if interval_n else None,
                relay_mean_ms=mean_delta(pa.get('relay_timing',{}).get(p,{}),pb.get('relay_timing',{}).get(p,{}))))
        a=next(iter(pa.get('profile',{}).get('channels',{}).values()),{})
        b=next(iter(pb.get('profile',{}).get('channels',{}).values()),{})
        timing={}
        for key,value in b.get('timings',{}).items():
            old=a.get('timings',{}).get(key,{});n=d(old,value,'count')
            timing[key]=dict(count=n,mean_ms=(value['count']*value['mean_ms']-old.get('count',0)*old.get('mean_ms',0))/n if n else None)
        senders.append(dict(level=level,camera=camera,timings=timing,
            counts={k:d(a.get('counts',{}),b.get('counts',{}),k) for k in b.get('counts',{})}))
save('batch-sot.json',models);save('linear-lanes.json',lanes);save('sender-sot.json',senders)
for name,rows in [('batch-sot.csv',models),('linear-lanes.csv',lanes)]:
    with (HERE/name).open('x',newline='') as f:
        writer=csv.DictWriter(f,fieldnames=list(rows[0]));writer.writeheader();writer.writerows(rows)
print(json.dumps(dict(stages=len(summary),lanes=len(lanes),batch_rows=len(models),queue_expired=sum(r['completed_queue_expired'] for r in lanes))))
