All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@domain.hid>
To: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
Cc: xenomai@xenomai.org
Subject: Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
Date: Wed, 28 Jun 2006 14:28:14 +0200	[thread overview]
Message-ID: <44A275DE.5080500@domain.hid> (raw)
In-Reply-To: <17570.29185.754625.871443@domain.hid>

[-- Attachment #1: Type: text/plain, Size: 11554 bytes --]

Gilles Chanteperdrix wrote:
> jan.kiszka@domain.hid 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 <jan.kiszka@domain.hid>.
>  > + *
>  > + * 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 #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]

  reply	other threads:[~2006-06-28 12:28 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-26 17:21 [Xenomai-core] [PATCH 0/6] Various refactoring and new IRQ test jan.kiszka
2006-06-26 17:21 ` [Xenomai-core] [PATCH 1/6] Refactor tracer API jan.kiszka
2006-06-26 17:21 ` [Xenomai-core] [PATCH 2/6] Improve fault report jan.kiszka
2006-06-28  7:42   ` Philippe Gerum
2006-06-28  7:51     ` Jan Kiszka
2006-06-28  8:04       ` Philippe Gerum
2006-06-28  8:18         ` Jan Kiszka
2006-06-28  8:36           ` Philippe Gerum
2006-06-28  8:51             ` Jan Kiszka
2006-06-28  9:00               ` Philippe Gerum
2006-06-28  9:17                 ` Jan Kiszka
2006-06-28 16:36                   ` Philippe Gerum
2006-06-26 17:21 ` [Xenomai-core] [PATCH 3/6] Refactor rttesting device interface jan.kiszka
2006-06-26 17:21 ` [Xenomai-core] [PATCH 4/6] Add prio switch to latency test jan.kiszka
2006-06-28 19:38   ` Jan Kiszka
2006-06-26 17:21 ` [Xenomai-core] [PATCH 5/6] Overread dev-prefix on posix open jan.kiszka
2006-06-28 19:38   ` Jan Kiszka
2006-06-26 17:21 ` [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark jan.kiszka
2006-06-27 16:45   ` Jan Kiszka
2006-06-28 12:11   ` Gilles Chanteperdrix
2006-06-28 12:28     ` Jan Kiszka [this message]
2006-06-28 12:35       ` Gilles Chanteperdrix
2006-06-28 13:42       ` Gilles Chanteperdrix
2006-06-28 14:14         ` Dmitry Adamushko
2006-06-28 14:37           ` Jan Kiszka
2006-06-28 15:18             ` Dmitry Adamushko
2006-06-28 14:44         ` Jan Kiszka
2006-06-28 19:39   ` Jan Kiszka
2006-06-29 11:20     ` Jan Kiszka
2006-07-01 15:38       ` Philippe Gerum
2006-07-01 18:17         ` Jan Kiszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=44A275DE.5080500@domain.hid \
    --to=jan.kiszka@domain.hid \
    --cc=gilles.chanteperdrix@xenomai.org \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.