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