All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] testsuite: App of gpio loopback/react benchmark
@ 2020-08-03  6:04 chensong
  2020-08-11  7:15 ` Jan Kiszka
  0 siblings, 1 reply; 14+ messages in thread
From: chensong @ 2020-08-03  6:04 UTC (permalink / raw)
  To: xenomai, jan.kiszka, greg

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 <jan.kiszka@siemens.com>
CC: Greg Gallagher <greg@embeddedgreg.com>

Signed-off-by: chensong <chensong@tj.kylinos.cn>
---
 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 <chensong@tj.kylinos.cn>
+//
+// 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
+
+*-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 <chensong@tj.kylinos.cn>
+ *
+ * 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;
+}
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2020-08-13 10:41 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-03  6:04 [PATCH v3] testsuite: App of gpio loopback/react benchmark chensong
2020-08-11  7:15 ` Jan Kiszka
2020-08-11 15:36   ` Greg Gallagher
2020-08-12  3:36     ` Greg Gallagher
2020-08-12 14:55       ` Jan Kiszka
2020-08-12 15:28         ` Jan Kiszka
2020-08-12 15:43           ` Jan Kiszka
2020-08-12 16:10             ` Greg Gallagher
2020-08-12 16:14               ` Jan Kiszka
2020-08-13  1:57                 ` chensong
2020-08-13  8:54                   ` Jan Kiszka
2020-08-13 10:06                     ` chensong
2020-08-13 10:27                       ` Jan Kiszka
2020-08-13 10:41                         ` chensong

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.