bfin: remove inline keyword
[xenomai-head.git] / src / testsuite / irqbench / irqbench.c
blobca7a3133347f3cdea5e6eca40ac64d967f9329b3
1 /*
2 * Copyright (C) 2006 Jan Kiszka <jan.kiszka@web.de>.
4 * Xenomai is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * Xenomai is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Xenomai; if not, write to the Free Software Foundation,
16 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <sys/io.h>
26 #include <sys/mman.h>
29 #define SERPORT 0
30 #define PARPORT 1
32 /* --- Serial port --- */
34 #define MCR_DTR 0x01
35 #define MCR_RTS 0x02
36 #define MCR_OUT2 0x08
38 #define MSR_DELTA 0x0F
40 #define LCR(base) (base + 3) /* Line Control Register */
41 #define MCR(base) (base + 4) /* Modem Control Register */
42 #define LSR(base) (base + 5) /* Line Status Register */
43 #define MSR(base) (base + 6) /* Modem Status Register */
45 /* --- Parallel port --- */
47 #define CTRL_INIT 0x04
48 #define CTRL_STROBE 0x10
50 #define DATA(base) (base + 0) /* Data register */
51 #define STAT(base) (base + 1) /* Status register */
52 #define CTRL(base) (base + 2) /* Control register */
54 static double tsc2ns_scale;
55 static long long min_lat = LONG_MAX;
56 static long long max_lat = LONG_MIN;
57 static long long avg_lat;
58 static long outer_loops;
59 static int warmup = 1;
60 static int terminate;
61 static unsigned long port_ioaddr = 0x3F8;
62 static int port_type = SERPORT;
63 static unsigned int toggle;
64 static long loop_avg;
65 static long long period = 100000;
66 static int trigger_trace;
68 static inline long long rdtsc(void)
70 unsigned long long tsc;
72 __asm__ __volatile__("rdtsc" : "=A" (tsc));
73 return tsc;
76 static long tsc2ns(long long tsc)
78 if (tsc > LONG_MAX || tsc < LONG_MIN) {
79 fprintf(stderr, "irqbench: overflow (%lld ns)!\n",
80 (long long)(tsc2ns_scale * (double)tsc));
81 exit(2);
83 return (long)(tsc2ns_scale * (double)tsc);
86 static inline long long ns2tsc(long long ns)
88 return (long long)(((double)ns) / tsc2ns_scale);
91 static void calibrate_tsc(void)
93 FILE *proc;
94 char *lineptr = NULL;
95 size_t len;
96 double cpu_mhz;
98 proc = fopen("/proc/cpuinfo", "r");
99 if (proc == NULL) {
100 perror("irqbench: Unable to open /proc/cpuinfo");
101 exit(1);
104 while (getline(&lineptr, &len, proc) != -1)
105 if (strncmp(lineptr, "cpu MHz", 7) == 0) {
106 sscanf(strchr(lineptr, ':') + 1, "%lf", &cpu_mhz);
107 break;
110 if (lineptr)
111 free(lineptr);
112 fclose(proc);
114 printf("CPU frequency: %.3lf MHz\n", cpu_mhz);
116 tsc2ns_scale = 1000.0 / cpu_mhz;
119 static void sighand(int signal)
121 if (warmup)
122 exit(0);
123 else
124 terminate = 1;
127 static void do_inner_loop(void)
129 long long start, delay, timeout;
130 long lat;
132 __asm__ __volatile__("cli");
134 if (port_type == SERPORT) {
135 start = rdtsc();
137 toggle ^= MCR_RTS;
138 outb(toggle, MCR(port_ioaddr));
140 timeout = start + period * 100;
141 while ((inb(MSR(port_ioaddr)) & MSR_DELTA) == 0 &&
142 rdtsc() < timeout);
144 delay = rdtsc() - start;
145 } else {
146 int status = inb(STAT(port_ioaddr));
148 outb(0x08, DATA(port_ioaddr));
150 start = rdtsc();
152 outb(0x00, DATA(port_ioaddr));
154 timeout = start + period * 100;
155 while (inb(STAT(port_ioaddr)) == status &&
156 rdtsc() < timeout);
158 delay = rdtsc() - start;
161 if (!warmup) {
162 lat = tsc2ns(delay);
164 loop_avg += lat;
165 if (lat < min_lat)
166 min_lat = lat;
167 if (lat > max_lat) {
168 max_lat = lat;
169 if (trigger_trace) {
170 if (port_type == SERPORT) {
171 toggle ^= MCR_DTR;
172 outb(toggle, MCR(port_ioaddr));
173 } else {
174 outb(0x18, DATA(port_ioaddr));
175 outb(0x10, DATA(port_ioaddr));
181 __asm__ __volatile__("sti");
183 while (rdtsc() < start + period);
186 int main(int argc, char *argv[])
188 int ioaddr_set = 0;
189 unsigned long long count = 1;
190 int c;
192 signal(SIGINT, sighand);
193 signal(SIGTERM, sighand);
194 signal(SIGHUP, sighand);
195 signal(SIGALRM, sighand);
197 calibrate_tsc();
199 while ((c = getopt(argc, argv, "p:T:o:a:f")) != EOF)
200 switch (c) {
201 case 'p':
202 period = atoi(optarg) * 1000;
203 break;
205 case 'T':
206 alarm(atoi(optarg));
207 break;
209 case 'o':
210 port_type = atoi(optarg);
211 break;
213 case 'a':
214 port_ioaddr = strtol(optarg, NULL, 0);
215 ioaddr_set = 1;
216 break;
218 case 'f':
219 trigger_trace = 1;
220 break;
222 default:
223 fprintf(stderr, "usage: irqbench [options]\n"
224 " [-p <period_us>] # signal period, default=100 us\n"
225 " [-T <test_duration_seconds>] # default=0, so ^C to end\n"
226 " [-o <port_type>] # 0=serial (default), 1=parallel\n"
227 " [-a <port_io_address>] # default=0x3f8/0x378\n"
228 " [-f] # freeze trace for each new max latency\n");
229 exit(2);
232 /* set defaults for parallel port */
233 if (port_type == 1 && !ioaddr_set)
234 port_ioaddr = 0x378;
236 if (iopl(3) < 0) {
237 fprintf(stderr, "irqbench: superuser permissions required\n");
238 exit(1);
240 mlockall(MCL_CURRENT | MCL_FUTURE);
242 switch (port_type) {
243 case SERPORT:
244 toggle = MCR_OUT2;
245 inb(MSR(port_ioaddr));
246 break;
248 case PARPORT:
249 outb(CTRL_INIT, CTRL(port_ioaddr));
250 break;
252 default:
253 fprintf(stderr, "irqbench: invalid port type\n");
254 exit(1);
257 period = ns2tsc(period);
259 printf("Port type: %s\n"
260 "Port address: 0x%lx\n\n",
261 (port_type == SERPORT) ? "serial" : "parallel", port_ioaddr);
263 printf("Waiting on target...\n");
265 while (1)
266 if (port_type == SERPORT) {
267 toggle ^= MCR_RTS;
268 outb(toggle, MCR(port_ioaddr));
269 usleep(100000);
270 if ((inb(MSR(port_ioaddr)) & MSR_DELTA) != 0)
271 break;
272 } else {
273 int status = inb(STAT(port_ioaddr));
275 outb(0x08, DATA(port_ioaddr));
276 outb(0x00, DATA(port_ioaddr));
277 usleep(100000);
278 if (inb(STAT(port_ioaddr)) != status)
279 break;
282 printf("Warming up...\n");
284 while (!terminate) {
285 long long loop_timeout = rdtsc() + ns2tsc(1000000000LL);
286 int inner_loops = 0;
288 loop_avg = 0;
289 while (rdtsc() < loop_timeout) {
290 do_inner_loop();
291 inner_loops++;
294 count += inner_loops;
296 if (!warmup && !terminate) {
297 loop_avg /= inner_loops;
299 printf("%llu: %.3f / %.3f / %.3f us\n", count,
300 ((double)min_lat) / 1000.0,
301 ((double)loop_avg) / 1000.0,
302 ((double)max_lat) / 1000.0);
304 avg_lat += loop_avg;
305 outer_loops++;
306 } else
307 warmup = 0;
310 avg_lat /= outer_loops;
311 printf("---\n%llu: %.3f / %.3f / %.3f us\n", count,
312 ((double)min_lat) / 1000.0, ((double)avg_lat) / 1000.0,
313 ((double)max_lat) / 1000.0);
315 return 0;