Based on librtprint, this is an attempt to unintrusively (/wrt timing) instrument Xenomai syscalls inside the user space libs.
The support is compiled into the skin libs if --enable-debug was passed to configure. To switch rt-syscall tracing on for an RT application, the environment variable XNTRACE_SYS has to be defined (to whatever). Output happens to stderr so far. Here is a demo trace of the rtprint example from the previous patch: > # XNTRACE_SYS= examples/native/rtprint > [b7df36c0 Task 1] ENTER rt_task_shadow(task=0xbfd55aa8, name=Task 1, prio=10, > mode=0x0) > [b7df36c0 Task 1] EXIT rt_task_shadow() = 0 > [b7df36c0 Task 1] ENTER rt_task_create(task=0xbfd55aa0, name=Task 2, > stksize=0, prio=11, mode=0x0) > [b7df36c0 Task 1] EXIT rt_task_create() = 0 > [b7df36c0 Task 1] ENTER rt_task_start(task=0xbfd55aa0, entry=0x8048754, > cookie=(nil)) > [b7f65b90 Task 2] ENTER rt_task_trampoline(cookie=(nil)) > This triggers auto-init of rt_print for the calling thread. > A last switch to secondary mode can occure here, but future invocations of > rt_printf are safe. > [b7f65b90 Task 2] ENTER rt_task_sleep(delay=3333333) > [b7df36c0 Task 1] EXIT rt_task_start() = 0 > [b7df36c0 Task 1] ENTER rt_task_sleep(delay=5000000) > [b7f65b90 Task 2] EXIT rt_task_sleep() = 0 > b7f65b90 Task 2: #1 Yet another RT printer - but to stderr. > [b7f65b90 Task 2] ENTER rt_task_sleep(delay=3333333) > [b7df36c0 Task 1] EXIT rt_task_sleep() = 0 ... Besides introducing the generic bits of rt-syscall tracing, this patch also instruments very few functions of the native and the posix skin. As I said earlier, full instrumentation like this requires a) a consensus that we want this and b) quite some typing work which could luckily happen step by step. Yet further ideas to enhance this approach: o Time stamping based on cheap TSCs could be added. o A lib-internal handler for SIGXCHG could be installed, and the related mode switch signal could be forced on. That way the tracing back-end would become aware of switches from primary to secondary mode and could report this automatically. o Support to dump the trace to a file could be provided (already possibly via redirection "2>output-file", but may contain stderr stuff from the traced program). OK, looking forward to any feedback. Jan
--- configure.in | 20 ++++++++--- include/asm-generic/Makefile.am | 2 - include/asm-generic/bits/bind.h | 12 +++++++ include/asm-generic/usystrace.h | 59 ++++++++++++++++++++++++++++++++++ src/skins/native/Makefile.am | 2 - src/skins/native/init.c | 3 + src/skins/native/task.c | 68 ++++++++++++++++++++++++++++++++-------- src/skins/posix/Makefile.am | 2 - src/skins/posix/clock.c | 26 ++++++++++++--- src/skins/posix/init.c | 3 + src/skins/posix/mutex.c | 21 +++++++++++- src/skins/posix/thread.c | 15 ++++++-- 12 files changed, 200 insertions(+), 33 deletions(-) Index: xenomai/configure.in =================================================================== --- xenomai.orig/configure.in +++ xenomai/configure.in @@ -111,15 +111,22 @@ dnl dnl Debug build (default: off) -debug_symbols= -AC_MSG_CHECKING(for debug symbols) +CONFIG_DEBUG= +AC_MSG_CHECKING(for debug support) AC_ARG_ENABLE(debug, AS_HELP_STRING([--enable-debug], [Enable debug support in nucleus and debug symbols in programs]), [case "$enableval" in - y | yes) debug_symbols=y ;; - *) unset debug_symbols ;; + y | yes) CONFIG_DEBUG=y ;; + *) unset CONFIG_DEBUG ;; esac]) -AC_MSG_RESULT(${debug_symbols:-no}) +AC_MSG_RESULT(${CONFIG_DEBUG:-no}) + +if test x$CONFIG_DEBUG = xy ; then + SYSTRACE_LIB="-L\$(top_builddir)/src/rtprint -lrtprint" +else + unset SYSTRACE_LIB +fi +AC_SUBST(SYSTRACE_LIB) dnl SMP support (default: off) @@ -419,6 +426,7 @@ dnl don't need to make particular cases dnl also be compiled in user-space libs. dnl +test x$CONFIG_DEBUG = xy && AC_DEFINE(CONFIG_DEBUG,1,[config]) test x$CONFIG_XENO_X86_SEP = xy && AC_DEFINE(CONFIG_XENO_X86_SEP,1,[config]) test x$CONFIG_SMP = xy && AC_DEFINE(CONFIG_SMP,1,[config]) test x$CONFIG_X86_TSC = xy && AC_DEFINE(CONFIG_X86_TSC,1,[config]) @@ -531,7 +539,7 @@ case $XENO_TARGET_ARCH in ;; esac -if test x$debug_symbols = xy; then +if test x$CONFIG_DEBUG = xy; then XENO_USER_CFLAGS="-g $XENO_USER_CFLAGS" else XENO_USER_CFLAGS="-O2 $XENO_USER_CFLAGS" Index: xenomai/include/asm-generic/Makefile.am =================================================================== --- xenomai.orig/include/asm-generic/Makefile.am +++ xenomai/include/asm-generic/Makefile.am @@ -1,5 +1,5 @@ includedir = $(prefix)/include/asm-generic -include_HEADERS = features.h hal.h syscall.h system.h wrappers.h +include_HEADERS = features.h hal.h syscall.h system.h usystrace.h wrappers.h SUBDIRS = bits Index: xenomai/include/asm-generic/bits/bind.h =================================================================== --- xenomai.orig/include/asm-generic/bits/bind.h +++ xenomai/include/asm-generic/bits/bind.h @@ -8,6 +8,10 @@ #include <signal.h> #include <asm/xenomai/syscall.h> +#ifdef CONFIG_DEBUG +int __xeno_systrace; +#endif /* CONFIG_DEBUG */ + void xeno_handle_mlock_alert(int sig); static inline int @@ -21,6 +25,10 @@ xeno_bind_skin(unsigned skin_magic, cons xeno_arch_features_check(); #endif /* xeno_arch_features_check */ +#ifdef CONFIG_DEBUG + __xeno_systrace = !!getenv("XNTRACE_SYS"); +#endif /* CONFIG_DEBUG */ + muxid = XENOMAI_SYSBIND(skin_magic, XENOMAI_FEAT_DEP, XENOMAI_ABI_REV, &finfo); switch (muxid) { @@ -75,6 +83,10 @@ xeno_bind_skin_opt(unsigned skin_magic, xeno_arch_features_check(); #endif /* xeno_arch_features_check */ +#ifdef CONFIG_DEBUG + __xeno_systrace = !!getenv("XNTRACE_SYS"); +#endif /* CONFIG_DEBUG */ + muxid = XENOMAI_SYSBIND(skin_magic, XENOMAI_FEAT_DEP, XENOMAI_ABI_REV, &finfo); switch (muxid) { Index: xenomai/include/asm-generic/usystrace.h =================================================================== --- /dev/null +++ xenomai/include/asm-generic/usystrace.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2007 Jan Kiszka <[EMAIL PROTECTED]>. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _XENO_ASM_GENERIC_USYSTRACE_H +#define _XENO_ASM_GENERIC_USYSTRACE_H + +#include <xeno_config.h> +#include <rtprint.h> + +#define SYSTRACE_VOID "<void>" + +#define systrace_str(string) (string) ? string : "(nil)" + +#ifdef CONFIG_DEBUG + +extern int __xeno_systrace; + +#define systrace_init() rt_print_auto_init(1) +#define systrace_init_thread(name) rt_print_init(0, name) + +#define systrace_enter(func, arg_format, ...) \ +do { \ + if (__xeno_systrace) \ + rt_fprintf(stderr, "[%s] ENTER %s(" arg_format ")\n", \ + rt_print_buffer_name(), func, ##__VA_ARGS__); \ +} while (0) + +#define systrace_exit(func, ret_format, ...) \ +do { \ + if (__xeno_systrace) \ + rt_fprintf(stderr, "[%s] EXIT %s() = " ret_format "\n", \ + rt_print_buffer_name(), func, ##__VA_ARGS__); \ +} while (0) + +#else /* !CONFIG_DEBUG */ + +#define systrace_init() do { } while (0) +#define systrace_init_thread(name) do { } while (0) +#define systrace_enter(func, arg_format, ...) do { } while (0) +#define systrace_exit(func, ret_format, ...) do { } while (0) + +#endif /* !CONFIG_DEBUG */ + +#endif /* !_XENO_ASM_GENERIC_USYSTRACE_H */ Index: xenomai/src/skins/native/Makefile.am =================================================================== --- xenomai.orig/src/skins/native/Makefile.am +++ xenomai/src/skins/native/Makefile.am @@ -1,6 +1,6 @@ lib_LTLIBRARIES = libnative.la -libnative_la_LDFLAGS = -version-info 0:0:0 -lpthread +libnative_la_LDFLAGS = -version-info 0:0:0 -lpthread @SYSTRACE_LIB@ libnative_la_SOURCES = \ alarm.c \ Index: xenomai/src/skins/native/init.c =================================================================== --- xenomai.orig/src/skins/native/init.c +++ xenomai/src/skins/native/init.c @@ -26,6 +26,7 @@ #include <native/task.h> #include <asm-generic/bits/bind.h> #include <asm-generic/bits/mlock_alert.h> +#include <asm-generic/usystrace.h> pthread_key_t __native_tskey; @@ -49,4 +50,6 @@ void __init_xeno_interface(void) fprintf(stderr, "Xenomai: failed to allocate new TSD key?!\n"); exit(1); } + + systrace_init(); } Index: xenomai/src/skins/native/task.c =================================================================== --- xenomai.orig/src/skins/native/task.c +++ xenomai/src/skins/native/task.c @@ -26,6 +26,7 @@ #include <limits.h> #include <native/syscall.h> #include <native/task.h> +#include <asm-generic/usystrace.h> extern pthread_key_t __native_tskey; @@ -54,6 +55,8 @@ static void *rt_task_trampoline(void *co struct rt_arg_bulk bulk; long err; + systrace_init_thread(iargs->name); + if (iargs->prio > 0) { /* Ok, this looks like weird, but we need this. */ param.sched_priority = sched_get_priority_max(SCHED_FIFO); @@ -85,8 +88,11 @@ static void *rt_task_trampoline(void *co err = XENOMAI_SYSCALL2(__xn_sys_barrier, &entry, &cookie); while (err == -EINTR); - if (!err) + if (!err) { + systrace_enter(__FUNCTION__, "cookie=%p", cookie); entry(cookie); + systrace_exit(__FUNCTION__, SYSTRACE_VOID); + } fail: @@ -103,6 +109,10 @@ int rt_task_create(RT_TASK *task, pthread_t thid; int err; + systrace_enter(__FUNCTION__, "task=%p, name=%s, stksize=%d, " + "prio=%d, mode=0x%x", task, systrace_str(name), + stksize, prio, mode); + /* Migrate this thread to the Linux domain since we are about to issue a series of regular kernel syscalls in order to create the new Linux thread, which in turn will be mapped to a @@ -135,24 +145,39 @@ int rt_task_create(RT_TASK *task, } pthread_attr_setschedparam(&thattr, ¶m); - err = pthread_create(&thid, &thattr, &rt_task_trampoline, &iargs); + err = -pthread_create(&thid, &thattr, &rt_task_trampoline, &iargs); - if (err) - return -err; + if (!err) { + /* Wait for sync with rt_task_trampoline() */ + err = XENOMAI_SYSCALL1(__xn_sys_completion, &completion); + } - /* Wait for sync with rt_task_trampoline() */ - return XENOMAI_SYSCALL1(__xn_sys_completion, &completion); + systrace_exit(__FUNCTION__, "%d", err); + return err; } int rt_task_start(RT_TASK *task, void (*entry) (void *cookie), void *cookie) { - return XENOMAI_SKINCALL3(__native_muxid, - __native_task_start, task, entry, cookie); + int err; + + systrace_enter(__FUNCTION__, "task=%p, entry=%p, cookie=%p", + task, entry, cookie); + + err = XENOMAI_SKINCALL3(__native_muxid, + __native_task_start, task, entry, cookie); + + systrace_exit(__FUNCTION__, "%d", err); + return err; } int rt_task_shadow(RT_TASK *task, const char *name, int prio, int mode) { struct rt_arg_bulk bulk; + int err; + + systrace_init_thread(name); + systrace_enter(__FUNCTION__, "task=%p, name=%s, prio=%d, mode=0x%x", + task, systrace_str(name), prio, mode); /* rt_task_delete requires asynchronous cancellation */ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); @@ -165,8 +190,11 @@ int rt_task_shadow(RT_TASK *task, const bulk.a4 = (u_long)mode; bulk.a5 = (u_long)pthread_self(); - return XENOMAI_SKINCALL2(__native_muxid, __native_task_create, &bulk, - NULL); + err = XENOMAI_SKINCALL2(__native_muxid, __native_task_create, &bulk, + NULL); + + systrace_exit(__FUNCTION__, "%d", err); + return err; } int rt_task_bind(RT_TASK *task, const char *name, RTIME timeout) @@ -216,8 +244,16 @@ int rt_task_set_periodic(RT_TASK *task, int rt_task_wait_period(unsigned long *overruns_r) { - return XENOMAI_SKINCALL1(__native_muxid, - __native_task_wait_period, overruns_r); + int err; + + systrace_enter(__FUNCTION__, "overruns_r=%p", overruns_r); + + err = XENOMAI_SKINCALL1(__native_muxid, + __native_task_wait_period, overruns_r); + + systrace_exit(__FUNCTION__, "%d, *overruns_r=%d", err, + (overruns_r) ? *overruns_r : 0); + return err; } int rt_task_set_priority(RT_TASK *task, int prio) @@ -228,8 +264,14 @@ int rt_task_set_priority(RT_TASK *task, int rt_task_sleep(RTIME delay) { - return XENOMAI_SKINCALL1(__native_muxid, __native_task_sleep, &delay); + int err; + systrace_enter(__FUNCTION__, "delay=%llu", delay); + + err = XENOMAI_SKINCALL1(__native_muxid, __native_task_sleep, &delay); + + systrace_exit(__FUNCTION__, "%d", err); + return err; } int rt_task_sleep_until(RTIME date) Index: xenomai/src/skins/posix/Makefile.am =================================================================== --- xenomai.orig/src/skins/posix/Makefile.am +++ xenomai/src/skins/posix/Makefile.am @@ -2,7 +2,7 @@ includedir = $(prefix)/include/posix lib_LTLIBRARIES = libpthread_rt.la -libpthread_rt_la_LDFLAGS = -version-info 0:0:0 -lpthread +libpthread_rt_la_LDFLAGS = -version-info 0:0:0 -lpthread @SYSTRACE_LIB@ libpthread_rt_la_SOURCES = \ init.c \ Index: xenomai/src/skins/posix/clock.c =================================================================== --- xenomai.orig/src/skins/posix/clock.c +++ xenomai/src/skins/posix/clock.c @@ -20,6 +20,7 @@ #include <pthread.h> /* For pthread_setcanceltype. */ #include <posix/syscall.h> #include <time.h> +#include <asm-generic/xenomai/usystrace.h> extern int __pse51_muxid; @@ -39,15 +40,22 @@ int __wrap_clock_getres(clockid_t clock_ int __wrap_clock_gettime(clockid_t clock_id, struct timespec *tp) { - int err = -XENOMAI_SKINCALL2(__pse51_muxid, - __pse51_clock_gettime, - clock_id, - tp); + int err; + + systrace_enter("clock_gettime", "clock_id=%d, tp=%p", clock_id, tp); + + err = XENOMAI_SKINCALL2(__pse51_muxid, + __pse51_clock_gettime, + clock_id, + tp); + + systrace_exit("clock_gettime", "%d, tp={%d, %d}", err, + tp ? tp->tv_sec : 0, tp ? tp->tv_nsec : 0); if (!err) return 0; - errno = err; + errno = -err; return -1; } @@ -71,6 +79,11 @@ int __wrap_clock_nanosleep(clockid_t clo { int err, oldtype; + systrace_enter("clock_nanosleep", "clock_id=%d, flags=0x%x, " + "rqtp=%p {%d, %d}, rmtp=%p", clock_id, flags, rqtp, + rqtp ? rqtp->tv_sec : 0, rqtp ? rqtp->tv_nsec : 0, + rmtp); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); err = -XENOMAI_SKINCALL4(__pse51_muxid, @@ -79,6 +92,9 @@ int __wrap_clock_nanosleep(clockid_t clo pthread_setcanceltype(oldtype, NULL); + systrace_exit("clock_nanosleep", "%d, rmtp={%d, %d}", err, + rmtp ? rmtp->tv_sec : 0, rmtp ? rmtp->tv_nsec : 0); + return err; } Index: xenomai/src/skins/posix/init.c =================================================================== --- xenomai.orig/src/skins/posix/init.c +++ xenomai/src/skins/posix/init.c @@ -28,6 +28,7 @@ #include <rtdm/syscall.h> #include <asm-generic/bits/bind.h> #include <asm-generic/bits/mlock_alert.h> +#include <asm-generic/xenomai/usystrace.h> int __pse51_muxid = -1; int __rtdm_muxid = -1; @@ -85,4 +86,6 @@ void __init_posix_interface(void) } fork_handler_registered = 1; } + + systrace_init(); } Index: xenomai/src/skins/posix/mutex.c =================================================================== --- xenomai.orig/src/skins/posix/mutex.c +++ xenomai/src/skins/posix/mutex.c @@ -19,6 +19,7 @@ #include <errno.h> #include <posix/syscall.h> #include <pthread.h> +#include <asm-generic/xenomai/usystrace.h> extern int __pse51_muxid; @@ -97,12 +98,16 @@ int __wrap_pthread_mutex_lock(pthread_mu union __xeno_mutex *_mutex = (union __xeno_mutex *)mutex; int err; + systrace_enter("pthread_mutex_lock", "mutex=%p", mutex); + do { err = XENOMAI_SKINCALL1(__pse51_muxid, __pse51_mutex_lock, &_mutex->shadow_mutex); } while (err == -EINTR); + systrace_exit("pthread_mutex_lock", "%d", -err); + return -err; } @@ -112,12 +117,17 @@ int __wrap_pthread_mutex_timedlock(pthre union __xeno_mutex *_mutex = (union __xeno_mutex *)mutex; int err; + systrace_enter("pthread_mutex_timedlock", "mutex=%p, to=%p {%d, %d}", + mutex, to, to ? to->tv_sec : 0, to ? to->tv_nsec : 0); + do { err = XENOMAI_SKINCALL2(__pse51_muxid, __pse51_mutex_timedlock, &_mutex->shadow_mutex, to); } while (err == -EINTR); + systrace_exit("pthread_mutex_timedlock", "%d", -err); + return -err; } @@ -132,7 +142,14 @@ int __wrap_pthread_mutex_trylock(pthread int __wrap_pthread_mutex_unlock(pthread_mutex_t * mutex) { union __xeno_mutex *_mutex = (union __xeno_mutex *)mutex; + int err; - return -XENOMAI_SKINCALL1(__pse51_muxid, - __pse51_mutex_unlock, &_mutex->shadow_mutex); + systrace_enter("pthread_mutex_unlock", "mutex=%p", mutex); + + err = -XENOMAI_SKINCALL1(__pse51_muxid, + __pse51_mutex_unlock, &_mutex->shadow_mutex); + + systrace_exit("pthread_mutex_unlock", "%d", err); + + return err; } Index: xenomai/src/skins/posix/thread.c =================================================================== --- xenomai.orig/src/skins/posix/thread.c +++ xenomai/src/skins/posix/thread.c @@ -22,6 +22,7 @@ #include <pthread.h> #include <semaphore.h> #include <posix/syscall.h> +#include <asm-generic/xenomai/usystrace.h> extern int __pse51_muxid; @@ -36,18 +37,22 @@ int __wrap_pthread_setschedparam(pthread pthread_t myself = pthread_self(); int err, promoted; + systrace_enter("pthread_setschedparam", "pthread=%p, policy=%d, " + "param=%p {%d}", thread, policy, param, + param ? param->sched_priority : 0); + err = -XENOMAI_SKINCALL5(__pse51_muxid, __pse51_thread_setschedparam, thread, policy, param, myself, &promoted); - if (err == EPERM) - return __real_pthread_setschedparam(thread, policy, param); - if (!err && promoted) { signal(SIGHARDEN, &__pthread_sigharden_handler); if (policy != SCHED_OTHER) XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN); - } + } else if (err == EPERM) + err = __real_pthread_setschedparam(thread, policy, param); + + systrace_exit("pthread_setschedparam", "%d%", err); return err; } @@ -114,7 +119,9 @@ static void *__pthread_trampoline(void * if (!err) { if (policy != SCHED_OTHER) XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN); + systrace_enter("pthread_trampoline", "cookie=%p", cookie); status = start(cookie); + systrace_exit("pthread_trampoline", "%p", status); } else status = (void *)-err;
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Xenomai-core mailing list Xenomai-core@gna.org https://mail.gna.org/listinfo/xenomai-core