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.c
     21  *
     22  * DESCRIPTION
     23  *      Measure variation in computational execution time
     24  *      at various periods and priorities.
     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-April-27:    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 PRIO_A 63
     45 #define PRIO_B 53
     46 #define PRIO_C 43
     47 
     48 #define PERIOD_A 40*NS_PER_MS
     49 #define PERIOD_B 80*NS_PER_MS
     50 #define PERIOD_C 160*NS_PER_MS
     51 
     52 #define CALC_LOOPS_A (27*100)
     53 #define CALC_LOOPS_B (50*100)
     54 #define CALC_LOOPS_C (72*100)
     55 
     56 #define NUM_GROUPS 3
     57 #define THREADS_PER_GROUP 4
     58 
     59 //#define ITERATIONS 100 /* short functional test run */
     60 #define ITERATIONS 6000		/* about 15 minutes @ 2GHz on 1 CPU */
     61 //#define ITERATIONS 1000 /* min iters for 3 nines */
     62 // FIXME: need some kind of passing criteria calculation
     63 //#define PASS_US 100
     64 
     65 int fail[THREADS_PER_GROUP * NUM_GROUPS];
     66 stats_container_t dat[THREADS_PER_GROUP * NUM_GROUPS];
     67 stats_record_t rec;
     68 stats_quantiles_t quantiles[THREADS_PER_GROUP * NUM_GROUPS];
     69 static const char groupname[NUM_GROUPS] = "ABC";
     70 
     71 static int iterations = ITERATIONS;
     72 static int ret = 0;
     73 
     74 void usage(void)
     75 {
     76 	rt_help();
     77 	printf("periodic_cpu_load specific options:\n");
     78 	printf
     79 	    ("  -iITERATIONS  number of iterations to calculate the average over\n");
     80 }
     81 
     82 int parse_args(int c, char *v)
     83 {
     84 	int handled = 1;
     85 	switch (c) {
     86 		break;
     87 	case 'i':
     88 		iterations = atoi(v);
     89 		break;
     90 	case 'h':
     91 		usage();
     92 		exit(0);
     93 	default:
     94 		handled = 0;
     95 		break;
     96 	}
     97 	return handled;
     98 }
     99 
    100 struct periodic_arg {
    101 	int period;
    102 	int iterations;
    103 	void *(*func) (void *);
    104 	void *arg;
    105 };
    106 
    107 void *calc(void *arg)
    108 {
    109 	int i, j;
    110 	int loops = (intptr_t) arg;
    111 	for (i = 0; i < loops; i++) {
    112 		for (j = 0; j < 125; j++) {
    113 			// Sum of the numbers up to J
    114 			int temp = j * (j + 1) / 2;
    115 			(void)temp;
    116 		}
    117 	}
    118 	return NULL;
    119 }
    120 
    121 void *periodic_thread(void *thread)
    122 {
    123 	struct thread *t = (struct thread *)thread;
    124 	struct periodic_arg *parg = (struct periodic_arg *)t->arg;
    125 	nsec_t period = parg->period;
    126 	void *(*func) (void *) = parg->func;
    127 
    128 	int i = 0;
    129 	nsec_t next, now;
    130 	nsec_t exe_start, exe_end, exe_time;
    131 
    132 	next = rt_gettime();
    133 	while (i < parg->iterations) {
    134 		next += period;
    135 		if (rt_gettime() > next) {
    136 			printf("TID %d missed period, aborting\n", t->id);
    137 			fail[t->id] = 1;
    138 			break;
    139 		}
    140 		exe_start = rt_gettime();
    141 		func(parg->arg);
    142 		exe_end = rt_gettime();
    143 		exe_time = exe_end - exe_start;
    144 		rec.x = i;
    145 		rec.y = exe_time / NS_PER_US;
    146 		stats_container_append(&dat[t->id], rec);
    147 
    148 		i++;
    149 
    150 		now = rt_gettime();
    151 		if (now > next) {
    152 			printf
    153 			    ("Missed period, aborting (calc took too long)\n");
    154 			fail[t->id] = 1;
    155 			break;
    156 		}
    157 		rt_nanosleep(next - now);
    158 	}
    159 
    160 	printf("TID %d (%c - prio %d) complete\n", t->id, groupname[t->id >> 2],
    161 	       t->priority);
    162 
    163 	return NULL;
    164 }
    165 
    166 int main(int argc, char *argv[])
    167 {
    168 	int i;
    169 	setup();
    170 
    171 	rt_init("hi:", parse_args, argc, argv);
    172 
    173 	if (iterations < 100) {
    174 		fprintf(stderr,
    175 			"Number of iteration cannot be less than 100.\n");
    176 		exit(1);
    177 	}
    178 
    179 	printf("------------------------------------\n");
    180 	printf("Periodic CPU Load Execution Variance\n");
    181 	printf("------------------------------------\n\n");
    182 	printf("Running %d iterations per thread\n", iterations);
    183 	printf("Thread Group A:\n");
    184 	printf("  threads: %d\n", THREADS_PER_GROUP);
    185 	printf("  priority: %d\n", PRIO_A);
    186 	printf("  period: %d ms\n", PERIOD_A / NS_PER_MS);
    187 	printf("Thread Group B:\n");
    188 	printf("  threads: %d\n", THREADS_PER_GROUP);
    189 	printf("  priority: %d\n", PRIO_B);
    190 	printf("  period: %d ms\n", PERIOD_B / NS_PER_MS);
    191 	printf("Thread Group C:\n");
    192 	printf("  threads: %d\n", THREADS_PER_GROUP);
    193 	printf("  priority: %d\n", PRIO_C);
    194 	printf("  period: %d ms\n", PERIOD_C / NS_PER_MS);
    195 	printf("\n");
    196 
    197 	for (i = 0; i < (THREADS_PER_GROUP * NUM_GROUPS); i++) {
    198 		stats_container_init(&dat[i], iterations);
    199 		stats_quantiles_init(&quantiles[i], (int)log10(iterations));
    200 	}
    201 
    202 	struct periodic_arg parg_a =
    203 	    { PERIOD_A, iterations, calc, (void *)CALC_LOOPS_A };
    204 	struct periodic_arg parg_b =
    205 	    { PERIOD_B, iterations, calc, (void *)CALC_LOOPS_B };
    206 	struct periodic_arg parg_c =
    207 	    { PERIOD_C, iterations, calc, (void *)CALC_LOOPS_C };
    208 
    209 	for (i = 0; i < THREADS_PER_GROUP; i++)
    210 		create_fifo_thread(periodic_thread, (void *)&parg_a, PRIO_A);
    211 	for (i = 0; i < THREADS_PER_GROUP; i++)
    212 		create_fifo_thread(periodic_thread, (void *)&parg_b, PRIO_B);
    213 	for (i = 0; i < THREADS_PER_GROUP; i++)
    214 		create_fifo_thread(periodic_thread, (void *)&parg_c, PRIO_C);
    215 
    216 	join_threads();
    217 
    218 	printf("\nExecution Time Statistics:\n\n");
    219 
    220 	for (i = 0; i < (THREADS_PER_GROUP * NUM_GROUPS); i++) {
    221 		printf("TID %d (%c)\n", i, groupname[i >> 2]);
    222 		printf("  Min: %ld us\n", stats_min(&dat[i]));
    223 		printf("  Max: %ld us\n", stats_max(&dat[i]));
    224 		printf("  Avg: %f us\n", stats_avg(&dat[i]));
    225 		printf("  StdDev: %f us\n\n", stats_stddev(&dat[i]));
    226 		printf("  Quantiles:\n");
    227 		stats_quantiles_calc(&dat[i], &quantiles[i]);
    228 		stats_quantiles_print(&quantiles[i]);
    229 		printf("Criteria: TID %d did not miss a period\n", i);
    230 		printf("Result: %s\n", fail[i] ? "FAIL" : "PASS");
    231 		printf("\n");
    232 
    233 		if (fail[i])
    234 			ret = 1;
    235 	}
    236 
    237 	// FIXME: define pass criteria
    238 	// printf("\nCriteria: latencies < %d us\n", PASS_US);
    239 	// printf("Result: %s\n", ret ? "FAIL" : "PASS");
    240 
    241 	for (i = 0; i < (THREADS_PER_GROUP * NUM_GROUPS); i++) {
    242 		stats_container_free(&dat[i]);
    243 		stats_quantiles_free(&quantiles[i]);
    244 	}
    245 
    246 	return ret;
    247 }
    248