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.
32 /* --- Serial port --- */
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;
61 static unsigned long port_ioaddr
= 0x3F8;
62 static int port_type
= SERPORT
;
63 static unsigned int toggle
;
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
));
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
));
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)
98 proc
= fopen("/proc/cpuinfo", "r");
100 perror("irqbench: Unable to open /proc/cpuinfo");
104 while (getline(&lineptr
, &len
, proc
) != -1)
105 if (strncmp(lineptr
, "cpu MHz", 7) == 0) {
106 sscanf(strchr(lineptr
, ':') + 1, "%lf", &cpu_mhz
);
114 printf("CPU frequency: %.3lf MHz\n", cpu_mhz
);
116 tsc2ns_scale
= 1000.0 / cpu_mhz
;
119 static void sighand(int signal
)
127 static void do_inner_loop(void)
129 long long start
, delay
, timeout
;
132 __asm__
__volatile__("cli");
134 if (port_type
== SERPORT
) {
138 outb(toggle
, MCR(port_ioaddr
));
140 timeout
= start
+ period
* 100;
141 while ((inb(MSR(port_ioaddr
)) & MSR_DELTA
) == 0 &&
144 delay
= rdtsc() - start
;
146 int status
= inb(STAT(port_ioaddr
));
148 outb(0x08, DATA(port_ioaddr
));
152 outb(0x00, DATA(port_ioaddr
));
154 timeout
= start
+ period
* 100;
155 while (inb(STAT(port_ioaddr
)) == status
&&
158 delay
= rdtsc() - start
;
170 if (port_type
== SERPORT
) {
172 outb(toggle
, MCR(port_ioaddr
));
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
[])
189 unsigned long long count
= 1;
192 signal(SIGINT
, sighand
);
193 signal(SIGTERM
, sighand
);
194 signal(SIGHUP
, sighand
);
195 signal(SIGALRM
, sighand
);
199 while ((c
= getopt(argc
, argv
, "p:T:o:a:f")) != EOF
)
202 period
= atoi(optarg
) * 1000;
210 port_type
= atoi(optarg
);
214 port_ioaddr
= strtol(optarg
, NULL
, 0);
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");
232 /* set defaults for parallel port */
233 if (port_type
== 1 && !ioaddr_set
)
237 fprintf(stderr
, "irqbench: superuser permissions required\n");
240 mlockall(MCL_CURRENT
| MCL_FUTURE
);
245 inb(MSR(port_ioaddr
));
249 outb(CTRL_INIT
, CTRL(port_ioaddr
));
253 fprintf(stderr
, "irqbench: invalid port type\n");
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");
266 if (port_type
== SERPORT
) {
268 outb(toggle
, MCR(port_ioaddr
));
270 if ((inb(MSR(port_ioaddr
)) & MSR_DELTA
) != 0)
273 int status
= inb(STAT(port_ioaddr
));
275 outb(0x08, DATA(port_ioaddr
));
276 outb(0x00, DATA(port_ioaddr
));
278 if (inb(STAT(port_ioaddr
)) != status
)
282 printf("Warming up...\n");
285 long long loop_timeout
= rdtsc() + ns2tsc(1000000000LL);
289 while (rdtsc() < loop_timeout
) {
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);
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);