/*
 * Copyright (c) 2001-2003 Shiman Associates Inc. All Rights Reserved.
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */
/*
 * $Id: masbench.c,v 1.2 2003/06/30 02:20:23 rocko Exp $
 *
 * Copyright (c) 2000, 2001 by Shiman Associates Inc. and Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions: The above
 * copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the names of the authors or
 * copyright holders shall not be used in advertising or otherwise to
 * promote the sale, use or other dealings in this Software without
 * prior written authorization from the authors or copyright holders,
 * as applicable.
 *
 * All trademarks and registered trademarks mentioned herein are the
 * property of their respective owners. No right, title or interest in
 * or to any trademark, service mark, logo or trade name of the
 * authors or copyright holders or their licensors is granted.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "mas/mas_common.h"
#include "mas/mas_real_time_process.h"
#include "nanosleep_benchmark.h"

#define NSBENCH_NUM 99
#define NSBENCH_START 1000000
#define NSBENCH_END   100000000
#define roundup_u_int32(a) ((u_int32)(a + 1.0))
#define round_u_int32(a) ((u_int32)(a + 0.5))
#define HEADER_OUT "/tmp/mas_nanosleep_reality.h"
#define VARS_OUT   "/tmp/mas_nanosleep_reality.c"

int main(int argc, char* argv[])
{
    struct mas_benchmark nanosleep_b[NSBENCH_NUM];
    u_int32 i, j, tmin = 0, tmax = 0, unique = 0;
    u_int32 real_min, real_max;
    u_int32 value[NSBENCH_NUM];
    u_int32 wall_clock[NSBENCH_NUM];
    u_int32 avg_nonzero_delta = 0, delta;
    int contributors = 0;
    int real_time = 0;
    FILE* header;
    FILE* vars;

    if (masc_set_real_time_priority( 0 ) < 0)
    {
	fprintf(stderr, "[can't set real-time scheduling parameters]\n");
	fprintf(stderr, "Not benchmarking under real-time conditions.\n\n");
    }
    else
    {
	fprintf(stderr, "Benchmarking under real-time conditions.\n\n");
	real_time = 1;
    }

    masc_init_timing();
    mas_benchmark_nanosleep( nanosleep_b, NSBENCH_NUM, NSBENCH_START,
			     NSBENCH_END, 1); 
    tmin = NSBENCH_END;
    tmax = NSBENCH_START;

    /* find how long it takes to sleep in msec increments from min to
       max */
    for (i=0; i<NSBENCH_NUM; i++)
    {
	if (nanosleep_b[i].wall_clock_time < tmin) 
	    tmin = nanosleep_b[i].wall_clock_time; 
	if (nanosleep_b[i].wall_clock_time > tmax) 
	    tmax = nanosleep_b[i].wall_clock_time;
	if ( i > 0 )
	{
	    if (nanosleep_b[i].wall_clock_time >
		nanosleep_b[i-1].wall_clock_time)
	    {
		delta = round_u_int32( (nanosleep_b[i].wall_clock_time -
					nanosleep_b[i-1].wall_clock_time)
				       / 1000000.0 );
	    }
	    else
	    {
		delta = round_u_int32( (nanosleep_b[i-1].wall_clock_time -
					nanosleep_b[i].wall_clock_time)
				       / 1000000.0 );
	    }
	    
	    fprintf(stderr, "delta: %u\n", delta);
	    if (delta > 0)
	    {
		avg_nonzero_delta += delta;
		contributors++;
	    }
	}
    }
    /* delta is taken as the closest power of 10 */
    avg_nonzero_delta = pow(10, round_u_int32( log10(
	avg_nonzero_delta/contributors )));
    tmin = roundup_u_int32(tmin/(avg_nonzero_delta*1000000.0)) * avg_nonzero_delta;
    tmax = roundup_u_int32(tmax/(avg_nonzero_delta*1000000.0)) * avg_nonzero_delta;

    real_min = NSBENCH_END;
    real_max = NSBENCH_START;

    for (i=tmin; i<=tmax; i++)
    {
	j = 0;
	while ( ( roundup_u_int32(nanosleep_b[j].wall_clock_time /
				  (avg_nonzero_delta*1000000.0)) 
		  *avg_nonzero_delta != i )
		&& ( j < NSBENCH_NUM ) ) j++;

	if ( j < NSBENCH_NUM )
	{
	    if ( nanosleep_b[j].cpu_time > 0)
	    {
		fprintf(stderr, "Discarding %u, cpu usage is %u.\n",
			i, nanosleep_b[j].cpu_time);
	    }
	    else
	    {
		value[unique] = nanosleep_b[j].value;
		wall_clock[unique] = i*1000000;
		fprintf(stderr, "call nanosleep(%u) to sleep for %ums\n",
			value[unique], wall_clock[unique]/1000000);
		if (wall_clock[unique] < real_min) real_min = wall_clock[unique];
		if (wall_clock[unique] > real_max) real_max = wall_clock[unique];
		unique++;
	    }
	}
    }
    
    fprintf(stderr, "Minimum sleep time: %ums\n", real_min/1000000);
    fprintf(stderr, "Maximum sleep time: %ums\n", real_max/1000000);
    fprintf(stderr,
	    "Rounding to average nonzero delta time, nearest power of 10: %ums\n",
	    avg_nonzero_delta); 
    
    /*********** OUTPUT THE .h and .c FILES ********************************/

    fprintf(stderr, "Creating %s and %s\n", HEADER_OUT, VARS_OUT );
    header = fopen( HEADER_OUT, "w");
    vars = fopen( VARS_OUT, "w");
    
    fprintf(header, "/* this file is automagically generated by masbench */\n\n");
    fprintf(vars, "/* this file is automagically generated by masbench */\n\n");

    fprintf(header, "#ifndef _MAS_NANOSLEEP_REALITY_H\n");
    fprintf(header, "#define _MAS_NANOSLEEP_REALITY_H\n\n");

    if (real_time)
    {
	fprintf(header, "/*** Results are for real-time scheduling ********/\n\n");
	fprintf(vars, "/*** Results are for real-time scheduling ********/\n\n");
    }

    fprintf(header, "#define MAS_MIN_SLEEP %u\n", real_min);
    fprintf(header, "#define MAS_MAX_SLEEP %u\n\n", real_max);
    
    fprintf(header, "extern u_int32 mas_nanosleep_real_value[];\n");
    fprintf(header, "extern u_int32 mas_nanosleep_real_wall_clock[];\n");
   
    fprintf(header, "\n#endif /* _MAS_NANOSLEEP_REALITY_H */\n\n");

    fprintf(vars, "#include \"mas/mas_types.h\"\n\n");

    fprintf(vars, "u_int32 mas_nanosleep_real_value[] = {\n");
    for (i=0; i<unique; i++)
    {
	fprintf(vars, "    %u,\n", value[i]);
    }
    fprintf(vars, "    0 };\n\n");
    
    fprintf(vars, "u_int32 mas_nanosleep_real_wall_clock[] = {\n");
    for (i=0; i<unique; i++)
    {
	fprintf(vars, "    %u,\n", wall_clock[i]);
    }
    fprintf(vars, "    0 };\n\n");
    
    fclose(header);
    fclose(vars);

    masc_exit_timing();
    
    exit(0);
}
