* [Xenomai-core] [PATCH 1/6] Refactor tracer API
2006-06-26 17:21 [Xenomai-core] [PATCH 0/6] Various refactoring and new IRQ test jan.kiszka
@ 2006-06-26 17:21 ` jan.kiszka
2006-06-26 17:21 ` [Xenomai-core] [PATCH 2/6] Improve fault report jan.kiszka
` (4 subsequent siblings)
5 siblings, 0 replies; 31+ messages in thread
From: jan.kiszka @ 2006-06-26 17:21 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: xntrace-refactoring.patch --]
[-- Type: text/plain, Size: 23122 bytes --]
This patch encapsulates the I-pipe tracer facilities more cleanly according to the Xenomai layers. The changes are propagated to all current ipipe_trace_xxx users. Furthermore, the patch introduces a user-space inline API to invoke the tracer without the previous need to go through xeno_timerbench.
---
include/asm-generic/hal.h | 83 ++++++++++++++++++++++++++++++++
include/asm-generic/syscall.h | 1
include/asm-generic/system.h | 19 ++++---
include/asm-sim/system.h | 13 ++++-
include/asm-uvm/system.h | 13 ++++-
include/nucleus/assert.h | 4 -
include/nucleus/trace.h | 98 ++++++++++++++++++++++++++++++++++++++
include/nucleus/types.h | 2
include/rtdm/rttesting.h | 33 +-----------
ksrc/arch/i386/hal.c | 27 ++++------
ksrc/drivers/testing/timerbench.c | 55 ---------------------
ksrc/nucleus/shadow.c | 48 ++++++++++++++++++
src/testsuite/cyclic/cyclictest.c | 18 +-----
src/testsuite/latency/latency.c | 6 +-
14 files changed, 289 insertions(+), 131 deletions(-)
Index: include/asm-generic/syscall.h
===================================================================
--- include/asm-generic/syscall.h.orig
+++ include/asm-generic/syscall.h
@@ -29,6 +29,7 @@
#define __xn_sys_barrier 3 /* started = xnshadow_wait_barrier(&entry,&cookie) */
#define __xn_sys_info 4 /* xnshadow_get_info(muxid,&info) */
#define __xn_sys_arch 5 /* r = xnarch_local_syscall(args) */
+#define __xn_sys_trace 6 /* r = xntrace_xxx(...) */
#define XENOMAI_LINUX_DOMAIN 0
#define XENOMAI_XENO_DOMAIN 1
Index: include/rtdm/rttesting.h
===================================================================
--- include/rtdm/rttesting.h.orig
+++ include/rtdm/rttesting.h
@@ -1,6 +1,6 @@
/**
* @file
- * Real-Time Driver Model for Xenomai, benchmark device profile header
+ * Real-Time Driver Model for Xenomai, testing device profile header
*
* @note Copyright (C) 2005 Jan Kiszka <jan.kiszka@domain.hid>
*
@@ -18,16 +18,16 @@
* along with Xenomai; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * @ingroup rtbenchmark
+ * @ingroup rttesting
*/
/*!
* @ingroup profiles
- * @defgroup rtbenchmark Timer benchmark Device
+ * @defgroup rttesting Testing Device
*
- * This group of devices is intended to provide in-kernel benchmark results.
+ * This group of devices is intended to provide in-kernel testing results.
* Feel free to comment on this profile via the Xenomai mailing list
- * (Xenomai-help@domain.hid) or directly to the author (jan.kiszka@domain.hid). @n
+ * (xenomai@xenomai.org) or directly to the author (jan.kiszka@domain.hid). @n
* @n
*
* @par Device Characteristics
@@ -91,11 +91,6 @@ typedef struct rtbnch_overall_result {
long *histogram_max;
} rtbnch_overall_result_t;
-typedef struct rtbnch_trace_special {
- unsigned char id;
- long v;
-} rtbnch_trace_special_t;
-
#define RTIOC_TYPE_BENCHMARK RTDM_CLASS_TESTING
@@ -120,24 +115,6 @@ typedef struct rtbnch_trace_special {
#define RTBNCH_RTIOC_STOP_TMTEST \
_IOWR(RTIOC_TYPE_BENCHMARK, 0x11, struct rtbnch_overall_result)
-
-#define RTBNCH_RTIOC_BEGIN_TRACE \
- _IOW(RTIOC_TYPE_BENCHMARK, 0x20, long)
-
-#define RTBNCH_RTIOC_END_TRACE \
- _IOW(RTIOC_TYPE_BENCHMARK, 0x21, long)
-
-#define RTBNCH_RTIOC_FREEZE_TRACE \
- _IOW(RTIOC_TYPE_BENCHMARK, 0x22, long)
-
-#define RTBNCH_RTIOC_REFREEZE_TRACE \
- _IOW(RTIOC_TYPE_BENCHMARK, 0x23, long)
-
-#define RTBNCH_RTIOC_SPECIAL_TRACE \
- _IOW(RTIOC_TYPE_BENCHMARK, 0x24, unsigned char)
-
-#define RTBNCH_RTIOC_SPECIAL_TRACE_EX \
- _IOW(RTIOC_TYPE_BENCHMARK, 0x25, struct rtbnch_trace_special)
/** @} */
Index: src/testsuite/latency/latency.c
===================================================================
--- src/testsuite/latency/latency.c.orig
+++ src/testsuite/latency/latency.c
@@ -12,6 +12,7 @@
#include <native/timer.h>
#include <native/sem.h>
#include <rtdm/rttesting.h>
+#include <nucleus/trace.h>
RT_TASK latency_task, display_task;
@@ -130,8 +131,7 @@ void latency (void *cookie)
if (freeze_max && (dt > gmaxjitter) && !(finished || warmup))
{
- rt_dev_ioctl(benchdev, RTBNCH_RTIOC_REFREEZE_TRACE,
- rt_timer_tsc2ns(dt));
+ xntrace_user_freeze(rt_timer_tsc2ns(dt), 0);
gmaxjitter = dt;
}
@@ -545,7 +545,7 @@ int main (int argc, char **argv)
mlockall(MCL_CURRENT|MCL_FUTURE);
- if ((test_mode != USER_TASK) || freeze_max)
+ if (test_mode != USER_TASK)
{
char devname[RTDM_MAX_DEVNAME_LEN];
Index: src/testsuite/cyclic/cyclictest.c
===================================================================
--- src/testsuite/cyclic/cyclictest.c.orig
+++ src/testsuite/cyclic/cyclictest.c
@@ -36,7 +36,7 @@
#include <sys/mman.h>
#if IPIPE_TRACE
-#include <rtdm/rttesting.h>
+#include <nucleus/trace.h>
#endif
/* Ugly, but .... */
@@ -93,11 +93,6 @@ struct thread_stat {
static int test_shutdown;
static int tracelimit = 100000;
static struct timespec start;
-#if IPIPE_TRACE
-static int benchdev = -1;
-#else
-#define benchdev -1
-#endif
static inline void tsnorm(struct timespec *ts)
{
@@ -266,7 +261,7 @@ void *timerthread(void *param)
stat->max = diff;
#if IPIPE_TRACE
if (stat->traced)
- ioctl(benchdev, RTBNCH_RTIOC_REFREEZE_TRACE, diff);
+ xntrace_user_freeze(diff, 0);
#endif
}
@@ -411,9 +406,6 @@ static void process_options (int argc, c
static void sighand(int sig)
{
-#if IPIPE_TRACE
- close(benchdev);
-#endif
test_shutdown = 1;
}
@@ -469,10 +461,6 @@ int main(int argc, char **argv)
if (!stat)
goto outpar;
-#if IPIPE_TRACE
- benchdev = open("rtbenchmark0", O_RDWR);
-#endif
-
clock_gettime(clocksources[clocksel], &start);
for (i = 0; i < num_threads; i++) {
@@ -500,7 +488,7 @@ int main(int argc, char **argv)
pthread_attr_setstacksize(&thattr, 131072);
pthread_create(&stat[i].thread, &thattr, timerthread, &par[i]);
stat[i].threadstarted = 1;
- stat[i].traced = (i == 0 && benchdev >= 0);
+ stat[i].traced = (i == 0 && IPIPE_TRACE > 0);
}
while (!test_shutdown) {
Index: ksrc/drivers/testing/timerbench.c
===================================================================
--- ksrc/drivers/testing/timerbench.c.orig
+++ ksrc/drivers/testing/timerbench.c
@@ -232,55 +232,6 @@ int rt_tmbench_close(struct rtdm_dev_con
}
-#ifdef CONFIG_IPIPE_TRACE
-int tracer_ioctl(int request, rtdm_user_info_t *user_info, void *arg)
-{
- switch (request) {
- case RTBNCH_RTIOC_BEGIN_TRACE:
- ipipe_trace_begin((long)arg);
- break;
-
- case RTBNCH_RTIOC_END_TRACE:
- ipipe_trace_end((long)arg);
- break;
-
- case RTBNCH_RTIOC_REFREEZE_TRACE:
- ipipe_trace_frozen_reset();
- /* fall through */
-
- case RTBNCH_RTIOC_FREEZE_TRACE:
- ipipe_trace_freeze((long)arg);
- break;
-
- case RTBNCH_RTIOC_SPECIAL_TRACE:
- ipipe_trace_special((long)arg, 0);
- break;
-
- case RTBNCH_RTIOC_SPECIAL_TRACE_EX: {
- struct rtbnch_trace_special special;
-
- if (user_info) {
- if (!rtdm_read_user_ok(user_info, arg,
- sizeof(struct rtbnch_trace_special)) ||
- rtdm_copy_from_user(user_info, &special, arg,
- sizeof(struct rtbnch_trace_special)))
- return 0;
- } else
- special = *(struct rtbnch_trace_special *)arg;
- ipipe_trace_special(special.id, special.v);
- break;
- }
-
- default:
- return 0;
- }
- return 1;
-}
-#else /* !CONFIG_IPIPE_TRACE */
-#define tracer_ioctl(request, user_info, arg) (0)
-#endif /* CONFIG_IPIPE_TRACE */
-
-
int rt_tmbench_ioctl_nrt(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info, int request, void *arg)
{
@@ -288,9 +239,6 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
int ret = 0;
- if (tracer_ioctl(request, user_info, arg))
- return 0;
-
ctx = (struct rt_tmbench_context *)context->dev_private;
switch (request) {
@@ -475,9 +423,6 @@ int rt_tmbench_ioctl_rt(struct rtdm_dev_
int ret = 0;
- if (tracer_ioctl(request, user_info, arg))
- return 0;
-
ctx = (struct rt_tmbench_context *)context->dev_private;
switch (request) {
Index: ksrc/nucleus/shadow.c
===================================================================
--- ksrc/nucleus/shadow.c.orig
+++ ksrc/nucleus/shadow.c
@@ -51,6 +51,7 @@
#include <nucleus/ltt.h>
#include <nucleus/jhash.h>
#include <nucleus/ppd.h>
+#include <nucleus/trace.h>
#include <asm/xenomai/features.h>
int nkthrptd;
@@ -1262,6 +1263,50 @@ static int xnshadow_sys_barrier(struct t
return xnshadow_wait_barrier(regs);
}
+static int xnshadow_sys_trace(struct task_struct *curr, struct pt_regs *regs)
+{
+ int err = -ENOSYS;
+
+ switch (__xn_reg_arg1(regs)) {
+ case __xntrace_op_max_begin:
+ err = xnarch_trace_max_begin(__xn_reg_arg2(regs));
+ break;
+
+ case __xntrace_op_max_end:
+ err = xnarch_trace_max_end(__xn_reg_arg2(regs));
+ break;
+
+ case __xntrace_op_max_reset:
+ err = xnarch_trace_max_reset();
+ break;
+
+ case __xntrace_op_user_start:
+ err = xnarch_trace_user_start();
+ break;
+
+ case __xntrace_op_user_stop:
+ err = xnarch_trace_user_stop(__xn_reg_arg2(regs));
+ break;
+
+ case __xntrace_op_user_freeze:
+ err = xnarch_trace_user_freeze(__xn_reg_arg2(regs),
+ __xn_reg_arg3(regs));
+ break;
+
+ case __xntrace_op_special:
+ err = xnarch_trace_special(__xn_reg_arg2(regs) & 0xFF,
+ __xn_reg_arg3(regs));
+ break;
+
+ case __xntrace_op_special_u64:
+ err = xnarch_trace_special_u64(__xn_reg_arg2(regs) & 0xFF,
+ (((u64)__xn_reg_arg3(regs)) << 32) |
+ __xn_reg_arg4(regs));
+ break;
+ }
+ return err;
+}
+
static xnsysent_t xnshadow_systab[] = {
[__xn_sys_migrate] = {&xnshadow_sys_migrate, __xn_exec_current},
[__xn_sys_arch] = {&xnshadow_sys_arch, __xn_exec_any},
@@ -1269,6 +1314,7 @@ static xnsysent_t xnshadow_systab[] = {
[__xn_sys_info] = {&xnshadow_sys_info, __xn_exec_lostage},
[__xn_sys_completion] = {&xnshadow_sys_completion, __xn_exec_lostage},
[__xn_sys_barrier] = {&xnshadow_sys_barrier, __xn_exec_lostage},
+ [__xn_sys_trace] = {&xnshadow_sys_trace, __xn_exec_any},
};
static inline int substitute_linux_syscall(struct task_struct *curr,
@@ -1628,7 +1674,7 @@ static inline void do_schedule_event(str
properly recover from a stopped state. */
testbits(status, XNSTARTED)
&& testbits(status, XNPEND)) {
- ipipe_trace_panic_freeze();
+ xnarch_trace_panic_freeze();
show_stack(xnthread_user_task(threadin), NULL);
xnpod_fatal
("blocked thread %s[%d] rescheduled?! (status=0x%lx, sig=%d, prev=%s[%d])",
Index: include/asm-generic/hal.h
===================================================================
--- include/asm-generic/hal.h.orig
+++ include/asm-generic/hal.h
@@ -589,6 +589,89 @@ struct proc_dir_entry *__rthal_add_proc_
struct proc_dir_entry *parent);
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_IPIPE_TRACE
+#include <linux/ipipe_trace.h>
+
+static inline int rthal_trace_max_begin(unsigned long v)
+{
+ ipipe_trace_begin(v);
+ return 0;
+}
+
+static inline int rthal_trace_max_end(unsigned long v)
+{
+ ipipe_trace_end(v);
+ return 0;
+}
+
+static inline int rthal_trace_max_reset(void)
+{
+ ipipe_trace_max_reset();
+ return 0;
+}
+
+static inline int rthal_trace_user_start(void)
+{
+ return ipipe_trace_frozen_reset();
+}
+
+static inline int rthal_trace_user_stop(unsigned long v)
+{
+ ipipe_trace_freeze(v);
+ return 0;
+}
+
+static inline int rthal_trace_user_freeze(unsigned long v, int once)
+{
+ int err = 0;
+
+ if (!once)
+ err = ipipe_trace_frozen_reset();
+ ipipe_trace_freeze(v);
+ return err;
+}
+
+static inline int rthal_trace_special(unsigned char id, unsigned long v)
+{
+ ipipe_trace_special(id, v);
+ return 0;
+}
+
+static inline int rthal_trace_special_u64(unsigned char id,
+ unsigned long long v)
+{
+ ipipe_trace_special(id, (unsigned long)(v >> 32));
+ ipipe_trace_special(id, (unsigned long)(v & 0xFFFFFFFF));
+ return 0;
+}
+
+static inline int rthal_trace_panic_freeze(void)
+{
+ ipipe_trace_panic_freeze();
+ return 0;
+}
+
+static inline int rthal_trace_panic_dump(void)
+{
+ ipipe_trace_panic_dump();
+ return 0;
+}
+
+#else /* !CONFIG_IPIPE_TRACE */
+
+#define rthal_trace_max_begin(v) ({-ENOSYS;})
+#define rthal_trace_max_end(v) ({-ENOSYS;})
+#define rthal_trace_max_reset(v) ({-ENOSYS;})
+#define rthal_trace_user_start() ({-ENOSYS;})
+#define rthal_trace_user_stop(v) ({-ENOSYS;})
+#define rthal_trace_user_freeze(v, once) ({-ENOSYS;})
+#define rthal_trace_special(id, v) ({-ENOSYS;})
+#define rthal_trace_special_u64(id, v) ({-ENOSYS;})
+#define rthal_trace_panic_freeze() ({-ENOSYS;})
+#define rthal_trace_panic_dump() ({-ENOSYS;})
+
+#endif /* CONFIG_IPIPE_TRACE */
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Index: include/asm-generic/system.h
===================================================================
--- include/asm-generic/system.h.orig
+++ include/asm-generic/system.h
@@ -40,12 +40,17 @@
#include <asm/xenomai/atomic.h>
#include <nucleus/shadow.h>
-#ifdef CONFIG_IPIPE_TRACE
-#include <linux/ipipe_trace.h>
-#else /* !CONFIG_IPIPE_TRACE */
-#define ipipe_trace_panic_freeze()
-#define ipipe_trace_panic_dump()
-#endif /* CONFIG_IPIPE_TRACE */
+/* Tracer interface */
+#define xnarch_trace_max_begin(v) rthal_trace_max_begin(v)
+#define xnarch_trace_max_end(v) rthal_trace_max_end(v)
+#define xnarch_trace_max_reset() rthal_trace_max_reset()
+#define xnarch_trace_user_start() rthal_trace_user_start()
+#define xnarch_trace_user_stop(v) rthal_trace_user_stop(v)
+#define xnarch_trace_user_freeze(v, once) rthal_trace_user_freeze(v, once)
+#define xnarch_trace_special(id, v) rthal_trace_special(id, v)
+#define xnarch_trace_special_u64(id, v) rthal_trace_special_u64(id, v)
+#define xnarch_trace_panic_freeze() rthal_trace_panic_freeze()
+#define xnarch_trace_panic_dump() rthal_trace_panic_dump()
#define module_param_value(parm) (parm)
@@ -199,7 +204,7 @@ do { \
rthal_emergency_console(); \
xnarch_logerr("fatal: %s\n",emsg); \
show_stack(NULL,NULL); \
- ipipe_trace_panic_dump(); \
+ xnarch_trace_panic_dump(); \
for (;;) cpu_relax(); \
} while(0)
Index: include/asm-sim/system.h
===================================================================
--- include/asm-sim/system.h.orig
+++ include/asm-sim/system.h
@@ -762,8 +762,17 @@ if (cond) \
__mvm_breakable(mvm_post_graph)(&(obj)->__mvm_display_context,state); \
while(0)
-/* Ipipe-tracer */
-#define ipipe_trace_panic_freeze()
+/* Tracer interface */
+#define xnarch_trace_max_begin(v) ({-ENOSYS;})
+#define xnarch_trace_max_end(v) ({-ENOSYS;})
+#define xnarch_trace_max_reset() ({-ENOSYS;})
+#define xnarch_trace_user_start() ({-ENOSYS;})
+#define xnarch_trace_user_stop(v) ({-ENOSYS;})
+#define xnarch_trace_user_freeze(v, once) ({-ENOSYS;})
+#define xnarch_trace_special(id, v) ({-ENOSYS;})
+#define xnarch_trace_special_u64(id, v) ({-ENOSYS;})
+#define xnarch_trace_panic_freeze() ({-ENOSYS;})
+#define xnarch_trace_panic_dump() ({-ENOSYS;})
#ifndef PAGE_SIZE
#define PAGE_SIZE sysconf(_SC_PAGESIZE)
Index: include/asm-uvm/system.h
===================================================================
--- include/asm-uvm/system.h.orig
+++ include/asm-uvm/system.h
@@ -784,7 +784,16 @@ static inline void xnarch_sysfree (void
#define xnarch_post_graph(obj,state)
#define xnarch_post_graph_if(obj,state,cond)
-/* Ipipe-tracer */
-#define ipipe_trace_panic_freeze()
+/* Tracer interface */
+#define xnarch_trace_max_begin(v) ({-ENOSYS;})
+#define xnarch_trace_max_end(v) ({-ENOSYS;})
+#define xnarch_trace_max_reset() ({-ENOSYS;})
+#define xnarch_trace_user_start() ({-ENOSYS;})
+#define xnarch_trace_user_stop(v) ({-ENOSYS;})
+#define xnarch_trace_user_freeze(v, once) ({-ENOSYS;})
+#define xnarch_trace_special(id, v) ({-ENOSYS;})
+#define xnarch_trace_special_u64(id, v) ({-ENOSYS;})
+#define xnarch_trace_panic_freeze() ({-ENOSYS;})
+#define xnarch_trace_panic_dump() ({-ENOSYS;})
#endif /* !_XENO_ASM_UVM_SYSTEM_H */
Index: include/nucleus/assert.h
===================================================================
--- include/nucleus/assert.h.orig
+++ include/nucleus/assert.h
@@ -24,9 +24,9 @@
#define XENO_ASSERT(subsystem,cond,action) do { \
if (unlikely(CONFIG_XENO_OPT_DEBUG_##subsystem > 0 && !(cond))) { \
- ipipe_trace_panic_freeze(); \
+ xnarch_trace_panic_freeze(); \
xnlogerr("assertion failed at %s:%d (%s)\n", __FILE__, __LINE__, (#cond)); \
- ipipe_trace_panic_dump(); \
+ xnarch_trace_panic_dump(); \
action; \
} \
} while(0)
Index: include/nucleus/trace.h
===================================================================
--- /dev/null
+++ include/nucleus/trace.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ *
+ * User space interface to the I-pipe tracer.
+ */
+
+#ifndef _XENO_NUCLEUS_TRACE_H
+#define _XENO_NUCLEUS_TRACE_H
+
+#define __xntrace_op_max_begin 0
+#define __xntrace_op_max_end 1
+#define __xntrace_op_max_reset 2
+#define __xntrace_op_user_start 3
+#define __xntrace_op_user_stop 4
+#define __xntrace_op_user_freeze 5
+#define __xntrace_op_special 6
+#define __xntrace_op_special_u64 7
+
+#if defined(__KERNEL__) || defined(__XENO_SIM__)
+
+#include <asm/xenomai/system.h>
+
+#define xntrace_max_begin(v) xnarch_trace_max_begin(v)
+#define xntrace_max_end(v) xnarch_trace_max_end(v)
+#define xntrace_max_reset() xnarch_trace_max_reset()
+#define xntrace_user_start() xnarch_trace_user_start()
+#define xntrace_user_stop(v) xnarch_trace_user_stop(v)
+#define xntrace_user_freeze(v, once) xnarch_trace_user_freeze(v, once)
+#define xntrace_special(id, v) xnarch_trace_special(id, v)
+#define xntrace_special_u64(id, v) xnarch_trace_special_u64(id, v)
+#define xntrace_panic_freeze() xnarch_trace_panic_freeze()
+#define xntrace_panic_dump() xnarch_trace_panic_dump()
+
+#else /* !(defined(__KERNEL__) || defined(__XENO_SIM__)) */
+
+#include <asm/xenomai/syscall.h>
+
+static inline int xntrace_max_begin(unsigned long v)
+{
+ return XENOMAI_SYSCALL2(__xn_sys_trace, __xntrace_op_max_begin, v);
+}
+
+static inline int xntrace_max_end(unsigned long v)
+{
+ return XENOMAI_SYSCALL2(__xn_sys_trace, __xntrace_op_max_end, v);
+}
+
+static inline int xntrace_max_reset(void)
+{
+ return XENOMAI_SYSCALL1(__xn_sys_trace, __xntrace_op_max_reset);
+}
+
+static inline int xntrace_user_start(void)
+{
+ return XENOMAI_SYSCALL1(__xn_sys_trace, __xntrace_op_user_start);
+}
+
+static inline int xntrace_user_stop(unsigned long v)
+{
+ return XENOMAI_SYSCALL2(__xn_sys_trace, __xntrace_op_user_stop, v);
+}
+
+static inline int xntrace_user_freeze(unsigned long v, int once)
+{
+ return XENOMAI_SYSCALL3(__xn_sys_trace, __xntrace_op_user_freeze,
+ v, once);
+}
+
+static inline int xntrace_special(unsigned char id, unsigned long v)
+{
+ return XENOMAI_SYSCALL3(__xn_sys_trace, __xntrace_op_special, id, v);
+}
+
+static inline int xntrace_special_u64(unsigned char id, unsigned long long v)
+{
+ return XENOMAI_SYSCALL4(__xn_sys_trace, __xntrace_op_special_u64, id,
+ (unsigned long)(v >> 32),
+ (unsigned long)(v & 0xFFFFFFFF));
+}
+
+#endif /* defined(__KERNEL__) || defined(__XENO_SIM__) */
+
+#endif /* !_XENO_NUCLEUS_TRACE_H */
Index: include/nucleus/types.h
===================================================================
--- include/nucleus/types.h.orig
+++ include/nucleus/types.h
@@ -112,7 +112,7 @@ void __xeno_user_exit(void);
#define xnpod_fatal(format,args...) \
do { \
const char *panic; \
- ipipe_trace_panic_freeze(); \
+ xnarch_trace_panic_freeze(); \
panic = xnpod_fatal_helper(format,##args); \
xnarch_halt(panic); \
} while (0)
Index: ksrc/arch/i386/hal.c
===================================================================
--- ksrc/arch/i386/hal.c.orig
+++ ksrc/arch/i386/hal.c
@@ -61,9 +61,6 @@
#endif /* CONFIG_X86_LOCAL_APIC */
#include <asm/xenomai/hal.h>
#include <stdarg.h>
-#ifdef CONFIG_IPIPE_TRACE
-#include <linux/ipipe_trace.h>
-#endif /* CONFIG_IPIPE_TRACE */
extern struct desc_struct idt_table[];
@@ -176,7 +173,7 @@ unsigned long rthal_timer_calibrate(void
#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
/* reset the max trace, it contains the excessive calibration now */
- ipipe_trace_max_reset();
+ rthal_trace_max_reset();
#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
return rthal_imuldiv(dt, 100000, RTHAL_CPU_FREQ);
@@ -211,16 +208,16 @@ void die_nmi(struct pt_regs *regs, const
static void rthal_latency_above_max(struct pt_regs *regs)
{
-#ifdef CONFIG_IPIPE_TRACE
- ipipe_trace_freeze(rthal_maxlat_us);
-#else /* !CONFIG_IPIPE_TRACE */
- char buf[128];
- snprintf(buf,
- sizeof(buf),
- "NMI watchdog detected timer latency above %u us\n",
- rthal_maxlat_us);
- die_nmi(regs, buf);
-#endif /* CONFIG_IPIPE_TRACE */
+ /* Try to report via latency tracer first, then fall back to panic. */
+ if (rthal_trace_user_freeze(rthal_maxlat_us, 1) < 0) {
+ char buf[128];
+
+ snprintf(buf,
+ sizeof(buf),
+ "NMI watchdog detected timer latency above %u us\n",
+ rthal_maxlat_us);
+ die_nmi(regs, buf);
+ }
}
#endif /* CONFIG_XENO_HW_NMI_DEBUG_LATENCY */
@@ -341,7 +338,7 @@ unsigned long rthal_timer_calibrate(void
#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
/* reset the max trace, it contains the excessive calibration now */
- ipipe_trace_max_reset();
+ rthal_trace_max_reset();
#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */
return rthal_imuldiv(dt, 100000, RTHAL_CPU_FREQ);
--
^ permalink raw reply [flat|nested] 31+ messages in thread* [Xenomai-core] [PATCH 2/6] Improve fault report
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 ` jan.kiszka
2006-06-28 7:42 ` Philippe Gerum
2006-06-26 17:21 ` [Xenomai-core] [PATCH 3/6] Refactor rttesting device interface jan.kiszka
` (3 subsequent siblings)
5 siblings, 1 reply; 31+ messages in thread
From: jan.kiszka @ 2006-06-26 17:21 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: enhance-kernel-fault-report.patch --]
[-- Type: text/plain, Size: 2846 bytes --]
Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
---
include/asm-generic/system.h | 5 +++++
include/asm-sim/system.h | 1 +
include/asm-uvm/system.h | 1 +
ksrc/nucleus/pod.c | 11 ++++++++++-
4 files changed, 17 insertions(+), 1 deletion(-)
Index: xenomai/include/asm-generic/system.h
===================================================================
--- xenomai.orig/include/asm-generic/system.h
+++ xenomai/include/asm-generic/system.h
@@ -35,6 +35,7 @@
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/mmu_context.h>
+#include <asm/ptrace.h>
#include <linux/config.h>
#include <asm/xenomai/hal.h>
#include <asm/xenomai/atomic.h>
@@ -52,6 +53,10 @@
#define xnarch_trace_panic_freeze() rthal_trace_panic_freeze()
#define xnarch_trace_panic_dump() rthal_trace_panic_dump()
+#ifndef xnarch_fault_um
+#define xnarch_fault_um(fi) user_mode(fi->regs)
+#endif
+
#define module_param_value(parm) (parm)
typedef unsigned long spl_t;
Index: xenomai/include/asm-sim/system.h
===================================================================
--- xenomai.orig/include/asm-sim/system.h
+++ xenomai/include/asm-sim/system.h
@@ -56,6 +56,7 @@ typedef void *xnarch_fltinfo_t; /* Unuse
#define xnarch_fault_code(fi) 0
#define xnarch_fault_pc(fi) 0L
#define xnarch_fault_notify(fi) 1
+#define xnarch_fault_um(fi) 0
typedef int spl_t;
Index: xenomai/include/asm-uvm/system.h
===================================================================
--- xenomai.orig/include/asm-uvm/system.h
+++ xenomai/include/asm-uvm/system.h
@@ -192,6 +192,7 @@ typedef void *xnarch_fltinfo_t; /* Unuse
#define xnarch_fault_code(fi) 0
#define xnarch_fault_pc(fi) 0L
#define xnarch_fault_notify(fi) 1
+#define xnarch_fault_um(fi) 0
typedef struct xnarch_heapcb {
Index: xenomai/ksrc/nucleus/pod.c
===================================================================
--- xenomai.orig/ksrc/nucleus/pod.c
+++ xenomai/ksrc/nucleus/pod.c
@@ -194,7 +194,16 @@ static int xnpod_fault_handler(xnarch_fl
if (xnpod_shadow_p()) {
#ifdef CONFIG_XENO_OPT_DEBUG
- if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
+ if (!xnarch_fault_um(fltinfo)) {
+ xnarch_trace_panic_freeze();
+ xnprintf
+ ("Switching %s to secondary mode after exception #%u in "
+ "kernel-space at 0x%lx (pid %d)\n", thread->name,
+ xnarch_fault_trap(fltinfo),
+ xnarch_fault_pc(fltinfo),
+ xnthread_user_pid(thread));
+ xnarch_trace_panic_dump();
+ } else if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
xnprintf
("Switching %s to secondary mode after exception #%u from "
"user-space at 0x%lx (pid %d)\n", thread->name,
--
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
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
0 siblings, 1 reply; 31+ messages in thread
From: Philippe Gerum @ 2006-06-28 7:42 UTC (permalink / raw)
To: jan.kiszka; +Cc: xenomai
On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
> plain text document attachment (enhance-kernel-fault-report.patch)
> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
> if (xnpod_shadow_p()) {
> #ifdef CONFIG_XENO_OPT_DEBUG
> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
> + if (!xnarch_fault_um(fltinfo)) {
> + xnarch_trace_panic_freeze();
KGDB breakpoint issue?
> + xnprintf
> + ("Switching %s to secondary mode after exception #%u in "
> + "kernel-space at 0x%lx (pid %d)\n", thread->name,
> + xnarch_fault_trap(fltinfo),
> + xnarch_fault_pc(fltinfo),
> + xnthread_user_pid(thread));
> + xnarch_trace_panic_dump();
> + } else if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
--
Philippe.
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 7:42 ` Philippe Gerum
@ 2006-06-28 7:51 ` Jan Kiszka
2006-06-28 8:04 ` Philippe Gerum
0 siblings, 1 reply; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 7:51 UTC (permalink / raw)
To: rpm; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 1034 bytes --]
Philippe Gerum wrote:
> On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
>> plain text document attachment (enhance-kernel-fault-report.patch)
>> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
>
>> if (xnpod_shadow_p()) {
>> #ifdef CONFIG_XENO_OPT_DEBUG
>> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
>> + if (!xnarch_fault_um(fltinfo)) {
>> + xnarch_trace_panic_freeze();
>
> KGDB breakpoint issue?
Sorry, please switch on verbose mode, didn't get yet what you mean.
>
>> + xnprintf
>> + ("Switching %s to secondary mode after exception #%u in "
>> + "kernel-space at 0x%lx (pid %d)\n", thread->name,
>> + xnarch_fault_trap(fltinfo),
>> + xnarch_fault_pc(fltinfo),
>> + xnthread_user_pid(thread));
>> + xnarch_trace_panic_dump();
>> + } else if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
>
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 7:51 ` Jan Kiszka
@ 2006-06-28 8:04 ` Philippe Gerum
2006-06-28 8:18 ` Jan Kiszka
0 siblings, 1 reply; 31+ messages in thread
From: Philippe Gerum @ 2006-06-28 8:04 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai
On Wed, 2006-06-28 at 09:51 +0200, Jan Kiszka wrote:
> Philippe Gerum wrote:
> > On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
> >> plain text document attachment (enhance-kernel-fault-report.patch)
> >> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
> >
> >> if (xnpod_shadow_p()) {
> >> #ifdef CONFIG_XENO_OPT_DEBUG
> >> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
> >> + if (!xnarch_fault_um(fltinfo)) {
> >> + xnarch_trace_panic_freeze();
> >
> > KGDB breakpoint issue?
>
> Sorry, please switch on verbose mode, didn't get yet what you mean.
Oops, sorry. I meant: what if a KGDB breakpoint is hit from kernel space
while running a shadow thread? The way I read the modified test sequence
above, such bp trap is going to trigger a panic, instead of being
silently passed to Linux.
>
> >
> >> + xnprintf
> >> + ("Switching %s to secondary mode after exception #%u in "
> >> + "kernel-space at 0x%lx (pid %d)\n", thread->name,
> >> + xnarch_fault_trap(fltinfo),
> >> + xnarch_fault_pc(fltinfo),
> >> + xnthread_user_pid(thread));
> >> + xnarch_trace_panic_dump();
> >> + } else if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
> >
>
> Jan
>
--
Philippe.
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 8:04 ` Philippe Gerum
@ 2006-06-28 8:18 ` Jan Kiszka
2006-06-28 8:36 ` Philippe Gerum
0 siblings, 1 reply; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 8:18 UTC (permalink / raw)
To: rpm; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 1114 bytes --]
Philippe Gerum wrote:
> On Wed, 2006-06-28 at 09:51 +0200, Jan Kiszka wrote:
>> Philippe Gerum wrote:
>>> On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
>>>> plain text document attachment (enhance-kernel-fault-report.patch)
>>>> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
>>>> if (xnpod_shadow_p()) {
>>>> #ifdef CONFIG_XENO_OPT_DEBUG
>>>> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
>>>> + if (!xnarch_fault_um(fltinfo)) {
>>>> + xnarch_trace_panic_freeze();
>>> KGDB breakpoint issue?
>> Sorry, please switch on verbose mode, didn't get yet what you mean.
>
> Oops, sorry. I meant: what if a KGDB breakpoint is hit from kernel space
> while running a shadow thread? The way I read the modified test sequence
> above, such bp trap is going to trigger a panic, instead of being
> silently passed to Linux.
I would say: KGDB will not come along here with a breakpoint. It should
already got involved in __ipipe_divert_exception().
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 8:18 ` Jan Kiszka
@ 2006-06-28 8:36 ` Philippe Gerum
2006-06-28 8:51 ` Jan Kiszka
0 siblings, 1 reply; 31+ messages in thread
From: Philippe Gerum @ 2006-06-28 8:36 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai
On Wed, 2006-06-28 at 10:18 +0200, Jan Kiszka wrote:
> Philippe Gerum wrote:
> > On Wed, 2006-06-28 at 09:51 +0200, Jan Kiszka wrote:
> >> Philippe Gerum wrote:
> >>> On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
> >>>> plain text document attachment (enhance-kernel-fault-report.patch)
> >>>> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
> >>>> if (xnpod_shadow_p()) {
> >>>> #ifdef CONFIG_XENO_OPT_DEBUG
> >>>> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
> >>>> + if (!xnarch_fault_um(fltinfo)) {
> >>>> + xnarch_trace_panic_freeze();
> >>> KGDB breakpoint issue?
> >> Sorry, please switch on verbose mode, didn't get yet what you mean.
> >
> > Oops, sorry. I meant: what if a KGDB breakpoint is hit from kernel space
> > while running a shadow thread? The way I read the modified test sequence
> > above, such bp trap is going to trigger a panic, instead of being
> > silently passed to Linux.
>
> I would say: KGDB will not come along here with a breakpoint. It should
> already got involved in __ipipe_divert_exception().
Ok, so the only problem that remains would be inlined asm("int 1/3") in
kernel space not handled by KGDB (whether the KGDB patch is in or not).
I'm still scratching my head pondering if we can live with this or not.
>
> Jan
>
--
Philippe.
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 8:36 ` Philippe Gerum
@ 2006-06-28 8:51 ` Jan Kiszka
2006-06-28 9:00 ` Philippe Gerum
0 siblings, 1 reply; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 8:51 UTC (permalink / raw)
To: rpm; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 1636 bytes --]
Philippe Gerum wrote:
> On Wed, 2006-06-28 at 10:18 +0200, Jan Kiszka wrote:
>> Philippe Gerum wrote:
>>> On Wed, 2006-06-28 at 09:51 +0200, Jan Kiszka wrote:
>>>> Philippe Gerum wrote:
>>>>> On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
>>>>>> plain text document attachment (enhance-kernel-fault-report.patch)
>>>>>> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
>>>>>> if (xnpod_shadow_p()) {
>>>>>> #ifdef CONFIG_XENO_OPT_DEBUG
>>>>>> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
>>>>>> + if (!xnarch_fault_um(fltinfo)) {
>>>>>> + xnarch_trace_panic_freeze();
>>>>> KGDB breakpoint issue?
>>>> Sorry, please switch on verbose mode, didn't get yet what you mean.
>>> Oops, sorry. I meant: what if a KGDB breakpoint is hit from kernel space
>>> while running a shadow thread? The way I read the modified test sequence
>>> above, such bp trap is going to trigger a panic, instead of being
>>> silently passed to Linux.
>> I would say: KGDB will not come along here with a breakpoint. It should
>> already got involved in __ipipe_divert_exception().
>
> Ok, so the only problem that remains would be inlined asm("int 1/3") in
> kernel space not handled by KGDB (whether the KGDB patch is in or not).
> I'm still scratching my head pondering if we can live with this or not.
But this is perfectly one of the situations my patch tries to catch: a
fatal bug in the kernel! Such a hand-coded kernel breakpoint without a
debugger caring is a bug to me.
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 8:51 ` Jan Kiszka
@ 2006-06-28 9:00 ` Philippe Gerum
2006-06-28 9:17 ` Jan Kiszka
0 siblings, 1 reply; 31+ messages in thread
From: Philippe Gerum @ 2006-06-28 9:00 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai
On Wed, 2006-06-28 at 10:51 +0200, Jan Kiszka wrote:
> Philippe Gerum wrote:
> > On Wed, 2006-06-28 at 10:18 +0200, Jan Kiszka wrote:
> >> Philippe Gerum wrote:
> >>> On Wed, 2006-06-28 at 09:51 +0200, Jan Kiszka wrote:
> >>>> Philippe Gerum wrote:
> >>>>> On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
> >>>>>> plain text document attachment (enhance-kernel-fault-report.patch)
> >>>>>> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
> >>>>>> if (xnpod_shadow_p()) {
> >>>>>> #ifdef CONFIG_XENO_OPT_DEBUG
> >>>>>> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
> >>>>>> + if (!xnarch_fault_um(fltinfo)) {
> >>>>>> + xnarch_trace_panic_freeze();
> >>>>> KGDB breakpoint issue?
> >>>> Sorry, please switch on verbose mode, didn't get yet what you mean.
> >>> Oops, sorry. I meant: what if a KGDB breakpoint is hit from kernel space
> >>> while running a shadow thread? The way I read the modified test sequence
> >>> above, such bp trap is going to trigger a panic, instead of being
> >>> silently passed to Linux.
> >> I would say: KGDB will not come along here with a breakpoint. It should
> >> already got involved in __ipipe_divert_exception().
> >
> > Ok, so the only problem that remains would be inlined asm("int 1/3") in
> > kernel space not handled by KGDB (whether the KGDB patch is in or not).
> > I'm still scratching my head pondering if we can live with this or not.
>
> But this is perfectly one of the situations my patch tries to catch: a
> fatal bug in the kernel! Such a hand-coded kernel breakpoint without a
> debugger caring is a bug to me.
Not that sure: passive debug code may exist. Only the presence of the
debugger should activate it.
>
> Jan
>
--
Philippe.
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 9:00 ` Philippe Gerum
@ 2006-06-28 9:17 ` Jan Kiszka
2006-06-28 16:36 ` Philippe Gerum
0 siblings, 1 reply; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 9:17 UTC (permalink / raw)
To: rpm; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 2158 bytes --]
Philippe Gerum wrote:
> On Wed, 2006-06-28 at 10:51 +0200, Jan Kiszka wrote:
>> Philippe Gerum wrote:
>>> On Wed, 2006-06-28 at 10:18 +0200, Jan Kiszka wrote:
>>>> Philippe Gerum wrote:
>>>>> On Wed, 2006-06-28 at 09:51 +0200, Jan Kiszka wrote:
>>>>>> Philippe Gerum wrote:
>>>>>>> On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
>>>>>>>> plain text document attachment (enhance-kernel-fault-report.patch)
>>>>>>>> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
>>>>>>>> if (xnpod_shadow_p()) {
>>>>>>>> #ifdef CONFIG_XENO_OPT_DEBUG
>>>>>>>> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
>>>>>>>> + if (!xnarch_fault_um(fltinfo)) {
>>>>>>>> + xnarch_trace_panic_freeze();
>>>>>>> KGDB breakpoint issue?
>>>>>> Sorry, please switch on verbose mode, didn't get yet what you mean.
>>>>> Oops, sorry. I meant: what if a KGDB breakpoint is hit from kernel space
>>>>> while running a shadow thread? The way I read the modified test sequence
>>>>> above, such bp trap is going to trigger a panic, instead of being
>>>>> silently passed to Linux.
>>>> I would say: KGDB will not come along here with a breakpoint. It should
>>>> already got involved in __ipipe_divert_exception().
>>> Ok, so the only problem that remains would be inlined asm("int 1/3") in
>>> kernel space not handled by KGDB (whether the KGDB patch is in or not).
>>> I'm still scratching my head pondering if we can live with this or not.
>> But this is perfectly one of the situations my patch tries to catch: a
>> fatal bug in the kernel! Such a hand-coded kernel breakpoint without a
>> debugger caring is a bug to me.
>
> Not that sure: passive debug code may exist. Only the presence of the
> debugger should activate it.
>
...but remains a bug for me /w RT code. We now complain about this
exception happened. And there is no crash/BUG in this case, just a
desirable warning with back-trace in the log.
Jan
PS: Other OSes show you a nice blue-screen when they ran on such
orphaned breakpoints.
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 2/6] Improve fault report
2006-06-28 9:17 ` Jan Kiszka
@ 2006-06-28 16:36 ` Philippe Gerum
0 siblings, 0 replies; 31+ messages in thread
From: Philippe Gerum @ 2006-06-28 16:36 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai
On Wed, 2006-06-28 at 11:17 +0200, Jan Kiszka wrote:
> Philippe Gerum wrote:
> > On Wed, 2006-06-28 at 10:51 +0200, Jan Kiszka wrote:
> >> Philippe Gerum wrote:
> >>> On Wed, 2006-06-28 at 10:18 +0200, Jan Kiszka wrote:
> >>>> Philippe Gerum wrote:
> >>>>> On Wed, 2006-06-28 at 09:51 +0200, Jan Kiszka wrote:
> >>>>>> Philippe Gerum wrote:
> >>>>>>> On Mon, 2006-06-26 at 19:21 +0200, jan.kiszka@domain.hid wrote:
> >>>>>>>> plain text document attachment (enhance-kernel-fault-report.patch)
> >>>>>>>> Introduce xnarch_fault_um() to test if a fault happened in user-mode and applies the new feature to report core and driver crashes more verbosely.
> >>>>>>>> if (xnpod_shadow_p()) {
> >>>>>>>> #ifdef CONFIG_XENO_OPT_DEBUG
> >>>>>>>> - if (xnarch_fault_notify(fltinfo)) /* Don't report debug traps */
> >>>>>>>> + if (!xnarch_fault_um(fltinfo)) {
> >>>>>>>> + xnarch_trace_panic_freeze();
> >>>>>>> KGDB breakpoint issue?
> >>>>>> Sorry, please switch on verbose mode, didn't get yet what you mean.
> >>>>> Oops, sorry. I meant: what if a KGDB breakpoint is hit from kernel space
> >>>>> while running a shadow thread? The way I read the modified test sequence
> >>>>> above, such bp trap is going to trigger a panic, instead of being
> >>>>> silently passed to Linux.
> >>>> I would say: KGDB will not come along here with a breakpoint. It should
> >>>> already got involved in __ipipe_divert_exception().
> >>> Ok, so the only problem that remains would be inlined asm("int 1/3") in
> >>> kernel space not handled by KGDB (whether the KGDB patch is in or not).
> >>> I'm still scratching my head pondering if we can live with this or not.
> >> But this is perfectly one of the situations my patch tries to catch: a
> >> fatal bug in the kernel! Such a hand-coded kernel breakpoint without a
> >> debugger caring is a bug to me.
> >
> > Not that sure: passive debug code may exist. Only the presence of the
> > debugger should activate it.
> >
>
> ...but remains a bug for me /w RT code.
Someone inserting such passive breakpoints would have to know what she's
doing, in any case. Looking the relax counter in /proc/xenomai/stats
(which is among the first things to do when chasing unexpected
latencies) would also give a serious hint to the inattentive folks. What
bothers me is to restrict the usage one can do of debug vectors on
certain archs, just for the purpose of saving one's from careless
coding.
> We now complain about this
> exception happened. And there is no crash/BUG in this case, just a
> desirable warning with back-trace in the log.
>
Ok, If *_panic() routines do not actually panic at all, it's acceptable.
>
>
> PS: Other OSes show you a nice blue-screen when they ran on such
> orphaned breakpoints.
What other O/S do in this respect is not relevant; it's not an
inter-operability or compatibility issue between Xenomai and others,
it's a decision to make about which behaviour is the least intrusive wrt
debug strategies.
>
--
Philippe.
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Xenomai-core] [PATCH 3/6] Refactor rttesting device interface
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-26 17:21 ` jan.kiszka
2006-06-26 17:21 ` [Xenomai-core] [PATCH 4/6] Add prio switch to latency test jan.kiszka
` (2 subsequent siblings)
5 siblings, 0 replies; 31+ messages in thread
From: jan.kiszka @ 2006-06-26 17:21 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: rttesting-refactoring.patch --]
[-- Type: text/plain, Size: 33678 bytes --]
Refactors the RTDM rttesting header to apply more regular naming and propagates the changes through all users. The patch also extends the testing devices to automatically acquire a free rttestX device name if the first one is busy.
---
include/rtdm/rttesting.h | 129 ++++++++++++++++++--------------------
ksrc/drivers/testing/switchtest.c | 97 +++++++++++++++-------------
ksrc/drivers/testing/timerbench.c | 111 +++++++++++++++++---------------
src/testsuite/latency/latency.c | 26 +++----
src/testsuite/switchtest/switch.c | 69 ++++++++++----------
5 files changed, 223 insertions(+), 209 deletions(-)
Index: xenomai/include/rtdm/rttesting.h
===================================================================
--- xenomai.orig/include/rtdm/rttesting.h
+++ xenomai/include/rtdm/rttesting.h
@@ -31,9 +31,9 @@
* @n
*
* @par Device Characteristics
- * @ref rtdm_device.device_flags "Device Flags": @c RTDM_NAMED_DEVICE, @c RTDM_EXCLUSIVE @n
+ * @ref rtdm_device.device_flags "Device Flags": @c RTDM_NAMED_DEVICE @n
* @n
- * @ref rtdm_device.device_name "Device Name": @c "rtbenchmark<N>", N >= 0 @n
+ * @ref rtdm_device.device_name "Device Name": @c "rttest<N>", N >= 0 @n
* @n
* @ref rtdm_device.device_class "Device Class": @c RTDM_CLASS_TESTING @n
* @n
@@ -48,8 +48,8 @@
* Specific return values: none @n
* @n
* @b IOCTL @n
- * Mandatory Environments: see @ref TIMER_IOCTLs "below" @n
- * Specific return values: see @ref TIMER_IOCTLs "below" @n
+ * Mandatory Environments: see @ref IOCTLs below @n
+ * Specific return values: see @ref IOCTLs below @n
*
* @{
*/
@@ -59,105 +59,100 @@
#include <rtdm/rtdm.h>
-#define RTBNCH_TIMER_TASK 0
-#define RTBNCH_TIMER_HANDLER 1
-
-typedef struct rtbnch_result {
+typedef struct rttst_bench_res {
long long avg;
long min;
long max;
long overruns;
long test_loops;
-} rtbnch_result_t;
+} rttst_bench_res_t;
+
+typedef struct rttst_interm_bench_res {
+ struct rttst_bench_res last;
+ struct rttst_bench_res overall;
+} rttst_interm_bench_res_t;
+
+typedef struct rttst_overall_bench_res {
+ struct rttst_bench_res result;
+ long *histogram_avg;
+ long *histogram_min;
+ long *histogram_max;
+} rttst_overall_bench_res_t;
+
+
+#define RTTST_TMBENCH_TASK 0
+#define RTTST_TMBENCH_HANDLER 1
-typedef struct rtbnch_timerconfig {
+typedef struct rttst_tmbench_config {
int mode;
uint64_t period;
int warmup_loops;
int histogram_size;
int histogram_bucketsize;
int freeze_max;
-} rtbnch_timerconfig_t;
+} rttst_tmbench_config_t;
-typedef struct rtbnch_interm_result {
- struct rtbnch_result last;
- struct rtbnch_result overall;
-} rtbnch_interm_result_t;
-typedef struct rtbnch_overall_result {
- struct rtbnch_result result;
- long *histogram_avg;
- long *histogram_min;
- long *histogram_max;
-} rtbnch_overall_result_t;
+#define RTTST_SWTEST_FPU 0x1
+#define RTTST_SWTEST_USE_FPU 0x2 /* Only for kernel-space tasks. */
+
+struct rttst_swtest_task {
+ unsigned index;
+ unsigned flags;
+};
+
+struct rttst_swtest_dir {
+ unsigned from;
+ unsigned to;
+};
-#define RTIOC_TYPE_BENCHMARK RTDM_CLASS_TESTING
+#define RTIOC_TYPE_TESTING RTDM_CLASS_TESTING
/*!
* @name Sub-Classes of RTDM_CLASS_TESTING
* @{ */
-#define RTDM_SUBCLASS_TIMER 0
-
-#define RTDM_SUBCLASS_SWITCH 1
+#define RTDM_SUBCLASS_TIMERBENCH 0
+#define RTDM_SUBCLASS_IRQBENCH 1
+#define RTDM_SUBCLASS_SWITCHTEST 2
/** @} */
/*!
- * @anchor TIMER_IOCTLs @name TIMER_IOCTLs
- * Timer benchmark device IOCTLs
+ * @anchor IOCTLs @name IOCTLs
+ * Testing device IOCTLs
* @{ */
-#define RTBNCH_RTIOC_INTERM_RESULT \
- _IOWR(RTIOC_TYPE_BENCHMARK, 0x00, struct rtbnch_interm_result)
-
-#define RTBNCH_RTIOC_START_TMTEST \
- _IOW(RTIOC_TYPE_BENCHMARK, 0x10, struct rtbnch_timerconfig)
-
-#define RTBNCH_RTIOC_STOP_TMTEST \
- _IOWR(RTIOC_TYPE_BENCHMARK, 0x11, struct rtbnch_overall_result)
-/** @} */
-
+#define RTTST_RTIOC_INTERM_BENCH_RES \
+ _IOWR(RTIOC_TYPE_TESTING, 0x00, struct rttst_interm_bench_res)
-#define RTIOC_TYPE_SWITCH RTDM_CLASS_TESTING
-#define RTSWITCH_FPU 0x1
-#define RTSWITCH_USE_FPU 0x2 /* Only for kernel-space tasks. */
+#define RTTST_RTIOC_TMBENCH_START \
+ _IOW(RTIOC_TYPE_TESTING, 0x10, struct rttst_tmbench_config)
+#define RTTST_RTIOC_TMBENCH_STOP \
+ _IOWR(RTIOC_TYPE_TESTING, 0x11, struct rttst_overall_bench_res)
-struct rtswitch_task {
- unsigned index;
- unsigned flags;
-};
-
-struct rtswitch {
- unsigned from;
- unsigned to;
-};
-/**
- * @anchor SWITCH_IOCTLs @name @SWITCH_IOCTLs
- * Context-switch testing device IOCTLs
- * @{ */
-#define RTSWITCH_RTIOC_TASKS_COUNT \
- _IOW(RTIOC_TYPE_SWITCH, 0x30, unsigned long)
+#define RTTST_RTIOC_SWTEST_SET_TASKS_COUNT \
+ _IOW(RTIOC_TYPE_TESTING, 0x30, unsigned long)
-#define RTSWITCH_RTIOC_SET_CPU \
- _IOW(RTIOC_TYPE_SWITCH, 0x31, unsigned long)
+#define RTTST_RTIOC_SWTEST_SET_CPU \
+ _IOW(RTIOC_TYPE_TESTING, 0x31, unsigned long)
-#define RTSWITCH_RTIOC_REGISTER_UTASK \
- _IOW(RTIOC_TYPE_SWITCH, 0x32, struct rtswitch_task)
+#define RTTST_RTIOC_SWTEST_REGISTER_UTASK \
+ _IOW(RTIOC_TYPE_TESTING, 0x32, struct rttst_swtest_task)
-#define RTSWITCH_RTIOC_CREATE_KTASK \
- _IOWR(RTIOC_TYPE_SWITCH, 0x33, struct rtswitch_task)
+#define RTTST_RTIOC_SWTEST_CREATE_KTASK \
+ _IOWR(RTIOC_TYPE_TESTING, 0x33, struct rttst_swtest_task)
-#define RTSWITCH_RTIOC_PEND \
- _IOR(RTIOC_TYPE_SWITCH, 0x34, struct rtswitch_task)
+#define RTTST_RTIOC_SWTEST_PEND \
+ _IOR(RTIOC_TYPE_TESTING, 0x34, struct rttst_swtest_task)
-#define RTSWITCH_RTIOC_SWITCH_TO \
- _IOR(RTIOC_TYPE_SWITCH, 0x35, struct rtswitch)
+#define RTTST_RTIOC_SWTEST_SWITCH_TO \
+ _IOR(RTIOC_TYPE_TESTING, 0x35, struct rttst_swtest_dir)
-#define RTSWITCH_RTIOC_GET_SWITCHES_COUNT \
- _IOR(RTIOC_TYPE_SWITCH, 0x36, unsigned long)
+#define RTTST_RTIOC_SWTEST_GET_SWITCHES_COUNT \
+ _IOR(RTIOC_TYPE_TESTING, 0x36, unsigned long)
/** @} */
/** @} */
Index: xenomai/ksrc/drivers/testing/switchtest.c
===================================================================
--- xenomai.orig/ksrc/drivers/testing/switchtest.c
+++ xenomai/ksrc/drivers/testing/switchtest.c
@@ -10,7 +10,7 @@
#define RTSWITCH_KERNEL 0x8
typedef struct {
- struct rtswitch_task base;
+ struct rttst_swtest_task base;
xnsynch_t rt_synch;
struct semaphore nrt_synch;
xnthread_t ktask; /* For kernel-space real-time tasks. */
@@ -25,6 +25,11 @@ typedef struct rtswitch_context {
unsigned switches_count;
} rtswitch_context_t;
+static unsigned int start_index;
+
+module_param(start_index, uint, 0400);
+MODULE_PARM_DESC(start_index, "First device instance number to be used");
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gilles.Chanteperdrix@domain.hid");
@@ -163,9 +168,9 @@ static int rtswitch_set_tasks_count(rtsw
if (!tasks)
return -ENOMEM;
-
+
down(&ctx->lock);
-
+
if (ctx->tasks)
kfree(ctx->tasks);
@@ -179,7 +184,7 @@ static int rtswitch_set_tasks_count(rtsw
}
static int rtswitch_register_task(rtswitch_context_t *ctx,
- struct rtswitch_task *arg)
+ struct rttst_swtest_task *arg)
{
rtswitch_task_t *t;
@@ -226,10 +231,10 @@ static void rtswitch_ktask(void *cookie)
if (to == task->base.index)
++to;
- if (task->base.flags & RTSWITCH_USE_FPU)
+ if (task->base.flags & RTTST_SWTEST_USE_FPU)
fp_regs_set(task->base.index + i * 1000);
rtswitch_to_rt(ctx, task->base.index, to);
- if (task->base.flags & RTSWITCH_USE_FPU)
+ if (task->base.flags & RTTST_SWTEST_USE_FPU)
if (fp_regs_check(task->base.index + i * 1000))
xnpod_suspend_self();
@@ -239,7 +244,7 @@ static void rtswitch_ktask(void *cookie)
}
static int rtswitch_create_ktask(rtswitch_context_t *ctx,
- struct rtswitch_task *ptask)
+ struct rttst_swtest_task *ptask)
{
rtswitch_task_t *task;
xnflags_t init_flags;
@@ -260,14 +265,14 @@ static int rtswitch_create_ktask(rtswitc
arg.ctx = ctx;
arg.task = task;
- init_flags = (ptask->flags & RTSWITCH_FPU) ? XNFPU : 0;
+ init_flags = (ptask->flags & RTTST_SWTEST_FPU) ? XNFPU : 0;
/* Migrate the calling thread to the same CPU as the created task, in
order to be sure that the created task is suspended when this function
returns. This also allow us to use the stack to pass the parameters to
the created task. */
set_cpus_allowed(current, cpumask_of_cpu(ctx->cpu));
-
+
err = xnpod_init_thread(&task->ktask, name, 1, init_flags, 0);
if (!err)
@@ -331,25 +336,25 @@ static int rtswitch_ioctl_nrt(struct rtd
void *arg)
{
rtswitch_context_t *ctx = (rtswitch_context_t *) context->dev_private;
- struct rtswitch_task task;
- struct rtswitch fromto;
+ struct rttst_swtest_task task;
+ struct rttst_swtest_dir fromto;
unsigned long count;
int err;
switch (request)
{
- case RTSWITCH_RTIOC_TASKS_COUNT:
+ case RTTST_RTIOC_SWTEST_SET_TASKS_COUNT:
return rtswitch_set_tasks_count(ctx,
(unsigned long) arg);
- case RTSWITCH_RTIOC_SET_CPU:
+ case RTTST_RTIOC_SWTEST_SET_CPU:
if ((unsigned long) arg > xnarch_num_online_cpus() - 1)
return -EINVAL;
ctx->cpu = (unsigned long) arg;
return 0;
- case RTSWITCH_RTIOC_REGISTER_UTASK:
+ case RTTST_RTIOC_SWTEST_REGISTER_UTASK:
if (!rtdm_rw_user_ok(user_info, arg, sizeof(task)))
return -EFAULT;
@@ -365,7 +370,7 @@ static int rtswitch_ioctl_nrt(struct rtd
return err;
- case RTSWITCH_RTIOC_CREATE_KTASK:
+ case RTTST_RTIOC_SWTEST_CREATE_KTASK:
if (!rtdm_rw_user_ok(user_info, arg, sizeof(task)))
return -EFAULT;
@@ -381,15 +386,15 @@ static int rtswitch_ioctl_nrt(struct rtd
return err;
- case RTSWITCH_RTIOC_PEND:
+ case RTTST_RTIOC_SWTEST_PEND:
if (!rtdm_read_user_ok(user_info, arg, sizeof(task)))
return -EFAULT;
rtdm_copy_from_user(user_info, &task, arg, sizeof(task));
-
+
return rtswitch_pend_nrt(ctx, task.index);
- case RTSWITCH_RTIOC_SWITCH_TO:
+ case RTTST_RTIOC_SWTEST_SWITCH_TO:
if (!rtdm_read_user_ok(user_info, arg, sizeof(fromto)))
return -EFAULT;
@@ -402,7 +407,7 @@ static int rtswitch_ioctl_nrt(struct rtd
return 0;
- case RTSWITCH_RTIOC_GET_SWITCHES_COUNT:
+ case RTTST_RTIOC_SWTEST_GET_SWITCHES_COUNT:
if (!rtdm_rw_user_ok(user_info, arg, sizeof(count)))
return -EFAULT;
@@ -411,7 +416,7 @@ static int rtswitch_ioctl_nrt(struct rtd
rtdm_copy_to_user(user_info, arg, &count, sizeof(count));
return 0;
-
+
default:
return -ENOTTY;
}
@@ -423,25 +428,25 @@ static int rtswitch_ioctl_rt(struct rtdm
void *arg)
{
rtswitch_context_t *ctx = (rtswitch_context_t *) context->dev_private;
- struct rtswitch_task task;
- struct rtswitch fromto;
+ struct rttst_swtest_task task;
+ struct rttst_swtest_dir fromto;
- switch (request)
+ switch (request)
{
- case RTSWITCH_RTIOC_REGISTER_UTASK:
- case RTSWITCH_RTIOC_CREATE_KTASK:
- case RTSWITCH_RTIOC_GET_SWITCHES_COUNT:
+ case RTTST_RTIOC_SWTEST_REGISTER_UTASK:
+ case RTTST_RTIOC_SWTEST_CREATE_KTASK:
+ case RTTST_RTIOC_SWTEST_GET_SWITCHES_COUNT:
return -ENOSYS;
- case RTSWITCH_RTIOC_PEND:
+ case RTTST_RTIOC_SWTEST_PEND:
if (!rtdm_read_user_ok(user_info, arg, sizeof(task)))
return -EFAULT;
rtdm_copy_from_user(user_info, &task, arg, sizeof(task));
-
+
return rtswitch_pend_rt(ctx, task.index);
- case RTSWITCH_RTIOC_SWITCH_TO:
+ case RTTST_RTIOC_SWTEST_SWITCH_TO:
if (!rtdm_read_user_ok(user_info, arg, sizeof(fromto)))
return -EFAULT;
@@ -464,7 +469,7 @@ static struct rtdm_device device = {
device_flags: RTDM_NAMED_DEVICE,
context_size: sizeof(rtswitch_context_t),
- device_name: "rtswitch",
+ device_name: "",
open_rt: NULL,
open_nrt: rtswitch_open,
@@ -490,10 +495,10 @@ static struct rtdm_device device = {
},
device_class: RTDM_CLASS_TESTING,
- device_sub_class: RTDM_SUBCLASS_SWITCH,
- driver_name: "xeno_switchbench",
- driver_version: RTDM_DRIVER_VER(0, 1, 0),
- peripheral_name: "Context switch benchmark",
+ device_sub_class: RTDM_SUBCLASS_SWITCHTEST,
+ driver_name: "xeno_switchtest",
+ driver_version: RTDM_DRIVER_VER(0, 1, 1),
+ peripheral_name: "Context Switch Test",
provider_name: "Gilles Chanteperdrix",
proc_name: device.device_name,
};
@@ -503,7 +508,7 @@ void rtswitch_utask_waker(rtdm_nrtsig_t
up(&rtswitch_utask[xnarch_current_cpu()]->nrt_synch);
}
-int __init __switchbench_init(void)
+int __init __switchtest_init(void)
{
int err;
@@ -511,17 +516,23 @@ int __init __switchbench_init(void)
if (err)
return err;
-
- return rtdm_dev_register(&device);
+
+ do {
+ snprintf(device.device_name, RTDM_MAX_DEVNAME_LEN, "rttest%d",
+ start_index);
+ err = rtdm_dev_register(&device);
+
+ start_index++;
+ } while (err == -EEXIST);
+
+ return err;
}
-void __switchbench_exit(void)
+void __switchtest_exit(void)
{
- if(rtdm_dev_unregister(&device, 0))
- printk("Warning: could not unregister driver %s\n",
- device.device_name);
+ rtdm_dev_unregister(&device, 1000);
rtdm_nrtsig_destroy(&rtswitch_wake_utask);
}
-module_init(__switchbench_init);
-module_exit(__switchbench_exit);
+module_init(__switchtest_init);
+module_exit(__switchtest_exit);
Index: xenomai/ksrc/drivers/testing/timerbench.c
===================================================================
--- xenomai.orig/ksrc/drivers/testing/timerbench.c
+++ xenomai/ksrc/drivers/testing/timerbench.c
@@ -26,29 +26,29 @@
#include <rtdm/rtdm_driver.h>
struct rt_tmbench_context {
- int mode;
- unsigned long period;
- int freeze_max;
- int warmup_loops;
- int samples_per_sec;
- long *histogram_min;
- long *histogram_max;
- long *histogram_avg;
- int histogram_size;
- int bucketsize;
-
- rtdm_task_t timer_task;
-
- xntimer_t timer;
- int warmup;
- uint64_t start_time;
- uint64_t date;
- struct rtbnch_result curr;
+ int mode;
+ unsigned long period;
+ int freeze_max;
+ int warmup_loops;
+ int samples_per_sec;
+ long *histogram_min;
+ long *histogram_max;
+ long *histogram_avg;
+ int histogram_size;
+ int bucketsize;
+
+ rtdm_task_t timer_task;
+
+ xntimer_t timer;
+ int warmup;
+ uint64_t start_time;
+ uint64_t date;
+ struct rttst_bench_res curr;
- rtdm_event_t result_event;
- struct rtbnch_interm_result result;
+ rtdm_event_t result_event;
+ struct rttst_interm_bench_res result;
- struct semaphore nrt_mutex;
+ struct semaphore nrt_mutex;
};
static unsigned int start_index;
@@ -211,7 +211,7 @@ int rt_tmbench_close(struct rtdm_dev_con
down(&ctx->nrt_mutex);
if (ctx->mode >= 0) {
- if (ctx->mode == RTBNCH_TIMER_TASK)
+ if (ctx->mode == RTTST_TMBENCH_TASK)
rtdm_task_destroy(&ctx->timer_task);
else
/* FIXME: convert to RTDM timers */
@@ -242,17 +242,17 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
ctx = (struct rt_tmbench_context *)context->dev_private;
switch (request) {
- case RTBNCH_RTIOC_START_TMTEST: {
- struct rtbnch_timerconfig config_buf;
- struct rtbnch_timerconfig *config;
+ case RTTST_RTIOC_TMBENCH_START: {
+ struct rttst_tmbench_config config_buf;
+ struct rttst_tmbench_config *config;
- config = (struct rtbnch_timerconfig *)arg;
+ config = (struct rttst_tmbench_config *)arg;
if (user_info) {
if (!rtdm_read_user_ok(user_info, arg,
- sizeof(struct rtbnch_timerconfig)) ||
+ sizeof(struct rttst_tmbench_config)) ||
rtdm_copy_from_user(user_info, &config_buf, arg,
- sizeof(struct rtbnch_timerconfig)))
+ sizeof(struct rttst_tmbench_config)))
return -EFAULT;
config = &config_buf;
@@ -300,9 +300,9 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
rtdm_event_init(&ctx->result_event, 0);
- if (config->mode == RTBNCH_TIMER_TASK) {
+ if (config->mode == RTTST_TMBENCH_TASK) {
if (!test_bit(RTDM_CLOSING, &context->context_flags)) {
- ctx->mode = RTBNCH_TIMER_TASK;
+ ctx->mode = RTTST_TMBENCH_TASK;
ret = rtdm_task_init(&ctx->timer_task, "timerbench",
timer_task_proc, ctx,
RTDM_TASK_HIGHEST_PRIORITY, 0);
@@ -314,7 +314,7 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
ctx->curr.test_loops = 0;
if (!test_bit(RTDM_CLOSING, &context->context_flags)) {
- ctx->mode = RTBNCH_TIMER_HANDLER;
+ ctx->mode = RTTST_TMBENCH_HANDLER;
RTDM_EXECUTE_ATOMICALLY(
/* start time: one millisecond from now. */
ctx->start_time = rtdm_clock_read() + 1000000;
@@ -333,11 +333,11 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
break;
}
- case RTBNCH_RTIOC_STOP_TMTEST: {
- struct rtbnch_overall_result *usr_res;
+ case RTTST_RTIOC_TMBENCH_STOP: {
+ struct rttst_overall_bench_res *usr_res;
- usr_res = (struct rtbnch_overall_result *)arg;
+ usr_res = (struct rttst_overall_bench_res *)arg;
down(&ctx->nrt_mutex);
@@ -346,7 +346,7 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
return -EINVAL;
}
- if (ctx->mode == RTBNCH_TIMER_TASK)
+ if (ctx->mode == RTTST_TMBENCH_TASK)
rtdm_task_destroy(&ctx->timer_task);
else
/* FIXME: convert to RTDM timers */
@@ -363,14 +363,14 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
if (user_info) {
if (!rtdm_rw_user_ok(user_info, usr_res,
- sizeof(struct rtbnch_overall_result)) ||
+ sizeof(struct rttst_overall_bench_res)) ||
rtdm_copy_to_user(user_info, &usr_res->result,
&ctx->result.overall,
- sizeof(struct rtbnch_result)))
+ sizeof(struct rttst_bench_res)))
ret = -EFAULT;
} else {
memcpy(&usr_res->result, &ctx->result.overall,
- sizeof(struct rtbnch_result));
+ sizeof(struct rttst_bench_res));
}
if (ctx->histogram_size) {
@@ -404,7 +404,7 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
break;
}
- case RTBNCH_RTIOC_INTERM_RESULT:
+ case RTTST_RTIOC_INTERM_BENCH_RES:
ret = -ENOSYS;
break;
@@ -426,11 +426,11 @@ int rt_tmbench_ioctl_rt(struct rtdm_dev_
ctx = (struct rt_tmbench_context *)context->dev_private;
switch (request) {
- case RTBNCH_RTIOC_INTERM_RESULT: {
- struct rtbnch_interm_result *usr_res;
+ case RTTST_RTIOC_INTERM_BENCH_RES: {
+ struct rttst_interm_bench_res *usr_res;
- usr_res = (struct rtbnch_interm_result *)arg;
+ usr_res = (struct rttst_interm_bench_res *)arg;
ret = rtdm_event_wait(&ctx->result_event);
if (ret < 0)
@@ -438,19 +438,19 @@ int rt_tmbench_ioctl_rt(struct rtdm_dev_
if (user_info) {
if (!rtdm_rw_user_ok(user_info, usr_res,
- sizeof(struct rtbnch_interm_result)) ||
+ sizeof(struct rttst_interm_bench_res)) ||
rtdm_copy_to_user(user_info, usr_res, &ctx->result,
- sizeof(struct rtbnch_interm_result)))
+ sizeof(struct rttst_interm_bench_res)))
ret = -EFAULT;
} else
memcpy(usr_res, &ctx->result,
- sizeof(struct rtbnch_interm_result));
+ sizeof(struct rttst_interm_bench_res));
break;
}
- case RTBNCH_RTIOC_START_TMTEST:
- case RTBNCH_RTIOC_STOP_TMTEST:
+ case RTTST_RTIOC_TMBENCH_START:
+ case RTTST_RTIOC_TMBENCH_STOP:
ret = -ENOSYS;
break;
@@ -493,9 +493,9 @@ static struct rtdm_device device = {
},
device_class: RTDM_CLASS_TESTING,
- device_sub_class: RTDM_SUBCLASS_TIMER,
+ device_sub_class: RTDM_SUBCLASS_TIMERBENCH,
driver_name: "xeno_timerbench",
- driver_version: RTDM_DRIVER_VER(0, 1, 0),
+ driver_version: RTDM_DRIVER_VER(0, 2, 0),
peripheral_name: "Timer Latency Benchmark",
provider_name: "Jan Kiszka",
proc_name: device.device_name,
@@ -503,10 +503,17 @@ static struct rtdm_device device = {
int __init __timerbench_init(void)
{
- snprintf(device.device_name, RTDM_MAX_DEVNAME_LEN, "rtbenchmark%d",
- start_index);
+ int ret;
- return rtdm_dev_register(&device);
+ do {
+ snprintf(device.device_name, RTDM_MAX_DEVNAME_LEN, "rttest%d",
+ start_index);
+ ret = rtdm_dev_register(&device);
+
+ start_index++;
+ } while (ret == -EEXIST);
+
+ return ret;
}
Index: xenomai/src/testsuite/latency/latency.c
===================================================================
--- xenomai.orig/src/testsuite/latency/latency.c
+++ xenomai/src/testsuite/latency/latency.c
@@ -77,7 +77,7 @@ void latency (void *cookie)
RT_TIMER_INFO timer_info;
err = rt_timer_inquire(&timer_info);
-
+
if (err)
{
fprintf(stderr,"latency: rt_timer_inquire, code %d\n",err);
@@ -107,7 +107,7 @@ void latency (void *cookie)
for (count = sumj = 0; count < nsamples; count++)
{
- unsigned long ov;
+ unsigned long ov;
expected_tsc += period_tsc;
err = rt_task_wait_period(&ov);
@@ -186,12 +186,12 @@ void display (void *cookie)
}
} else {
- struct rtbnch_timerconfig config;
+ struct rttst_tmbench_config config;
if (test_mode == KERNEL_TASK)
- config.mode = RTBNCH_TIMER_TASK;
+ config.mode = RTTST_TMBENCH_TASK;
else
- config.mode = RTBNCH_TIMER_HANDLER;
+ config.mode = RTTST_TMBENCH_HANDLER;
config.period = period_ns;
config.warmup_loops = WARMUP_TIME;
@@ -199,7 +199,7 @@ void display (void *cookie)
config.histogram_bucketsize = bucketsize;
config.freeze_max = freeze_max;
- err = rt_dev_ioctl(benchdev, RTBNCH_RTIOC_START_TMTEST, &config);
+ err = rt_dev_ioctl(benchdev, RTTST_RTIOC_TMBENCH_START, &config);
if (err)
{
@@ -239,14 +239,14 @@ void display (void *cookie)
gmaxj = rt_timer_tsc2ns(gmaxjitter);
} else {
- struct rtbnch_interm_result result;
+ struct rttst_interm_bench_res result;
- err = rt_dev_ioctl(benchdev, RTBNCH_RTIOC_INTERM_RESULT, &result);
+ err = rt_dev_ioctl(benchdev, RTTST_RTIOC_INTERM_BENCH_RES, &result);
if (err)
{
if (err != -EIDRM)
- fprintf(stderr,"latency: failed to call RTBNCH_RTIOC_INTERM_RESULT, code %d\n",err);
+ fprintf(stderr,"latency: failed to call RTTST_RTIOC_INTERM_BENCH_RES, code %d\n",err);
return;
}
@@ -375,13 +375,13 @@ void cleanup_upon_sig(int sig __attribut
gmaxj = rt_timer_tsc2ns(gmaxjitter);
gavgj = rt_timer_tsc2ns(gavgjitter);
} else {
- struct rtbnch_overall_result overall;
+ struct rttst_overall_bench_res overall;
overall.histogram_min = histogram_min;
overall.histogram_max = histogram_max;
overall.histogram_avg = histogram_avg;
- rt_dev_ioctl(benchdev, RTBNCH_RTIOC_STOP_TMTEST, &overall);
+ rt_dev_ioctl(benchdev, RTTST_RTIOC_TMBENCH_STOP, &overall);
gminj = overall.result.min;
gmaxj = overall.result.max;
@@ -499,7 +499,7 @@ int main (int argc, char **argv)
" [-l <data-lines per header>] # default=21, 0 to supress headers\n"
" [-T <test_duration_seconds>] # default=0, so ^C to end\n"
" [-q] # supresses RTD, RTH lines if -T is used\n"
- " [-D <benchmark_device_no>] # number of benchmark device, default=0\n"
+ " [-D <testing_device_no>] # number of testing device, default=0\n"
" [-t <test_mode>] # 0=user task (default), 1=kernel task, 2=timer IRQ\n"
" [-f] # freeze trace for each new max latency\n"
" [-c <cpu>] # pin measuring task down to given CPU\n");
@@ -549,7 +549,7 @@ int main (int argc, char **argv)
{
char devname[RTDM_MAX_DEVNAME_LEN];
- snprintf(devname, RTDM_MAX_DEVNAME_LEN, "rtbenchmark%d", benchdev_no);
+ snprintf(devname, RTDM_MAX_DEVNAME_LEN, "rttest%d", benchdev_no);
benchdev = rt_dev_open(devname, O_RDWR);
if (benchdev < 0)
Index: xenomai/src/testsuite/switchtest/switch.c
===================================================================
--- xenomai.orig/src/testsuite/switchtest/switch.c
+++ xenomai/src/testsuite/switchtest/switch.c
@@ -35,7 +35,7 @@ struct task_params {
unsigned fp;
pthread_t thread;
struct cpu_tasks *cpu;
- struct rtswitch_task swt;
+ struct rttst_swtest_task swt;
};
struct cpu_tasks {
@@ -83,7 +83,7 @@ static void *sleeper(void *cookie)
unsigned tasks_count = param->cpu->tasks_count;
struct timespec ts, last;
int fd = param->cpu->fd;
- struct rtswitch rtsw;
+ struct rttst_swtest_dir rtsw;
cpu_set_t cpu_set;
unsigned i = 0;
@@ -121,13 +121,13 @@ static void *sleeper(void *cookie)
last = now;
if (ioctl(fd,
- RTSWITCH_RTIOC_GET_SWITCHES_COUNT,
+ RTTST_RTIOC_SWTEST_GET_SWITCHES_COUNT,
&switches_count)) {
- perror("sleeper: ioctl(RTSWITCH_RTIOC_GET_"
- "SWITCHES_COUNT)");
+ perror("sleeper: ioctl(RTTST_RTIOC_SWTEST_"
+ "GET_SWITCHES_COUNT)");
exit(EXIT_FAILURE);
}
-
+
printf("cpu %u: %lu\n",
param->cpu->index,
switches_count);
@@ -144,7 +144,7 @@ static void *sleeper(void *cookie)
++rtsw.to;
fp_regs_set(rtsw.from + i * 1000);
- if (ioctl(fd, RTSWITCH_RTIOC_SWITCH_TO, &rtsw))
+ if (ioctl(fd, RTTST_RTIOC_SWTEST_SWITCH_TO, &rtsw))
break;
if (fp_regs_check(rtsw.from + i * 1000))
pthread_kill(pthread_self(), SIGSTOP);
@@ -161,7 +161,7 @@ static void *rtup(void *cookie)
struct task_params *param = (struct task_params *) cookie;
unsigned tasks_count = param->cpu->tasks_count;
int err, fd = param->cpu->fd;
- struct rtswitch rtsw;
+ struct rttst_swtest_dir rtsw;
cpu_set_t cpu_set;
unsigned i = 0;
@@ -186,7 +186,7 @@ static void *rtup(void *cookie)
exit(EXIT_FAILURE);
}
- if (ioctl(fd, RTSWITCH_RTIOC_PEND, ¶m->swt))
+ if (ioctl(fd, RTTST_RTIOC_SWTEST_PEND, ¶m->swt))
return NULL;
for (;;) {
@@ -199,7 +199,7 @@ static void *rtup(void *cookie)
if (param->fp & UFPP)
fp_regs_set(rtsw.from + i * 1000);
- if (ioctl(fd, RTSWITCH_RTIOC_SWITCH_TO, &rtsw))
+ if (ioctl(fd, RTTST_RTIOC_SWTEST_SWITCH_TO, &rtsw))
break;
if (param->fp & UFPP)
if (fp_regs_check(rtsw.from + i * 1000))
@@ -217,7 +217,7 @@ static void *rtus(void *cookie)
struct task_params *param = (struct task_params *) cookie;
unsigned tasks_count = param->cpu->tasks_count;
int err, fd = param->cpu->fd;
- struct rtswitch rtsw;
+ struct rttst_swtest_dir rtsw;
cpu_set_t cpu_set;
unsigned i = 0;
@@ -242,7 +242,7 @@ static void *rtus(void *cookie)
exit(EXIT_FAILURE);
}
- if (ioctl(fd, RTSWITCH_RTIOC_PEND, ¶m->swt))
+ if (ioctl(fd, RTTST_RTIOC_SWTEST_PEND, ¶m->swt))
return NULL;
for (;;) {
@@ -255,7 +255,7 @@ static void *rtus(void *cookie)
if (param->fp & UFPS)
fp_regs_set(rtsw.from + i * 1000);
- if (ioctl(fd, RTSWITCH_RTIOC_SWITCH_TO, &rtsw))
+ if (ioctl(fd, RTTST_RTIOC_SWTEST_SWITCH_TO, &rtsw))
break;
if (param->fp & UFPS)
if (fp_regs_check(rtsw.from + i * 1000))
@@ -273,7 +273,7 @@ static void *rtuo(void *cookie)
struct task_params *param = (struct task_params *) cookie;
unsigned mode, tasks_count = param->cpu->tasks_count;
int err, fd = param->cpu->fd;
- struct rtswitch rtsw;
+ struct rttst_swtest_dir rtsw;
cpu_set_t cpu_set;
unsigned i = 0;
@@ -296,8 +296,8 @@ static void *rtuo(void *cookie)
"rtup: pthread_set_mode_np: %s\n",
strerror(err));
exit(EXIT_FAILURE);
- }
- if (ioctl(fd, RTSWITCH_RTIOC_PEND, ¶m->swt))
+ }
+ if (ioctl(fd, RTTST_RTIOC_SWTEST_PEND, ¶m->swt))
return NULL;
mode = PTHREAD_PRIMARY;
@@ -311,7 +311,7 @@ static void *rtuo(void *cookie)
if ((mode && param->fp & UFPP) || (!mode && param->fp & UFPS))
fp_regs_set(rtsw.from + i * 1000);
- if (ioctl(fd, RTSWITCH_RTIOC_SWITCH_TO, &rtsw))
+ if (ioctl(fd, RTTST_RTIOC_SWTEST_SWITCH_TO, &rtsw))
break;
if ((mode && param->fp & UFPP) || (!mode && param->fp & UFPS))
if (fp_regs_check(rtsw.from + i * 1000))
@@ -341,7 +341,7 @@ static int parse_arg(struct task_params
const char *text;
unsigned flag;
};
-
+
static struct t2f type2flags [] = {
{ "rtk", RTK },
{ "rtup", RTUP },
@@ -380,14 +380,14 @@ static int parse_arg(struct task_params
if (isdigit(*text))
goto cpu_nr;
-
+
for(i = 0; i < sizeof(fp2flags)/sizeof(struct t2f); i++) {
size_t len = strlen(fp2flags[i].text);
if(!strncmp(text, fp2flags[i].text, len)) {
param->fp |= fp2flags[i].flag;
text += len;
-
+
goto fpflags;
}
}
@@ -688,22 +688,23 @@ int main(int argc, const char *argv[])
for (i = 0; i < nr_cpus; i ++) {
struct cpu_tasks *cpu = &cpus[i];
- cpu->fd = open("rtswitch", O_RDWR);
+ /* FIXME: grab number from -D option when provided */
+ cpu->fd = open("rttest0", O_RDWR);
if (cpu->fd == -1) {
- perror("open(\"rtswitch\")");
+ perror("open(\"rttest0\")");
goto failure;
}
if (ioctl(cpu->fd,
- RTSWITCH_RTIOC_TASKS_COUNT,
+ RTTST_RTIOC_SWTEST_SET_TASKS_COUNT,
cpu->tasks_count)) {
- perror("ioctl(RTSWITCH_RTIOC_TASKS_COUNT)");
+ perror("ioctl(RTTST_RTIOC_SWTEST_SET_TASKS_COUNT)");
goto failure;
}
- if (ioctl(cpu->fd, RTSWITCH_RTIOC_SET_CPU, i)) {
- perror("ioctl(RTSWITCH_RTIOC_SET_CPU)");
+ if (ioctl(cpu->fd, RTTST_RTIOC_SWTEST_SET_CPU, i)) {
+ perror("ioctl(RTTST_RTIOC_SWTEST_SET_CPU)");
goto failure;
}
@@ -717,17 +718,17 @@ int main(int argc, const char *argv[])
switch(param->type) {
case RTK:
param->swt.flags = (param->fp & AFP
- ? RTSWITCH_FPU
+ ? RTTST_SWTEST_FPU
: 0)
| (param->fp & UFPP
- ? RTSWITCH_USE_FPU
+ ? RTTST_SWTEST_USE_FPU
: 0);
if (ioctl(cpu->fd,
- RTSWITCH_RTIOC_CREATE_KTASK,
+ RTTST_RTIOC_SWTEST_CREATE_KTASK,
¶m->swt)) {
- perror("ioctl(RTSWITCH_RTIOC_CREATE_"
- "KTASK)");
+ perror("ioctl(RTTST_RTIOC_SWTEST_"
+ "CREATE_KTASK)");
goto failure;
}
break;
@@ -754,10 +755,10 @@ int main(int argc, const char *argv[])
param->swt.flags = 0;
if (ioctl(cpu->fd,
- RTSWITCH_RTIOC_REGISTER_UTASK,
+ RTTST_RTIOC_SWTEST_REGISTER_UTASK,
¶m->swt)) {
- perror("ioctl(RTSWITCH_RTIOC_REGISTER_"
- "UTASK)");
+ perror("ioctl(RTTST_RTIOC_SWTEST_"
+ "REGISTER_UTASK)");
goto failure;
}
break;
--
^ permalink raw reply [flat|nested] 31+ messages in thread* [Xenomai-core] [PATCH 4/6] Add prio switch to latency test
2006-06-26 17:21 [Xenomai-core] [PATCH 0/6] Various refactoring and new IRQ test jan.kiszka
` (2 preceding siblings ...)
2006-06-26 17:21 ` [Xenomai-core] [PATCH 3/6] Refactor rttesting device interface jan.kiszka
@ 2006-06-26 17:21 ` 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-26 17:21 ` [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark jan.kiszka
5 siblings, 1 reply; 31+ messages in thread
From: jan.kiszka @ 2006-06-26 17:21 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: latency-add-prio-switch.patch --]
[-- Type: text/plain, Size: 5197 bytes --]
Introduces -P <priority> switch to the latency test and extends xeno_timerbench to respect this for the kernel-based timer task as well. The patch also allows now to run multiple latency tests (both in-kernel and user-space) in parallel.
---
include/rtdm/rttesting.h | 1 +
ksrc/drivers/testing/timerbench.c | 4 ++--
src/testsuite/latency/latency.c | 20 ++++++++++++++++----
3 files changed, 19 insertions(+), 6 deletions(-)
Index: xenomai/include/rtdm/rttesting.h
===================================================================
--- xenomai.orig/include/rtdm/rttesting.h
+++ xenomai/include/rtdm/rttesting.h
@@ -86,6 +86,7 @@ typedef struct rttst_overall_bench_res {
typedef struct rttst_tmbench_config {
int mode;
uint64_t period;
+ int priority;
int warmup_loops;
int histogram_size;
int histogram_bucketsize;
Index: xenomai/ksrc/drivers/testing/timerbench.c
===================================================================
--- xenomai.orig/ksrc/drivers/testing/timerbench.c
+++ xenomai/ksrc/drivers/testing/timerbench.c
@@ -305,7 +305,7 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
ctx->mode = RTTST_TMBENCH_TASK;
ret = rtdm_task_init(&ctx->timer_task, "timerbench",
timer_task_proc, ctx,
- RTDM_TASK_HIGHEST_PRIORITY, 0);
+ config->priority, 0);
}
} else {
/* FIXME: convert to RTDM timers */
@@ -465,7 +465,7 @@ int rt_tmbench_ioctl_rt(struct rtdm_dev_
static struct rtdm_device device = {
struct_version: RTDM_DEVICE_STRUCT_VER,
- device_flags: RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
+ device_flags: RTDM_NAMED_DEVICE,
context_size: sizeof(struct rt_tmbench_context),
device_name: "",
Index: xenomai/src/testsuite/latency/latency.c
===================================================================
--- xenomai.orig/src/testsuite/latency/latency.c
+++ xenomai/src/testsuite/latency/latency.c
@@ -34,6 +34,7 @@ int quiet = 0; /* suppress prin
int benchdev_no = 0;
int benchdev = -1;
int freeze_max = 0;
+int priority = T_HIPRIO;
#define USER_TASK 0
#define KERNEL_TASK 1
@@ -194,6 +195,7 @@ void display (void *cookie)
config.mode = RTTST_TMBENCH_HANDLER;
config.period = period_ns;
+ config.priority = priority;
config.warmup_loops = WARMUP_TIME;
config.histogram_size = (do_histogram || do_stats) ? histogram_size : 0;
config.histogram_bucketsize = bucketsize;
@@ -425,7 +427,7 @@ int main (int argc, char **argv)
char task_name[16];
int cpu = 0;
- while ((c = getopt(argc,argv,"hp:l:T:qH:B:sD:t:fc:")) != EOF)
+ while ((c = getopt(argc,argv,"hp:l:T:qH:B:sD:t:fc:P:")) != EOF)
switch (c)
{
case 'h':
@@ -488,6 +490,10 @@ int main (int argc, char **argv)
cpu = T_CPU(atoi(optarg));
break;
+ case 'P':
+ priority = atoi(optarg);
+ break;
+
default:
fprintf(stderr, "usage: latency [options]\n"
@@ -502,7 +508,8 @@ int main (int argc, char **argv)
" [-D <testing_device_no>] # number of testing device, default=0\n"
" [-t <test_mode>] # 0=user task (default), 1=kernel task, 2=timer IRQ\n"
" [-f] # freeze trace for each new max latency\n"
- " [-c <cpu>] # pin measuring task down to given CPU\n");
+ " [-c <cpu>] # pin measuring task down to given CPU\n"
+ " [-P <priority>] # task priority (test mode 0 and 1 only)\n");
exit(2);
}
@@ -530,6 +537,11 @@ int main (int argc, char **argv)
if (period_ns == 0)
period_ns = 100000LL; /* ns */
+ if (priority <= T_LOPRIO)
+ priority = T_LOPRIO + 1;
+ else if (priority > T_HIPRIO)
+ priority = T_HIPRIO;
+
signal(SIGINT, cleanup_upon_sig);
signal(SIGTERM, cleanup_upon_sig);
signal(SIGHUP, cleanup_upon_sig);
@@ -563,7 +575,7 @@ int main (int argc, char **argv)
rt_timer_set_mode(TM_ONESHOT); /* Force aperiodic timing. */
snprintf(task_name, sizeof(task_name), "display-%d", getpid());
- err = rt_task_create(&display_task,task_name,0,98,T_FPU);
+ err = rt_task_create(&display_task,task_name,0,0,T_FPU);
if (err)
{
@@ -581,7 +593,7 @@ int main (int argc, char **argv)
if (test_mode == USER_TASK) {
snprintf(task_name, sizeof(task_name), "sampling-%d", getpid());
- err = rt_task_create(&latency_task,task_name,0,99,T_FPU|cpu);
+ err = rt_task_create(&latency_task,task_name,0,priority,T_FPU|cpu);
if (err)
{
--
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 4/6] Add prio switch to latency test
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
0 siblings, 0 replies; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 19:38 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: Type: text/plain, Size: 70 bytes --]
This is just a rebased version of the patch over revision #1275.
Jan
[-- Attachment #2: latency-add-prio-switch.patch --]
[-- Type: text/x-patch, Size: 5207 bytes --]
Subject: Add prio switch to latency test
Introduces -P <priority> switch to the latency test and extends xeno_timerbench to respect this for the kernel-based timer task as well. The patch also allows now to run multiple latency tests (both in-kernel and user-space) in parallel.
---
include/rtdm/rttesting.h | 1 +
ksrc/drivers/testing/timerbench.c | 4 ++--
src/testsuite/latency/latency.c | 20 ++++++++++++++++----
3 files changed, 19 insertions(+), 6 deletions(-)
Index: xenomai/include/rtdm/rttesting.h
===================================================================
--- xenomai.orig/include/rtdm/rttesting.h
+++ xenomai/include/rtdm/rttesting.h
@@ -86,6 +86,7 @@ typedef struct rttst_overall_bench_res {
typedef struct rttst_tmbench_config {
int mode;
uint64_t period;
+ int priority;
int warmup_loops;
int histogram_size;
int histogram_bucketsize;
Index: xenomai/ksrc/drivers/testing/timerbench.c
===================================================================
--- xenomai.orig/ksrc/drivers/testing/timerbench.c
+++ xenomai/ksrc/drivers/testing/timerbench.c
@@ -305,7 +305,7 @@ int rt_tmbench_ioctl_nrt(struct rtdm_dev
ctx->mode = RTTST_TMBENCH_TASK;
ret = rtdm_task_init(&ctx->timer_task, "timerbench",
timer_task_proc, ctx,
- RTDM_TASK_HIGHEST_PRIORITY, 0);
+ config->priority, 0);
}
} else {
/* FIXME: convert to RTDM timers */
@@ -465,7 +465,7 @@ int rt_tmbench_ioctl_rt(struct rtdm_dev_
static struct rtdm_device device = {
struct_version: RTDM_DEVICE_STRUCT_VER,
- device_flags: RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
+ device_flags: RTDM_NAMED_DEVICE,
context_size: sizeof(struct rt_tmbench_context),
device_name: "",
Index: xenomai/src/testsuite/latency/latency.c
===================================================================
--- xenomai.orig/src/testsuite/latency/latency.c
+++ xenomai/src/testsuite/latency/latency.c
@@ -34,6 +34,7 @@ int quiet = 0; /* suppress prin
int benchdev_no = 0;
int benchdev = -1;
int freeze_max = 0;
+int priority = T_HIPRIO;
#define USER_TASK 0
#define KERNEL_TASK 1
@@ -194,6 +195,7 @@ void display (void *cookie)
config.mode = RTTST_TMBENCH_HANDLER;
config.period = period_ns;
+ config.priority = priority;
config.warmup_loops = WARMUP_TIME;
config.histogram_size = (do_histogram || do_stats) ? histogram_size : 0;
config.histogram_bucketsize = bucketsize;
@@ -424,7 +426,7 @@ int main (int argc, char **argv)
char task_name[16];
int cpu = 0;
- while ((c = getopt(argc,argv,"hp:l:T:qH:B:sD:t:fc:")) != EOF)
+ while ((c = getopt(argc,argv,"hp:l:T:qH:B:sD:t:fc:P:")) != EOF)
switch (c)
{
case 'h':
@@ -487,6 +489,10 @@ int main (int argc, char **argv)
cpu = T_CPU(atoi(optarg));
break;
+ case 'P':
+ priority = atoi(optarg);
+ break;
+
default:
fprintf(stderr, "usage: latency [options]\n"
@@ -501,7 +507,8 @@ int main (int argc, char **argv)
" [-D <testing_device_no>] # number of testing device, default=0\n"
" [-t <test_mode>] # 0=user task (default), 1=kernel task, 2=timer IRQ\n"
" [-f] # freeze trace for each new max latency\n"
- " [-c <cpu>] # pin measuring task down to given CPU\n");
+ " [-c <cpu>] # pin measuring task down to given CPU\n"
+ " [-P <priority>] # task priority (test mode 0 and 1 only)\n");
exit(2);
}
@@ -529,6 +536,11 @@ int main (int argc, char **argv)
if (period_ns == 0)
period_ns = 100000LL; /* ns */
+ if (priority <= T_LOPRIO)
+ priority = T_LOPRIO + 1;
+ else if (priority > T_HIPRIO)
+ priority = T_HIPRIO;
+
signal(SIGINT, sighand);
signal(SIGTERM, sighand);
signal(SIGHUP, sighand);
@@ -562,7 +574,7 @@ int main (int argc, char **argv)
rt_timer_set_mode(TM_ONESHOT); /* Force aperiodic timing. */
snprintf(task_name, sizeof(task_name), "display-%d", getpid());
- err = rt_task_create(&display_task,task_name,0,98,T_FPU);
+ err = rt_task_create(&display_task,task_name,0,0,T_FPU);
if (err)
{
@@ -580,7 +592,7 @@ int main (int argc, char **argv)
if (test_mode == USER_TASK) {
snprintf(task_name, sizeof(task_name), "sampling-%d", getpid());
- err = rt_task_create(&latency_task,task_name,0,99,T_FPU|cpu);
+ err = rt_task_create(&latency_task,task_name,0,priority,T_FPU|cpu);
if (err)
{
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Xenomai-core] [PATCH 5/6] Overread dev-prefix on posix open
2006-06-26 17:21 [Xenomai-core] [PATCH 0/6] Various refactoring and new IRQ test jan.kiszka
` (3 preceding siblings ...)
2006-06-26 17:21 ` [Xenomai-core] [PATCH 4/6] Add prio switch to latency test jan.kiszka
@ 2006-06-26 17:21 ` 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
5 siblings, 1 reply; 31+ messages in thread
From: jan.kiszka @ 2006-06-26 17:21 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: accept-rtdm-dev-prefix.patch --]
[-- Type: text/plain, Size: 956 bytes --]
Adds support to the posix user-space lib to address RTDM-devices also with a (here meaningless) "/dev/" name prefix. Intended to increase user convenience slightly.
---
src/skins/posix/rtdm.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
Index: xenomai/src/skins/posix/rtdm.c
===================================================================
--- xenomai.orig/src/skins/posix/rtdm.c
+++ xenomai/src/skins/posix/rtdm.c
@@ -41,10 +41,15 @@ static inline int set_errno(int ret)
int __wrap_open(const char *path, int oflag, ...)
{
int ret, oldtype;
+ char *rtdm_path = path;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
- ret = XENOMAI_SKINCALL2(__rtdm_muxid, __rtdm_open, path, oflag);
+ /* skip path prefix for RTDM invocation */
+ if (strncmp(path, "/dev/", 5) == 0)
+ rtdm_path += 5;
+
+ ret = XENOMAI_SKINCALL2(__rtdm_muxid, __rtdm_open, rtdm_path, oflag);
pthread_setcanceltype(oldtype, NULL);
--
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 5/6] Overread dev-prefix on posix open
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
0 siblings, 0 replies; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 19:38 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: Type: text/plain, Size: 65 bytes --]
Update to fix a compiler warning (char * vs. const char *).
Jan
[-- Attachment #2: accept-rtdm-dev-prefix.patch --]
[-- Type: text/x-patch, Size: 1001 bytes --]
Subject: Overread dev-prefix on posix open
Adds support to the posix user-space lib to address RTDM-devices also with a (here meaningless) "/dev/" name prefix. Intended to increase user convenience slightly.
---
src/skins/posix/rtdm.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
Index: xenomai/src/skins/posix/rtdm.c
===================================================================
--- xenomai.orig/src/skins/posix/rtdm.c
+++ xenomai/src/skins/posix/rtdm.c
@@ -41,10 +41,15 @@ static inline int set_errno(int ret)
int __wrap_open(const char *path, int oflag, ...)
{
int ret, oldtype;
+ const char *rtdm_path = path;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
- ret = XENOMAI_SKINCALL2(__rtdm_muxid, __rtdm_open, path, oflag);
+ /* skip path prefix for RTDM invocation */
+ if (strncmp(path, "/dev/", 5) == 0)
+ rtdm_path += 5;
+
+ ret = XENOMAI_SKINCALL2(__rtdm_muxid, __rtdm_open, rtdm_path, oflag);
pthread_setcanceltype(oldtype, NULL);
^ permalink raw reply [flat|nested] 31+ messages in thread
* [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-26 17:21 [Xenomai-core] [PATCH 0/6] Various refactoring and new IRQ test jan.kiszka
` (4 preceding siblings ...)
2006-06-26 17:21 ` [Xenomai-core] [PATCH 5/6] Overread dev-prefix on posix open jan.kiszka
@ 2006-06-26 17:21 ` jan.kiszka
2006-06-27 16:45 ` Jan Kiszka
` (2 more replies)
5 siblings, 3 replies; 31+ messages in thread
From: jan.kiszka @ 2006-06-26 17:21 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: irqbench.patch --]
[-- Type: text/plain, Size: 35797 bytes --]
This patch introduces another rttesting driver, xeno_irqbench, for measuring external IRQ latencies. The irqbench device is controlled by a user-mode tool irqloop. A second tool for plain Linux, irqbench, is provided to trigger the event over serial or parallel cross-link (the latter is incomplete yet) and measure the reaction latency.
---
configure.in | 1
include/rtdm/rttesting.h | 38 ++
ksrc/drivers/Makefile | 2
ksrc/drivers/testing/Kconfig | 21 +
ksrc/drivers/testing/Makefile | 13 -
ksrc/drivers/testing/irqbench.c | 472 +++++++++++++++++++++++++++++++++++++
src/testsuite/Makefile.am | 2
src/testsuite/irqbench/Makefile.am | 47 +++
src/testsuite/irqbench/irqbench.c | 301 +++++++++++++++++++++++
src/testsuite/irqbench/irqloop.c | 169 +++++++++++++
src/testsuite/irqbench/runinfo | 1
11 files changed, 1056 insertions(+), 11 deletions(-)
Index: xenomai/include/rtdm/rttesting.h
===================================================================
--- xenomai.orig/include/rtdm/rttesting.h
+++ xenomai/include/rtdm/rttesting.h
@@ -94,6 +94,28 @@ typedef struct rttst_tmbench_config {
} rttst_tmbench_config_t;
+#define RTTST_IRQBENCH_USER_TASK 0
+#define RTTST_IRQBENCH_KERNEL_TASK 1
+#define RTTST_IRQBENCH_HANDLER 2
+
+#define RTTST_IRQBENCH_SERPORT 0
+#define RTTST_IRQBENCH_PARPORT 1
+
+struct rttst_irqbench_config {
+ int mode;
+ int priority;
+ int calibration_loops;
+ unsigned int port_type;
+ unsigned long port_ioaddr;
+ unsigned int port_irq;
+} rttst_irqbench_config_t;
+
+struct rttst_irqbench_stats {
+ unsigned long long irqs_received;
+ unsigned long long irqs_acknowledged;
+} rttst_irqbench_stats_t;
+
+
#define RTTST_SWTEST_FPU 0x1
#define RTTST_SWTEST_USE_FPU 0x2 /* Only for kernel-space tasks. */
@@ -134,6 +156,22 @@ struct rttst_swtest_dir {
_IOWR(RTIOC_TYPE_TESTING, 0x11, struct rttst_overall_bench_res)
+#define RTTST_RTIOC_IRQBENCH_START \
+ _IOW(RTIOC_TYPE_TESTING, 0x20, struct rttst_irqbench_config)
+
+#define RTTST_RTIOC_IRQBENCH_STOP \
+ _IO(RTIOC_TYPE_TESTING, 0x21)
+
+#define RTTST_RTIOC_IRQBENCH_GET_STATS \
+ _IOR(RTIOC_TYPE_TESTING, 0x22, struct rttst_irqbench_stats)
+
+#define RTTST_RTIOC_IRQBENCH_WAIT_IRQ \
+ _IO(RTIOC_TYPE_TESTING, 0x23)
+
+#define RTTST_RTIOC_IRQBENCH_REPLY_IRQ \
+ _IO(RTIOC_TYPE_TESTING, 0x24)
+
+
#define RTTST_RTIOC_SWTEST_SET_TASKS_COUNT \
_IOW(RTIOC_TYPE_TESTING, 0x30, unsigned long)
Index: xenomai/configure.in
===================================================================
--- xenomai.orig/configure.in
+++ xenomai/configure.in
@@ -602,6 +602,7 @@ AC_CONFIG_FILES([ \
src/testsuite/switchbench/Makefile \
src/testsuite/cyclic/Makefile \
src/testsuite/switchtest/Makefile \
+ src/testsuite/irqbench/Makefile \
include/Makefile \
include/asm-generic/Makefile \
include/asm-blackfin/Makefile \
Index: xenomai/ksrc/drivers/Makefile
===================================================================
--- xenomai.orig/ksrc/drivers/Makefile
+++ xenomai/ksrc/drivers/Makefile
@@ -11,7 +11,7 @@ else
subdir-$(CONFIG_XENO_DRIVERS_16550A) += 16550A
subdir-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += testing
-
+subdir-$(CONFIG_XENO_DRIVERS_IRQBENCH) += testing
subdir-$(CONFIG_XENO_DRIVERS_SWITCHTEST) += testing
include $(TOPDIR)/Rules.make
Index: xenomai/ksrc/drivers/testing/Kconfig
===================================================================
--- xenomai.orig/ksrc/drivers/testing/Kconfig
+++ xenomai/ksrc/drivers/testing/Kconfig
@@ -6,10 +6,19 @@ config XENO_DRIVERS_TIMERBENCH
Kernel-based benchmark driver for timer latency evaluation.
See testsuite/latency for a possible front-end.
+config XENO_DRIVERS_IRQBENCH
+ depends on XENO_SKIN_RTDM
+ tristate "IRQ benchmark driver"
+ default n
+ help
+ Loopback driver for IRQ latency evaluation over serial or parallel
+ port links. Additionally requires user-space helper and a logging tool
+ (see testsuite/irqbench).
+
config XENO_DRIVERS_SWITCHTEST
- depends on XENO_SKIN_RTDM
- tristate "Context switch unit testing driver"
- default n
- help
- Kernel-based driver for unit testing context switches and
- FPU switches.
+ depends on XENO_SKIN_RTDM
+ tristate "Context switch unit testing driver"
+ default n
+ help
+ Kernel-based driver for unit testing context switches and
+ FPU switches.
Index: xenomai/ksrc/drivers/testing/Makefile
===================================================================
--- xenomai.orig/ksrc/drivers/testing/Makefile
+++ xenomai/ksrc/drivers/testing/Makefile
@@ -5,11 +5,13 @@ ifeq ($(PATCHLEVEL),6)
EXTRA_CFLAGS += -Iinclude/xenomai
obj-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += xeno_timerbench.o
-
+obj-$(CONFIG_XENO_DRIVERS_IRQBENCH) += xeno_irqbench.o
obj-$(CONFIG_XENO_DRIVERS_SWITCHTEST) += xeno_switchtest.o
xeno_timerbench-y := timerbench.o
+xeno_irqbench-y := irqbench.o
+
xeno_switchtest-y := switchtest.o
EXTRA_CFLAGS += -Iinclude/xenomai
@@ -21,14 +23,16 @@ else
O_TARGET := built-in.o
obj-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += xeno_timerbench.o
-
+obj-$(CONFIG_XENO_DRIVERS_IRQBENCH) += xeno_irqbench.o
obj-$(CONFIG_XENO_DRIVERS_SWITCHTEST) += xeno_switchtest.o
xeno_timerbench-objs := timerbench.o
+xeno_irqbench-objs := irqbench.o
+
xeno_switchtest-objs := switchtest.o
-export-objs := $(xeno_timerbench-objs) $(xeno_switchtest-objs)
+export-objs := $(xeno_timerbench-objs) $(xeno_irqbench-objs) $(xeno_switchtest-objs)
EXTRA_CFLAGS += -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat
@@ -37,6 +41,9 @@ include $(TOPDIR)/Rules.make
xeno_timerbench.o: $(xeno_timerbench-objs)
$(LD) -r -o $@ $(xeno_timerbench-objs)
+xeno_irqbench.o: $(xeno_irqbench-objs)
+ $(LD) -r -o $@ $(xeno_irqbench-objs)
+
xeno_switchtest.o: $(xeno_switchtest-objs)
$(LD) -r -o $@ $(xeno_switchtest-objs)
Index: xenomai/ksrc/drivers/testing/irqbench.c
===================================================================
--- /dev/null
+++ xenomai/ksrc/drivers/testing/irqbench.c
@@ -0,0 +1,472 @@
+/*
+ * 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 <linux/module.h>
+#include <asm/semaphore.h>
+
+#include <rtdm/rttesting.h>
+#include <rtdm/rtdm_driver.h>
+#include <nucleus/trace.h>
+
+/* --- Serial port --- */
+
+#define MSR_DCTS 0x01
+#define MSR_DDSR 0x02
+#define MSR_DDCD 0x08
+
+#define MCR_RTS 0x02
+#define MCR_OUT2 0x08
+
+#define IER_MODEM 0x08
+
+#define RHR(ctx) (ctx->port_ioaddr + 0) /* Receive Holding Buffer */
+#define IER(ctx) (ctx->port_ioaddr + 1) /* Interrupt Enable Register */
+#define IIR(ctx) (ctx->port_ioaddr + 2) /* Interrupt Id Register */
+#define LCR(ctx) (ctx->port_ioaddr + 3) /* Line Control Register */
+#define MCR(ctx) (ctx->port_ioaddr + 4) /* Modem Control Register */
+#define LSR(ctx) (ctx->port_ioaddr + 5) /* Line Status Register */
+#define MSR(ctx) (ctx->port_ioaddr + 6) /* Modem Status Register */
+
+/* --- Parallel port --- */
+
+#define CTRL_INIT 0x04
+
+#define STAT_STROBE 0x10
+
+#define DATA(ctx) (ctx->port_ioaddr + 0) /* Data register */
+#define STAT(ctx) (ctx->port_ioaddr + 1) /* Status register */
+#define CTRL(ctx) (ctx->port_ioaddr + 2) /* Control register */
+
+struct rt_irqbench_context {
+ int mode;
+ int port_type;
+ unsigned long port_ioaddr;
+ unsigned int toggle;
+ struct rttst_irqbench_stats stats;
+ rtdm_irq_t irq_handle;
+ rtdm_event_t irq_event;
+ rtdm_task_t irq_task;
+ struct semaphore nrt_mutex;
+};
+
+static unsigned int start_index;
+
+module_param(start_index, uint, 0400);
+MODULE_PARM_DESC(start_index, "First device instance number to be used");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("jan.kiszka@domain.hid");
+
+
+static inline int rt_irqbench_check_irq(struct rt_irqbench_context *ctx)
+{
+ int status;
+
+
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ status = inb(MSR(ctx));
+ if (status & (MSR_DDSR | MSR_DDCD))
+ xntrace_user_freeze(0, 0);
+ if (!(status & MSR_DCTS))
+ return 0;
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ // todo
+ break;
+ }
+ ctx->stats.irqs_received++;
+ return 1;
+}
+
+
+static inline void rt_irqbench_hwreply(struct rt_irqbench_context *ctx)
+{
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ /* toggle RTS */
+ ctx->toggle ^= MCR_RTS;
+ outb(ctx->toggle, MCR(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ ctx->toggle ^= 0xFF;
+ outb(ctx->toggle, DATA(ctx));
+ break;
+ }
+ xntrace_special(0xBE, 0);
+ ctx->stats.irqs_acknowledged++;
+}
+
+
+static void rt_irqbench_task(void *arg)
+{
+ struct rt_irqbench_context *ctx = (struct rt_irqbench_context *)arg;
+
+
+ while (1) {
+ if (rtdm_event_wait(&ctx->irq_event) < 0)
+ return;
+ rt_irqbench_hwreply(ctx);
+ }
+}
+
+
+static int rt_irqbench_task_irq(rtdm_irq_t *irq_handle)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = rtdm_irq_get_arg(irq_handle, struct rt_irqbench_context);
+
+ if (rt_irqbench_check_irq(ctx))
+ rtdm_event_signal(&ctx->irq_event);
+
+ return RTDM_IRQ_HANDLED;
+}
+
+
+static int rt_irqbench_direct_irq(rtdm_irq_t *irq_handle)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = rtdm_irq_get_arg(irq_handle, struct rt_irqbench_context);
+
+ if (rt_irqbench_check_irq(ctx))
+ rt_irqbench_hwreply(ctx);
+
+ return RTDM_IRQ_HANDLED;
+}
+
+
+static int rt_irqbench_stop(struct rt_irqbench_context *ctx)
+{
+ if (ctx->mode < 0)
+ return -EINVAL;
+
+ /* Disable hardware */
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ outb(0, IER(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ outb(0, CTRL(ctx));
+ break;
+ }
+
+ rtdm_irq_free(&ctx->irq_handle);
+
+ if (ctx->mode == RTTST_IRQBENCH_KERNEL_TASK)
+ rtdm_task_destroy(&ctx->irq_task);
+
+ ctx->mode = -1;
+
+ return 0;
+}
+
+
+static int rt_irqbench_open(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int oflags)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ ctx->mode = -1;
+ rtdm_event_init(&ctx->irq_event, 0);
+ init_MUTEX(&ctx->nrt_mutex);
+
+ return 0;
+}
+
+
+static int rt_irqbench_close(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ down(&ctx->nrt_mutex);
+ rt_irqbench_stop(ctx);
+ rtdm_event_destroy(&ctx->irq_event);
+ up(&ctx->nrt_mutex);
+
+ return 0;
+}
+
+
+static int rt_irqbench_ioctl_nrt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int request,
+ void *arg)
+{
+ struct rt_irqbench_context *ctx;
+ int ret = 0;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ switch (request) {
+ case RTTST_RTIOC_IRQBENCH_START: {
+ struct rttst_irqbench_config config_buf;
+ struct rttst_irqbench_config *config;
+
+ config = (struct rttst_irqbench_config *)arg;
+ if (user_info) {
+ if (!rtdm_read_user_ok(user_info, arg,
+ sizeof(struct rttst_irqbench_config)) ||
+ rtdm_copy_from_user(user_info, &config_buf, arg,
+ sizeof(struct rttst_irqbench_config)))
+ return -EFAULT;
+
+ config = &config_buf;
+ }
+
+ if (config->port_type > RTTST_IRQBENCH_PARPORT)
+ return -EINVAL;
+
+ down(&ctx->nrt_mutex);
+
+ if (test_bit(RTDM_CLOSING, &context->context_flags))
+ goto unlock_start_out;
+
+ switch (config->mode) {
+ case RTTST_IRQBENCH_USER_TASK:
+ ret = rtdm_irq_request(&ctx->irq_handle, config->port_irq,
+ rt_irqbench_task_irq, 0,
+ "irqbench", ctx);
+ break;
+
+ case RTTST_IRQBENCH_KERNEL_TASK:
+ ret = rtdm_irq_request(&ctx->irq_handle, config->port_irq,
+ rt_irqbench_task_irq, 0,
+ "irqbench", ctx);
+ if (ret < 0)
+ goto unlock_start_out;
+
+ ret = rtdm_task_init(&ctx->irq_task, "irqbench",
+ rt_irqbench_task, ctx,
+ config->priority, 0);
+ if (ret < 0)
+ rtdm_irq_free(&ctx->irq_handle);
+ break;
+
+ case RTTST_IRQBENCH_HANDLER:
+ ret = rtdm_irq_request(&ctx->irq_handle, config->port_irq,
+ rt_irqbench_direct_irq, 0,
+ "irqbench", ctx);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret < 0)
+ goto unlock_start_out;
+
+ rtdm_irq_enable(&ctx->irq_handle);
+
+ ctx->mode = config->mode;
+
+ memset(&ctx->stats, 0, sizeof(ctx->stats));
+
+ ctx->port_type = config->port_type;
+ ctx->port_ioaddr = config->port_ioaddr;
+
+ /* Initialise hardware */
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ ctx->toggle = MCR_OUT2;
+
+ /* Reset DLAB, reset RTS, enable OUT2 */
+ outb(0, LCR(ctx));
+ outb(MCR_OUT2, MCR(ctx));
+
+ /* Mask all UART interrupts and clear pending ones. */
+ outb(0, IER(ctx));
+ inb(IIR(ctx));
+ inb(LSR(ctx));
+ inb(RHR(ctx));
+ inb(MSR(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ ctx->toggle = 0xAA;
+ outb(0xAA, DATA(ctx));
+ outb(CTRL_INIT, CTRL(ctx));
+ break;
+ }
+
+ // calibration
+
+ /* Arm IRQ */
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ outb(IER_MODEM, IER(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ outb(STAT_STROBE, CTRL(ctx));
+ break;
+ }
+
+ unlock_start_out:
+ up(&ctx->nrt_mutex);
+ break;
+ }
+
+ case RTTST_RTIOC_IRQBENCH_STOP:
+ down(&ctx->nrt_mutex);
+ ret = rt_irqbench_stop(ctx);
+ up(&ctx->nrt_mutex);
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_GET_STATS: {
+ struct rttst_irqbench_stats *usr_stats;
+
+ usr_stats = (struct rttst_irqbench_stats *)arg;
+
+ if (user_info) {
+ if (!rtdm_rw_user_ok(user_info, usr_stats,
+ sizeof(struct rttst_irqbench_stats)) ||
+ rtdm_copy_to_user(user_info, usr_stats,
+ &ctx->stats,
+ sizeof(struct rttst_irqbench_stats)))
+ ret = -EFAULT;
+ } else
+ *usr_stats = ctx->stats;
+ break;
+ }
+
+ case RTTST_RTIOC_IRQBENCH_WAIT_IRQ:
+ ret = -ENOSYS;
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_REPLY_IRQ:
+ rt_irqbench_hwreply(ctx);
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+
+static int rt_irqbench_ioctl_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int request,
+ void *arg)
+{
+ struct rt_irqbench_context *ctx;
+ int ret = 0;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ switch (request) {
+ case RTTST_RTIOC_IRQBENCH_WAIT_IRQ:
+ ret = rtdm_event_wait(&ctx->irq_event);
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_REPLY_IRQ:
+ rt_irqbench_hwreply(ctx);
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_START:
+ case RTTST_RTIOC_IRQBENCH_STOP:
+ case RTTST_RTIOC_IRQBENCH_GET_STATS:
+ ret = -ENOSYS;
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+
+static struct rtdm_device device = {
+ struct_version: RTDM_DEVICE_STRUCT_VER,
+
+ device_flags: RTDM_NAMED_DEVICE,
+ context_size: sizeof(struct rt_irqbench_context),
+ device_name: "",
+
+ open_rt: NULL,
+ open_nrt: rt_irqbench_open,
+
+ ops: {
+ close_rt: NULL,
+ close_nrt: rt_irqbench_close,
+
+ ioctl_rt: rt_irqbench_ioctl_rt,
+ ioctl_nrt: rt_irqbench_ioctl_nrt,
+
+ read_rt: NULL,
+ read_nrt: NULL,
+
+ write_rt: NULL,
+ write_nrt: NULL,
+
+ recvmsg_rt: NULL,
+ recvmsg_nrt: NULL,
+
+ sendmsg_rt: NULL,
+ sendmsg_nrt: NULL,
+ },
+
+ device_class: RTDM_CLASS_TESTING,
+ device_sub_class: RTDM_SUBCLASS_IRQBENCH,
+ driver_name: "xeno_irqbench",
+ driver_version: RTDM_DRIVER_VER(0, 1, 0),
+ peripheral_name: "IRQ Latency Benchmark",
+ provider_name: "Jan Kiszka",
+ proc_name: device.device_name,
+};
+
+int __init __timerbench_init(void)
+{
+ int ret;
+
+ do {
+ snprintf(device.device_name, RTDM_MAX_DEVNAME_LEN, "rttest%d",
+ start_index);
+ ret = rtdm_dev_register(&device);
+
+ start_index++;
+ } while (ret == -EEXIST);
+
+ return ret;
+}
+
+
+void __exit __timerbench_exit(void)
+{
+ rtdm_dev_unregister(&device, 1000);
+}
+
+
+module_init(__timerbench_init);
+module_exit(__timerbench_exit);
Index: xenomai/src/testsuite/Makefile.am
===================================================================
--- xenomai.orig/src/testsuite/Makefile.am
+++ xenomai/src/testsuite/Makefile.am
@@ -1 +1 @@
-SUBDIRS = latency switchbench cyclic switchtest
+SUBDIRS = latency switchbench cyclic switchtest irqbench
Index: xenomai/src/testsuite/irqbench/Makefile.am
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/Makefile.am
@@ -0,0 +1,47 @@
+testdir = $(prefix)/testsuite/irqbench
+
+test_PROGRAMS = irqloop
+
+ifeq ($(XENO_TARGET_ARCH),i386)
+test_PROGRAMS += irqbench
+endif
+
+
+irqloop_SOURCES = irqloop.c
+
+irqloop_CPPFLAGS = \
+ -I$(top_srcdir)/include/posix \
+ $(XENO_USER_CFLAGS) \
+ -I$(top_srcdir)/include
+
+irqloop_LDFLAGS = \
+ $(XENO_POSIX_WRAPPERS) \
+ $(XENO_USER_LDFLAGS)
+
+irqloop_LDADD = \
+ -lpthread \
+ ../../skins/posix/.libs/libpthread_rt.a
+
+
+irqbench_SOURCES = irqbench.c
+
+irqbench_CPPFLAGS = \
+ $(XENO_USER_CFLAGS) \
+ -I$(top_srcdir)/include
+
+irqbench_LDFLAGS = $(XENO_USER_LDFLAGS)
+
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(testdir)
+ $(INSTALL_DATA) $(srcdir)/runinfo $(DESTDIR)$(testdir)/.runinfo
+ @echo "\$${DESTDIR}$(prefix)/bin/xeno-load \$$*" > $(DESTDIR)$(testdir)/run
+ @chmod +x $(DESTDIR)$(testdir)/run
+
+uninstall-local:
+ $(RM) $(DESTDIR)$(testdir)/.runinfo $(DESTDIR)$(testdir)/run
+
+run: all
+ @$(top_srcdir)/scripts/xeno-load --verbose
+
+EXTRA_DIST = runinfo
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;
+ }
+}
Index: xenomai/src/testsuite/irqbench/irqloop.c
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/irqloop.c
@@ -0,0 +1,169 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <rtdm/rttesting.h>
+
+static int benchdev;
+static int terminate;
+
+void *irq_thread(void *arg)
+{
+ while (1) {
+ if (ioctl(benchdev, RTTST_RTIOC_IRQBENCH_WAIT_IRQ) ||
+ ioctl(benchdev, RTTST_RTIOC_IRQBENCH_REPLY_IRQ))
+ return NULL;
+ }
+}
+
+
+void sighand(int sig)
+{
+ terminate = 1;
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char *mode_name[] =
+ { "user-space task", "kernel-space task", "IRQ handler" };
+ const char *port_type_name[] = { "serial", "parallel" };
+ char devname[RTDM_MAX_DEVNAME_LEN];
+ int benchdev_no = 0;
+ struct rttst_irqbench_config config = {
+ mode: RTTST_IRQBENCH_USER_TASK,
+ priority: sched_get_priority_max(SCHED_FIFO),
+ calibration_loops: 0,
+ port_type: RTTST_IRQBENCH_SERPORT,
+ port_ioaddr: 0x3f8,
+ port_irq: 4
+ };
+ struct rttst_irqbench_stats stats;
+ unsigned long long last_received = 0;
+ pthread_t thr;
+ int c;
+
+
+ while ((c = getopt(argc,argv,"D:t:P:o:a:i:")) != EOF)
+ switch (c) {
+ case 'D':
+ benchdev_no = atoi(optarg);
+ break;
+
+ case 't':
+ config.mode = atoi(optarg);
+ break;
+
+ case 'P':
+ config.priority = atoi(optarg);
+ break;
+
+ case 'o':
+ config.port_type = atoi(optarg);
+ break;
+
+ case 'a':
+ config.port_ioaddr = strtol(optarg, NULL,
+ (strncmp(optarg, "0x", 2) == 0) ? 16 : 10);
+ break;
+
+ case 'i':
+ config.port_irq = atoi(optarg);
+ break;
+
+ default:
+ fprintf(stderr, "usage: irqloop [options]\n"
+ " [-D <testing_device_no>] # number of testing device, default=0\n"
+ " [-t <test_mode>] # 0=user task (default), 1=kernel task, 2=IRQ\n"
+ " [-P <priority>] # task priority (test mode 0 and 1 only)\n"
+ " [-o <port_type>] # 0=serial (default), 1=parallel\n"
+ " [-a <port_io_address>] # default=0x3f8\n"
+ " [-i <port_irq>] # default=4\n");
+ exit(2);
+ }
+
+ signal(SIGINT, sighand);
+ signal(SIGTERM, sighand);
+ signal(SIGHUP, sighand);
+
+ mlockall(MCL_CURRENT|MCL_FUTURE);
+
+ snprintf(devname, RTDM_MAX_DEVNAME_LEN, "/dev/rttest%d", benchdev_no);
+ benchdev = open(devname, O_RDWR);
+ if (benchdev < 0) {
+ perror("irqloop: failed to open benchmark device");
+ fprintf(stderr, "(modprobe xeno_irqbench?)\n");
+ return 1;
+ }
+
+ if (config.mode == RTTST_IRQBENCH_USER_TASK) {
+ pthread_attr_t attr;
+ struct sched_param param;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+ param.sched_priority = config.priority;
+ pthread_attr_setschedparam(&attr, ¶m);
+ pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+
+ pthread_create(&thr, &attr, irq_thread, NULL);
+ }
+
+ if (ioctl(benchdev, RTTST_RTIOC_IRQBENCH_START, &config)) {
+ perror("irqloop: error starting test");
+ goto cleanup;
+ }
+
+ printf("Test mode: %s\n"
+ "Port type: %s\n"
+ "Port address: 0x%lx\n"
+ "Port IRQ: %d\n\n\n\n",
+ mode_name[config.mode], port_type_name[config.port_type],
+ config.port_ioaddr, config.port_irq);
+
+ while (!terminate) {
+ if (ioctl(benchdev, RTTST_RTIOC_IRQBENCH_GET_STATS, &stats) < 0) {
+ perror("irqloop: error reading stats");
+ break;
+ }
+
+ if ((last_received > 0) && (stats.irqs_received == last_received))
+ break; /* timed out */
+ last_received = stats.irqs_received;
+
+ printf("\033[2AReceived IRQs: %lld\nAcknowledged IRQs: %lld\n",
+ stats.irqs_received, stats.irqs_acknowledged);
+ usleep(250000);
+ }
+
+ ioctl(benchdev, RTTST_RTIOC_IRQBENCH_STOP);
+
+ cleanup:
+ close(benchdev);
+ if (config.mode == RTTST_IRQBENCH_USER_TASK) {
+ pthread_cancel(thr);
+ pthread_join(thr, NULL);
+ }
+
+ return 0;
+}
Index: xenomai/src/testsuite/irqbench/runinfo
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/runinfo
@@ -0,0 +1 @@
+irqloop:posix+rtdm+irqbench:!./irqloop;popall:control_c
--
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
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 19:39 ` Jan Kiszka
2 siblings, 0 replies; 31+ messages in thread
From: Jan Kiszka @ 2006-06-27 16:45 UTC (permalink / raw)
To: xenomai
[-- Attachment #1.1: Type: text/plain, Size: 579 bytes --]
jan.kiszka@domain.hid wrote:
> This patch introduces another rttesting driver, xeno_irqbench, for
> measuring external IRQ latencies. The irqbench device is controlled
> by a user-mode tool irqloop. A second tool for plain Linux, irqbench,
> is provided to trigger the event over serial or parallel cross-link
> (the latter is incomplete yet) and measure the reaction latency.
>
As a follow-up, here is a patch to add some documentation for irqbench.
I do not repeat the command line args of irqbench/irqloop, but feel free
to point out missing explanations.
Jan
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: irqbench-doc.patch --]
[-- Type: text/x-patch; name="irqbench-doc.patch", Size: 2592 bytes --]
Index: xenomai/doc/txt/irqbench.txt
===================================================================
--- /dev/null
+++ xenomai/doc/txt/irqbench.txt
@@ -0,0 +1,48 @@
+IRQ Latency Benchmark
+---------------------
+
+This latency benchmark for external interrupts consists of three parts:
+
+1. xeno_irqbench (ksrc/drivers/testing)
+ RTDM driver for the test target to handle and reply to the IRQ events, or
+ forward them to user-space.
+
+2. irqloop (src/testsuite/irqbench)
+ xeno_irqbench control front-end and user-space loop-closer. Runs against
+ the POSIX skin on the test target.
+
+3. irqbench (src/testsuite/irqbench)
+ IRQ triggering and reaction measuring tool for the log system. Runs over
+ plain Linux on x86 hosts (contains inline assembly, ports to other archs
+ will be welcome).
+
+To link both test and log system, a null-modem cable between 8250-compatible
+two RS232 ports is required. The infrastructure for parallel port cross-over
+is prepared as well, but yet untested and incomplete. The null-modem cable
+must provide at least the following links:
+
+ test target log system
+ ----------- ----------
+ CTS(8) <------ RTS(7) IRQ trigger
+ RTS(7) ------> CTS(8) reply
+
+ DCD(1)
+ and/or <------ DTR(4) trace trigger (optional)
+ DSR(6)
+
+ (Pin number on 9-pin sub-D socket)
+
+Test and log system can be started in arbitrary order, they will wait on
+each other.
+
+The log system runs each single IRQ measurement with local IRQs disabled. It
+will wait up to 100 times the current period on the test system's reply (after
+initial successful synchronisation, which happens with IRQs enabled). Note that
+these timeouts may disturb other processes or drivers on the log system.
+
+Keep in mind for test evaluations that, by design, irqbench will not trigger a
+new IRQ event before the reply on the previous one has arrived or timed out.
+Thus the specified test period may be dynamically expended in case of
+overload. But maximum a latency close or above the period will clearly
+indicate this.
+
Index: xenomai/doc/txt/Makefile.am
===================================================================
--- xenomai.orig/doc/txt/Makefile.am
+++ xenomai/doc/txt/Makefile.am
@@ -2,6 +2,7 @@ txtdocdir = $(datadir)/doc/$(PACKAGE)-$(
dist_txtdoc_DATA = \
16550A-driver.txt \
+ irqbench.txt \
pse51-skin.txt \
psos-skin.txt \
rtai-skin.txt \
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
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
2006-06-28 19:39 ` Jan Kiszka
2 siblings, 1 reply; 31+ messages in thread
From: Gilles Chanteperdrix @ 2006-06-28 12:11 UTC (permalink / raw)
To: jan.kiszka; +Cc: xenomai
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 ?
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.
--
Gilles Chanteperdrix.
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 12:11 ` Gilles Chanteperdrix
@ 2006-06-28 12:28 ` Jan Kiszka
2006-06-28 12:35 ` Gilles Chanteperdrix
2006-06-28 13:42 ` Gilles Chanteperdrix
0 siblings, 2 replies; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 12:28 UTC (permalink / raw)
To: Gilles Chanteperdrix; +Cc: xenomai
[-- 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 --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 12:28 ` Jan Kiszka
@ 2006-06-28 12:35 ` Gilles Chanteperdrix
2006-06-28 13:42 ` Gilles Chanteperdrix
1 sibling, 0 replies; 31+ messages in thread
From: Gilles Chanteperdrix @ 2006-06-28 12:35 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai
Jan Kiszka wrote:
> >
> > 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.
The mutex used by the stdio lib depends on the file descriptor, so, it
is possible to use a different file descriptor in the signal handler and
on the interrupted context.
--
Gilles Chanteperdrix.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 12:28 ` Jan Kiszka
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:44 ` Jan Kiszka
1 sibling, 2 replies; 31+ messages in thread
From: Gilles Chanteperdrix @ 2006-06-28 13:42 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai
Jan Kiszka wrote:
> > 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.
I do not understand: it appears to me that Xenomai trunk does not
compile on other architectures than x86 when applying the IRQ latency
benchmark patch. So, something needs to be done. It may be the enabling
of an automake conditional in configure.in when compiling for x86.
>
> >
> > 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.
The latency test used to deadlock, that is why the summary printed on
signal is printed on stderr. Unfortunately, there seem to be one display
left on stdout, so it should still deadlock. The reason why we never see
the deadlock is (perhaps) that the continuous intermediate results are
printed on the context of the "display" thread, whereas the termination
signals are preferably delivered by the kernel to the "main" thread,
that only calls pause. Which makes the use of stderr in signals handlers
pointless.
Anyway, since your program is frequently using printf on the context of
the main thread, the risk of deadlock is real.
--
Gilles Chanteperdrix.
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 13:42 ` Gilles Chanteperdrix
@ 2006-06-28 14:14 ` Dmitry Adamushko
2006-06-28 14:37 ` Jan Kiszka
2006-06-28 14:44 ` Jan Kiszka
1 sibling, 1 reply; 31+ messages in thread
From: Dmitry Adamushko @ 2006-06-28 14:14 UTC (permalink / raw)
To: Gilles Chanteperdrix; +Cc: Jan Kiszka, xenomai
On 28/06/06, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org> wrote:
> Jan Kiszka wrote:
> >
> > 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.
>
> The latency test used to deadlock, that is why the summary printed on
> signal is printed on stderr. Unfortunately, there seem to be one display
> left on stdout, so it should still deadlock. The reason why we never see
> the deadlock is (perhaps) that the continuous intermediate results are
> printed on the context of the "display" thread, whereas the termination
> signals are preferably delivered by the kernel to the "main" thread,
> that only calls pause. Which makes the use of stderr in signals handlers
> pointless.
It's very likely so.
The main thread would use instead something like :
...
while (!sig_term_received)
pause();
do_cleanup_chores();
return 0;
cleanup_upon_sig() should only set the sig_term_received flag up.
Then all other threads must block signal delivering with sigprocmask()
so that the main thread is the only one which "accepts" signals.
btw, according to POSIX 1003.1-2003, the write() call is amongst "safe" ones.
http://www.die.net/doc/linux/man/man2/signal.2.html
So write(1, ....); heh... not that nice? :)
--
Best regards,
Dmitry Adamushko
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 14:14 ` Dmitry Adamushko
@ 2006-06-28 14:37 ` Jan Kiszka
2006-06-28 15:18 ` Dmitry Adamushko
0 siblings, 1 reply; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 14:37 UTC (permalink / raw)
To: Dmitry Adamushko; +Cc: xenomai
[-- Attachment #1.1: Type: text/plain, Size: 1766 bytes --]
Dmitry Adamushko wrote:
> On 28/06/06, Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org> wrote:
>> Jan Kiszka wrote:
>> >
>> > 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.
>>
>> The latency test used to deadlock, that is why the summary printed on
>> signal is printed on stderr. Unfortunately, there seem to be one display
>> left on stdout, so it should still deadlock. The reason why we never see
>> the deadlock is (perhaps) that the continuous intermediate results are
>> printed on the context of the "display" thread, whereas the termination
>> signals are preferably delivered by the kernel to the "main" thread,
>> that only calls pause. Which makes the use of stderr in signals handlers
>> pointless.
>
> It's very likely so.
>
> The main thread would use instead something like :
> ...
> while (!sig_term_received)
> pause();
>
> do_cleanup_chores();
> return 0;
>
> cleanup_upon_sig() should only set the sig_term_received flag up.
>
> Then all other threads must block signal delivering with sigprocmask()
> so that the main thread is the only one which "accepts" signals.
Is that required, i.e. does pause() only wake up if the signal handler
executed in the main thread's context? Then cyclictest contains a bug as
well...
>
> btw, according to POSIX 1003.1-2003, the write() call is amongst "safe"
> ones.
> http://www.die.net/doc/linux/man/man2/signal.2.html
>
> So write(1, ....); heh... not that nice? :)
>
>
Something like this? Developed on top of my prio-switch patch. So far
without signal masking.
Jan
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: fix-printf-from-sig.patch --]
[-- Type: text/x-patch; name="fix-printf-from-sig.patch", Size: 3542 bytes --]
---
src/testsuite/latency/latency.c | 46 ++++++++++++++++++++--------------------
1 file changed, 24 insertions(+), 22 deletions(-)
Index: xenomai/src/testsuite/latency/latency.c
===================================================================
--- xenomai.orig/src/testsuite/latency/latency.c
+++ xenomai/src/testsuite/latency/latency.c
@@ -293,7 +293,7 @@ double dump_histogram (long *histogram,
double avg = 0; /* used to sum hits 1st */
if (do_histogram)
- fprintf(stderr,"---|--param|----range-|--samples\n");
+ printf("---|--param|----range-|--samples\n");
for (n = 0; n < histogram_size; n++)
{
@@ -304,12 +304,11 @@ double dump_histogram (long *histogram,
total_hits += hits;
avg += n * hits;
if (do_histogram)
- fprintf(stderr,
- "HSD| %s| %3d -%3d | %8ld\n",
- kind,
- n,
- n+1,
- hits);
+ printf("HSD| %s| %3d -%3d | %8ld\n",
+ kind,
+ n,
+ n+1,
+ hits);
}
}
@@ -338,8 +337,8 @@ void dump_stats (long *histogram, char*
variance /= total_hits - 1;
variance = sqrt(variance);
- fprintf(stderr,"HSS| %s| %9d| %10.3f| %10.3f\n",
- kind, total_hits, avg, variance);
+ printf("HSS| %s| %9d| %10.3f| %10.3f\n",
+ kind, total_hits, avg, variance);
}
void dump_hist_stats (void)
@@ -351,23 +350,18 @@ void dump_hist_stats (void)
avgavg = dump_histogram (histogram_avg, "avg");
maxavg = dump_histogram (histogram_max, "max");
- fprintf(stderr,"HSH|--param|--samples-|--average--|---stddev--\n");
+ printf("HSH|--param|--samples-|--average--|---stddev--\n");
dump_stats (histogram_min, "min", minavg);
dump_stats (histogram_avg, "avg", avgavg);
dump_stats (histogram_max, "max", maxavg);
}
-void cleanup_upon_sig(int sig __attribute__((unused)))
+void cleanup(void)
{
time_t actual_duration;
long gmaxj, gminj, gavgj;
- if (finished)
- return;
-
- finished = 1;
-
if (test_mode == USER_TASK) {
rt_sem_delete(&display_sem);
@@ -421,6 +415,11 @@ void cleanup_upon_sig(int sig __attribut
exit(0);
}
+void sighand(int sig __attribute__((unused)))
+{
+ finished = 1;
+}
+
int main (int argc, char **argv)
{
int c, err;
@@ -532,7 +531,7 @@ int main (int argc, char **argv)
histogram_min = calloc(histogram_size, sizeof(long));
if (!(histogram_avg && histogram_max && histogram_min))
- cleanup_upon_sig(0);
+ cleanup();
if (period_ns == 0)
period_ns = 100000LL; /* ns */
@@ -542,10 +541,10 @@ int main (int argc, char **argv)
else if (priority > T_HIPRIO)
priority = T_HIPRIO;
- signal(SIGINT, cleanup_upon_sig);
- signal(SIGTERM, cleanup_upon_sig);
- signal(SIGHUP, cleanup_upon_sig);
- signal(SIGALRM, cleanup_upon_sig);
+ signal(SIGINT, sighand);
+ signal(SIGTERM, sighand);
+ signal(SIGHUP, sighand);
+ signal(SIGALRM, sighand);
setlinebuf(stdout);
@@ -610,7 +609,10 @@ int main (int argc, char **argv)
}
}
- pause();
+ while (!finished)
+ pause();
+
+ cleanup();
return 0;
}
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 14:37 ` Jan Kiszka
@ 2006-06-28 15:18 ` Dmitry Adamushko
0 siblings, 0 replies; 31+ messages in thread
From: Dmitry Adamushko @ 2006-06-28 15:18 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai
> >
> > Then all other threads must block signal delivering with sigprocmask()
> > so that the main thread is the only one which "accepts" signals.
>
> Is that required, i.e. does pause() only wake up if the signal handler
> executed in the main thread's context? Then cyclictest contains a bug as
> well...
If strictly speaking, then yes, it's required. But I expect your fix
to be working perfectly, just because the current linux implementation
always favors the main thread when it comes to choosing a thread to
handle the signal.
look at signal.c :: __group_complete_signal() routine where the actual
magic happens.
from the comments
/*
* Now find a thread we can wake up to take the signal off the queue.
*
* If the main thread wants the signal, it gets first crack.
* Probably the least surprising to the average bear.
*/
...
As I understand, the only case when another thread may handle the
signal indeed is when the main thread has already another pending
signal. But even then nothing bad happens as pause() (in the main
thread) will be interrupted by this pending signal. Just "finished"
will be set up by some other thread but it doesn't really matter.
--
Best regards,
Dmitry Adamushko
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 13:42 ` Gilles Chanteperdrix
2006-06-28 14:14 ` Dmitry Adamushko
@ 2006-06-28 14:44 ` Jan Kiszka
1 sibling, 0 replies; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 14:44 UTC (permalink / raw)
To: Gilles Chanteperdrix; +Cc: xenomai
[-- Attachment #1: Type: text/plain, Size: 2727 bytes --]
Gilles Chanteperdrix wrote:
> Jan Kiszka wrote:
> > > 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.
>
> I do not understand: it appears to me that Xenomai trunk does not
> compile on other architectures than x86 when applying the IRQ latency
> benchmark patch. So, something needs to be done. It may be the enabling
> of an automake conditional in configure.in when compiling for x86.
>
See the patch:
Index: xenomai/src/testsuite/irqbench/Makefile.am
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/Makefile.am
@@ -0,0 +1,47 @@
+testdir = $(prefix)/testsuite/irqbench
+
+test_PROGRAMS = irqloop
+
+ifeq ($(XENO_TARGET_ARCH),i386)
+test_PROGRAMS += irqbench
+endif
I just realised that some hint in the documentation that irqbench can
easily be compiled outside Xenomai is required.
> >
> > >
> > > 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.
>
> The latency test used to deadlock, that is why the summary printed on
> signal is printed on stderr. Unfortunately, there seem to be one display
> left on stdout, so it should still deadlock. The reason why we never see
> the deadlock is (perhaps) that the continuous intermediate results are
> printed on the context of the "display" thread, whereas the termination
> signals are preferably delivered by the kernel to the "main" thread,
> that only calls pause. Which makes the use of stderr in signals handlers
> pointless.
>
> Anyway, since your program is frequently using printf on the context of
> the main thread, the risk of deadlock is real.
>
Ok, I'm going to address this.
Thanks for the hint!
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread
* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
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 19:39 ` Jan Kiszka
2006-06-29 11:20 ` Jan Kiszka
2 siblings, 1 reply; 31+ messages in thread
From: Jan Kiszka @ 2006-06-28 19:39 UTC (permalink / raw)
To: xenomai
[-- Attachment #1.1: Type: text/plain, Size: 460 bytes --]
Here comes an update of the irqbench patch.
Changelog:
- avoid printf from signal context in irqloop
- reorder irq-enable code in the driver to avoid spurious replies on
startup
- avoid creating/destroying pthread under SCHED_FIFO (but still suffers
from prio inversion during cleanup here)
- fix broken conditional compilation of irqbench for x86 (probably
unnoticed due to forgotten bootstrap run, sigh)
- include irqbench-doc.patch
Jan
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: irqbench.patch --]
[-- Type: text/x-patch; name="irqbench.patch", Size: 40079 bytes --]
Subject: Introduce IRQ latency benchmark
This patch introduces another rttesting driver, xeno_irqbench, for measuring external IRQ latencies. The irqbench device is controlled by a user-mode tool irqloop. A second tool for plain Linux, irqbench, is provided to trigger the event over serial or parallel cross-link (the latter is incomplete yet) and measure the reaction latency.
---
configure.in | 2
doc/txt/Makefile.am | 1
doc/txt/irqbench.txt | 51 ++++
include/rtdm/rttesting.h | 38 ++
ksrc/drivers/Makefile | 2
ksrc/drivers/testing/Kconfig | 21 +
ksrc/drivers/testing/Makefile | 13 -
ksrc/drivers/testing/irqbench.c | 470 +++++++++++++++++++++++++++++++++++++
src/testsuite/Makefile.am | 2
src/testsuite/irqbench/Makefile.am | 47 +++
src/testsuite/irqbench/irqbench.c | 306 ++++++++++++++++++++++++
src/testsuite/irqbench/irqloop.c | 173 +++++++++++++
src/testsuite/irqbench/runinfo | 1
13 files changed, 1116 insertions(+), 11 deletions(-)
Index: xenomai/include/rtdm/rttesting.h
===================================================================
--- xenomai.orig/include/rtdm/rttesting.h
+++ xenomai/include/rtdm/rttesting.h
@@ -94,6 +94,28 @@ typedef struct rttst_tmbench_config {
} rttst_tmbench_config_t;
+#define RTTST_IRQBENCH_USER_TASK 0
+#define RTTST_IRQBENCH_KERNEL_TASK 1
+#define RTTST_IRQBENCH_HANDLER 2
+
+#define RTTST_IRQBENCH_SERPORT 0
+#define RTTST_IRQBENCH_PARPORT 1
+
+struct rttst_irqbench_config {
+ int mode;
+ int priority;
+ int calibration_loops;
+ unsigned int port_type;
+ unsigned long port_ioaddr;
+ unsigned int port_irq;
+} rttst_irqbench_config_t;
+
+struct rttst_irqbench_stats {
+ unsigned long long irqs_received;
+ unsigned long long irqs_acknowledged;
+} rttst_irqbench_stats_t;
+
+
#define RTTST_SWTEST_FPU 0x1
#define RTTST_SWTEST_USE_FPU 0x2 /* Only for kernel-space tasks. */
@@ -134,6 +156,22 @@ struct rttst_swtest_dir {
_IOWR(RTIOC_TYPE_TESTING, 0x11, struct rttst_overall_bench_res)
+#define RTTST_RTIOC_IRQBENCH_START \
+ _IOW(RTIOC_TYPE_TESTING, 0x20, struct rttst_irqbench_config)
+
+#define RTTST_RTIOC_IRQBENCH_STOP \
+ _IO(RTIOC_TYPE_TESTING, 0x21)
+
+#define RTTST_RTIOC_IRQBENCH_GET_STATS \
+ _IOR(RTIOC_TYPE_TESTING, 0x22, struct rttst_irqbench_stats)
+
+#define RTTST_RTIOC_IRQBENCH_WAIT_IRQ \
+ _IO(RTIOC_TYPE_TESTING, 0x23)
+
+#define RTTST_RTIOC_IRQBENCH_REPLY_IRQ \
+ _IO(RTIOC_TYPE_TESTING, 0x24)
+
+
#define RTTST_RTIOC_SWTEST_SET_TASKS_COUNT \
_IOW(RTIOC_TYPE_TESTING, 0x30, unsigned long)
Index: xenomai/configure.in
===================================================================
--- xenomai.orig/configure.in
+++ xenomai/configure.in
@@ -82,6 +82,7 @@ case "$host" in
esac
AC_MSG_RESULT([$XENO_TARGET_ARCH])
+AM_CONDITIONAL(XENO_TARGET_ARCH_I386,[test $XENO_TARGET_ARCH = i386])
dnl
dnl Parse options
@@ -602,6 +603,7 @@ AC_CONFIG_FILES([ \
src/testsuite/switchbench/Makefile \
src/testsuite/cyclic/Makefile \
src/testsuite/switchtest/Makefile \
+ src/testsuite/irqbench/Makefile \
include/Makefile \
include/asm-generic/Makefile \
include/asm-blackfin/Makefile \
Index: xenomai/ksrc/drivers/Makefile
===================================================================
--- xenomai.orig/ksrc/drivers/Makefile
+++ xenomai/ksrc/drivers/Makefile
@@ -11,7 +11,7 @@ else
subdir-$(CONFIG_XENO_DRIVERS_16550A) += 16550A
subdir-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += testing
-
+subdir-$(CONFIG_XENO_DRIVERS_IRQBENCH) += testing
subdir-$(CONFIG_XENO_DRIVERS_SWITCHTEST) += testing
include $(TOPDIR)/Rules.make
Index: xenomai/ksrc/drivers/testing/Kconfig
===================================================================
--- xenomai.orig/ksrc/drivers/testing/Kconfig
+++ xenomai/ksrc/drivers/testing/Kconfig
@@ -6,10 +6,19 @@ config XENO_DRIVERS_TIMERBENCH
Kernel-based benchmark driver for timer latency evaluation.
See testsuite/latency for a possible front-end.
+config XENO_DRIVERS_IRQBENCH
+ depends on XENO_SKIN_RTDM
+ tristate "IRQ benchmark driver"
+ default n
+ help
+ Loopback driver for IRQ latency evaluation over serial or parallel
+ port links. Additionally requires user-space helper and a logging tool
+ (see testsuite/irqbench).
+
config XENO_DRIVERS_SWITCHTEST
- depends on XENO_SKIN_RTDM
- tristate "Context switch unit testing driver"
- default n
- help
- Kernel-based driver for unit testing context switches and
- FPU switches.
+ depends on XENO_SKIN_RTDM
+ tristate "Context switch unit testing driver"
+ default n
+ help
+ Kernel-based driver for unit testing context switches and
+ FPU switches.
Index: xenomai/ksrc/drivers/testing/Makefile
===================================================================
--- xenomai.orig/ksrc/drivers/testing/Makefile
+++ xenomai/ksrc/drivers/testing/Makefile
@@ -5,11 +5,13 @@ ifeq ($(PATCHLEVEL),6)
EXTRA_CFLAGS += -Iinclude/xenomai
obj-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += xeno_timerbench.o
-
+obj-$(CONFIG_XENO_DRIVERS_IRQBENCH) += xeno_irqbench.o
obj-$(CONFIG_XENO_DRIVERS_SWITCHTEST) += xeno_switchtest.o
xeno_timerbench-y := timerbench.o
+xeno_irqbench-y := irqbench.o
+
xeno_switchtest-y := switchtest.o
EXTRA_CFLAGS += -Iinclude/xenomai
@@ -21,14 +23,16 @@ else
O_TARGET := built-in.o
obj-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += xeno_timerbench.o
-
+obj-$(CONFIG_XENO_DRIVERS_IRQBENCH) += xeno_irqbench.o
obj-$(CONFIG_XENO_DRIVERS_SWITCHTEST) += xeno_switchtest.o
xeno_timerbench-objs := timerbench.o
+xeno_irqbench-objs := irqbench.o
+
xeno_switchtest-objs := switchtest.o
-export-objs := $(xeno_timerbench-objs) $(xeno_switchtest-objs)
+export-objs := $(xeno_timerbench-objs) $(xeno_irqbench-objs) $(xeno_switchtest-objs)
EXTRA_CFLAGS += -I$(TOPDIR)/include/xenomai -I$(TOPDIR)/include/xenomai/compat
@@ -37,6 +41,9 @@ include $(TOPDIR)/Rules.make
xeno_timerbench.o: $(xeno_timerbench-objs)
$(LD) -r -o $@ $(xeno_timerbench-objs)
+xeno_irqbench.o: $(xeno_irqbench-objs)
+ $(LD) -r -o $@ $(xeno_irqbench-objs)
+
xeno_switchtest.o: $(xeno_switchtest-objs)
$(LD) -r -o $@ $(xeno_switchtest-objs)
Index: xenomai/ksrc/drivers/testing/irqbench.c
===================================================================
--- /dev/null
+++ xenomai/ksrc/drivers/testing/irqbench.c
@@ -0,0 +1,470 @@
+/*
+ * 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 <linux/module.h>
+#include <asm/semaphore.h>
+
+#include <rtdm/rttesting.h>
+#include <rtdm/rtdm_driver.h>
+#include <nucleus/trace.h>
+
+/* --- Serial port --- */
+
+#define MSR_DCTS 0x01
+#define MSR_DDSR 0x02
+#define MSR_DDCD 0x08
+
+#define MCR_RTS 0x02
+#define MCR_OUT2 0x08
+
+#define IER_MODEM 0x08
+
+#define RHR(ctx) (ctx->port_ioaddr + 0) /* Receive Holding Buffer */
+#define IER(ctx) (ctx->port_ioaddr + 1) /* Interrupt Enable Register */
+#define IIR(ctx) (ctx->port_ioaddr + 2) /* Interrupt Id Register */
+#define LCR(ctx) (ctx->port_ioaddr + 3) /* Line Control Register */
+#define MCR(ctx) (ctx->port_ioaddr + 4) /* Modem Control Register */
+#define LSR(ctx) (ctx->port_ioaddr + 5) /* Line Status Register */
+#define MSR(ctx) (ctx->port_ioaddr + 6) /* Modem Status Register */
+
+/* --- Parallel port --- */
+
+#define CTRL_INIT 0x04
+
+#define STAT_STROBE 0x10
+
+#define DATA(ctx) (ctx->port_ioaddr + 0) /* Data register */
+#define STAT(ctx) (ctx->port_ioaddr + 1) /* Status register */
+#define CTRL(ctx) (ctx->port_ioaddr + 2) /* Control register */
+
+struct rt_irqbench_context {
+ int mode;
+ int port_type;
+ unsigned long port_ioaddr;
+ unsigned int toggle;
+ struct rttst_irqbench_stats stats;
+ rtdm_irq_t irq_handle;
+ rtdm_event_t irq_event;
+ rtdm_task_t irq_task;
+ struct semaphore nrt_mutex;
+};
+
+static unsigned int start_index;
+
+module_param(start_index, uint, 0400);
+MODULE_PARM_DESC(start_index, "First device instance number to be used");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("jan.kiszka@domain.hid");
+
+
+static inline int rt_irqbench_check_irq(struct rt_irqbench_context *ctx)
+{
+ int status;
+
+
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ status = inb(MSR(ctx));
+ if (status & (MSR_DDSR | MSR_DDCD))
+ xntrace_user_freeze(0, 0);
+ if (!(status & MSR_DCTS))
+ return 0;
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ // todo
+ break;
+ }
+ ctx->stats.irqs_received++;
+ return 1;
+}
+
+
+static inline void rt_irqbench_hwreply(struct rt_irqbench_context *ctx)
+{
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ /* toggle RTS */
+ ctx->toggle ^= MCR_RTS;
+ outb(ctx->toggle, MCR(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ ctx->toggle ^= 0xFF;
+ outb(ctx->toggle, DATA(ctx));
+ break;
+ }
+ xntrace_special(0xBE, 0);
+ ctx->stats.irqs_acknowledged++;
+}
+
+
+static void rt_irqbench_task(void *arg)
+{
+ struct rt_irqbench_context *ctx = (struct rt_irqbench_context *)arg;
+
+
+ while (1) {
+ if (rtdm_event_wait(&ctx->irq_event) < 0)
+ return;
+ rt_irqbench_hwreply(ctx);
+ }
+}
+
+
+static int rt_irqbench_task_irq(rtdm_irq_t *irq_handle)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = rtdm_irq_get_arg(irq_handle, struct rt_irqbench_context);
+
+ if (rt_irqbench_check_irq(ctx))
+ rtdm_event_signal(&ctx->irq_event);
+
+ return RTDM_IRQ_HANDLED;
+}
+
+
+static int rt_irqbench_direct_irq(rtdm_irq_t *irq_handle)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = rtdm_irq_get_arg(irq_handle, struct rt_irqbench_context);
+
+ if (rt_irqbench_check_irq(ctx))
+ rt_irqbench_hwreply(ctx);
+
+ return RTDM_IRQ_HANDLED;
+}
+
+
+static int rt_irqbench_stop(struct rt_irqbench_context *ctx)
+{
+ if (ctx->mode < 0)
+ return -EINVAL;
+
+ /* Disable hardware */
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ outb(0, IER(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ outb(0, CTRL(ctx));
+ break;
+ }
+
+ rtdm_irq_free(&ctx->irq_handle);
+
+ if (ctx->mode == RTTST_IRQBENCH_KERNEL_TASK)
+ rtdm_task_destroy(&ctx->irq_task);
+
+ ctx->mode = -1;
+
+ return 0;
+}
+
+
+static int rt_irqbench_open(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int oflags)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ ctx->mode = -1;
+ rtdm_event_init(&ctx->irq_event, 0);
+ init_MUTEX(&ctx->nrt_mutex);
+
+ return 0;
+}
+
+
+static int rt_irqbench_close(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info)
+{
+ struct rt_irqbench_context *ctx;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ down(&ctx->nrt_mutex);
+ rt_irqbench_stop(ctx);
+ rtdm_event_destroy(&ctx->irq_event);
+ up(&ctx->nrt_mutex);
+
+ return 0;
+}
+
+
+static int rt_irqbench_ioctl_nrt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int request,
+ void *arg)
+{
+ struct rt_irqbench_context *ctx;
+ int ret = 0;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ switch (request) {
+ case RTTST_RTIOC_IRQBENCH_START: {
+ struct rttst_irqbench_config config_buf;
+ struct rttst_irqbench_config *config;
+
+ config = (struct rttst_irqbench_config *)arg;
+ if (user_info) {
+ if (!rtdm_read_user_ok(user_info, arg,
+ sizeof(struct rttst_irqbench_config)) ||
+ rtdm_copy_from_user(user_info, &config_buf, arg,
+ sizeof(struct rttst_irqbench_config)))
+ return -EFAULT;
+
+ config = &config_buf;
+ }
+
+ if (config->port_type > RTTST_IRQBENCH_PARPORT)
+ return -EINVAL;
+
+ down(&ctx->nrt_mutex);
+
+ if (test_bit(RTDM_CLOSING, &context->context_flags))
+ goto unlock_start_out;
+
+ ctx->port_type = config->port_type;
+ ctx->port_ioaddr = config->port_ioaddr;
+
+ /* Initialise hardware */
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ ctx->toggle = MCR_OUT2;
+
+ /* Reset DLAB, reset RTS, enable OUT2 */
+ outb(0, LCR(ctx));
+ outb(MCR_OUT2, MCR(ctx));
+
+ /* Mask all UART interrupts and clear pending ones. */
+ outb(0, IER(ctx));
+ inb(IIR(ctx));
+ inb(LSR(ctx));
+ inb(RHR(ctx));
+ inb(MSR(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ ctx->toggle = 0xAA;
+ outb(0xAA, DATA(ctx));
+ outb(CTRL_INIT, CTRL(ctx));
+ break;
+ }
+
+ switch (config->mode) {
+ case RTTST_IRQBENCH_USER_TASK:
+ ret = rtdm_irq_request(&ctx->irq_handle, config->port_irq,
+ rt_irqbench_task_irq, 0,
+ "irqbench", ctx);
+ break;
+
+ case RTTST_IRQBENCH_KERNEL_TASK:
+ ret = rtdm_irq_request(&ctx->irq_handle, config->port_irq,
+ rt_irqbench_task_irq, 0,
+ "irqbench", ctx);
+ if (ret < 0)
+ goto unlock_start_out;
+
+ ret = rtdm_task_init(&ctx->irq_task, "irqbench",
+ rt_irqbench_task, ctx,
+ config->priority, 0);
+ if (ret < 0)
+ rtdm_irq_free(&ctx->irq_handle);
+ break;
+
+ case RTTST_IRQBENCH_HANDLER:
+ ret = rtdm_irq_request(&ctx->irq_handle, config->port_irq,
+ rt_irqbench_direct_irq, 0,
+ "irqbench", ctx);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret < 0)
+ goto unlock_start_out;
+
+ ctx->mode = config->mode;
+
+ memset(&ctx->stats, 0, sizeof(ctx->stats));
+
+ rtdm_irq_enable(&ctx->irq_handle);
+
+ /* Arm IRQ */
+ switch (ctx->port_type) {
+ case RTTST_IRQBENCH_SERPORT:
+ outb(IER_MODEM, IER(ctx));
+ break;
+
+ case RTTST_IRQBENCH_PARPORT:
+ outb(STAT_STROBE, CTRL(ctx));
+ break;
+ }
+
+ unlock_start_out:
+ up(&ctx->nrt_mutex);
+ break;
+ }
+
+ case RTTST_RTIOC_IRQBENCH_STOP:
+ down(&ctx->nrt_mutex);
+ ret = rt_irqbench_stop(ctx);
+ up(&ctx->nrt_mutex);
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_GET_STATS: {
+ struct rttst_irqbench_stats *usr_stats;
+
+ usr_stats = (struct rttst_irqbench_stats *)arg;
+
+ if (user_info) {
+ if (!rtdm_rw_user_ok(user_info, usr_stats,
+ sizeof(struct rttst_irqbench_stats)) ||
+ rtdm_copy_to_user(user_info, usr_stats,
+ &ctx->stats,
+ sizeof(struct rttst_irqbench_stats)))
+ ret = -EFAULT;
+ } else
+ *usr_stats = ctx->stats;
+ break;
+ }
+
+ case RTTST_RTIOC_IRQBENCH_WAIT_IRQ:
+ ret = -ENOSYS;
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_REPLY_IRQ:
+ rt_irqbench_hwreply(ctx);
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+
+static int rt_irqbench_ioctl_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int request,
+ void *arg)
+{
+ struct rt_irqbench_context *ctx;
+ int ret = 0;
+
+
+ ctx = (struct rt_irqbench_context *)context->dev_private;
+
+ switch (request) {
+ case RTTST_RTIOC_IRQBENCH_WAIT_IRQ:
+ ret = rtdm_event_wait(&ctx->irq_event);
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_REPLY_IRQ:
+ rt_irqbench_hwreply(ctx);
+ break;
+
+ case RTTST_RTIOC_IRQBENCH_START:
+ case RTTST_RTIOC_IRQBENCH_STOP:
+ case RTTST_RTIOC_IRQBENCH_GET_STATS:
+ ret = -ENOSYS;
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+
+static struct rtdm_device device = {
+ struct_version: RTDM_DEVICE_STRUCT_VER,
+
+ device_flags: RTDM_NAMED_DEVICE,
+ context_size: sizeof(struct rt_irqbench_context),
+ device_name: "",
+
+ open_rt: NULL,
+ open_nrt: rt_irqbench_open,
+
+ ops: {
+ close_rt: NULL,
+ close_nrt: rt_irqbench_close,
+
+ ioctl_rt: rt_irqbench_ioctl_rt,
+ ioctl_nrt: rt_irqbench_ioctl_nrt,
+
+ read_rt: NULL,
+ read_nrt: NULL,
+
+ write_rt: NULL,
+ write_nrt: NULL,
+
+ recvmsg_rt: NULL,
+ recvmsg_nrt: NULL,
+
+ sendmsg_rt: NULL,
+ sendmsg_nrt: NULL,
+ },
+
+ device_class: RTDM_CLASS_TESTING,
+ device_sub_class: RTDM_SUBCLASS_IRQBENCH,
+ driver_name: "xeno_irqbench",
+ driver_version: RTDM_DRIVER_VER(0, 1, 0),
+ peripheral_name: "IRQ Latency Benchmark",
+ provider_name: "Jan Kiszka",
+ proc_name: device.device_name,
+};
+
+int __init __timerbench_init(void)
+{
+ int ret;
+
+ do {
+ snprintf(device.device_name, RTDM_MAX_DEVNAME_LEN, "rttest%d",
+ start_index);
+ ret = rtdm_dev_register(&device);
+
+ start_index++;
+ } while (ret == -EEXIST);
+
+ return ret;
+}
+
+
+void __exit __timerbench_exit(void)
+{
+ rtdm_dev_unregister(&device, 1000);
+}
+
+
+module_init(__timerbench_init);
+module_exit(__timerbench_exit);
Index: xenomai/src/testsuite/Makefile.am
===================================================================
--- xenomai.orig/src/testsuite/Makefile.am
+++ xenomai/src/testsuite/Makefile.am
@@ -1 +1 @@
-SUBDIRS = latency switchbench cyclic switchtest
+SUBDIRS = latency switchbench cyclic switchtest irqbench
Index: xenomai/src/testsuite/irqbench/Makefile.am
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/Makefile.am
@@ -0,0 +1,47 @@
+testdir = $(prefix)/testsuite/irqbench
+
+test_PROGRAMS = irqloop
+
+if XENO_TARGET_ARCH_I386
+test_PROGRAMS += irqbench
+endif
+
+
+irqloop_SOURCES = irqloop.c
+
+irqloop_CPPFLAGS = \
+ -I$(top_srcdir)/include/posix \
+ $(XENO_USER_CFLAGS) \
+ -I$(top_srcdir)/include
+
+irqloop_LDFLAGS = \
+ $(XENO_POSIX_WRAPPERS) \
+ $(XENO_USER_LDFLAGS)
+
+irqloop_LDADD = \
+ -lpthread \
+ ../../skins/posix/.libs/libpthread_rt.a
+
+
+irqbench_SOURCES = irqbench.c
+
+irqbench_CPPFLAGS = \
+ $(XENO_USER_CFLAGS) \
+ -I$(top_srcdir)/include
+
+irqbench_LDFLAGS = $(XENO_USER_LDFLAGS)
+
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(testdir)
+ $(INSTALL_DATA) $(srcdir)/runinfo $(DESTDIR)$(testdir)/.runinfo
+ @echo "\$${DESTDIR}$(prefix)/bin/xeno-load \$$*" > $(DESTDIR)$(testdir)/run
+ @chmod +x $(DESTDIR)$(testdir)/run
+
+uninstall-local:
+ $(RM) $(DESTDIR)$(testdir)/.runinfo $(DESTDIR)$(testdir)/run
+
+run: all
+ @$(top_srcdir)/scripts/xeno-load --verbose
+
+EXTRA_DIST = runinfo
Index: xenomai/src/testsuite/irqbench/irqbench.c
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/irqbench.c
@@ -0,0 +1,306 @@
+/*
+ * 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 = LONG_MAX;
+long long max_lat = LONG_MIN;
+long long avg_lat = 0;
+long outer_loops = 0;
+int warmup = 1;
+int terminate = 0;
+
+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)
+ exit(0);
+ else
+ terminate = 1;
+}
+
+
+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 (!terminate) {
+ 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 && !terminate) {
+ 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;
+ }
+
+ 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);
+
+ return 0;
+}
Index: xenomai/src/testsuite/irqbench/irqloop.c
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/irqloop.c
@@ -0,0 +1,173 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <rtdm/rttesting.h>
+
+static int benchdev;
+static int terminate;
+
+void *irq_thread(void *arg)
+{
+ struct sched_param param = { .sched_priority = (int)arg };
+
+ pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m);
+
+ while (1) {
+ if (ioctl(benchdev, RTTST_RTIOC_IRQBENCH_WAIT_IRQ) ||
+ ioctl(benchdev, RTTST_RTIOC_IRQBENCH_REPLY_IRQ))
+ break;
+ }
+
+ param.sched_priority = 0;
+ pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m);
+
+ return NULL;
+}
+
+
+void sighand(int sig)
+{
+ terminate = 1;
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char *mode_name[] =
+ { "user-space task", "kernel-space task", "IRQ handler" };
+ const char *port_type_name[] = { "serial", "parallel" };
+ char devname[RTDM_MAX_DEVNAME_LEN];
+ int benchdev_no = 0;
+ struct rttst_irqbench_config config = {
+ mode: RTTST_IRQBENCH_USER_TASK,
+ priority: sched_get_priority_max(SCHED_FIFO),
+ calibration_loops: 0,
+ port_type: RTTST_IRQBENCH_SERPORT,
+ port_ioaddr: 0x3f8,
+ port_irq: 4
+ };
+ struct rttst_irqbench_stats stats;
+ unsigned long long last_received = 0;
+ pthread_t thr;
+ int c;
+
+
+ while ((c = getopt(argc,argv,"D:t:P:o:a:i:")) != EOF)
+ switch (c) {
+ case 'D':
+ benchdev_no = atoi(optarg);
+ break;
+
+ case 't':
+ config.mode = atoi(optarg);
+ break;
+
+ case 'P':
+ config.priority = atoi(optarg);
+ break;
+
+ case 'o':
+ config.port_type = atoi(optarg);
+ break;
+
+ case 'a':
+ config.port_ioaddr = strtol(optarg, NULL,
+ (strncmp(optarg, "0x", 2) == 0) ? 16 : 10);
+ break;
+
+ case 'i':
+ config.port_irq = atoi(optarg);
+ break;
+
+ default:
+ fprintf(stderr, "usage: irqloop [options]\n"
+ " [-D <testing_device_no>] # number of testing device, default=0\n"
+ " [-t <test_mode>] # 0=user task (default), 1=kernel task, 2=IRQ\n"
+ " [-P <priority>] # task priority (test mode 0 and 1 only)\n"
+ " [-o <port_type>] # 0=serial (default), 1=parallel\n"
+ " [-a <port_io_address>] # default=0x3f8\n"
+ " [-i <port_irq>] # default=4\n");
+ exit(2);
+ }
+
+ signal(SIGINT, sighand);
+ signal(SIGTERM, sighand);
+ signal(SIGHUP, sighand);
+
+ mlockall(MCL_CURRENT|MCL_FUTURE);
+
+ snprintf(devname, RTDM_MAX_DEVNAME_LEN, "/dev/rttest%d", benchdev_no);
+ benchdev = open(devname, O_RDWR);
+ if (benchdev < 0) {
+ perror("irqloop: failed to open benchmark device");
+ fprintf(stderr, "(modprobe xeno_irqbench?)\n");
+ return 1;
+ }
+
+ if (config.mode == RTTST_IRQBENCH_USER_TASK) {
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+
+ pthread_create(&thr, &attr, irq_thread, (void *)config.priority);
+ }
+
+ if (ioctl(benchdev, RTTST_RTIOC_IRQBENCH_START, &config)) {
+ perror("irqloop: error starting test");
+ goto cleanup;
+ }
+
+ printf("Test mode: %s\n"
+ "Port type: %s\n"
+ "Port address: 0x%lx\n"
+ "Port IRQ: %d\n\n\n\n",
+ mode_name[config.mode], port_type_name[config.port_type],
+ config.port_ioaddr, config.port_irq);
+
+ while (!terminate) {
+ if (ioctl(benchdev, RTTST_RTIOC_IRQBENCH_GET_STATS, &stats) < 0) {
+ perror("irqloop: error reading stats");
+ break;
+ }
+
+ if ((last_received > 0) && (stats.irqs_received == last_received))
+ break; /* timed out */
+ last_received = stats.irqs_received;
+
+ printf("\033[2AReceived IRQs: %lld\nAcknowledged IRQs: %lld\n",
+ stats.irqs_received, stats.irqs_acknowledged);
+ usleep(250000);
+ }
+
+ ioctl(benchdev, RTTST_RTIOC_IRQBENCH_STOP);
+
+ cleanup:
+ close(benchdev);
+ if (config.mode == RTTST_IRQBENCH_USER_TASK) {
+ pthread_cancel(thr);
+ pthread_join(thr, NULL);
+ }
+
+ return 0;
+}
Index: xenomai/src/testsuite/irqbench/runinfo
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/irqbench/runinfo
@@ -0,0 +1 @@
+irqloop:posix+rtdm+irqbench:!./irqloop;popall:control_c
Index: xenomai/doc/txt/Makefile.am
===================================================================
--- xenomai.orig/doc/txt/Makefile.am
+++ xenomai/doc/txt/Makefile.am
@@ -2,6 +2,7 @@ txtdocdir = $(datadir)/doc/$(PACKAGE)-$(
dist_txtdoc_DATA = \
16550A-driver.txt \
+ irqbench.txt \
pse51-skin.txt \
psos-skin.txt \
rtai-skin.txt \
Index: xenomai/doc/txt/irqbench.txt
===================================================================
--- /dev/null
+++ xenomai/doc/txt/irqbench.txt
@@ -0,0 +1,51 @@
+IRQ Latency Benchmark
+---------------------
+
+This latency benchmark for external interrupts consists of three parts:
+
+1. xeno_irqbench (ksrc/drivers/testing)
+ RTDM driver for the test target to handle and reply to the IRQ events, or
+ forward them to user-space.
+
+2. irqloop (src/testsuite/irqbench)
+ xeno_irqbench control front-end and user-space loop-closer. Runs against
+ the POSIX skin on the test target.
+
+3. irqbench (src/testsuite/irqbench)
+ IRQ triggering and reaction measuring tool for the log system. Runs over
+ plain Linux on x86 hosts. Note that this tool will only be compiled
+ automatically with Xenomai if the target architecture is x86. To compile
+ it manually, invoke
+
+ <gcc-x86-compiler> irqbench.c -o irqbench -O2
+
+To link both test and log system, a null-modem cable between 8250-compatible
+two RS232 ports is required. The infrastructure for parallel port cross-over
+is prepared as well, but yet untested and incomplete. The null-modem cable
+must provide at least the following links:
+
+ test target log system
+ ----------- ----------
+ CTS(8) <------ RTS(7) IRQ trigger
+ RTS(7) ------> CTS(8) reply
+
+ DCD(1)
+ and/or <------ DTR(4) trace trigger (optional)
+ DSR(6)
+
+ (Pin number on 9-pin sub-D socket)
+
+Test and log system can be started in arbitrary order, they will wait on
+each other.
+
+The log system runs each single IRQ measurement with local IRQs disabled. It
+will wait up to 100 times the current period on the test system's reply (after
+initial successful synchronisation, which happens with IRQs enabled). Note that
+these timeouts may disturb other processes or drivers on the log system.
+
+Keep in mind for test evaluations that, by design, irqbench will not trigger a
+new IRQ event before the reply on the previous one has arrived or timed out.
+Thus the specified test period may be dynamically expended in case of
+overload. But maximum a latency close or above the period will clearly
+indicate this.
+
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread* Re: [Xenomai-core] [PATCH 6/6] Introduce IRQ latency benchmark
2006-06-28 19:39 ` Jan Kiszka
@ 2006-06-29 11:20 ` Jan Kiszka
2006-07-01 15:38 ` Philippe Gerum
0 siblings, 1 reply; 31+ messages in thread
From: Jan Kiszka @ 2006-06-29 11:20 UTC (permalink / raw)
To: xenomai
[-- Attachment #1: Type: text/plain, Size: 997 bytes --]
Jan Kiszka wrote:
> Here comes an update of the irqbench patch.
>
And this add-on fixes a classic copy&paste issue.
Jan
---
ksrc/drivers/testing/irqbench.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
Index: xenomai/ksrc/drivers/testing/irqbench.c
===================================================================
--- xenomai.orig/ksrc/drivers/testing/irqbench.c
+++ xenomai/ksrc/drivers/testing/irqbench.c
@@ -444,7 +444,7 @@ static struct rtdm_device device = {
proc_name: device.device_name,
};
-int __init __timerbench_init(void)
+int __init __irqbench_init(void)
{
int ret;
@@ -460,11 +460,11 @@ int __init __timerbench_init(void)
}
-void __exit __timerbench_exit(void)
+void __exit __irqbench_exit(void)
{
rtdm_dev_unregister(&device, 1000);
}
-module_init(__timerbench_init);
-module_exit(__timerbench_exit);
+module_init(__irqbench_init);
+module_exit(__irqbench_exit);
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 249 bytes --]
^ permalink raw reply [flat|nested] 31+ messages in thread