base/arch/i386/calibration/calibrate.c

Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 2003 Paolo Mantegazza <mantegazza@aero.polimi.it> 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00017 */ 00018 00019 #include <float.h> 00020 #include <stdio.h> 00021 #include <stdlib.h> 00022 #include <ctype.h> 00023 #include <signal.h> 00024 #include <string.h> 00025 #include <sys/mman.h> 00026 #include <sys/io.h> 00027 #include <getopt.h> 00028 #include <pthread.h> 00029 #include <math.h> 00030 00031 #include <stdio.h> 00032 #include <stdlib.h> 00033 #include <errno.h> 00034 #include <termio.h> 00035 #include <sys/poll.h> 00036 #include <sys/wait.h> 00037 #include <fcntl.h> 00038 #include <unistd.h> 00039 #include <ctype.h> 00040 #include <time.h> 00041 #include <signal.h> 00042 00043 #include <asm/rtai_srq.h> 00044 #include <rtai_fifos.h> 00045 #include "calibrate.h" 00046 00047 struct option options[] = { 00048 { "help", 0, 0, 'h' }, 00049 { "r8254", 0, 0, 'r' }, 00050 { "kernel", 0, 0, 'k' }, 00051 { "user", 0, 0, 'u' }, 00052 { "period", 1, 0, 'p' }, 00053 { "time", 1, 0, 't' }, 00054 { "cpu", 0, 0, 'c' }, 00055 { "apic", 0, 0, 'a' }, 00056 { "both", 0, 0, 'b' }, 00057 { "scope", 1, 0, 's' }, 00058 { "interrupt", 0, 0, 'i' }, 00059 { NULL, 0, 0, 0 } 00060 }; 00061 00062 void print_usage(void) 00063 { 00064 fputs( 00065 ("\n*** i386 calibrations ***\n" 00066 "\n" 00067 "OPTIONS:\n" 00068 " -h, --help\n" 00069 " print usage\n" 00070 " -r, --r8254\n" 00071 " calibrate 8254 oneshot programming type\n" 00072 " -k, --kernel\n" 00073 " oneshot latency calibrated for scheduling kernel space tasks\n" 00074 " -u, --user\n" 00075 " oneshot latency calibrated for scheduling user space tasks\n" 00076 " -p <period (us)>, --period <period (us)>\n" 00077 " the period of the underlying hard real time task/intr, default 100 (us)\n" 00078 " -t <duration (s)>, --time <duration (s)>\n" 00079 " set the duration of the requested calibration, default 5 (s)\n" 00080 " -c, --cpufreq\n" 00081 " calibrate cpu frequency\n" 00082 " -a, --apic\n" 00083 " calibrate apic frequency\n" 00084 " -b, --both\n" 00085 " calibrate both apic and cpu frequency\n" 00086 " -i, --interrupt\n" 00087 " check worst case interrupt locking/contention on your PC\n" 00088 " -s<y/n>, --scope<y/n>\n" 00089 " toggle parport bit to monitor scheduling on a scope, default y(es)\n" 00090 "\n") 00091 , stderr); 00092 } 00093 00094 static void endme(int dummy) { } 00095 00096 static void unload_kernel_helper (void) 00097 00098 { 00099 char modunload[1024]; 00100 00101 snprintf(modunload,sizeof(modunload),"/sbin/rmmod %s >/dev/null 2>&1",KERNEL_HELPER_PATH); 00102 system(modunload); 00103 } 00104 00105 int main(int argc, char *argv[]) 00106 { 00107 int srq, fifo, command, commands[20], ncommands, c, option_index, i; 00108 struct params_t params; 00109 char str[80], nm[RTF_NAMELEN+1], modload[1024]; 00110 unsigned long period = 100, duration = 5, parport = 'y'; 00111 unsigned long args[MAXARGS]; 00112 struct pollfd polls[2] = { { 0, POLLIN }, { 0, POLLIN } }; 00113 00114 option_index = ncommands = 0; 00115 while (1) { 00116 if ((c = getopt_long(argc, argv, "hrkucabip:t:s:", options, &option_index)) == -1) { 00117 break; 00118 } 00119 switch(c) { 00120 case 'h': { 00121 print_usage(); 00122 exit(0); 00123 } 00124 case 'r': 00125 case 'u': 00126 case 'c': 00127 case 'b': 00128 case 'a': 00129 case 'i': 00130 case 'k': { 00131 commands[ncommands++] = c; 00132 break; 00133 } 00134 case 'p': { 00135 period = atoi(optarg); 00136 break; 00137 } 00138 case 't': { 00139 duration = atoi(optarg); 00140 break; 00141 } 00142 case 's': { 00143 parport = optarg[0] == 'y' ? 'y' : 'n'; 00144 break; 00145 } 00146 } 00147 } 00148 if (ncommands <= 0) { 00149 printf("\n*** NOTHING TO BE DONE ***\n"); 00150 exit(0); 00151 } 00152 00153 atexit(&unload_kernel_helper); 00154 00155 snprintf(modload,sizeof(modload),"/sbin/insmod %s >/dev/null 2>&1",KERNEL_HELPER_PATH); 00156 system(modload); 00157 00158 signal(SIGINT, endme); 00159 00160 srq = rtai_open_srq(CALSRQ); 00161 if ((fifo = open(rtf_getfifobyminor(0,nm,sizeof(nm)), O_RDONLY)) < 0) { 00162 printf("Error opening %s\n",nm); 00163 exit(1); 00164 } 00165 polls[1].fd = fifo; 00166 00167 args[0] = GET_PARAMS; 00168 rtai_srq(srq, (unsigned long)args); 00169 read(fifo, &params, sizeof(params)); 00170 printf("\n*** NUMBER OF REQUESTS: %d. ***\n", ncommands); 00171 00172 for (i = 0; i < ncommands; i++) { 00173 switch (command = commands[i]) { 00174 00175 case 'r': { 00176 args[0] = CAL_8254; 00177 printf("\n*** '#define SETUP_TIME_8254 %lu', IN USE %lu ***\n\n", (unsigned long) rtai_srq(srq, (unsigned long)args), params.setup_time_8254); 00178 break; 00179 } 00180 00181 case 'k': { 00182 int average; 00183 args[0] = KLATENCY; 00184 args[1] = period; 00185 args[2] = duration; 00186 printf("\n*** KERNEL SPACE LATENCY CALIBRATION, wait %lu seconds for it ... ***\n", args[2]); 00187 args[2] = (1000000*args[2])/args[1]; 00188 args[1] *= 1000; 00189 rtai_srq(srq, (unsigned long)args); 00190 read(fifo, &average, sizeof(average)); 00191 average /= (int)args[2]; 00192 if (params.mp) { 00193 printf("\n*** '#define LATENCY_APIC %d' (IN USE %lu)\n\n", (int)params.latency_apic + average, params.latency_apic); 00194 } else { 00195 printf("\n*** '#define LATENCY_8254 %d' (IN USE %lu)\n\n", (int)params.latency_8254 + average, params.latency_8254); 00196 } 00197 args[0] = END_KLATENCY; 00198 rtai_srq(srq, (unsigned long)args); 00199 break; 00200 } 00201 00202 case 'u': { 00203 int pid, average; 00204 args[1] = period; 00205 args[2] = duration; 00206 printf("\n*** USER SPACE LATENCY CALIBRATION, wait %lu seconds for it ... ***\n", args[2]); 00207 args[2] = (1000000*args[2])/args[1]; 00208 args[1] *= 1000; 00209 sprintf(str, "%lu", args[1]); 00210 sprintf(str + sizeof(str)/2, "%lu", args[2]); 00211 pid = fork(); 00212 if (!pid) { 00213 execl(USER_HELPER_PATH, USER_HELPER_PATH, str, str + sizeof(str)/2, NULL); 00214 _exit(1); 00215 } 00216 read(fifo, &average, sizeof(average)); 00217 waitpid(pid, 0, 0); 00218 if (kill(pid,0) < 0) 00219 { 00220 // printf("\n*** Cannot execute calibration helper %s -- aborting\n",USER_HELPER_PATH); 00221 // exit(1); 00222 } 00223 average /= (int)args[2]; 00224 if (params.mp) { 00225 printf("\n*** '#define LATENCY_APIC %d' (IN USE %lu)\n\n", (int)params.latency_apic + average, params.latency_apic); 00226 } else { 00227 printf("\n*** '#define LATENCY_8254 %d' (IN USE %lu)\n\n", (int)params.latency_8254 + average, params.latency_8254); 00228 } 00229 break; 00230 } 00231 00232 case 'a': 00233 if (!params.mp) { 00234 printf("*** APIC FREQUENCY CALIBRATION NOT AVAILABLE UNDER UP ***\n"); 00235 break; 00236 } 00237 case 'b': 00238 case 'c': { 00239 unsigned long time, cpu_freq = 0, apic_freq = 0; 00240 struct times_t times; 00241 args[0] = FREQ_CAL; 00242 args[1] = duration; 00243 printf("\n->>> FREQ CALIB (PRINTING EVERY %lu SECONDS, press enter to end calibrating) <<<-\n\n", args[1]); 00244 rtai_srq(srq, (unsigned long)args); 00245 time = 0; 00246 while (1) { 00247 time += args[1]; 00248 if (poll(polls, 2, 1000*duration) > 0 &&polls[0].revents) { 00249 getchar(); 00250 args[0] = END_FREQ_CAL; 00251 rtai_srq(srq, (unsigned long)args); 00252 if (command == 'c' || command == 'b') { 00253 printf("\n*** '#define CPU_FREQ %lu', IN USE %lu ***\n\n", cpu_freq, params.cpu_freq); 00254 } 00255 if (params.mp && (command == 'a' || command == 'b')) { 00256 printf("\n*** '#define APIC_FREQ %lu', IN USE %lu ***\n\n", apic_freq, params.freq_apic); 00257 } 00258 break; 00259 } 00260 read(fifo, &times, sizeof(times)); 00261 if (command == 'c' || command == 'b') { 00262 cpu_freq = (((double)times.cpu_time)*params.clock_tick_rate)/(((double)times.intrs)*params.latch) + 0.49999999999999999; 00263 printf("\n->>> MEASURED CPU_FREQ: %lu (Hz) [%lu (s)], IN USE %lu (Hz) <<<-\n", cpu_freq, time, params.cpu_freq); 00264 } 00265 if (params.mp && (command == 'a' || command == 'b')) { 00266 apic_freq = (((double)times.apic_time)*params.clock_tick_rate)/(((double)times.intrs)*params.latch) + 0.49999999999999999; 00267 printf("\n->>> MEASURED APIC_FREQ: %lu (Hz) [%lu (s)], IN USE %lu (Hz) <<<-\n", apic_freq, time, params.freq_apic); 00268 } 00269 } 00270 break; 00271 } 00272 00273 case 'i': { 00274 time_t timestamp; 00275 struct tm *tm_timestamp; 00276 args[0] = BUS_CHECK; 00277 args[1] = period; 00278 args[2] = 1; 00279 args[3] = parport; 00280 printf("\n->>> INTERRUPT LATENCY CHECK (press enter to end check) <<<-\n\n"); 00281 args[1] *= 1000; 00282 args[2] *= 1000; 00283 rtai_srq(srq, (unsigned long)args); 00284 while (1) { 00285 int maxj; 00286 if (poll(polls, 2, 100) > 0) { 00287 if (polls[0].revents) { 00288 getchar(); 00289 args[0] = END_BUS_CHECK; 00290 rtai_srq(srq, (unsigned long)args); 00291 break; 00292 } 00293 read(fifo, &maxj, sizeof(maxj)); 00294 time(&timestamp); 00295 tm_timestamp = localtime(&timestamp); 00296 printf("%04d/%02d/%0d-%02d:%02d:%02d -> ", tm_timestamp->tm_year+1900, tm_timestamp->tm_mon+1, tm_timestamp->tm_mday, tm_timestamp->tm_hour, tm_timestamp->tm_min, tm_timestamp->tm_sec); 00297 printf("%d.%-3d (us)\n", maxj/1000, maxj%1000); 00298 } 00299 } 00300 break; 00301 } 00302 00303 } 00304 } 00305 exit(0); 00306 }

Generated on Thu Nov 20 11:49:47 2008 for RTAI API by doxygen 1.3.8