/**
 * \file
 * \brief Bench library.
 */

/*
 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich.
 * All rights reserved.
 *
 * This file is distributed under the terms in the attached LICENSE file.
 * If you do not find this file, copies can be found by writing to:
 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
 */

#ifndef BENCH_H
#define BENCH_H

#include <aos/types.h> // for cycles_t
#include <bench/bench_arch.h>
#include <sys/cdefs.h>

#define BENCH_IGNORE_WATERMARK 0XDEADBEEF

#define BENCH_DUMP_OCTAVE 0

__BEGIN_DECLS
void bench_init(void);
cycles_t bench_avg(cycles_t *array, size_t len);
cycles_t bench_variance(cycles_t *array, size_t len);
void bench_stddev(cycles_t *array, size_t len, uint8_t correction,
                  cycles_t *ret_avg, cycles_t *ret_stddev);
cycles_t bench_min(cycles_t *array, size_t len);
cycles_t bench_max(cycles_t *array, size_t len);
cycles_t bench_tscoverhead(void);
cycles_t bench_time_diff(cycles_t tsc_start, cycles_t tsc_end);
__END_DECLS


/*
 * Control functions for benchmarks
 */

enum bench_ctl_mode {
    // Fixed number of runs (exactly min_runs)
    BENCH_MODE_FIXEDRUNS,
};

struct bench_ctl {
    enum bench_ctl_mode mode;
    size_t              result_dimensions;

    size_t              min_runs;
    size_t              dry_runs;

    size_t              result_count;
    cycles_t           *data;
};

typedef struct bench_ctl bench_ctl_t;


/**
 * Initialize a benchmark control instance.
 *
 * @param mode       Mode of the benchmark (enum bench_ctl_mode)
 * @param dimensions Number of values each run produces
 * @param min_runs   Minimal number of runs to be executed
 *
 * @return Control handle, to be passed on subsequent calls to bench_ctl_
 *         functions.
 */
bench_ctl_t *bench_ctl_init(enum bench_ctl_mode mode,
                            size_t              dimensions,
                            size_t              min_runs);

/**
 * Frees all resources associated with this benchmark control instance. Should
 * be called after the benchmark is done and the results are dumped.
 *
 * @param ctl Control handle
 */
void bench_ctl_destroy(bench_ctl_t *ctl);

/**
 * Add a fixed number of dry runs whose results should not be recorded. Should
 * be called before any calls to bench_ctl_add_run().
 *
 * @param ctl      Control handle
 * @param dry_runs Number of dry runs
 */
void bench_ctl_dry_runs(bench_ctl_t *ctl,
                        size_t       dry_runs);

/**
 * Add results from one run of the benchmark.
 *
 * @param ctl    Control handle
 * @param result Pointer to the 'dimensions' values of this run
 *
 * @return true if this was the last run necessary, false if more runs are
 *         needed.
 */
bool bench_ctl_add_run(bench_ctl_t *ctl,
                       cycles_t* result);

/**
 * Dump results of the benchmark to the standard output. One line per run, the
 * lines will be prefixed with prefix, the values separeted using commas.
 *
 * @param ctl    Control handle
 * @param prefix String to be printed before each line
 */
void bench_ctl_dump_csv(bench_ctl_t *ctl,
                        const char  *prefix, uint64_t tscperus);
/**
 * Use bincounting to reduce the amount of data that is printed.
 * One line per bin (bin_count + 2 for those below and above the specified
 * range) with two columns each is emited at most. Lines for empty bins are
 * omitted except for above and below. The first column contains the start
 * of the range for this bin (or below/above for the border cases), while the
 * second column contains the number of values in that bin.
 *
 * @param ctl       Control handle
 * @param dimenison Index of the value in the run
 * @param bin_count Number of bins to create
 * @param min       Minimum of range to be represented by bins
 * @param max       Maximum of range to be represented by bins
 * @param prefix    String to be printed before each line
 * @param tscperus  cpu ticks per micro-second
 */
void bench_ctl_dump_csv_bincounting(bench_ctl_t *ctl,
                                    size_t dimension,
                                    size_t bin_count,
                                    cycles_t min,
                                    cycles_t max,
                                    const char *prefix,
                                    cycles_t tscperus);


void bench_ctl_dump_analysis(bench_ctl_t *ctl,
                                    size_t dimension,
                                    const char *prefix,
                                    cycles_t tscperus);


#endif // BENCH_H
