On Wed, Aug 12, 2020 at 11:43 AM Jan Kiszka <[email protected]> wrote:
>
> On 12.08.20 17:28, Jan Kiszka wrote:
> > On 12.08.20 16:55, Jan Kiszka wrote:
> >> On 12.08.20 05:36, Greg Gallagher wrote:
> >>> On Tue, Aug 11, 2020 at 11:36 AM Greg Gallagher
> >>> <[email protected]> wrote:
> >>>>
> >>>> On Tue, Aug 11, 2020 at 3:15 AM Jan Kiszka <[email protected]>
> >>>> wrote:
> >>>>>
> >>>>> On 03.08.20 08:04, chensong wrote:
> >>>>>> This a tool to benchmark the latency of GPIO driver,
> >>>>>> it's able to run 2 kinds of benchmark test:
> >>>>>>
> >>>>>> 1, loopback mode
> >>>>>> 1) apply 2 gpio pins by calling service in gpio RTDM driver
> >>>>>>     like gpio-bcm2835 and gpio-core.c, one is as output,
> >>>>>>     the other is as interrupt
> >>>>>> 2) call write_rt to send a pulse from output
> >>>>>> 3) call read_rt to get timestamps recorded in driver (inner loop)
> >>>>>> 4) also record timespace in user space(outer_loop)
> >>>>>>     outer_loop is inner_loop plus overhead of event wakeup
> >>>>>> 5) ftrace enable/disable
> >>>>>>
> >>>>>> 2, react mode
> >>>>>> 1) apply 2 gpio pins by calling service in gpio RTDM driver
> >>>>>>     like gpio-bcm2835 and gpio-core.c, one is as ourput,
> >>>>>>     the other is as interrupt
> >>>>>> 2) call read_rt to wait for a pulse from latency box
> >>>>>> 3) call write_rt to send a signal back to latency box
> >>>>>>     as a reaction
> >>>>>> 4) latency box calculates the diff and makes the histogram
> >>>>>>
> >>>>>> e.g.:
> >>>>>> 1) react mode:
> >>>>>>     gpiobench -o 20 -i 21 -c pinctrl-bcm2835 -m 1 -l 1000
> >>>>>> 2) loopback mode:
> >>>>>>     gpiobench -o 20 -i 21 -c pinctrl-bcm2835 -m 0 -l 1000 -h 100
> >>>>>> -b 50
> >>>>>>
> >>>>>> CC: Jan Kiszka <[email protected]>
> >>>>>> CC: Greg Gallagher <[email protected]>
> >>>>>>
> >>>>>> Signed-off-by: chensong <[email protected]>
> >>>>>> ---
> >>>>>>   configure.ac                     |   1 +
> >>>>>>   doc/asciidoc/man1/gpiobench.adoc |  70 +++++
> >>>>>>   testsuite/Makefile.am            |   3 +-
> >>>>>>   testsuite/gpiobench/Makefile.am  |  18 ++
> >>>>>>   testsuite/gpiobench/gpiobench.c  | 654
> >>>>>> +++++++++++++++++++++++++++++++++++++++
> >>>>>>   5 files changed, 745 insertions(+), 1 deletion(-)
> >>>>>>   create mode 100644 doc/asciidoc/man1/gpiobench.adoc
> >>>>>>   create mode 100644 testsuite/gpiobench/Makefile.am
> >>>>>>   create mode 100644 testsuite/gpiobench/gpiobench.c
> >>>>>>
> >>>>>> diff --git a/configure.ac b/configure.ac
> >>>>>> index 29fefab..164c449 100644
> >>>>>> --- a/configure.ac
> >>>>>> +++ b/configure.ac
> >>>>>> @@ -939,6 +939,7 @@ AC_CONFIG_FILES([ \
> >>>>>>        testsuite/latency/Makefile \
> >>>>>>        testsuite/switchtest/Makefile \
> >>>>>>        testsuite/gpiotest/Makefile \
> >>>>>> +     testsuite/gpiobench/Makefile \
> >>>>>>        testsuite/spitest/Makefile \
> >>>>>>        testsuite/smokey/Makefile \
> >>>>>>        testsuite/smokey/arith/Makefile \
> >>>>>> diff --git a/doc/asciidoc/man1/gpiobench.adoc
> >>>>>> b/doc/asciidoc/man1/gpiobench.adoc
> >>>>>> new file mode 100644
> >>>>>> index 0000000..bd32ea8
> >>>>>> --- /dev/null
> >>>>>> +++ b/doc/asciidoc/man1/gpiobench.adoc
> >>>>>> @@ -0,0 +1,70 @@
> >>>>>> +// ** The above line should force tbl to be a preprocessor **
> >>>>>> +// Man page for gpiobench
> >>>>>> +//
> >>>>>> +// Copyright (C) 2020 song chen <[email protected]>
> >>>>>> +//
> >>>>>> +// You may distribute under the terms of the GNU General Public
> >>>>>> +// License as specified in the file COPYING that comes with the
> >>>>>> +// Xenomai distribution.
> >>>>>> +//
> >>>>>> +//
> >>>>>> +GPIOBENCH(1)
> >>>>>> +==========
> >>>>>> +:doctype: manpage
> >>>>>> +:revdate: 2020/08/03
> >>>>>> +:man source: Xenomai
> >>>>>> +:man version: {xenover}
> >>>>>> +:man manual: Xenomai Manual
> >>>>>> +
> >>>>>> +NAME
> >>>>>> +-----
> >>>>>> +gpiobench - Xenomai gpio latency benchmark
> >>>>>> +
> >>>>>> +SYNOPSIS
> >>>>>> +---------
> >>>>>> +// The general command line
> >>>>>> +*gpiobench* [ options ]
> >>>>>> +
> >>>>>> +DESCRIPTION
> >>>>>> +------------
> >>>>>> +*gpiobench* is part of the Xenomai test suite. It is a gpio latency
> >>>>>> +benchmark program.  The system must run a suitable Xenomai
> >>>>>> enabled kernel with
> >>>>>> +the respective module (xeno_timerbench).
> >>>>>> +
> >>>>>> +OPTIONS
> >>>>>> +--------
> >>>>>> +*gpiobench* accepts the following options:
> >>>>>> +
> >>>>>> +*-h <histogram-size>*::
> >>>>>> +default = 100, increase if your last bucket is full
> >>>>>> +
> >>>>>> +*-l <num-of-loops>*::
> >>>>>> +default=1000, number of loops to run the test
> >>>>>> +
> >>>>>> +*-q <quiet>*::
> >>>>>> +print only a summary on exit
> >>>>>> +
> >>>>>> +*-m <test-mode>*::
> >>>>>> +0 = loopback (default), 1 = react
> >>>>>> +
> >>>>>> +*-c <pin-controller>*::
> >>>>>> +name of pin controller
> >>>>
> >>>> Consider changing this to from pin controller to something a little
> >>>> more generic.  On the bcm2835 the gpios are
> >>>>>> +
> >>>>>> +*-o <output-pin>*::
> >>>>>> +number of gpio pin as output
> >>>>>> +
> >>>>>> +*-i <interrupt-pin>*::
> >>>>>> +number of gpin pin as interrupt
> >>>>>> +
> >>>>>> +*-p <priority>*::
> >>>>>> +default = 99, task priority
> >>>>>> +
> >>>>>> +*-b <bracktrace>*::
> >>>>>> +default = 1000, send break trace command when latency > breaktrace
> >>>>>> +
> >>>>>> +
> >>>>>> +
> >>>>>> +AUTHOR
> >>>>>> +-------
> >>>>>> +*gpiobench* was written by song chen. This man page
> >>>>>> +was written by song chen.
> >>>>>> diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
> >>>>>> index 76d108e..4932f6d 100644
> >>>>>> --- a/testsuite/Makefile.am
> >>>>>> +++ b/testsuite/Makefile.am
> >>>>>> @@ -1,5 +1,5 @@
> >>>>>>
> >>>>>> -SUBDIRS = latency smokey
> >>>>>> +SUBDIRS = latency smokey gpiobench
> >>>>>>
> >>>>>>   if XENO_COBALT
> >>>>>>   SUBDIRS +=           \
> >>>>>> @@ -13,6 +13,7 @@ endif
> >>>>>>   DIST_SUBDIRS =               \
> >>>>>>        clocktest       \
> >>>>>>        gpiotest        \
> >>>>>> +     gpiobench   \
> >>>>>>        latency         \
> >>>>>>        smokey          \
> >>>>>>        spitest         \
> >>>>>> diff --git a/testsuite/gpiobench/Makefile.am
> >>>>>> b/testsuite/gpiobench/Makefile.am
> >>>>>> new file mode 100644
> >>>>>> index 0000000..cca3395
> >>>>>> --- /dev/null
> >>>>>> +++ b/testsuite/gpiobench/Makefile.am
> >>>>>> @@ -0,0 +1,18 @@
> >>>>>> +testdir = @XENO_TEST_DIR@
> >>>>>> +
> >>>>>> +CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
> >>>>>> +
> >>>>>> +test_PROGRAMS = gpiobench
> >>>>>> +
> >>>>>> +gpiobench_SOURCES = gpiobench.c
> >>>>>> +
> >>>>>> +gpiobench_CPPFLAGS =                 \
> >>>>>> +     $(XENO_USER_CFLAGS)     \
> >>>>>> +     -I$(top_srcdir)/include
> >>>>>> +
> >>>>>> +gpiobench_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@ $(XENO_POSIX_WRAPPERS)
> >>>>>> +
> >>>>>> +gpiobench_LDADD =                    \
> >>>>>> +     @XENO_CORE_LDADD@       \
> >>>>>> +     @XENO_USER_LDADD@       \
> >>>>>> +     -lpthread -lrt -lm
> >>>>>> diff --git a/testsuite/gpiobench/gpiobench.c
> >>>>>> b/testsuite/gpiobench/gpiobench.c
> >>>>>> new file mode 100644
> >>>>>> index 0000000..7f19837
> >>>>>> --- /dev/null
> >>>>>> +++ b/testsuite/gpiobench/gpiobench.c
> >>>>>> @@ -0,0 +1,654 @@
> >>>>>> +/*
> >>>>>> + * Copyright (C) 2020 Song Chen <[email protected]>
> >>>>>> + *
> >>>>>> + * Permission is hereby granted, free of charge, to any person
> >>>>>> obtaining
> >>>>>> + * a copy of this software and associated documentation files (the
> >>>>>> + * "Software"), to deal in the Software without restriction,
> >>>>>> including
> >>>>>> + * without limitation the rights to use, copy, modify, merge,
> >>>>>> publish,
> >>>>>> + * distribute, sublicense, and/or sell copies of the Software,
> >>>>>> and to
> >>>>>> + * permit persons to whom the Software is furnished to do so,
> >>>>>> subject to
> >>>>>> + * the following conditions:
> >>>>>> + *
> >>>>>> + * The above copyright notice and this permission notice shall be
> >>>>>> included
> >>>>>> + * in all copies or substantial portions of the Software.
> >>>>>> + *
> >>>>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> >>>>>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
> >>>>>> WARRANTIES OF
> >>>>>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> >>>>>> NONINFRINGEMENT.
> >>>>>> + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
> >>>>>> FOR ANY
> >>>>>> + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
> >>>>>> CONTRACT,
> >>>>>> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> >>>>>> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> >>>>>> + */
> >>>>>> +#include <stdlib.h>
> >>>>>> +#include <math.h>
> >>>>>> +#include <stdio.h>
> >>>>>> +#include <string.h>
> >>>>>> +#include <errno.h>
> >>>>>> +#include <error.h>
> >>>>>> +#include <signal.h>
> >>>>>> +#include <sched.h>
> >>>>>> +#include <time.h>
> >>>>>> +#include <sys/time.h>
> >>>>>> +#include <unistd.h>
> >>>>>> +#include <pthread.h>
> >>>>>> +#include <semaphore.h>
> >>>>>> +#include <sys/timerfd.h>
> >>>>>> +#include <xeno_config.h>
> >>>>>> +#include <rtdm/testing.h>
> >>>>>> +#include <rtdm/gpio.h>
> >>>>>> +#include <boilerplate/trace.h>
> >>>>>> +#include <xenomai/init.h>
> >>>>>> +#include <sys/mman.h>
> >>>>>> +#include <getopt.h>
> >>>>>> +
> >>>>>> +#define NS_PER_MS (1000000)
> >>>>>> +#define NS_PER_S (1000000000)
> >>>>>> +
> >>>>>> +#define DEFAULT_PRIO 99
> >>>>>> +#define VERSION_STRING "0.1"
> >>>>>> +#define GPIO_HIGH 1
> >>>>>> +#define GPIO_LOW  0
> >>>>>> +#define MAX_HIST             100
> >>>>>> +#define MAX_CYCLES 1000000
> >>>>>> +#define DEFAULT_LIMIT 1000
> >>>>>> +#define DEV_PATH    "/dev/rtdm/"
> >>>>>> +#define TRACING_ON  "/sys/kernel/debug/tracing/tracing_on"
> >>>>>> +#define TRACING_EVENTS  "/sys/kernel/debug/tracing/events/enable"
> >>>>>> +#define TRACE_MARKER  "/sys/kernel/debug/tracing/trace_marker"
> >>>>>> +#define ON  "1"
> >>>>>> +#define OFF "0"
> >>>>>> +
> >>>>>> +enum {
> >>>>>> +     MODE_LOOPBACK,
> >>>>>> +     MODE_REACT,
> >>>>>> +     MODE_ALL
> >>>>>> +};
> >>>>>> +
> >>>>>> +/* Struct for statistics */
> >>>>>> +struct test_stat {
> >>>>>> +     long inner_min;
> >>>>>> +     long inner_max;
> >>>>>> +     double inner_avg;
> >>>>>> +     long *inner_hist_array;
> >>>>>> +     long inner_hist_overflow;
> >>>>>> +     long outer_min;
> >>>>>> +     long outer_max;
> >>>>>> +     double outer_avg;
> >>>>>> +     long *outer_hist_array;
> >>>>>> +     long outer_hist_overflow;
> >>>>>> +};
> >>>>>> +
> >>>>>> +/* Struct for information */
> >>>>>> +struct test_info {
> >>>>>> +     unsigned long max_cycles;
> >>>>>> +     unsigned long total_cycles;
> >>>>>> +     unsigned long max_histogram;
> >>>>>> +     int mode;
> >>>>>> +     int prio;
> >>>>>> +     int quiet;
> >>>>>> +     int tracelimit;
> >>>>>> +     int fd_dev_intr;
> >>>>>> +     int fd_dev_out;
> >>>>>> +     char pin_controller[32];
> >>>>>> +     pthread_t gpio_task;
> >>>>>> +     int gpio_intr;
> >>>>>> +     int gpio_out;
> >>>>>> +     struct test_stat ts;
> >>>>>> +};
> >>>>>> +
> >>>>>> +struct test_info ti;
> >>>>>> +/* Print usage information */
> >>>>>> +static void display_help(void)
> >>>>>> +{
> >>>>>> +     printf("gpiobench V %s\n", VERSION_STRING);
> >>>>>> +     printf("Usage:\n"
> >>>>>> +            "gpiobench <options>\n\n"
> >>>>>> +
> >>>>>> +            "-b       --breaktrace=USEC  send break trace command
> >>>>>> when latency > USEC\n"
> >>>>>> +            "                            default=1000\n"
> >>>>>> +            "-h       --histogram=US     dump a latency histogram
> >>>>>> to stdout after the run\n"
> >>>>>> +            "                            US is the max time to be
> >>>>>> tracked in microseconds,\n"
> >>>>>> +            "                            default=100\n"
> >>>>>> +            "-l       --loops            number of loops,
> >>>>>> default=1000\n"
> >>>>>> +            "-p       --prio             priority of highest prio
> >>>>>> thread, defaults=99\n"
> >>>>>> +            "-q       --quiet            print only a summary on
> >>>>>> exit\n"
> >>>>>> +            "-o       --output           gpio port number for
> >>>>>> output, no default value,\n"
> >>>>>> +            "                            must be specified\n"
> >>>>>> +            "-i       --intr             gpio port number as an
> >>>>>> interrupt, no default value,\n"
> >>>>>> +            "                            must be specified\n"
> >>>>>> +            "-c       --pinctrl          gpio pin controller's
> >>>>>> name, no default value,\n"
> >>>>>> +            "                            must be specified\n"
> >>>>>> +            "-m       --testmode         0 is loopback mode\n"
> >>>>>> +            "                            1 is react mode which
> >>>>>> works with a latency box,\n"
> >>>>>> +            "                            default=0\n\n"
> >>>>>> +
> >>>>>> +            "e.g.     gpiobench -o 20 -i 21 -c pinctrl-bcm2835\n"
> >>>>>> +             );
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void process_options(int argc, char *argv[])
> >>>>>> +{
> >>>>>> +     int c = 0;
> >>>>>> +     static const char optstring[] = "h:p:m:l:c:b:i:o:q";
> >>>>>> +
> >>>>>> +     struct option long_options[] = {
> >>>>>> +             { "bracetrace", required_argument, 0, 'b'},
> >>>>>> +             { "histogram", required_argument, 0, 'h'},
> >>>>>> +             { "loops", required_argument, 0, 'l'},
> >>>>>> +             { "prio", required_argument, 0, 'p'},
> >>>>>> +             { "quiet", no_argument, 0, 'q'},
> >>>>>> +             { "output", required_argument, 0, 'o'},
> >>>>>> +             { "intr", required_argument, 0, 'i'},
> >>>>>> +             { "pinctrl", required_argument, 0, 'c'},
> >>>>>> +             { "testmode", required_argument, 0, 'm'},
> >>>>>> +             { 0, 0, 0, 0},
> >>>>>> +     };
> >>>>>> +
> >>>>>> +     while ((c = getopt_long(argc, argv, optstring, long_options,
> >>>>>> +                                             NULL)) != -1) {
> >>>>>> +             switch (c) {
> >>>>>> +             case 'h':
> >>>>>> +                     ti.max_histogram = atoi(optarg);
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'p':
> >>>>>> +                     ti.prio = atoi(optarg);
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'l':
> >>>>>> +                     ti.max_cycles = atoi(optarg);
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'q':
> >>>>>> +                     ti.quiet = 1;
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'b':
> >>>>>> +                     ti.tracelimit = atoi(optarg);
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'i':
> >>>>>> +                     ti.gpio_intr = atoi(optarg);
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'o':
> >>>>>> +                     ti.gpio_out = atoi(optarg);
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'c':
> >>>>>> +                     strcpy(ti.pin_controller, optarg);
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             case 'm':
> >>>>>> +                     ti.mode = atoi(optarg) >=
> >>>>>> +                             MODE_REACT ? MODE_REACT :
> >>>>>> MODE_LOOPBACK;
> >>>>>> +                     break;
> >>>>>> +
> >>>>>> +             default:
> >>>>>> +                     display_help();
> >>>>>> +                     exit(2);
> >>>>>> +             }
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     if ((ti.gpio_out == -1) || (ti.gpio_intr == -1)
> >>>>>> +                             || (strlen(ti.pin_controller) == 0)) {
> >>>>>> +             display_help();
> >>>>>> +             exit(2);
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     ti.prio = ti.prio > DEFAULT_PRIO ? DEFAULT_PRIO : ti.prio;
> >>>>>> +     ti.max_cycles = ti.max_cycles > MAX_CYCLES ? MAX_CYCLES :
> >>>>>> ti.max_cycles;
> >>>>>> +
> >>>>>> +     ti.max_histogram = ti.max_histogram > MAX_HIST ?
> >>>>>> +             MAX_HIST : ti.max_histogram;
> >>>>>> +     ti.ts.inner_hist_array = calloc(ti.max_histogram,
> >>>>>> sizeof(long));
> >>>>>> +     ti.ts.outer_hist_array = calloc(ti.max_histogram,
> >>>>>> sizeof(long));
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int thread_msleep(unsigned int ms)
> >>>>>> +{
> >>>>>> +     struct timespec ts = {
> >>>>>> +             .tv_sec = (ms * NS_PER_MS) / NS_PER_S,
> >>>>>> +             .tv_nsec = (ms * NS_PER_MS) % NS_PER_S,
> >>>>>> +     };
> >>>>>> +
> >>>>>> +     return -nanosleep(&ts, NULL);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static inline int64_t calc_us(struct timespec t)
> >>>>>> +{
> >>>>>> +     return (t.tv_sec * NS_PER_S + t.tv_nsec);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int setevent(char *event, char *val)
> >>>>>> +{
> >>>>>> +     int fd;
> >>>>>> +     int ret;
> >>>>>> +
> >>>>>> +     fd = open(event, O_WRONLY);
> >>>>>> +     if (fd < 0) {
> >>>>>> +             printf("unable to open %s\n", event);
> >>>>>> +             return -1;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     ret = write(fd, val, strlen(val));
> >>>>>> +     if (ret < 0) {
> >>>>>> +             printf("unable to write %s to %s\n", val, event);
> >>>>>> +             close(fd);
> >>>>>> +             return -1;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     close(fd);
> >>>>>> +     return 0;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void tracing(char *enable)
> >>>>>> +{
> >>>>>> +     setevent(TRACING_EVENTS, enable);
> >>>>>> +     setevent(TRACING_ON, enable);
> >>>>>> +}
> >>>>>> +
> >>>>>> +#define write_check(__fd, __buf, __len)                      \
> >>>>>> +     do {                                            \
> >>>>>> +             int __ret = write(__fd, __buf, __len);  \
> >>>>>> +             (void)__ret;                            \
> >>>>>> +     } while (0)
> >>>>>> +
> >>>>>> +#define TRACEBUFSIZ 1024
> >>>>>> +static __thread char tracebuf[TRACEBUFSIZ];
> >>>>>> +
> >>>>>> +static void tracemark(char *fmt, ...)
> >>>>>> __attribute__((format(printf, 1, 2)));
> >>>>>> +static void tracemark(char *fmt, ...)
> >>>>>> +{
> >>>>>> +     va_list ap;
> >>>>>> +     int len;
> >>>>>> +     int tracemark_fd;
> >>>>>> +
> >>>>>> +     tracemark_fd = open(TRACE_MARKER, O_WRONLY);
> >>>>>> +     if (tracemark_fd == -1) {
> >>>>>> +             printf("unable to open trace_marker file: %s\n",
> >>>>>> TRACE_MARKER);
> >>>>>> +             return;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     /* bail out if we're not tracing */
> >>>>>> +     /* or if the kernel doesn't support trace_mark */
> >>>>>> +     if (tracemark_fd < 0)
> >>>>>> +             return;
> >>>>>> +
> >>>>>> +     va_start(ap, fmt);
> >>>>>> +     len = vsnprintf(tracebuf, TRACEBUFSIZ, fmt, ap);
> >>>>>> +     va_end(ap);
> >>>>>> +     write_check(tracemark_fd, tracebuf, len);
> >>>>>> +
> >>>>>> +     close(tracemark_fd);
> >>>>>> +}
> >>>>>> +
> >>>>>> +static int rw_gpio(int value, int index)
> >>>>>> +{
> >>>>>> +     int ret;
> >>>>>> +     struct timespec timestamp;
> >>>>>> +     struct rtdm_gpio_readout rdo;
> >>>>>> +     uint64_t gpio_write, gpio_read, inner_diff, outer_diff;
> >>>>>> +
> >>>>>> +     clock_gettime(CLOCK_MONOTONIC, &timestamp);
> >>>>>> +     gpio_write = calc_us(timestamp);
> >>>>>> +
> >>>>>> +     ret = write(ti.fd_dev_out, &value, sizeof(value));
> >>>>>> +     if (ret < 0) {
> >>>>>> +             printf("write GPIO, failed\n");
> >>>>>> +             return ret;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     ret = read(ti.fd_dev_intr, &rdo, sizeof(struct
> >>>>>> rtdm_gpio_readout));
> >>>>>> +     if (ret < 0) {
> >>>>>> +             printf("read GPIO, failed\n");
> >>>>>> +             return ret;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     clock_gettime(CLOCK_MONOTONIC, &timestamp);
> >>>>>> +     gpio_read = calc_us(timestamp);
> >>>>>> +
> >>>>>> +     inner_diff = (rdo.timestamp - gpio_write) / 1000;
> >>>>>> +     outer_diff = (gpio_read - gpio_write) / 1000;
> >>>>>> +
> >>>>>> +     if (inner_diff < ti.ts.inner_min)
> >>>>>> +             ti.ts.inner_min = inner_diff;
> >>>>>> +     if (inner_diff > ti.ts.inner_max)
> >>>>>> +             ti.ts.inner_max = inner_diff;
> >>>>>> +     ti.ts.inner_avg += (double) inner_diff;
> >>>>>> +     if (inner_diff >= ti.max_histogram)
> >>>>>> +             ti.ts.inner_hist_overflow++;
> >>>>>> +     else
> >>>>>> +             ti.ts.inner_hist_array[inner_diff]++;
> >>>>>> +
> >>>>>> +     if (outer_diff < ti.ts.outer_min)
> >>>>>> +             ti.ts.outer_min = outer_diff;
> >>>>>> +     if (inner_diff > ti.ts.outer_max)
> >>>>>> +             ti.ts.outer_max = outer_diff;
> >>>>>> +     ti.ts.outer_avg += (double) outer_diff;
> >>>>>> +     if (outer_diff >= ti.max_histogram)
> >>>>>> +             ti.ts.outer_hist_overflow++;
> >>>>>> +     else
> >>>>>> +             ti.ts.outer_hist_array[outer_diff]++;
> >>>>>> +
> >>>>>> +     if (ti.quiet == 0)
> >>>>>> +             printf("index: %d, inner_diff: %8ld, outer_diff:
> >>>>>> %8ld\n",
> >>>>>> +                                     index, inner_diff, outer_diff);
> >>>>>> +
> >>>>>> +     return outer_diff;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void *run_gpiobench_loop(void *cookie)
> >>>>>> +{
> >>>>>> +     int i, ret;
> >>>>>> +
> >>>>>> +     printf("----rt task, gpio loop, test run----\n");
> >>>>>> +
> >>>>>> +     for (i = 0; i < ti.max_cycles; i++) {
> >>>>>> +             ti.total_cycles = i;
> >>>>>> +             /* send a high level pulse from gpio output pin and
> >>>>>> +              * receive an interrupt from the other gpio pin,
> >>>>>> +              * measuring the time elapsed between the two events
> >>>>>> +              */
> >>>>>> +             ret = rw_gpio(GPIO_HIGH, i);
> >>>>>> +             if (ret < 0) {
> >>>>>> +                     printf("RW GPIO, failed\n");
> >>>>>> +                     break;
> >>>>>> +             } else if (ret > ti.tracelimit) {
> >>>>>> +                     tracemark("hit latency threshold (%d > %d),
> >>>>>> index: %d",
> >>>>>> +                                             ret, ti.tracelimit, i);
> >>>>>> +                     break;
> >>>>>> +             }
> >>>>>> +
> >>>>>> +             /*take a break, nanosleep here will not jeopardize
> >>>>>> the latency*/
> >>>>>> +             thread_msleep(10);
> >>>>>> +
> >>>>>> +             ret = rw_gpio(GPIO_LOW, i);
> >>>>>> +             /* send a low level pulse from gpio output pin and
> >>>>>> +              * receive an interrupt from the other gpio pin,
> >>>>>> +              * measuring the time elapsed between the two events
> >>>>>> +              */
> >>>>>> +             if (ret < 0) {
> >>>>>> +                     printf("RW GPIO, failed\n");
> >>>>>> +                     break;
> >>>>>> +             } else if (ti.tracelimit && ret > ti.tracelimit) {
> >>>>>> +                     tracemark("hit latency threshold (%d > %d),
> >>>>>> index: %d",
> >>>>>> +                                             ret, ti.tracelimit, i);
> >>>>>> +                     break;
> >>>>>> +             }
> >>>>>> +
> >>>>>> +             /*take a break, nanosleep here will not jeopardize
> >>>>>> the latency*/
> >>>>>> +             thread_msleep(10);
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     ti.ts.inner_avg /= (ti.total_cycles * 2);
> >>>>>> +     ti.ts.outer_avg /= (ti.total_cycles * 2);
> >>>>>> +
> >>>>>> +     return NULL;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void *run_gpiobench_react(void *cookie)
> >>>>>> +{
> >>>>>> +     int value, ret, i;
> >>>>>> +     struct rtdm_gpio_readout rdo;
> >>>>>> +
> >>>>>> +     printf("----rt task, gpio react, test run----\n");
> >>>>>> +
> >>>>>> +     for (i = 0; i < ti.max_cycles; i++) {
> >>>>>> +             /* received a pulse from latency box from one of
> >>>>>> +              * the gpio pin pair
> >>>>>> +              */
> >>>>>> +             ret = read(ti.fd_dev_intr, &rdo, sizeof(rdo));
> >>>>>> +             if (ret < 0) {
> >>>>>> +                     printf("RW GPIO read, failed\n");
> >>>>>> +                     break;
> >>>>>> +             }
> >>>>>> +
> >>>>>> +             if (ti.quiet == 0)
> >>>>>> +                     printf("idx: %d, received signal from
> >>>>>> latency box\n",
> >>>>>> +                                 i);
> >>>>>> +
> >>>>>> +             /* send a signal back from the other gpio pin
> >>>>>> +              * to latency box as the acknowledge,
> >>>>>> +              * latency box will measure the time elapsed
> >>>>>> +              * between the two events
> >>>>>> +              */
> >>>>>> +             value = GPIO_HIGH;
> >>>>>> +             ret = write(ti.fd_dev_out, &value, sizeof(value));
> >>>>>> +             if (ret < 0) {
> >>>>>> +                     printf("RW GPIO write, failed\n");
> >>>>>> +                     break;
> >>>>>> +             }
> >>>>>> +
> >>>>>> +             if (ti.quiet == 0)
> >>>>>> +                     printf("idx: %d, sent reaction to latency
> >>>>>> box\n", i);
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     return NULL;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void setup_sched_parameters(pthread_attr_t *attr, int prio)
> >>>>>> +{
> >>>>>> +     struct sched_param p;
> >>>>>> +     int ret;
> >>>>>> +
> >>>>>> +     ret = pthread_attr_init(attr);
> >>>>>> +     if (ret) {
> >>>>>> +             printf("pthread_attr_init(), failed\n");
> >>>>>> +             return;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     ret = pthread_attr_setinheritsched(attr,
> >>>>>> PTHREAD_EXPLICIT_SCHED);
> >>>>>> +     if (ret) {
> >>>>>> +             printf("pthread_attr_setinheritsched(), failed\n");
> >>>>>> +             return;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     ret = pthread_attr_setschedpolicy(attr,
> >>>>>> +                             prio ? SCHED_FIFO : SCHED_OTHER);
> >>>>>> +     if (ret) {
> >>>>>> +             printf("pthread_attr_setschedpolicy(), failed\n");
> >>>>>> +             return;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     p.sched_priority = prio;
> >>>>>> +     ret = pthread_attr_setschedparam(attr, &p);
> >>>>>> +     if (ret) {
> >>>>>> +             printf("pthread_attr_setschedparam(), failed\n");
> >>>>>> +             return;
> >>>>>> +     }
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void init_ti(void)
> >>>>>> +{
> >>>>>> +     memset(&ti, 0, sizeof(struct test_info));
> >>>>>> +     ti.prio = DEFAULT_PRIO;
> >>>>>> +     ti.max_cycles = MAX_CYCLES;
> >>>>>> +     ti.total_cycles = MAX_CYCLES;
> >>>>>> +     ti.max_histogram = MAX_HIST;
> >>>>>> +     ti.tracelimit = DEFAULT_LIMIT;
> >>>>>> +     ti.quiet = 0;
> >>>>>> +     ti.gpio_out = -1;
> >>>>>> +     ti.gpio_intr = -1;
> >>>>>> +     ti.mode = MODE_LOOPBACK;
> >>>>>> +
> >>>>>> +     ti.ts.inner_min = ti.ts.outer_min = DEFAULT_LIMIT;
> >>>>>> +     ti.ts.inner_max = ti.ts.outer_max = 0;
> >>>>>> +     ti.ts.inner_avg = ti.ts.outer_avg = 0.0;
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void print_hist(void)
> >>>>>> +{
> >>>>>> +     int i;
> >>>>>> +
> >>>>>> +     printf("\n");
> >>>>>> +     printf("# Inner Loop Histogram\n");
> >>>>>> +     printf("# Inner Loop latency is the latency in kernel space\n"
> >>>>>> +                "# between gpio_set_value and irq handler\n");
> >>>>>> +
> >>>>>> +     for (i = 0; i < ti.max_histogram; i++) {
> >>>>>> +             unsigned long curr_latency = ti.ts.inner_hist_array[i];
> >>>>>> +
> >>>>>> +             printf("%06d ", i);
> >>>>>> +             printf("%06lu\n", curr_latency);
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     printf("# Total:");
> >>>>>> +     printf(" %09lu", ti.total_cycles);
> >>>>>> +     printf("\n");
> >>>>>> +
> >>>>>> +     printf("# Min Latencies:");
> >>>>>> +     printf(" %05lu", ti.ts.inner_min);
> >>>>>> +     printf("\n");
> >>>>>> +     printf("# Avg Latencies:");
> >>>>>> +     printf(" %05lf", ti.ts.inner_avg);
> >>>>>> +     printf("\n");
> >>>>>> +     printf("# Max Latencies:");
> >>>>>> +     printf(" %05lu", ti.ts.inner_max);
> >>>>>> +     printf("\n");
> >>>>>> +
> >>>>>> +     printf("\n");
> >>>>>> +     printf("\n");
> >>>>>> +
> >>>>>> +     printf("# Outer Loop Histogram\n");
> >>>>>> +     printf("# Outer Loop latency is the latency in user space\n"
> >>>>>> +                "# between write and read\n"
> >>>>>> +                "# Technically, outer loop latency is inner loop
> >>>>>> latercy\n"
> >>>>>> +                "# plus overhead of event wakeup\n");
> >>>>>> +
> >>>>>> +     for (i = 0; i < ti.max_histogram; i++) {
> >>>>>> +             unsigned long curr_latency = ti.ts.outer_hist_array[i];
> >>>>>> +
> >>>>>> +             printf("%06d ", i);
> >>>>>> +             printf("%06lu\n", curr_latency);
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     printf("# Total:");
> >>>>>> +     printf(" %09lu", ti.total_cycles);
> >>>>>> +     printf("\n");
> >>>>>> +
> >>>>>> +     printf("# Min Latencies:");
> >>>>>> +     printf(" %05lu", ti.ts.outer_min);
> >>>>>> +     printf("\n");
> >>>>>> +     printf("# Avg Latencies:");
> >>>>>> +     printf(" %05lf", ti.ts.outer_avg);
> >>>>>> +     printf("\n");
> >>>>>> +     printf("# Max Latencies:");
> >>>>>> +     printf(" %05lu", ti.ts.outer_max);
> >>>>>> +     printf("\n");
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void cleanup(void)
> >>>>>> +{
> >>>>>> +     int ret;
> >>>>>> +
> >>>>>> +     if (ti.tracelimit < DEFAULT_LIMIT)
> >>>>>> +             tracing(OFF);
> >>>>>> +
> >>>>>> +     ret = close(ti.fd_dev_out);
> >>>>>> +     if (ret < 0)
> >>>>>> +             printf("can't close gpio_out device\n");
> >>>>>> +
> >>>>>> +     ret = close(ti.fd_dev_intr);
> >>>>>> +     if (ret < 0)
> >>>>>> +             printf("can't close gpio_intr device\n");
> >>>>>> +
> >>>>>> +     if (ti.mode == MODE_LOOPBACK)
> >>>>>> +             print_hist();
> >>>>>> +
> >>>>>> +}
> >>>>>> +
> >>>>>> +static void cleanup_and_exit(int sig)
> >>>>>> +{
> >>>>>> +     printf("Signal %d received\n", sig);
> >>>>>> +     cleanup();
> >>>>>> +     exit(0);
> >>>>>> +}
> >>>>>> +
> >>>>>> +int main(int argc, char **argv)
> >>>>>> +{
> >>>>>> +     struct sigaction sa __attribute__((unused));
> >>>>>> +     int ret = 0;
> >>>>>> +     pthread_attr_t tattr;
> >>>>>> +     int trigger, value;
> >>>>>> +     char dev_name[64];
> >>>>>> +
> >>>>>> +     init_ti();
> >>>>>> +
> >>>>>> +     process_options(argc, argv);
> >>>>>> +
> >>>>>> +     ret = mlockall(MCL_CURRENT|MCL_FUTURE);
> >>>>>> +     if (ret) {
> >>>>>> +             printf("mlockall failed\n");
> >>>>>> +             goto out;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     sprintf(dev_name, "%s%s/gpio%d",
> >>>>>> +                 DEV_PATH, ti.pin_controller, ti.gpio_out);
> >>>>>> +     ti.fd_dev_out = open(dev_name, O_RDWR);
> >>>>>> +     if (ti.fd_dev_out < 0) {
> >>>>>> +             printf("can't open %s\n", dev_name);
> >>>>>> +             goto out;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     if (ti.gpio_out) {
> >>>>>> +             value = 0;
> >>>>>> +             ret = ioctl(ti.fd_dev_out, GPIO_RTIOC_DIR_OUT, &value);
> >>>>>> +             if (ret) {
> >>>>>> +                     printf("ioctl gpio port output, failed\n");
> >>>>>> +                     goto out;
> >>>>>> +             }
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     sprintf(dev_name, "%s%s/gpio%d",
> >>>>>> +                 DEV_PATH, ti.pin_controller, ti.gpio_intr);
> >>>>>> +     ti.fd_dev_intr = open(dev_name, O_RDWR);
> >>>>>> +     if (ti.fd_dev_intr < 0) {
> >>>>>> +             printf("can't open %s\n", dev_name);
> >>>>>> +             goto out;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     if (ti.gpio_intr) {
> >>>>>> +             trigger =
> >>>>>> GPIO_TRIGGER_EDGE_FALLING|GPIO_TRIGGER_EDGE_RISING;
> >>>>>> +             value = 1;
> >>>>>> +
> >>>>>> +             ret = ioctl(ti.fd_dev_intr, GPIO_RTIOC_IRQEN,
> >>>>>> &trigger);
> >>>>>> +             if (ret) {
> >>>>>> +                     printf("ioctl gpio port interrupt, failed\n");
> >>>>>> +                     goto out;
> >>>>>> +             }
> >>>>>> +
> >>>>>> +  ��          ret = ioctl(ti.fd_dev_intr, GPIO_RTIOC_TS, &value);
> >>>>>> +             if (ret) {
> >>>>>> +                     printf("ioctl gpio port ts, failed\n");
> >>>>>> +                     goto out;
> >>>>>> +             }
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     if (ti.tracelimit < DEFAULT_LIMIT)
> >>>>>> +             tracing(ON);
> >>>>>> +
> >>>>>> +     signal(SIGTERM, cleanup_and_exit);
> >>>>>> +     signal(SIGINT, cleanup_and_exit);
> >>>>>> +     setup_sched_parameters(&tattr, ti.prio);
> >>>>>> +
> >>>>>> +     if (ti.mode == MODE_LOOPBACK)
> >>>>>> +             ret = pthread_create(&ti.gpio_task, &tattr,
> >>>>>> +                                     run_gpiobench_loop, NULL);
> >>>>>> +     else
> >>>>>> +             ret = pthread_create(&ti.gpio_task, &tattr,
> >>>>>> +                                     run_gpiobench_react, NULL);
> >>>>>> +
> >>>>>> +     if (ret) {
> >>>>>> +             printf("pthread_create(gpiotask), failed\n");
> >>>>>> +             goto out;
> >>>>>> +     }
> >>>>>> +
> >>>>>> +     pthread_join(ti.gpio_task, NULL);
> >>>>>> +     pthread_attr_destroy(&tattr);
> >>>>>> +
> >>>>>> +out:
> >>>>>> +     cleanup();
> >>>>>> +     return 0;
> >>>>>> +}
> >>>>>>
> >>>>>
> >>>>> Looks good to me. Greg, any comments from your side?
> >>>>>
> >>>>> Jan
> >>>>>
> >>>>> --
> >>>>> Siemens AG, Corporate Technology, CT RDA IOT SES-DE
> >>>>> Corporate Competence Center Embedded Linux
> >>>>
> >>>> Hi,
> >>>>    I'll run this on the zynq platform for testing tonight.  It looks
> >>>> good, my only concern is the 'ti.pin_controller' name may be a little
> >>>> bit misleading, but I want to confirm that assumption tonight.
> >>>>
> >>>> Thanks
> >>>>
> >>>> Greg
> >>>
> >>> Tested well on zynq.  After looking at gpio-core again, the name
> >>> pinctrl makes sense.  Looks good to me :)
> >>>
> >>
> >> Perfect - applied to next.
> >>
> >
> > Had to fix
> > https://travis-ci.com/github/xenomai-ci/xenomai/jobs/371291149. Was
> > trivial enough to force-push a new version.
> >
>
> ...but it wasn't trivial. I migrated from uint64_t to long long, please
> have a look at the result in next. Should be tested again on both 64 and
> 32-bit targets.
>
> Jan
>
> --
> Siemens AG, Corporate Technology, CT RDA IOT SES-DE
> Corporate Competence Center Embedded Linux

Don't know why i didn't hit it in my testing, I can run it again on
ARM64/ARM platforms. I need to do an ipipe release on both soon
anyway.

Thanks

Greg

Reply via email to