#!/usr/bin/python3

# Apache License, Version 2.0
# Copyright (c) 2024 chciken/Niko
# Note: In order to execute the benchmark, the executable td_simple_bm.exe needs to be in the same directory

import matplotlib.pyplot as plt
import numpy as np
import re
import subprocess

MAX_QUANTUM = 400 # Maximum quantum in ns to simulate; start value is 1 ns
STEP_SIZE = 5 # Step size between two simulations in ns
SAVE_FIG = True # Save the matplotlib graph as an svg

def quant_formula(tq, oc):
    return tq / (tq + oc)

def calculate_oc_fitting(x_data, y_data):
    oc = 20 # init value
    last_oc = oc
    step = 0.5
    last_err = 1
    err = 1
    while (err > 0.001):
        err = 0
        oc += step
        for x, y in zip(x_data, y_data):
            err += abs(y - quant_formula(x, oc))**2
        err /= len(x_data)
        if err > last_err:
            step = step * -0.5
        if oc == last_oc:
            break
        last_oc = oc
        last_err = err
        print(oc, err)
    return oc

def calculate_oc_formula(x_data, y_data):
    tq1 = x_data[0]
    tq2 = x_data[-1]
    T1 = y_data[0]
    T2 = y_data[-1]
    return (T1 - T2) / ((T2 / tq1) - (T1 / tq2))

x_data, y_data = [], []

for i in range(1, MAX_QUANTUM, STEP_SIZE):
    print(f"Running quantum {i} ns")
    result = subprocess.run(['./td_simple_bm.exe', str(i)], stdout=subprocess.PIPE)
    m = re.match(r"MIPS\s=\s([0-9.]+)", str(result.stdout.decode("utf-8")))
    x_data.append(i)
    y_data.append(float(m.group(1)))

times = [1 / y for y in y_data]
y_data = [y / max(y_data) for y in y_data]
x_data = np.array(x_data)
y_data = np.array(y_data)

oc = calculate_oc_formula(x_data, times)
# oc = calculate_oc(x_data, y_data)
print("Oc' is:", oc)
y_data_gold = quant_formula(x_data, oc)

fig, ax = plt.subplots(figsize=(7.5,4))
ax.plot(x_data, y_data, linewidth=3.0)
ax.plot(x_data, y_data_gold, linewidth=3.0)
ax.set(xlabel="quantum (ns)", ylabel="speedup")
ax.grid()

if SAVE_FIG:
    fig.savefig("td_simple.svg")

plt.show()
