
/*
 * Sander van Veen (UvA ID: 6167969)
 */

#include <stdlib.h>
#include <stdio.h>

#include "interval.h"

#include "meten.h"
#include "testcache.h"

/*
 * Afhankelijk van de machine, moet de maximale waarde van size tussen de 20 en
 * 80 miljoen liggen, en de minimale bij een paar miljoen. De maximale waarde
 * van stride moet ergens tussen de 100 000 en 200 000 liggen, en de minimale
 * waarde moet 1 zijn. Zeker voor de kleinere waarden van size zullen de
 * functies zo snel zijn dat je ze een flink aantal malen moet meten voordat je
 * een betrouwbare meting van met name de CPU-tijd hebt.
 */
static long cur_size = 1e6;
static long cur_stride = 1;
static long min_size = 1e6;
static long max_size = 128e6;
static long min_stride = 1;
static long max_stride = 2e5;
static long *data;

/*
 * De invoerparameters omvatten in ieder geval een pointer naar een functie van
 * het type van fillArray en sumArray, size en stride. De uitvoerparameters
 * omvatten in ieder geval de gebruikte wall-clock tijd en de gebruikte CPU tijd
 * voor de aanroep. Of je het te gebruiken array als parameter meegeeft, of
 * binnen de functie zelf aanmaakt staat je vrij.
 */
void time_single_fn(array_fn* fn, double *wct, double *ust, double *syt)
{
    interval now = newInterval();
    double t_w = 0, t_u = 0, t_s = 0;

    int i = 0;

    do
    {
        (*fn)(data, cur_size, cur_stride);

        timeInterval(now, &t_w, &t_u, &t_s);

        *wct += t_w;
        *ust += t_u;
        *syt += t_s;

        i++;
    }
    while( *wct < 1 );

    if( i > 1 )
    {
        *wct /= i;
        *ust /= i;
        *syt /= i;
    }
}

/*
 * Deze functie gebruikt de bovengenoemde functie om achtereenvolgens de
 * performance te meten van een gegeven functie voor een reeks van waarden voor
 * size en stride. Een beetje afhankelijk van de machine waarop je werkt, moet
 * de maximale waarde van size tussen de 20 en 80 miljoen liggen, en de minimale
 * bij een paar miljoen. De maximale waarde van stride moet ergens tussen de
 * 100 000 en 200 000 liggen, en de minimale waarde moet 1 zijn. Zeker voor de
 * kleinere waarden van size zullen de functies zo snel zijn dat je ze een flink
 * aantal malen moet meten voordat je een betrouwbare meting van met name de
 * CPU-tijd hebt.
 *
 * Druk voor iedere combinatie van size en stride een regel af met de diverse
 * meetwaarden en de naam van de geteste functie. Om je resultaten met elkaar te
 * kunnen vergelijken kan je de waarde per geheugen-access berekenen.
 *
 * N.B.2 schrijf je routine zo dat de te meten routine herhaald wordt
 * aangeroepen totdat een vooraf bepaalde hoeveelheid CPU tijd is gebruikt
 * (b.v. 0.5 seconde). Tel het aantal aanroepen.
 *
 * N.B.3 als je de velden in de regel met een tab scheidt, kan je die later
 * eenvoudig in een spreadsheet inlezen.
 */

void time_fn(array_fn* fn, double *wct, double *ust, double *syt)
{
    for( cur_size = min_size; cur_size <= max_size; cur_size += cur_size )
    {
        for( cur_stride = min_stride;
                cur_stride <= max_stride;
                cur_stride *= 10 )
        {
            *wct = 0;
            *ust = 0;
            *syt = 0;

            time_single_fn(fn, wct, ust, syt);

            printf("%9.ld\t%6.ld\t%.3f\t%.3f\t%.3f\n",
                    cur_size, cur_stride, *wct, *ust, *syt);
        }
    }
}

/*
 * Deze functie doet de nodige initialisaties, drukt minimaal een kopregel voor
 * de tabel af, en roept timeAFunction aan voor de beide routines fillArray en
 * sumArray.
 */
int main (int argc, char **argv)
{
    data = malloc(max_size * sizeof(long *));

    double wct = 0, ust = 0, syt = 0;

    puts("### fillArray ###");
    puts("size     \tstride\ttime\tuser\tsys");

    time_fn(&fillArray, &wct, &ust, &syt);

    puts("### sumArray ###");
    puts("size     \tstride\ttime\tuser\tsys");

    time_fn(&sumArray, &wct, &ust, &syt);

    return (EXIT_SUCCESS);
}
