#!/usr/bin/env python3

import os
import math

uarchdate = {
  'a53':20121030,
  'a72':20160101, # XXX: announced in 2015.02 but supposedly not shipped until 2016
  'airmont':20150401, # XXX: not sure about exact date
  'broadwell':20141027,
  'core2':20060726,
  'firestorm':20201110,
  'goldencove':20211104,
  'goldmont':20160418,
  'haswell':20130604,
  'skylake':20150805,
  'tigerlake':20200902,
  'zen2':20190707,
  'zen3':20201105,
}

uarchname = {
  'a53':'Cortex-A53 (2012)',
  'a72':'Cortex-A72 (2016)',
  'airmont':'Airmont (2015)',
  'broadwell':'Broadwell (2014)',
  'core2':'Core 2 (2006)',
  'firestorm':'Firestorm (2020)',
  'goldencove':'Golden Cove (2021)',
  'goldmont':'Goldmont (2016)',
  'haswell':'Haswell (2013)',
  'skylake':'Skylake (2015)',
  'tigerlake':'Tiger Lake (2020)',
  'zen2':'Zen 2 (2019)',
  'zen3':'Zen 3 (2020)',
}

sizes = '11','26','61','139','314','709','1597','3595','8090','18205'

def sortkey(m):
  uarch = ''.join(m.split('-')[:1])
  return uarchdate[uarch]

machines = sorted(os.listdir('benchmarks'),key=sortkey,reverse=True)

def handle(bytes,base,data):
  bytes = int(bytes)
  base = int(base)
  data = data.replace('+',' +')
  data = data.replace('-',' -')
  data = data.split()
  data = [base+int(x) for x in data]
  data = sorted(data)
  n = len(data)
  assert n%4 == 0
  q1 = (data[n//4-1]+data[n//4])*0.5
  q3 = (data[3*n//4-1]+data[3*n//4])*0.5
  iqm = sum(data[n//4:3*n//4])*2.0/n
  assert math.fabs(iqm-float(base)) < 0.6
  return '%.3f | %.3f | %.3f'%(q1/bytes,iqm/bytes,q3/bytes)

def doit(m):
  uarch = uarchname[''.join(m.split('-')[:1])]

  auth = {}
  verify = {}

  for benchmarksdir in 'benchmarks','benchmarks+exp':
    with open(f'{benchmarksdir}/{m}') as f:
      for line in f:
        line = line.split()
        if len(line) < 4: continue
        if line[2] == 'implementation': continue
        if line[:2] == [f'onetimeauth_poly1305','selected']:
          if int(line[2]) < 1: continue
          auth[benchmarksdir,line[2]] = handle(line[2],line[3],line[4])
        if line[:2] == [f'onetimeauth_poly1305_verify','selected']:
          if int(line[2]) < 1: continue
          verify[benchmarksdir,line[2]] = handle(line[2],line[3],line[4])

  C = ''
  D = ''
  for size in sizes:
    a = auth["benchmarks",size]
    aexp = auth["benchmarks+exp",size]
    v = verify["benchmarks",size]
    vexp = verify["benchmarks+exp",size]
    out.write(f'| {uarch} | {size} | {C}{a}{D} | {C}{v}{D} | {C}{aexp}{D} | {C}{vexp}{D}\n')
    uarch = ''

with open('doc/speed.md.tmp','w') as out:
  with open('autogen/md-speed-top') as f:
    out.write(f.read())
  out.write('\n\n')
  out.write('| μarch | bytes  | auth q1  | iqm  |  q3  | verify q1 | iqm  |  q3  | exp auth q1  | iqm  |  q3  | exp verify q1  | iqm  | q3  \n')
  out.write('| :---- | -----: | -------: | ---: | ---: | --------: | ---: | ---: | -----------: | ---: | ---: | -------------: | ---: | --: \n')
  for m in machines:
    doit(m)
  out.write('\n\n')
  with open('autogen/md-speed-bot') as f:
    out.write(f.read())

with open('doc/speed.md') as f:
  x = f.read()
with open('doc/speed.md.tmp') as f:
  y = f.read()
if x != y:
  os.rename('doc/speed.md.tmp','doc/speed.md')
else:
  os.remove('doc/speed.md.tmp')
