import csv
import time

import numpy as np
from tqdm import tqdm


def check_sleep(duration, sleep_function):
    start = time.perf_counter()
    sleep_function(duration)
    end = time.perf_counter()
    elapsed = end - start
    return abs(elapsed - duration)

def busy_sleep(duration):
    end_time = time.perf_counter() + duration
    while time.perf_counter() < end_time:
        pass

def measure_accuracy(sleep_function, durations, iterations=100):
    average_errors = []
    for duration in tqdm(durations):
        errors = [check_sleep(duration, sleep_function) for _ in range(iterations)]
        average_error = np.mean(errors)
        average_errors.append(average_error)
    return average_errors

durations = np.arange(0.001, 0.101, 0.001)  # From 1ms to 100ms in 1ms increments
iterations = 100

sleep_errors = measure_accuracy(time.sleep, durations, iterations)
busy_sleep_errors = measure_accuracy(busy_sleep, durations, iterations)

def save_to_csv(filename, durations, sleep_errors, busy_sleep_errors):
    with open(filename, 'w', newline='') as csvfile:
        fieldnames = ['duration', 'sleep_error', 'busy_sleep_error']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        
        writer.writeheader()
        for duration, sleep_error, busy_sleep_error in zip(durations, sleep_errors, busy_sleep_errors):
            writer.writerow({
                'duration': duration,
                'sleep_error': sleep_error,
                'busy_sleep_error': busy_sleep_error
            })
    print("Data saved to", filename)

save_to_csv('sleep_data.csv', durations * 1000, np.array(sleep_errors) * 1000, np.array(busy_sleep_errors) * 1000)
