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