base/arch/x86_64/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     int rv;
00100     char modunload[1024];
00101 
00102     snprintf(modunload,sizeof(modunload),"/sbin/rmmod %s >/dev/null 2>&1",KERNEL_HELPER_PATH);
00103     rv = system(modunload);
00104 }
00105 
00106 int main(int argc, char *argv[])
00107 {
00108     int srq, fifo, command, commands[20], ncommands, c, option_index, i, rv;
00109     struct params_t params;
00110     char str[80], nm[RTF_NAMELEN+1], modload[1024];
00111     unsigned long period = 100, duration = 5, parport = 'y';
00112     unsigned long args[MAXARGS];
00113     struct pollfd polls[2] = { { 0, POLLIN }, { 0, POLLIN } };
00114 
00115     option_index = ncommands = 0;
00116     while (1) {
00117         if ((c = getopt_long(argc, argv, "hrkucabip:t:s:", options, &option_index)) == -1) {
00118             break;
00119         }
00120         switch(c) {
00121             case 'h': {
00122                 print_usage();
00123                 exit(0);
00124             }
00125             case 'r':
00126             case 'u':
00127             case 'c':
00128             case 'b':
00129             case 'a':
00130             case 'i':
00131             case 'k': {
00132                 commands[ncommands++] = c;
00133                 break;
00134             }
00135             case 'p': {
00136                 period = atoi(optarg);
00137                 break;
00138             }
00139             case 't': {
00140                 duration = atoi(optarg);
00141                 break;
00142             }
00143             case 's': {
00144                 parport = optarg[0] == 'y' ? 'y' : 'n';
00145                 break;
00146             }
00147         }
00148     }
00149     if (ncommands <= 0) {
00150         printf("\n*** NOTHING TO BE DONE ***\n");
00151         exit(0);
00152     }
00153 
00154     atexit(&unload_kernel_helper);
00155 
00156     snprintf(modload,sizeof(modload),"/sbin/insmod %s >/dev/null 2>&1",KERNEL_HELPER_PATH);
00157     rv = system(modload);
00158 
00159     signal(SIGINT, endme);
00160 
00161     srq = rtai_open_srq(CALSRQ);
00162     if ((fifo = open(rtf_getfifobyminor(0,nm,sizeof(nm)), O_RDONLY)) < 0) {
00163         printf("Error opening %s\n",nm);
00164         exit(1);
00165     }
00166     polls[1].fd = fifo;
00167 
00168     args[0] = GET_PARAMS;
00169     rtai_srq(srq, (unsigned long)args);
00170     rv = read(fifo, &params, sizeof(params));
00171     printf("\n*** NUMBER OF REQUESTS: %d. ***\n", ncommands);
00172 
00173     for (i = 0; i < ncommands; i++) {
00174         switch (command = commands[i]) {
00175 
00176             case 'r': {
00177                 args[0] = CAL_8254;
00178                 printf("\n*** '#define SETUP_TIME_8254 %lu', IN USE %lu ***\n\n", (unsigned long) rtai_srq(srq, (unsigned long)args), params.setup_time_8254);
00179                 break;
00180             }
00181 
00182             case 'k': {
00183                 int average;
00184                 args[0] = KLATENCY;
00185                 args[1] = period;
00186                 args[2] = duration;
00187                 printf("\n*** KERNEL SPACE LATENCY CALIBRATION, wait %lu seconds for it ... ***\n", args[2]);
00188                 args[2] = (1000000*args[2])/args[1];
00189                 args[1] *= 1000;
00190                 rtai_srq(srq, (unsigned long)args);
00191                 rv = read(fifo, &average, sizeof(average));
00192                 average /= (int)args[2];
00193                     if (params.mp) {
00194                         printf("\n*** '#define LATENCY_APIC %d' (IN USE %lu)\n\n", (int)params.latency_apic + average, params.latency_apic);
00195                 } else {
00196                     printf("\n*** '#define LATENCY_8254 %d' (IN USE %lu)\n\n", (int)params.latency_8254 + average, params.latency_8254);
00197                 }
00198                 args[0] = END_KLATENCY;
00199                 rtai_srq(srq, (unsigned long)args);
00200                 break;
00201             }
00202 
00203             case 'u': {
00204                 int pid, average;
00205                 args[1] = period;
00206                 args[2] = duration;
00207                 printf("\n*** USER SPACE LATENCY CALIBRATION, wait %lu seconds for it ... ***\n", args[2]);
00208                 args[2] = (1000000*args[2])/args[1];
00209                 args[1] *= 1000;
00210                 sprintf(str, "%lu", args[1]);
00211                 sprintf(str + sizeof(str)/2, "%lu", args[2]);
00212                 pid = fork();
00213                 if (!pid) {
00214                     execl(USER_HELPER_PATH, USER_HELPER_PATH, str, str + sizeof(str)/2, NULL);
00215                     _exit(1);
00216                 }
00217                 rv = read(fifo, &average, sizeof(average));
00218                 waitpid(pid, 0, 0);
00219                 if (kill(pid,0) < 0)
00220                     {
00221 //                  printf("\n*** Cannot execute calibration helper %s -- aborting\n",USER_HELPER_PATH);
00222 //                  exit(1);
00223                     }
00224                 average /= (int)args[2];
00225                     if (params.mp) {
00226                         printf("\n*** '#define LATENCY_APIC %d' (IN USE %lu)\n\n", (int)params.latency_apic + average, params.latency_apic);
00227                 } else {
00228                     printf("\n*** '#define LATENCY_8254 %d' (IN USE %lu)\n\n", (int)params.latency_8254 + average, params.latency_8254);
00229                 }
00230                 break;
00231             }
00232 
00233             case 'a': 
00234                 if (!params.mp) {
00235                     printf("*** APIC FREQUENCY CALIBRATION NOT AVAILABLE UNDER UP ***\n");  
00236                     break;  
00237                 }
00238             case 'b':
00239             case 'c': {
00240                 unsigned long time, cpu_freq = 0, apic_freq = 0;
00241                 struct times_t times;
00242                 args[0] = FREQ_CAL;
00243                 args[1] = duration;
00244                 printf("\n->>> FREQ CALIB (PRINTING EVERY %lu SECONDS, press enter to end calibrating) <<<-\n\n", args[1]);
00245                 rtai_srq(srq, (unsigned long)args);
00246                 time = 0;
00247                 while (1) {
00248                     time += args[1];
00249                     if (poll(polls, 2, 1000*duration) > 0 &&polls[0].revents) {
00250                         getchar();
00251                         args[0] = END_FREQ_CAL;
00252                         rtai_srq(srq, (unsigned long)args);
00253                         if (command == 'c' || command == 'b') {
00254                             printf("\n*** '#define CPU_FREQ %lu', IN USE %lu ***\n\n", cpu_freq, params.cpu_freq);
00255                         }
00256                         if (params.mp && (command == 'a' || command == 'b')) {
00257                             printf("\n*** '#define APIC_FREQ %lu', IN USE %lu ***\n\n", apic_freq, params.freq_apic);
00258                         }
00259                         break;
00260                     }
00261                     rv = read(fifo, &times, sizeof(times));
00262                     if (command == 'c' || command == 'b') {
00263                         cpu_freq = (((double)times.cpu_time)*params.clock_tick_rate)/(((double)times.intrs)*params.latch) + 0.49999999999999999;
00264                         printf("\n->>> MEASURED CPU_FREQ: %lu (Hz) [%lu (s)], IN USE %lu (Hz) <<<-\n", cpu_freq, time, params.cpu_freq);
00265                     }
00266                     if (params.mp && (command == 'a' || command == 'b')) {
00267                         apic_freq = (((double)times.apic_time)*params.clock_tick_rate)/(((double)times.intrs)*params.latch) + 0.49999999999999999;
00268                         printf("\n->>> MEASURED APIC_FREQ: %lu (Hz) [%lu (s)], IN USE %lu (Hz) <<<-\n", apic_freq, time, params.freq_apic);
00269                     }
00270                 }
00271                 break;
00272             }
00273 
00274             case 'i': {
00275                 time_t timestamp;
00276                 struct tm *tm_timestamp;
00277                 args[0] = BUS_CHECK;
00278                 args[1] = period;
00279                 args[2] = 1;
00280                 args[3] = parport;
00281                 printf("\n->>> INTERRUPT LATENCY CHECK (press enter to end check) <<<-\n\n");
00282                 args[1] *= 1000;
00283                 args[2] *= 1000;
00284                 rtai_srq(srq, (unsigned long)args);
00285                 while (1) {
00286                     int maxj;
00287                     if (poll(polls, 2, 100) > 0) {
00288                         if (polls[0].revents) {
00289                             getchar();
00290                             args[0] = END_BUS_CHECK;
00291                             rtai_srq(srq, (unsigned long)args);
00292                             break;
00293                         }
00294                         rv = read(fifo, &maxj, sizeof(maxj));
00295                         time(&timestamp);
00296                         tm_timestamp = localtime(&timestamp);
00297                         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);
00298                         printf("%d.%-3d (us)\n", maxj/1000, maxj%1000);
00299                     }
00300                 }
00301                 break;
00302             }
00303 
00304         }
00305     }
00306     exit(0);
00307 }

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