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     { "kthreads",   0, 0, 'x' },
00052     { "user",       0, 0, 'u' },
00053     { "period",     1, 0, 'p' },
00054     { "time",       1, 0, 't' },
00055     { "cpu",        0, 0, 'c' },
00056     { "apic",       0, 0, 'a' },
00057     { "both",       0, 0, 'b' },
00058     { "scope",      1, 0, 's' },
00059     { "interrupt",  0, 0, 'i' },
00060     { NULL,         0, 0,  0 }
00061 };
00062 
00063 void print_usage(void)
00064 {
00065     fputs(
00066     ("\n*** i386 calibrations ***\n"
00067      "\n"
00068      "OPTIONS:\n"
00069      "  -h, --help\n"
00070      "      print usage\n"
00071      "  -r, --r8254\n"
00072      "      calibrate 8254 oneshot programming type\n"
00073      "  -k, --kernel\n"
00074      "      oneshot latency calibrated for scheduling RTAI own kernel space tasks\n"
00075      "  -x, --kthreads\n"
00076      "      oneshot latency calibrated for scheduling hardened Linux kthreads\n"
00077      "  -u, --user\n"
00078      "      oneshot latency calibrated for scheduling user space tasks\n"
00079      "  -p <period (us)>, --period <period (us)>\n"
00080      "      the period of the underlying hard real time task/intr, default 100 (us)\n"
00081      "  -t <duration (s)>, --time <duration (s)>\n"
00082      "      set the duration of the requested calibration, default 5 (s)\n"
00083      "  -c, --cpufreq\n"
00084      "      calibrate cpu frequency\n"
00085      "  -a, --apic\n"
00086      "      calibrate apic frequency\n"
00087      "  -b, --both\n"
00088      "      calibrate both apic and cpu frequency\n"
00089      "  -i, --interrupt\n"
00090      "      check worst case interrupt locking/contention on your PC\n"
00091      "  -s<y/n>, --scope<y/n>\n"
00092      "      toggle parport bit to monitor scheduling on a scope, default y(es)\n"
00093      "\n")
00094     , stderr);
00095 }
00096 
00097 static void endme(int dummy) { }
00098 
00099 static void unload_kernel_helper (void)
00100 
00101 {
00102     char modunload[1024];
00103 
00104     snprintf(modunload,sizeof(modunload),"/sbin/rmmod %s >/dev/null 2>&1",KERNEL_HELPER_PATH);
00105     system(modunload);
00106 }
00107 
00108 int main(int argc, char *argv[])
00109 {
00110     int srq, fifo, command, commands[20], ncommands, c, option_index, i;
00111     struct params_t params;
00112     char str[80], nm[RTF_NAMELEN+1], modload[1024];
00113     unsigned long period = 100, duration = 5, parport = 'y';
00114     unsigned long args[MAXARGS];
00115     struct pollfd polls[2] = { { 0, POLLIN }, { 0, POLLIN } };
00116 
00117     option_index = ncommands = 0;
00118     while (1) {
00119         if ((c = getopt_long(argc, argv, "hrkxucabip:t:s:", options, &option_index)) == -1) {
00120             break;
00121         }
00122         switch(c) {
00123             case 'h': {
00124                 print_usage();
00125                 exit(0);
00126             }
00127             case 'r':
00128             case 'u':
00129             case 'c':
00130             case 'b':
00131             case 'a':
00132             case 'i':
00133             case 'x':
00134             case 'k': {
00135                 commands[ncommands++] = c;
00136                 break;
00137             }
00138             case 'p': {
00139                 period = atoi(optarg);
00140                 break;
00141             }
00142             case 't': {
00143                 duration = atoi(optarg);
00144                 break;
00145             }
00146             case 's': {
00147                 parport = optarg[0] == 'y' ? 'y' : 'n';
00148                 break;
00149             }
00150         }
00151     }
00152     if (ncommands <= 0) {
00153         printf("\n*** NOTHING TO BE DONE ***\n");
00154         exit(0);
00155     }
00156 
00157     atexit(&unload_kernel_helper);
00158 
00159     snprintf(modload,sizeof(modload),"/sbin/insmod %s >/dev/null 2>&1",KERNEL_HELPER_PATH);
00160     system(modload);
00161 
00162     signal(SIGINT, endme);
00163 
00164     srq = rtai_open_srq(CALSRQ);
00165     if ((fifo = open(rtf_getfifobyminor(0,nm,sizeof(nm)), O_RDONLY)) < 0) {
00166         printf("Error opening %s\n",nm);
00167         exit(1);
00168     }
00169     polls[1].fd = fifo;
00170 
00171     args[0] = GET_PARAMS;
00172     rtai_srq(srq, (unsigned long)args);
00173     read(fifo, &params, sizeof(params));
00174     printf("\n*** NUMBER OF REQUESTS: %d. ***\n", ncommands);
00175 
00176     for (i = 0; i < ncommands; i++) {
00177         switch (command = commands[i]) {
00178 
00179             case 'r': {
00180                 args[0] = CAL_8254;
00181                 printf("\n*** '#define SETUP_TIME_8254 %lu', IN USE %lu ***\n\n", (unsigned long) rtai_srq(srq, (unsigned long)args), params.setup_time_8254);
00182                 break;
00183             }
00184 
00185             case 'x':
00186             case 'k': {
00187                 int average;
00188                 args[0] = command == 'k' ? KLATENCY : KTHREADS;
00189                 args[1] = period;
00190                 args[2] = duration;
00191                 printf("\n*** KERNEL SPACE LATENCY CALIBRATION (%s), wait %lu seconds for it ... ***\n", command == 'k' ? "RTAI TASKS" : "KTHREADS", args[2]);
00192                 args[2] = (1000000*args[2])/args[1];
00193                 args[1] *= 1000;
00194                 rtai_srq(srq, (unsigned long)args);
00195                 read(fifo, &average, sizeof(average));
00196                 average /= (int)args[2];
00197                     if (params.mp) {
00198                         printf("\n*** '#define LATENCY_APIC %d' (IN USE %lu)\n\n", (int)params.latency_apic + average, params.latency_apic);
00199                 } else {
00200                     printf("\n*** '#define LATENCY_8254 %d' (IN USE %lu)\n\n", (int)params.latency_8254 + average, params.latency_8254);
00201                 }
00202                 args[0] = END_KLATENCY;
00203                 rtai_srq(srq, (unsigned long)args);
00204                 break;
00205             }
00206 
00207             case 'u': {
00208                 int pid, average;
00209                 args[1] = period;
00210                 args[2] = duration;
00211                 printf("\n*** USER SPACE LATENCY CALIBRATION, wait %lu seconds for it ... ***\n", args[2]);
00212                 args[2] = (1000000*args[2])/args[1];
00213                 args[1] *= 1000;
00214                 sprintf(str, "%lu", args[1]);
00215                 sprintf(str + sizeof(str)/2, "%lu", args[2]);
00216                 pid = fork();
00217                 if (!pid) {
00218                     execl(USER_HELPER_PATH, USER_HELPER_PATH, str, str + sizeof(str)/2, NULL);
00219                     _exit(1);
00220                 }
00221                 read(fifo, &average, sizeof(average));
00222                 waitpid(pid, 0, 0);
00223                 if (kill(pid,0) < 0)
00224                     {
00225 //                  printf("\n*** Cannot execute calibration helper %s -- aborting\n",USER_HELPER_PATH);
00226 //                  exit(1);
00227                     }
00228                 average /= (int)args[2];
00229                     if (params.mp) {
00230                         printf("\n*** '#define LATENCY_APIC %d' (IN USE %lu)\n\n", (int)params.latency_apic + average, params.latency_apic);
00231                 } else {
00232                     printf("\n*** '#define LATENCY_8254 %d' (IN USE %lu)\n\n", (int)params.latency_8254 + average, params.latency_8254);
00233                 }
00234                 break;
00235             }
00236 
00237             case 'a': 
00238                 if (!params.mp) {
00239                     printf("*** APIC FREQUENCY CALIBRATION NOT AVAILABLE UNDER UP ***\n");  
00240                     break;  
00241                 }
00242             case 'b':
00243             case 'c': {
00244                 unsigned long time, cpu_freq = 0, apic_freq = 0;
00245                 struct times_t times;
00246                 args[0] = FREQ_CAL;
00247                 args[1] = duration;
00248                 printf("\n->>> FREQ CALIB (PRINTING EVERY %lu SECONDS, press enter to end calibrating) <<<-\n\n", args[1]);
00249                 rtai_srq(srq, (unsigned long)args);
00250                 time = 0;
00251                 while (1) {
00252                     time += args[1];
00253                     if (poll(polls, 2, 1000*duration) > 0 &&polls[0].revents) {
00254                         getchar();
00255                         args[0] = END_FREQ_CAL;
00256                         rtai_srq(srq, (unsigned long)args);
00257                         if (command == 'c' || command == 'b') {
00258                             printf("\n*** '#define CPU_FREQ %lu', IN USE %lu ***\n\n", cpu_freq, params.cpu_freq);
00259                         }
00260                         if (params.mp && (command == 'a' || command == 'b')) {
00261                             printf("\n*** '#define APIC_FREQ %lu', IN USE %lu ***\n\n", apic_freq, params.freq_apic);
00262                         }
00263                         break;
00264                     }
00265                     read(fifo, &times, sizeof(times));
00266                     if (command == 'c' || command == 'b') {
00267                         cpu_freq = (((double)times.cpu_time)*params.clock_tick_rate)/(((double)times.intrs)*params.latch) + 0.49999999999999999;
00268                         printf("\n->>> MEASURED CPU_FREQ: %lu (Hz) [%lu (s)], IN USE %lu (Hz) <<<-\n", cpu_freq, time, params.cpu_freq);
00269                     }
00270                     if (params.mp && (command == 'a' || command == 'b')) {
00271                         apic_freq = (((double)times.apic_time)*params.clock_tick_rate)/(((double)times.intrs)*params.latch) + 0.49999999999999999;
00272                         printf("\n->>> MEASURED APIC_FREQ: %lu (Hz) [%lu (s)], IN USE %lu (Hz) <<<-\n", apic_freq, time, params.freq_apic);
00273                     }
00274                 }
00275                 break;
00276             }
00277 
00278             case 'i': {
00279                 time_t timestamp;
00280                 struct tm *tm_timestamp;
00281                 args[0] = BUS_CHECK;
00282                 args[1] = period;
00283                 args[2] = 1;
00284                 args[3] = parport;
00285                 printf("\n->>> INTERRUPT LATENCY CHECK (press enter to end check) <<<-\n\n");
00286                 args[1] *= 1000;
00287                 args[2] *= 1000;
00288                 rtai_srq(srq, (unsigned long)args);
00289                 while (1) {
00290                     int maxj;
00291                     if (poll(polls, 2, 100) > 0) {
00292                         if (polls[0].revents) {
00293                             getchar();
00294                             args[0] = END_BUS_CHECK;
00295                             rtai_srq(srq, (unsigned long)args);
00296                             break;
00297                         }
00298                         read(fifo, &maxj, sizeof(maxj));
00299                         time(&timestamp);
00300                         tm_timestamp = localtime(&timestamp);
00301                         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);
00302                         printf("%d.%-3d (us)\n", maxj/1000, maxj%1000);
00303                     }
00304                 }
00305                 break;
00306             }
00307 
00308         }
00309     }
00310     exit(0);
00311 }

Generated on Tue Feb 2 17:46:04 2010 for RTAI API by  doxygen 1.4.7