Home | History | Annotate | Download | only in periodic_cpu_load
      1 /******************************************************************************
      2  *
      3  *   Copyright  International Business Machines  Corp., 2006, 2008
      4  *
      5  *   This program is free software;  you can redistribute it and/or modify
      6  *   it under the terms of the GNU General Public License as published by
      7  *   the Free Software Foundation; either version 2 of the License, or
      8  *   (at your option) any later version.
      9  *
     10  *   This program is distributed in the hope that it will be useful,
     11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     13  *   the GNU General Public License for more details.
     14  *
     15  *   You should have received a copy of the GNU General Public License
     16  *   along with this program;  if not, write to the Free Software
     17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     18  *
     19  * NAME
     20  *      periodic_cpu_load_single.c
     21  *
     22  * DESCRIPTION
     23  *      Measure variation in computational execution time
     24  *      at the specified period, priority, and loops.
     25  *
     26  * USAGE:
     27  *      Use run_auto.sh script in current directory to build and run test.
     28  *
     29  * AUTHOR
     30  *      Darren Hart <dvhltc (at) us.ibm.com>
     31  *
     32  * HISTORY
     33  *      2007-May-2: Initial version by Darren Hart <dvhltc (at) us.ibm.com>
     34  *
     35  *      This line has to be added to avoid a stupid CVS problem
     36  *****************************************************************************/
     37 
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 #include <math.h>
     41 #include <librttest.h>
     42 #include <libstats.h>
     43 
     44 #define HIST_BUCKETS 100
     45 
     46 // define sane defaults
     47 #define DEFAULT_ITERATIONS 10000	/* 1000 is the min for 3 nines */
     48 #define DEFAULT_PERIOD 5
     49 #define DEFAULT_PRIO   90
     50 #define DEFAULT_CALC_LOOPS 1000
     51 #define LOOPS_MULTIPLIER 4.2
     52 #define DEFAULT_FILENAME_PREFIX "pcl"
     53 
     54 static int prio;
     55 static int period;
     56 static int calc_loops;
     57 static int ret = 0;
     58 static char *filename_prefix = DEFAULT_FILENAME_PREFIX;
     59 static int iterations = DEFAULT_ITERATIONS;
     60 
     61 void usage(void)
     62 {
     63 	rt_help();
     64 	printf("periodic_cpu_load_single specific options:\n");
     65 	printf("  -lCALC_LOOPS	loops per iteration\n");
     66 	printf("  -fFILENAME_PREFIX    filename prefix for plot output\n");
     67 	printf
     68 	    ("  -iITERATIONS  number of iterations to calculate the average over\n");
     69 	printf("  -r[0-99]	real-time priority\n");
     70 	printf("  -tPERIOD	period in ms\n");
     71 }
     72 
     73 void *calc(int loops)
     74 {
     75 	int i, j;
     76 	for (i = 0; i < loops * LOOPS_MULTIPLIER; i++) {
     77 		for (j = 0; j < 125; j++) {
     78 			// Sum of the numbers up to J
     79 			volatile int temp = j * (j + 1) / 2;
     80 			(void)temp;
     81 		}
     82 	}
     83 	return NULL;
     84 }
     85 
     86 int periodic_thread(nsec_t period, int iterations, int loops)
     87 {
     88 	stats_container_t dat;
     89 	stats_container_t hist;
     90 	stats_quantiles_t quantiles;
     91 	stats_record_t rec;
     92 
     93 	int i = 0;
     94 	int fail = 0;
     95 	nsec_t next, now;
     96 	nsec_t exe_start, exe_end, exe_time;
     97 	char *samples_filename;
     98 	char *hist_filename;
     99 
    100 	stats_container_init(&dat, iterations);
    101 	stats_container_init(&hist, HIST_BUCKETS);
    102 	stats_quantiles_init(&quantiles, (int)log10(iterations));
    103 	if (asprintf(&samples_filename, "%s-samples", filename_prefix) == -1) {
    104 		fprintf(stderr,
    105 			"Failed to allocate string for samples filename\n");
    106 		return -1;
    107 	}
    108 
    109 	if (asprintf(&hist_filename, "%s-hist", filename_prefix) == -1) {
    110 		fprintf(stderr,
    111 			"Failed to allocate string for samples filename\n");
    112 		return -1;
    113 	}
    114 	next = rt_gettime();
    115 	while (i < iterations) {
    116 		next += period;
    117 		now = rt_gettime();
    118 		if (now > next) {
    119 			printf
    120 			    ("Missed period, aborting (didn't get scheduled in time)\n");
    121 			fail = 1;
    122 			break;
    123 		}
    124 		exe_start = rt_gettime();
    125 		calc(loops);
    126 		exe_end = rt_gettime();
    127 		exe_time = exe_end - exe_start;
    128 		rec.x = i;
    129 		rec.y = exe_time / NS_PER_US;
    130 		stats_container_append(&dat, rec);
    131 
    132 		i++;
    133 
    134 		now = rt_gettime();
    135 		if (now > next) {
    136 			printf
    137 			    ("Missed period, aborting (calc took too long)\n");
    138 			fail = 1;
    139 			break;
    140 		}
    141 		rt_nanosleep(next - now);
    142 	}
    143 
    144 	stats_container_save(samples_filename, "Periodic CPU Load Scatter Plot",
    145 			     "Iteration", "Runtime (us)", &dat, "points");
    146 	stats_container_save(hist_filename, "Periodic CPU Load Histogram",
    147 			     "Runtime (us)", "Samples", &hist, "steps");
    148 
    149 	printf("  Execution Time Statistics:\n");
    150 	printf("Min: %ld us\n", stats_min(&dat));
    151 	printf("Max: %ld us\n", stats_max(&dat));
    152 	printf("Avg: %.4f us\n", stats_avg(&dat));
    153 	printf("StdDev: %.4f us\n", stats_stddev(&dat));
    154 	printf("Quantiles:\n");
    155 	stats_quantiles_calc(&dat, &quantiles);
    156 	stats_quantiles_print(&quantiles);
    157 	printf("Criteria: no missed periods\n");
    158 	printf("Result: %s\n", fail ? "FAIL" : "PASS");
    159 
    160 	free(samples_filename);
    161 	free(hist_filename);
    162 
    163 	return fail;
    164 }
    165 
    166 int parse_args(int c, char *v)
    167 {
    168 	int handled = 1;
    169 	switch (c) {
    170 	case 'l':
    171 		calc_loops = atoi(v);
    172 		break;
    173 	case 'f':
    174 		filename_prefix = v;
    175 		break;
    176 	case 'h':
    177 		usage();
    178 		exit(0);
    179 	case 'i':
    180 		iterations = atoi(v);
    181 		break;
    182 	case 'r':
    183 		prio = atoi(v);
    184 		break;
    185 	case 't':
    186 		period = atoi(v) * NS_PER_MS;
    187 		break;
    188 	default:
    189 		handled = 0;
    190 		break;
    191 	}
    192 	return handled;
    193 }
    194 
    195 int main(int argc, char *argv[])
    196 {
    197 	period = DEFAULT_PERIOD * NS_PER_MS;
    198 	prio = DEFAULT_PRIO;
    199 	calc_loops = DEFAULT_CALC_LOOPS;
    200 	setup();
    201 
    202 	rt_init("f:hi:r:t:l:", parse_args, argc, argv);
    203 
    204 	if (iterations < 100) {
    205 		printf("Number of iterations cannot be less than 100\n");
    206 		exit(1);
    207 	}
    208 
    209 	if (!period || !prio | !calc_loops) {
    210 		usage();
    211 		exit(1);
    212 	}
    213 
    214 	set_priority(prio);
    215 
    216 	printf("------------------------------------\n");
    217 	printf("Periodic CPU Load Execution Variance\n");
    218 	printf("------------------------------------\n\n");
    219 	printf("Running %d iterations\n", iterations);
    220 	printf("priority: %d\n", prio);
    221 	printf("  period: %d ms\n", period / NS_PER_MS);
    222 	printf("   loops: %d\n", calc_loops);
    223 	printf("    logs: %s*\n", filename_prefix);
    224 
    225 	ret = periodic_thread(period, iterations, calc_loops);
    226 
    227 	return ret;
    228 }
    229