00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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, ¶ms, 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
00226
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, ×, 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(×tamp);
00300 tm_timestamp = localtime(×tamp);
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 }