Gilles Chanteperdrix wrote:
> [EMAIL PROTECTED] wrote:
>  > Index: xenomai/src/testsuite/irqbench/irqbench.c
>  > ===================================================================
>  > --- /dev/null
>  > +++ xenomai/src/testsuite/irqbench/irqbench.c
>  > @@ -0,0 +1,301 @@
>  > +/*
>  > + * Copyright (C) 2006 Jan Kiszka <[EMAIL PROTECTED]>.
>  > + *
>  > + * Xenomai is free software; you can redistribute it and/or modify it
>  > + * under the terms of the GNU General Public License as published by
>  > + * the Free Software Foundation; either version 2 of the License, or
>  > + * (at your option) any later version.
>  > + *
>  > + * Xenomai is distributed in the hope that it will be useful, but
>  > + * WITHOUT ANY WARRANTY; without even the implied warranty of
>  > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>  > + * General Public License for more details.
>  > + *
>  > + * You should have received a copy of the GNU General Public License
>  > + * along with Xenomai; if not, write to the Free Software Foundation,
>  > + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>  > + */
>  > +
>  > +#include <limits.h>
>  > +#include <stdio.h>
>  > +#include <stdlib.h>
>  > +#include <string.h>
>  > +#include <signal.h>
>  > +#include <unistd.h>
>  > +#include <sys/io.h>
>  > +#include <sys/mman.h>
>  > +
>  > +
>  > +#define SERPORT                 0
>  > +#define PARPORT                 1
>  > +
>  > +/* --- Serial port --- */
>  > +
>  > +#define MCR_DTR                 0x01
>  > +#define MCR_RTS                 0x02
>  > +#define MCR_OUT2                0x08
>  > +
>  > +#define MSR_DELTA               0x0F
>  > +
>  > +#define LCR(base) (base + 3) /* Line Control Register */
>  > +#define MCR(base) (base + 4) /* Modem Control Register */
>  > +#define LSR(base) (base + 5) /* Line Status Register */
>  > +#define MSR(base) (base + 6) /* Modem Status Register */
>  > +
>  > +/* --- Parallel port --- */
>  > +
>  > +#define CTRL_INIT               0x04
>  > +
>  > +#define STAT_STROBE             0x10
>  > +
>  > +#define DATA(base) (base + 0) /* Data register */
>  > +#define STAT(base) (base + 1) /* Status register */
>  > +#define CTRL(base) (base + 2) /* Control register */
>  > +
>  > +double tsc2ns_scale;
>  > +long long min_lat = LLONG_MAX;
>  > +long long max_lat = LLONG_MIN;
>  > +long long avg_lat = 0;
>  > +long outer_loops = 0;
>  > +int warmup = 1;
>  > +
>  > +static inline long long rdtsc(void)
>  > +{
>  > +    unsigned long long tsc;
>  > +
>  > +    __asm__ __volatile__("rdtsc" : "=A" (tsc));
>  > +    return tsc;
>  > +}
>  > +
>  > +
>  > +static long tsc2ns(long long tsc)
>  > +{
>  > +    if ((tsc > LONG_MAX) || (tsc < LONG_MIN)) {
>  > +        fprintf(stderr, "irqbench: overflow (%lld ns)!\n",
>  > +                (long long)(tsc2ns_scale * (double)tsc));
>  > +        exit(2);
>  > +    }
>  > +    return (long)(tsc2ns_scale * (double)tsc);
>  > +}
>  > +
>  > +
>  > +static inline long long ns2tsc(long long ns)
>  > +{
>  > +    return (long long)(((double)ns) / tsc2ns_scale);
>  > +}
>  > +
>  > +
>  > +void calibrate_tsc(void)
>  > +{
>  > +    FILE *proc;
>  > +    char *lineptr = NULL;
>  > +    size_t len;
>  > +    double cpu_mhz;
>  > +
>  > +    proc = fopen("/proc/cpuinfo", "r");
>  > +    if (proc == NULL) {
>  > +        perror("irqbench: Unable to open /proc/cpuinfo");
>  > +        exit(1);
>  > +    }
>  > +
>  > +    while (getline(&lineptr, &len, proc) != -1)
>  > +        if (strncmp(lineptr, "cpu MHz", 7) == 0) {
>  > +            sscanf(strchr(lineptr, ':') + 1, "%lf", &cpu_mhz);
>  > +            break;
>  > +        }
>  > +
>  > +    if (lineptr)
>  > +        free(lineptr);
>  > +    fclose(proc);
>  > +
>  > +    printf("CPU frequency: %.3lf MHz\n", cpu_mhz);
>  > +
>  > +    tsc2ns_scale = 1000.0 / cpu_mhz;
>  > +}
>  > +
>  > +
>  > +void sighand(int signal)
>  > +{
>  > +    if (!warmup) {
>  > +        avg_lat /= outer_loops;
>  > +        printf("---\n%.3f / %.3f / %.3f us\n",
>  > +               ((double)min_lat) / 1000.0, ((double)avg_lat) / 1000.0,
>  > +               ((double)max_lat) / 1000.0);
>  > +    }
>  > +    exit(0);
>  > +}
>  > +
>  > +
>  > +int main(int argc, char *argv[])
>  > +{
>  > +    int             port_type   = SERPORT;
>  > +    unsigned long   port_ioaddr = 0x3F8;
>  > +    long long       period = 100000;
>  > +    long long       timeout;
>  > +    long long       start, delay;
>  > +    unsigned int    toggle;
>  > +    int             trigger_trace = 0;
>  > +    int             c;
>  > +
>  > +
>  > +    signal(SIGINT, sighand);
>  > +    signal(SIGTERM, sighand);
>  > +    signal(SIGHUP, sighand);
>  > +    signal(SIGALRM, sighand);
>  > +
>  > +    calibrate_tsc();
>  > +
>  > +    while ((c = getopt(argc,argv,"p:T:o:a:f")) != EOF)
>  > +        switch (c) {
>  > +            case 'p':
>  > +                period = atoi(optarg) * 1000;
>  > +                break;
>  > +
>  > +            case 'T':
>  > +                alarm(atoi(optarg));
>  > +                break;
>  > +
>  > +            case 'o':
>  > +                port_type = atoi(optarg);
>  > +                break;
>  > +
>  > +            case 'a':
>  > +                port_ioaddr = strtol(optarg, NULL,
>  > +                    (strncmp(optarg, "0x", 2) == 0) ? 16 : 10);
>  > +                break;
>  > +
>  > +            case 'f':
>  > +                trigger_trace = 1;
>  > +                break;
>  > +
>  > +            default:
>  > +                fprintf(stderr, "usage: irqbench [options]\n"
>  > +                        "  [-p <period_us>]             # signal period, 
> default=100 us\n"
>  > +                        "  [-T <test_duration_seconds>] # default=0, so 
> ^C to end\n"
>  > +                        "  [-o <port_type>]             # 0=serial 
> (default), 1=parallel\n"
>  > +                        "  [-a <port_io_address>]       # default=0x3f8\n"
>  > +                        "  [-f]                         # freeze trace 
> for each new max latency\n");
>  > +                exit(2);
>  > +        }
>  > +
>  > +    if (iopl(3) < 0) {
>  > +        fprintf(stderr, "irqbench: superuser permissions required\n");
>  > +        exit(1);
>  > +    }
>  > +    mlockall(MCL_CURRENT | MCL_FUTURE);
>  > +
>  > +    switch (port_type) {
>  > +        case SERPORT:
>  > +            toggle = MCR_OUT2;
>  > +            inb(MSR(port_ioaddr));
>  > +            break;
>  > +
>  > +        case PARPORT:
>  > +            toggle = 0xAA;
>  > +            outb(0xAA, DATA(port_ioaddr));
>  > +            outb(CTRL_INIT, CTRL(port_ioaddr));
>  > +            break;
>  > +
>  > +        default:
>  > +            fprintf(stderr, "irqbench: invalid port type\n");
>  > +            exit(1);
>  > +    }
>  > +
>  > +    period = ns2tsc(period);
>  > +
>  > +    printf("Port type:     %s\n"
>  > +           "Port address:  0x%lx\n\n",
>  > +           (port_type == SERPORT) ? "serial" : "parallel", port_ioaddr);
>  > +
>  > +    printf("Waiting on target...\n");
>  > +
>  > +    while (1)
>  > +        if (port_type ==  SERPORT) {
>  > +            toggle ^= MCR_RTS;
>  > +            outb(toggle, MCR(port_ioaddr));
>  > +            usleep(100000);
>  > +            if ((inb(MSR(port_ioaddr)) & MSR_DELTA) != 0)
>  > +                break;
>  > +        } else {
>  > +            int status = inb(STAT(port_ioaddr));
>  > +
>  > +            toggle ^= 0xFF;
>  > +            outb(toggle, DATA(port_ioaddr));
>  > +            if (inb(STAT(port_ioaddr)) != status)
>  > +                break;
>  > +        }
>  > +
>  > +    printf("Warming up...\n");
>  > +
>  > +    while (1) {
>  > +        long long loop_timeout = rdtsc() + ns2tsc(1000000000LL);
>  > +        long loop_avg = 0;
>  > +        int inner_loops;
>  > +
>  > +        for (inner_loops = 0; rdtsc() < loop_timeout; inner_loops++) {
>  > +            long lat;
>  > +
>  > +            __asm__ __volatile__("cli");
>  > +
>  > +            if (port_type ==  SERPORT) {
>  > +                start = rdtsc();
>  > +
>  > +                toggle ^= MCR_RTS;
>  > +                outb(toggle, MCR(port_ioaddr));
>  > +
>  > +                timeout = start + period * 100;
>  > +                while (((inb(MSR(port_ioaddr)) & MSR_DELTA) == 0) &&
>  > +                       (rdtsc() < timeout));
>  > +
>  > +                delay = rdtsc() - start;
>  > +            } else {
>  > +                int status = inb(STAT(port_ioaddr));
>  > +
>  > +                start = rdtsc();
>  > +
>  > +                toggle ^= 0xFF;
>  > +                outb(toggle, DATA(port_ioaddr));
>  > +
>  > +                timeout = start + period * 100;
>  > +                while ((inb(STAT(port_ioaddr)) == status) &&
>  > +                       (rdtsc() < timeout));
>  > +
>  > +                delay = rdtsc() - start;
>  > +            }
>  > +
>  > +            if (!warmup) {
>  > +                lat = tsc2ns(delay);
>  > +
>  > +                loop_avg += lat;
>  > +                if (lat < min_lat)
>  > +                    min_lat = lat;
>  > +                if (lat > max_lat) {
>  > +                    max_lat = lat;
>  > +                    if (trigger_trace) {
>  > +                        if (port_type == SERPORT) {
>  > +                            toggle ^= MCR_DTR;
>  > +                            outb(toggle, MCR(port_ioaddr));
>  > +                        } else {
>  > +                            // todo
>  > +                        }
>  > +                    }
>  > +                }
>  > +            }
>  > +
>  > +            __asm__ __volatile__("sti");
>  > +
>  > +            while (rdtsc() < start + period);
>  > +        }
>  > +        if (!warmup) {
>  > +            loop_avg /= inner_loops;
>  > +
>  > +            printf("%.3f / %.3f / %.3f us\n",
>  > +                ((double)min_lat) / 1000.0, ((double)loop_avg) / 1000.0,
>  > +                ((double)max_lat) / 1000.0);
>  > +
>  > +            avg_lat += loop_avg;
>  > +            outer_loops++;
>  > +        } else
>  > +            warmup = 0;
>  > +    }
>  > +}
> 
> Is there no way to make this code easier to port for example by using
> native or posix services for timings measurement and by abstracting the
> non portable part and moving them to include/asm-i386 ?

This tool is intentionally left Xenomai-free. You can put it on any x86
box around (and I assume that there is almost always some...) and run
the test. Thus, no need for a second RT-patched system.

Anyway, suggestions or patches to add a porting layer are welcome. The
following points need to be addressed: time measuring, irq protection,
hardware access. I just wonder if this is worth the effort.

> 
> Also note that calling printf from a signal handler risk deadlocking if
> the signal handler get called on the return path of the write call that
> take place in the middle of a printf call on the main thread.
> 

Ok, then we also need a fix for the latency test (this is where I
grabbed that pattern from). Is there a high risk that this locks up? I
wonder why I never observed or heard of problems with latency.

Jan

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to