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 { "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, ¶ms, 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
00222
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, ×, 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(×tamp);
00296 tm_timestamp = localtime(×tamp);
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 }