#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include "../cputimestamps/getcycles.h"

#ifndef US_PER_S
#define US_PER_S (1000000)
#endif


double tick_rate;

static inline cycle_t real_time(void)
{
        cycle_t r;
        struct timeval t = { 0, 0 };

        assert(gettimeofday(&t, NULL) == 0);

        r = (uint64_t)t.tv_sec * US_PER_S;
        r += t.tv_usec;

        return r;
}

static void
selectsleep(unsigned us) {
        struct timeval tv;
        tv.tv_sec = 0;
        tv.tv_usec = us;

        select(0,0,0,0,&tv);
}

void
microuptime_calibrate(void)
{
	double sumx = 0;
	double sumy = 0;
	double sumxx = 0;
	double sumxy = 0;
	double slope;
	cycle_t start;
	cycle_t now;
	cycle_t stop;

	// least squares linear regression of ticks onto real time
	// as returned by gettimeofday.

	printf("Begin microuptime calibration\n");
  
	const unsigned n = 50;
	unsigned i;
  
	for (i = 0; i < n; i++) {
		double real,ticks,sleeptime,ran;
    
		ran = drand48();
		sleeptime = (100000 + ran * 200000);

		now = real_time();
		start = get_cycles();
		
		selectsleep((unsigned int) sleeptime);
		
		ticks = get_cycles() - start;
		real = real_time() - now;

		sumx += real;
		sumxx += real * real;
		sumxy += real * ticks;
		sumy += ticks;
	}
	slope = ((sumxy - (sumx*sumy) / n) /
		 (sumxx - (sumx*sumx) / n));
	tick_rate = slope;

	printf("%g\n", tick_rate);
}

int main(void)
{
	microuptime_calibrate();
}
