• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@us.ibm.com>
31  *
32  * HISTORY
33  *      2007-May-2: Initial version by Darren Hart <dvhltc@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 
usage(void)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 
calc(int loops)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 
periodic_thread(nsec_t period,int iterations,int loops)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 
parse_args(int c,char * v)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 
main(int argc,char * argv[])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