* [Xenomai-core] [PATCH] in-kernel timer benchmark -v3
@ 2006-01-02 13:14 Jan Kiszka
2006-01-02 18:28 ` Philippe Gerum
0 siblings, 1 reply; 4+ messages in thread
From: Jan Kiszka @ 2006-01-02 13:14 UTC (permalink / raw)
To: xenomai-core
[-- Attachment #1.1: Type: text/plain, Size: 860 bytes --]
Happy New Year everyone!
Hope you all survived the turn of the year without complications. ;)
I would like to start with a new patch round. The first one is a revised
and extended version of the earlier posted in-kernel timer benchmark
based on a RTDM device. Changes since the first version:
* revised command line argument to set the test mode
* display test mode during startup
* display hint on missing benchmark device
* support of trace freeze on latency above specified threshold
* extended benchmark device to provide ipipe-tracing functions to
userspace
* further minor fixes
I think the patch should be ready to merge now. This would also be
helpful to provide a base on which Gilles can build his timer-scaling
tests. BTW, we still need some RTDM abstraction for timers, but this is
a different topic that will be addressed later.
Jan
[-- Attachment #1.2: timerbench.patch-v3 --]
[-- Type: text/plain, Size: 35796 bytes --]
Index: include/rtdm/rtbenchmark.h
===================================================================
--- include/rtdm/rtbenchmark.h (Revision 0)
+++ include/rtdm/rtbenchmark.h (Revision 0)
@@ -0,0 +1,131 @@
+/**
+ * @file
+ * Real-Time Driver Model for Xenomai, benchmark device profile header
+ *
+ * @note Copyright (C) 2005 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.
+ *
+ * @ingroup rtbenchmark
+ */
+
+/*!
+ * @ingroup profiles
+ * @defgroup rtbenchmark Benchmark Devices
+ *
+ * This group of devices is intended to provide in-kernel benchmark 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
+ * @n
+ *
+ * @par Device Characteristics
+ * @ref rtdm_device.device_flags "Device Flags": @c RTDM_NAMED_DEVICE, @c RTDM_EXCLUSIVE @n
+ * @n
+ * @ref rtdm_device.device_name "Device Name": @c "rtbenchmark<N>", N >= 0 @n
+ * @n
+ * @ref rtdm_device.device_class "Device Class": @c RTDM_CLASS_BENCHMARK @n
+ * @n
+ *
+ * @par Supported Operations
+ * @b Open @n
+ * Environments: non-RT (RT optional)@n
+ * Specific return values: none @n
+ * @n
+ * @b Close @n
+ * Environments: non-RT (RT optional)@n
+ * Specific return values: none @n
+ * @n
+ * @b IOCTL @n
+ * Mandatory Environments: see @ref IOCTLs "below" @n
+ * Specific return values: see @ref IOCTLs "below" @n
+ *
+ * @{
+ */
+
+#ifndef _RTBENCHMARK_H
+#define _RTBENCHMARK_H
+
+#include <asm/types.h>
+#include <xenomai/rtdm/rtdm.h>
+
+#define RTBNCH_TIMER_TASK 0
+#define RTBNCH_TIMER_HANDLER 1
+
+typedef struct rtbnch_result {
+ long avg;
+ long min;
+ long max;
+ long overruns;
+ long test_loops;
+} rtbnch_result_t;
+
+typedef struct rtbnch_timerconfig {
+ int mode;
+ uint64_t period;
+ int warmup_loops;
+ int histogram_size;
+ int histogram_bucketsize;
+ long freeze_threshold;
+} rtbnch_timerconfig_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 RTIOC_TYPE_BENCHMARK RTDM_CLASS_BENCHMARK
+
+
+/*!
+ * @name Sub-Classes of RTDM_CLASS_BENCHMARK
+ * @{ */
+#define RTDM_SUBCLASS_TIMER 0
+/** @} */
+
+
+/*!
+ * @anchor IOCTLs @name IOCTLs
+ * Benchmark 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 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, int)
+
+/** @} */
+
+#endif /* _RTBENCHMARK_H */
Index: include/rtdm/rtdm.h
===================================================================
--- include/rtdm/rtdm.h (Revision 334)
+++ include/rtdm/rtdm.h (Arbeitskopie)
@@ -68,6 +68,7 @@
#define RTDM_CLASS_CAN 3
#define RTDM_CLASS_NETWORK 4
#define RTDM_CLASS_RTMAC 5
+#define RTDM_CLASS_BENCHMARK 6
/*
#define RTDM_CLASS_USB ?
#define RTDM_CLASS_FIREWIRE ?
Index: src/testsuite/latency/latency.c
===================================================================
--- src/testsuite/latency/latency.c (Revision 334)
+++ src/testsuite/latency/latency.c (Arbeitskopie)
@@ -11,6 +11,7 @@
#include <xenomai/native/task.h>
#include <xenomai/native/timer.h>
#include <xenomai/native/sem.h>
+#include <xenomai/rtdm/rtbenchmark.h>
RT_TASK latency_task, display_task;
@@ -29,7 +30,16 @@
int test_duration = 0; /* sec of testing, via -T <sec>, 0 is inf */
int data_lines = 21; /* data lines per header line, -l <lines> to change */
int quiet = 0; /* suppress printing of RTH, RTD lines when -T given */
+int benchdev_no = 0;
+int benchdev = -1;
+long freeze_threshold = 0;
+#define USER_TASK 0
+#define KERNEL_TASK 1
+#define TIMER_HANDLER 2
+
+int test_mode = USER_TASK;
+
time_t test_start, test_end; /* report test duration */
int test_loops = 0; /* outer loop count */
@@ -60,14 +70,6 @@
RTIME expected_tsc, period_tsc, start_ticks;
RT_TIMER_INFO timer_info;
- err = rt_timer_start(TM_ONESHOT);
-
- if (err)
- {
- fprintf(stderr,"latency: cannot start timer, code %d\n",err);
- return;
- }
-
err = rt_timer_inquire(&timer_info);
if (err)
@@ -76,6 +78,9 @@
return;
}
+ if (freeze_threshold > 0)
+ freeze_threshold = rt_timer_ns2tsc(freeze_threshold*1000);
+
nsamples = ONE_BILLION / period_ns;
period_tsc = rt_timer_ns2tsc(period_ns);
/* start time: one millisecond from now. */
@@ -117,6 +122,9 @@
if (dt < minj) minj = dt;
sumj += dt;
+ if ((freeze_threshold > 0) && (dt > freeze_threshold))
+ rt_dev_ioctl(benchdev, RTBNCH_RTIOC_FREEZE_TRACE, freeze_threshold);
+
if (!(finished || warmup) && (do_histogram || do_stats))
add_histogram(histogram_avg, dt);
}
@@ -156,14 +164,43 @@
int err, n = 0;
time_t start;
- err = rt_sem_create(&display_sem,"dispsem",0,S_FIFO);
+ if (test_mode == USER_TASK) {
+ err = rt_sem_create(&display_sem,"dispsem",0,S_FIFO);
- if (err)
- {
- fprintf(stderr,"latency: cannot create semaphore: %s\n",strerror(-err));
- return;
- }
+ if (err)
+ {
+ fprintf(stderr,"latency: cannot create semaphore: %s\n",strerror(-err));
+ return;
+ }
+ printf("== Test mode: periodic userspace task\n");
+
+ } else {
+ struct rtbnch_timerconfig config;
+
+ if (test_mode == KERNEL_TASK)
+ config.mode = RTBNCH_TIMER_TASK;
+ else
+ config.mode = RTBNCH_TIMER_HANDLER;
+
+ config.period = period_ns;
+ config.warmup_loops = WARMUP_TIME;
+ config.histogram_size = (do_histogram || do_stats) ? histogram_size : 0;
+ config.histogram_bucketsize = bucketsize;
+ config.freeze_threshold = freeze_threshold;
+
+ err = rt_dev_ioctl(benchdev, RTBNCH_RTIOC_START_TMTEST, &config);
+
+ if (err)
+ {
+ fprintf(stderr,"latency: failed to start in-kernel timer benchmark, code %d\n",err);
+ return;
+ }
+
+ printf("== Test mode: in-kernel %s\n",
+ (test_mode == TIMER_HANDLER) ? "timer handler" : "periodic task");
+ }
+
time(&start);
if (quiet)
@@ -172,23 +209,46 @@
for (;;)
{
long minj, gminj, maxj, gmaxj, avgj;
- err = rt_sem_p(&display_sem,TM_INFINITE);
- if (err)
- {
- if (err != -EIDRM)
- fprintf(stderr,"latency: failed to pend on semaphore, code %d\n",err);
+ if (test_mode == USER_TASK) {
+ err = rt_sem_p(&display_sem,TM_INFINITE);
- rt_task_delete(NULL);
- }
+ if (err)
+ {
+ if (err != -EIDRM)
+ fprintf(stderr,"latency: failed to pend on semaphore, code %d\n",err);
- /* convert jitters to nanoseconds. */
- minj = rt_timer_tsc2ns(minjitter);
- gminj = rt_timer_tsc2ns(gminjitter);
- avgj = rt_timer_tsc2ns(avgjitter);
- maxj = rt_timer_tsc2ns(maxjitter);
- gmaxj = rt_timer_tsc2ns(gmaxjitter);
+ return;
+ }
+ /* convert jitters to nanoseconds. */
+ minj = rt_timer_tsc2ns(minjitter);
+ gminj = rt_timer_tsc2ns(gminjitter);
+ avgj = rt_timer_tsc2ns(avgjitter);
+ maxj = rt_timer_tsc2ns(maxjitter);
+ gmaxj = rt_timer_tsc2ns(gmaxjitter);
+
+ } else {
+ struct rtbnch_interm_result result;
+
+ err = rt_dev_ioctl(benchdev, RTBNCH_RTIOC_INTERM_RESULT, &result);
+
+ if (err)
+ {
+ if (err != -EIDRM)
+ fprintf(stderr,"latency: failed to call RTBNCH_RTIOC_INTERM_RESULT, code %d\n",err);
+
+ return;
+ }
+
+ minj = result.last.min;
+ gminj = result.overall.min;
+ avgj = result.last.avg;
+ maxj = result.last.max;
+ gmaxj = result.overall.max;
+ goverrun = result.overall.overruns;
+ }
+
if (!quiet)
{
if (data_lines && (n++ % data_lines)==0)
@@ -295,20 +355,40 @@
finished = 1;
rt_timer_stop();
- rt_sem_delete(&display_sem);
+ if (test_mode == USER_TASK) {
+ rt_sem_delete(&display_sem);
+
+ gavgjitter /= (test_loops > 1 ? test_loops : 2)-1;
+
+ gminj = rt_timer_tsc2ns(gminjitter);
+ gmaxj = rt_timer_tsc2ns(gmaxjitter);
+ gavgj = rt_timer_tsc2ns(gavgjitter);
+ } else {
+ struct rtbnch_overall_result 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);
+
+ gminj = overall.result.min;
+ gmaxj = overall.result.max;
+ gavgj = overall.result.avg;
+ goverrun = overall.result.overruns;
+ }
+
+ if (benchdev >= 0)
+ rt_dev_close(benchdev);
+
if (do_histogram || do_stats)
dump_hist_stats();
time(&test_end);
actual_duration = test_end - test_start - WARMUP_TIME;
if (!test_duration) test_duration = actual_duration;
- gavgjitter /= (test_loops > 1 ? test_loops : 2)-1;
- gminj = rt_timer_tsc2ns(gminjitter);
- gmaxj = rt_timer_tsc2ns(gmaxjitter);
- gavgj = rt_timer_tsc2ns(gavgjitter);
-
printf("---|------------|------------|------------|--------|-------------------------\n"
"RTS|%12ld|%12ld|%12ld|%8ld| %.2ld:%.2ld:%.2ld/%.2d:%.2d:%.2d\n",
gminj,
@@ -333,7 +413,7 @@
{
int c, err;
- while ((c = getopt(argc,argv,"hp:l:T:qH:B:s")) != EOF)
+ while ((c = getopt(argc,argv,"hp:l:T:qH:B:sD:t:f:")) != EOF)
switch (c)
{
case 'h':
@@ -377,6 +457,21 @@
quiet = 1;
break;
+ case 'D':
+
+ benchdev_no = atoi(optarg);
+ break;
+
+ case 't':
+
+ test_mode = atoi(optarg);
+ break;
+
+ case 'f':
+
+ freeze_threshold = atoi(optarg);
+ break;
+
default:
fprintf(stderr, "usage: latency [options]\n"
@@ -387,7 +482,10 @@
" [-p <period_us>] # sampling period\n"
" [-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");
+ " [-q] # supresses RTD, RTH lines if -T is used\n"
+ " [-D <benchmark_device_no>] # number of benchmark device, default=0\n"
+ " [-t <test_mode>] # 0=user task (default), 1=kernel task, 2=timer IRQ\n"
+ " [-f <threshold_us>] # freeze trace on latency exceeding threshold\n");
exit(2);
}
@@ -397,6 +495,12 @@
quiet = 0;
}
+ if ((test_mode < USER_TASK) || (test_mode > TIMER_HANDLER))
+ {
+ fprintf(stderr, "latency: invalid test mode.\n");
+ exit(2);
+ }
+
time(&test_start);
histogram_avg = calloc(histogram_size, sizeof(long));
@@ -420,38 +524,63 @@
mlockall(MCL_CURRENT|MCL_FUTURE);
- err = rt_task_create(&display_task,"display",0,98,0);
+ err = rt_timer_start(TM_ONESHOT);
if (err)
{
- fprintf(stderr,"latency: failed to create display task, code %d\n",err);
+ fprintf(stderr,"latency: cannot start timer, code %d\n",err);
return 0;
}
- err = rt_task_start(&display_task,&display,NULL);
+ if ((test_mode != USER_TASK) || (freeze_threshold > 0))
+ {
+ char devname[RTDM_MAX_DEVNAME_LEN];
- if (err)
- {
- fprintf(stderr,"latency: failed to start display task, code %d\n",err);
- return 0;
+ snprintf(devname, RTDM_MAX_DEVNAME_LEN, "rtbenchmark%d", benchdev_no);
+ benchdev = rt_dev_open(devname, O_RDWR);
+
+ if (benchdev < 0)
+ {
+ fprintf(stderr,"latency: failed to open benchmark device, code %d\n"
+ "(modprobe xeno_timerbench?)\n",benchdev);
+ return 0;
+ }
}
- err = rt_task_create(&latency_task,"sampling",0,99,T_FPU);
+ err = rt_task_create(&display_task,"display",0,98,0);
if (err)
{
- fprintf(stderr,"latency: failed to create latency task, code %d\n",err);
+ fprintf(stderr,"latency: failed to create display task, code %d\n",err);
return 0;
}
- err = rt_task_start(&latency_task,&latency,NULL);
+ err = rt_task_start(&display_task,&display,NULL);
if (err)
{
- fprintf(stderr,"latency: failed to start latency task, code %d\n",err);
+ fprintf(stderr,"latency: failed to start display task, code %d\n",err);
return 0;
}
+ if (test_mode == USER_TASK) {
+ err = rt_task_create(&latency_task,"sampling",0,99,T_FPU);
+
+ if (err)
+ {
+ fprintf(stderr,"latency: failed to create latency task, code %d\n",err);
+ return 0;
+ }
+
+ err = rt_task_start(&latency_task,&latency,NULL);
+
+ if (err)
+ {
+ fprintf(stderr,"latency: failed to start latency task, code %d\n",err);
+ return 0;
+ }
+ }
+
pause();
return 0;
Index: src/testsuite/latency/runinfo
===================================================================
--- src/testsuite/latency/runinfo (Revision 334)
+++ src/testsuite/latency/runinfo (Arbeitskopie)
@@ -1 +1 @@
-latency:native:!./latency;popall:control_c
+latency:native+rtdm+timerbench:!./latency;popall:control_c
Index: src/testsuite/latency/Makefile.am
===================================================================
--- src/testsuite/latency/Makefile.am (Revision 334)
+++ src/testsuite/latency/Makefile.am (Arbeitskopie)
@@ -10,6 +10,7 @@
latency_LDADD = \
../../skins/native/libnative.la \
+ ../../skins/rtdm/librtdm.la \
-lpthread -lm
install-data-local:
Index: ksrc/drivers/Kconfig
===================================================================
--- ksrc/drivers/Kconfig (Revision 334)
+++ ksrc/drivers/Kconfig (Arbeitskopie)
@@ -1 +1,2 @@
source "drivers/xenomai/16550A/Kconfig"
+source "drivers/xenomai/benchmark/Kconfig"
Index: ksrc/drivers/Config.in
===================================================================
--- ksrc/drivers/Config.in (Revision 334)
+++ ksrc/drivers/Config.in (Arbeitskopie)
@@ -8,5 +8,6 @@
mainmenu_option next_comment
comment 'Real-time drivers'
source drivers/xenomai/16550A/Config.in
+ source drivers/xenomai/benchmark/Config.in
endmenu
fi
Index: ksrc/drivers/benchmark/Kconfig
===================================================================
--- ksrc/drivers/benchmark/Kconfig (Revision 0)
+++ ksrc/drivers/benchmark/Kconfig (Revision 0)
@@ -0,0 +1,7 @@
+config XENO_DRIVERS_TIMERBENCH
+ depends on XENO_SKIN_RTDM
+ tristate "Timer benchmark driver"
+ default n
+ help
+ Kernel-based benchmark driver for timer latency evaluation.
+ See testsuite/latency for a possible front-end.
Index: ksrc/drivers/benchmark/timerbench.c
===================================================================
--- ksrc/drivers/benchmark/timerbench.c (Revision 0)
+++ ksrc/drivers/benchmark/timerbench.c (Revision 0)
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2005 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 <linux/ipipe_trace.h>
+
+#include <xenomai/rtdm/rtbenchmark.h>
+#include <xenomai/rtdm/rtdm_driver.h>
+
+struct rt_tmbench_context {
+ int mode;
+ unsigned long period;
+ unsigned long freeze_threshold;
+ 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;
+
+ rtdm_event_t result_event;
+ struct rtbnch_interm_result result;
+
+ 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 void add_histogram(struct rt_tmbench_context *ctx,
+ long *histogram, long addval)
+{
+ /* bucketsize steps */
+ long inabs = (addval >= 0 ? addval : -addval) / ctx->bucketsize;
+ histogram[inabs < ctx->histogram_size ? inabs : ctx->histogram_size-1]++;
+}
+
+
+void eval_inner_loop(struct rt_tmbench_context *ctx, long dt)
+{
+ if (ctx->date <= ctx->start_time)
+ ctx->curr.overruns++;
+
+ if (dt > ctx->curr.max)
+ ctx->curr.max = dt;
+ if (dt < ctx->curr.min)
+ ctx->curr.min = dt;
+ ctx->curr.avg += dt;
+
+#ifdef CONFIG_IPIPE_TRACE
+ if ((ctx->freeze_threshold > 0) && (dt > ctx->freeze_threshold))
+ ipipe_trace_freeze(ctx->freeze_threshold);
+#endif /* CONFIG_IPIPE_TRACE */
+
+ ctx->date += ctx->period;
+
+ if (!ctx->warmup && ctx->histogram_size)
+ add_histogram(ctx, ctx->histogram_avg, dt);
+}
+
+
+void eval_outer_loop(struct rt_tmbench_context *ctx)
+{
+ if (!ctx->warmup) {
+ if (ctx->histogram_size) {
+ add_histogram(ctx, ctx->histogram_max, ctx->curr.max);
+ add_histogram(ctx, ctx->histogram_min, ctx->curr.min);
+ }
+
+ ctx->result.last.min = ctx->curr.min;
+ if (ctx->curr.min < ctx->result.overall.min)
+ ctx->result.overall.min = ctx->curr.min;
+
+ ctx->result.last.max = ctx->curr.max;
+ if (ctx->curr.max > ctx->result.overall.max)
+ ctx->result.overall.max = ctx->curr.max;
+
+ ctx->result.last.avg = ctx->curr.avg / ctx->samples_per_sec;
+ ctx->result.overall.avg += ctx->result.last.avg;
+ ctx->result.overall.overruns += ctx->curr.overruns;
+ rtdm_event_pulse(&ctx->result_event);
+ }
+
+ if (ctx->warmup &&
+ (ctx->result.overall.test_loops == ctx->warmup_loops)) {
+ ctx->result.overall.test_loops = 0;
+ ctx->warmup = 0;
+ }
+
+ ctx->curr.min = 10000000;
+ ctx->curr.max = -10000000;
+ ctx->curr.avg = 0;
+ ctx->curr.overruns = 0;
+
+ ctx->result.overall.test_loops++;
+}
+
+
+void timer_task_proc(void *arg)
+{
+ struct rt_tmbench_context *ctx = (struct rt_tmbench_context *)arg;
+ int count;
+
+
+ /* start time: one millisecond from now. */
+ ctx->date = rtdm_clock_read() + 1000000;
+
+ while (1) {
+ int err;
+
+
+ for (count = 0; count < ctx->samples_per_sec; count++) {
+ RTDM_EXECUTE_ATOMICALLY(
+ ctx->start_time = rtdm_clock_read();
+ err = rtdm_task_sleep_until(ctx->date);
+ );
+
+ if (err)
+ return;
+
+ eval_inner_loop(ctx, (long)(rtdm_clock_read() - ctx->date));
+ }
+ eval_outer_loop(ctx);
+ }
+}
+
+
+void timer_proc(void *arg)
+{
+ struct rt_tmbench_context *ctx = (struct rt_tmbench_context *)arg;
+
+
+ eval_inner_loop(ctx, (long)(rtdm_clock_read() - ctx->date));
+
+ ctx->start_time = rtdm_clock_read();
+ /* FIXME: convert to RTDM timers */
+ xntimer_start(&ctx->timer, xnpod_ns2ticks(ctx->date-ctx->start_time),
+ XN_INFINITE);
+
+ if (++ctx->curr.test_loops < ctx->samples_per_sec)
+ return;
+
+ ctx->curr.test_loops = 0;
+ eval_outer_loop(ctx);
+}
+
+
+int rt_tmbench_open(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int oflags)
+{
+ struct rt_tmbench_context *ctx;
+
+
+ ctx = (struct rt_tmbench_context *)context->dev_private;
+
+ ctx->mode = -1;
+ init_MUTEX(&ctx->nrt_mutex);
+
+ return 0;
+}
+
+
+int rt_tmbench_close(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info)
+{
+ struct rt_tmbench_context *ctx;
+
+
+ ctx = (struct rt_tmbench_context *)context->dev_private;
+
+ down(&ctx->nrt_mutex);
+
+ if (ctx->mode >= 0) {
+ if (ctx->mode == RTBNCH_TIMER_TASK)
+ rtdm_task_destroy(&ctx->timer_task);
+ else
+ /* FIXME: convert to RTDM timers */
+ xntimer_destroy(&ctx->timer);
+
+ rtdm_event_destroy(&ctx->result_event);
+
+ if (ctx->histogram_size)
+ kfree(ctx->histogram_min);
+
+ ctx->mode = -1;
+ ctx->histogram_size = 0;
+ }
+
+ up(&ctx->nrt_mutex);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_IPIPE_TRACE
+int tracer_ioctl(int request, long v)
+{
+ switch (request) {
+ case RTBNCH_RTIOC_BEGIN_TRACE:
+ ipipe_trace_begin(v);
+ break;
+
+ case RTBNCH_RTIOC_END_TRACE:
+ ipipe_trace_end(v);
+ break;
+
+ case RTBNCH_RTIOC_FREEZE_TRACE:
+ ipipe_trace_freeze(v);
+ break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+#else /* !CONFIG_IPIPE_TRACE */
+#define tracer_ioctl(request, v) (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)
+{
+ struct rt_tmbench_context *ctx;
+ int ret = 0;
+
+
+ if (tracer_ioctl(request, (long)arg))
+ return 0;
+
+ ctx = (struct rt_tmbench_context *)context->dev_private;
+
+ switch (request) {
+ case RTBNCH_RTIOC_START_TMTEST: {
+ struct rtbnch_timerconfig config_buf;
+ struct rtbnch_timerconfig *config;
+
+
+ config = (struct rtbnch_timerconfig *)arg;
+ if (user_info) {
+ if (!rtdm_read_user_ok(user_info, arg,
+ sizeof(struct rtbnch_timerconfig)) ||
+ rtdm_copy_from_user(user_info, &config_buf, arg,
+ sizeof(struct rtbnch_timerconfig)))
+ return -EFAULT;
+
+ config = &config_buf;
+ }
+
+ down(&ctx->nrt_mutex);
+
+ ctx->period = config->period;
+ ctx->warmup_loops = config->warmup_loops;
+ ctx->samples_per_sec = 1000000000 / ctx->period;
+ ctx->histogram_size = config->histogram_size;
+ ctx->freeze_threshold = config->freeze_threshold;
+
+ if (ctx->histogram_size > 0) {
+ ctx->histogram_min =
+ kmalloc(3 * ctx->histogram_size * sizeof(long),
+ GFP_KERNEL);
+ ctx->histogram_max =
+ ctx->histogram_min + config->histogram_size;
+ ctx->histogram_avg =
+ ctx->histogram_max + config->histogram_size;
+
+ if (!ctx->histogram_min) {
+ up(&ctx->nrt_mutex);
+ return -ENOMEM;
+ }
+
+ memset(ctx->histogram_min, 0,
+ 3 * ctx->histogram_size * sizeof(long));
+ ctx->bucketsize = config->histogram_bucketsize;
+ }
+
+ ctx->result.overall.min = 10000000;
+ ctx->result.overall.max = -10000000;
+ ctx->result.overall.avg = 0;
+ ctx->result.overall.test_loops = 1;
+ ctx->result.overall.overruns = 0;
+
+ ctx->warmup = 1;
+
+ ctx->curr.min = 10000000;
+ ctx->curr.max = -10000000;
+ ctx->curr.avg = 0;
+ ctx->curr.overruns = 0;
+
+ rtdm_event_init(&ctx->result_event, 0);
+
+ if (config->mode == RTBNCH_TIMER_TASK) {
+ if (!test_bit(RTDM_CLOSING, &context->context_flags)) {
+ ctx->mode = RTBNCH_TIMER_TASK;
+ ret = rtdm_task_init(&ctx->timer_task, "timerbench",
+ timer_task_proc, ctx,
+ RTDM_TASK_HIGHEST_PRIORITY, 0);
+ }
+ } else {
+ /* FIXME: convert to RTDM timers */
+ xntimer_init(&ctx->timer, timer_proc, ctx);
+
+ ctx->curr.test_loops = 0;
+
+ if (!test_bit(RTDM_CLOSING, &context->context_flags)) {
+ ctx->mode = RTBNCH_TIMER_HANDLER;
+ RTDM_EXECUTE_ATOMICALLY(
+ /* start time: one millisecond from now. */
+ ctx->start_time = rtdm_clock_read() + 1000000;
+ ctx->date = ctx->start_time + ctx->period;
+
+ /* FIXME: convert to RTDM timers */
+ xntimer_start(&ctx->timer,
+ xnpod_ns2ticks(ctx->date-rtdm_clock_read()),
+ XN_INFINITE);
+ );
+ }
+ }
+
+ up(&ctx->nrt_mutex);
+
+ break;
+ }
+
+ case RTBNCH_RTIOC_STOP_TMTEST: {
+ struct rtbnch_overall_result *usr_res;
+
+
+ usr_res = (struct rtbnch_overall_result *)arg;
+
+ down(&ctx->nrt_mutex);
+
+ if (ctx->mode < 0) {
+ up(&ctx->nrt_mutex);
+ return -EINVAL;
+ }
+
+ if (ctx->mode == RTBNCH_TIMER_TASK)
+ rtdm_task_destroy(&ctx->timer_task);
+ else
+ /* FIXME: convert to RTDM timers */
+ xntimer_destroy(&ctx->timer);
+
+ rtdm_event_destroy(&ctx->result_event);
+
+ ctx->mode = -1;
+
+ ctx->result.overall.avg /=
+ ((ctx->result.overall.test_loops) > 1 ?
+ ctx->result.overall.test_loops : 2) - 1;
+
+ if (user_info) {
+ if (!rtdm_rw_user_ok(user_info, usr_res,
+ sizeof(struct rtbnch_overall_result)) ||
+ rtdm_copy_to_user(user_info, &usr_res->result,
+ &ctx->result.overall,
+ sizeof(struct rtbnch_result)))
+ ret = -EFAULT;
+ } else {
+ memcpy(&usr_res->result, &ctx->result.overall,
+ sizeof(struct rtbnch_result));
+ }
+
+ if (ctx->histogram_size) {
+ int size = ctx->histogram_size * sizeof(long);
+
+ if (user_info) {
+ if (!rtdm_rw_user_ok(user_info, usr_res->histogram_min,
+ size) ||
+ rtdm_copy_to_user(user_info, usr_res->histogram_min,
+ ctx->histogram_min, size) ||
+ !rtdm_rw_user_ok(user_info, usr_res->histogram_max,
+ size) ||
+ rtdm_copy_to_user(user_info, usr_res->histogram_max,
+ ctx->histogram_max, size) ||
+ !rtdm_rw_user_ok(user_info, usr_res->histogram_avg,
+ size) ||
+ rtdm_copy_to_user(user_info, usr_res->histogram_avg,
+ ctx->histogram_avg, size))
+ ret = -EFAULT;
+ } else {
+ memcpy(usr_res->histogram_min, ctx->histogram_min, size);
+ memcpy(usr_res->histogram_max, ctx->histogram_max, size);
+ memcpy(usr_res->histogram_avg, ctx->histogram_avg, size);
+ }
+
+ kfree(ctx->histogram_min);
+ }
+
+ up(&ctx->nrt_mutex);
+
+ break;
+ }
+
+ case RTBNCH_RTIOC_INTERM_RESULT:
+ ret = -ENOSYS;
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+
+int rt_tmbench_ioctl_rt(struct rtdm_dev_context *context,
+ rtdm_user_info_t *user_info, int request, void *arg)
+{
+ struct rt_tmbench_context *ctx;
+ int ret = 0;
+
+
+ if (tracer_ioctl(request, (long)arg))
+ return 0;
+
+ ctx = (struct rt_tmbench_context *)context->dev_private;
+
+ switch (request) {
+ case RTBNCH_RTIOC_INTERM_RESULT: {
+ struct rtbnch_interm_result *usr_res;
+
+
+ usr_res = (struct rtbnch_interm_result *)arg;
+
+ ret = rtdm_event_wait(&ctx->result_event);
+ if (ret < 0)
+ return ret;
+
+ if (user_info) {
+ if (!rtdm_rw_user_ok(user_info, usr_res,
+ sizeof(struct rtbnch_interm_result)) ||
+ rtdm_copy_to_user(user_info, usr_res, &ctx->result,
+ sizeof(struct rtbnch_interm_result)))
+ ret = -EFAULT;
+ } else
+ memcpy(usr_res, &ctx->result,
+ sizeof(struct rtbnch_interm_result));
+
+ break;
+ }
+
+ case RTBNCH_RTIOC_START_TMTEST:
+ case RTBNCH_RTIOC_STOP_TMTEST:
+ ret = -ENOSYS;
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+
+static struct rtdm_device device = {
+ struct_version: RTDM_DEVICE_STRUCT_VER,
+
+ device_flags: RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
+ context_size: sizeof(struct rt_tmbench_context),
+ device_name: "",
+
+ open_rt: NULL,
+ open_nrt: rt_tmbench_open,
+
+ ops: {
+ close_rt: NULL,
+ close_nrt: rt_tmbench_close,
+
+ ioctl_rt: rt_tmbench_ioctl_rt,
+ ioctl_nrt: rt_tmbench_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_BENCHMARK,
+ device_sub_class: RTDM_SUBCLASS_TIMER,
+ driver_name: "xeno_timerbench",
+ driver_version: RTDM_DRIVER_VER(0, 1, 0),
+ peripheral_name: "Timer Latency Benchmark",
+ provider_name: "Jan Kiszka",
+ proc_name: device.device_name,
+};
+
+int __init init_module(void)
+{
+ snprintf(device.device_name, RTDM_MAX_DEVNAME_LEN, "rtbenchmark%d",
+ start_index);
+
+ return rtdm_dev_register(&device);
+}
+
+
+void cleanup_module(void)
+{
+ rtdm_dev_unregister(&device, 1000);
+}
Index: ksrc/drivers/benchmark/Config.in
===================================================================
--- ksrc/drivers/benchmark/Config.in (Revision 0)
+++ ksrc/drivers/benchmark/Config.in (Revision 0)
@@ -0,0 +1,5 @@
+#
+# Xenomai configuration for Linux v2.4
+#
+
+dep_tristate 'Timer benchmark driver' CONFIG_XENO_DRIVERS_TIMERBENCH $CONFIG_XENO_SKIN_RTDM
Index: ksrc/drivers/benchmark/Makefile
===================================================================
--- ksrc/drivers/benchmark/Makefile (Revision 0)
+++ ksrc/drivers/benchmark/Makefile (Revision 0)
@@ -0,0 +1,30 @@
+ifeq ($(PATCHLEVEL),6)
+
+# Makefile frag for Linux v2.6
+
+obj-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += xeno_timerbench.o
+
+xeno_timerbench-y := timerbench.o
+
+else
+
+# Makefile frag for Linux v2.4
+
+O_TARGET := built-in.o
+
+obj-$(CONFIG_XENO_DRIVERS_TIMERBENCH) := xeno_timerbench.o
+
+list-multi := xeno_timerbench.o
+
+xeno_timerbench-objs := timerbench.o
+
+export-objs := $(xeno_timerbench-objs)
+
+EXTRA_CFLAGS += -I$(TOPDIR)/include/xenomai/compat
+
+include $(TOPDIR)/Rules.make
+
+xeno_timerbench.o: $(xeno_timerbench-objs)
+ $(LD) -r -o $@ $(xeno_timerbench-objs)
+
+endif
Index: ksrc/drivers/Makefile
===================================================================
--- ksrc/drivers/Makefile (Revision 334)
+++ ksrc/drivers/Makefile (Arbeitskopie)
@@ -2,7 +2,7 @@
# Makefile frag for Linux v2.6
-obj-$(CONFIG_XENOMAI) += 16550A/
+obj-$(CONFIG_XENOMAI) += 16550A/ benchmark/
else
@@ -10,6 +10,8 @@
subdir-$(CONFIG_XENO_DRIVERS_16550A) += 16550A
+subdir-$(CONFIG_XENO_DRIVERS_TIMERBENCH) += benchmark
+
include $(TOPDIR)/Rules.make
endif
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Xenomai-core] [PATCH] in-kernel timer benchmark -v3
2006-01-02 13:14 [Xenomai-core] [PATCH] in-kernel timer benchmark -v3 Jan Kiszka
@ 2006-01-02 18:28 ` Philippe Gerum
2006-01-02 19:20 ` Jan Kiszka
0 siblings, 1 reply; 4+ messages in thread
From: Philippe Gerum @ 2006-01-02 18:28 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai-core
Jan Kiszka wrote:
> Happy New Year everyone!
>
> Hope you all survived the turn of the year without complications. ;)
>
Nearly buried alive in patches, but this is hardly a complication.
> I would like to start with a new patch round. The first one is a revised
> and extended version of the earlier posted in-kernel timer benchmark
> based on a RTDM device. Changes since the first version:
>
> * revised command line argument to set the test mode
> * display test mode during startup
> * display hint on missing benchmark device
> * support of trace freeze on latency above specified threshold
> * extended benchmark device to provide ipipe-tracing functions to
> userspace
> * further minor fixes
>
Ok, merged.
> I think the patch should be ready to merge now. This would also be
> helpful to provide a base on which Gilles can build his timer-scaling
> tests. BTW, we still need some RTDM abstraction for timers, but this is
> a different topic that will be addressed later.
>
Btw, since -rc1 is out, I've deprecated the Adeos oldgen support for all
archs (ia64 is now I-pipe based too), so that I can merge Dmitry's work
later on, exclusively into the newgen codebase. So if anyone still keeps
any venerable pre-Ipipe patch in some hideout of his hdd, just let it go
now; I know it's heartbreaking, but Xenomai is thankless.
--
Philippe.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Xenomai-core] [PATCH] in-kernel timer benchmark -v3
2006-01-02 18:28 ` Philippe Gerum
@ 2006-01-02 19:20 ` Jan Kiszka
2006-01-03 14:43 ` Jan Kiszka
0 siblings, 1 reply; 4+ messages in thread
From: Jan Kiszka @ 2006-01-02 19:20 UTC (permalink / raw)
To: Philippe Gerum; +Cc: xenomai-core
[-- Attachment #1.1: Type: text/plain, Size: 155 bytes --]
...as a follow-up, here is a patch to fix some bugs in the new trace
triggering and to improve (from my POV) the output of this tool in some
regards.
Jan
[-- Attachment #1.2: latency.patch --]
[-- Type: text/x-patch, Size: 3413 bytes --]
Index: src/testsuite/latency/latency.c
===================================================================
--- src/testsuite/latency/latency.c (Revision 345)
+++ src/testsuite/latency/latency.c (Arbeitskopie)
@@ -39,6 +39,11 @@
#define TIMER_HANDLER 2
int test_mode = USER_TASK;
+const char *test_mode_names[] = {
+ "periodic user-mode task",
+ "in-kernel periodic task",
+ "in-kernel timer handler"
+};
time_t test_start, test_end; /* report test duration */
int test_loops = 0; /* outer loop count */
@@ -78,8 +83,7 @@
return;
}
- if (freeze_threshold > 0)
- freeze_threshold = rt_timer_ns2tsc(freeze_threshold*1000);
+ freeze_threshold = rt_timer_ns2tsc(freeze_threshold);
nsamples = ONE_BILLION / period_ns;
period_tsc = rt_timer_ns2tsc(period_ns);
@@ -122,11 +126,15 @@
if (dt < minj) minj = dt;
sumj += dt;
- if ((freeze_threshold > 0) && (dt > freeze_threshold))
- rt_dev_ioctl(benchdev, RTBNCH_RTIOC_FREEZE_TRACE, freeze_threshold);
+ if (!(finished || warmup))
+ {
+ if ((freeze_threshold > 0) && (dt > freeze_threshold))
+ rt_dev_ioctl(benchdev, RTBNCH_RTIOC_FREEZE_TRACE,
+ freeze_threshold);
- if (!(finished || warmup) && (do_histogram || do_stats))
- add_histogram(histogram_avg, dt);
+ if (do_histogram || do_stats)
+ add_histogram(histogram_avg, dt);
+ }
}
if(!warmup)
@@ -173,8 +181,6 @@
return;
}
- printf("== Test mode: periodic userspace task\n");
-
} else {
struct rtbnch_timerconfig config;
@@ -196,13 +202,13 @@
fprintf(stderr,"latency: failed to start in-kernel timer benchmark, code %d\n",err);
return;
}
-
- printf("== Test mode: in-kernel %s\n",
- (test_mode == TIMER_HANDLER) ? "timer handler" : "periodic task");
}
time(&start);
+ if (WARMUP_TIME)
+ printf("warming up...\n");
+
if (quiet)
fprintf(stderr, "running quietly for %d seconds\n", test_duration);
@@ -256,8 +262,9 @@
time_t now, dt;
time(&now);
dt = now - start - WARMUP_TIME;
- printf("RTT| %.2ld:%.2ld:%.2ld\n",
- dt / 3600,(dt / 60) % 60,dt % 60);
+ printf("RTT| %.2ld:%.2ld:%.2ld (%s, %Ld us period)\n",
+ dt / 3600,(dt / 60) % 60,dt % 60,
+ test_mode_names[test_mode],period_ns / 1000);
printf("RTH|%12s|%12s|%12s|%8s|%12s|%12s\n",
"-----lat min","-----lat avg","-----lat max","-overrun",
"----lat best","---lat worst");
@@ -469,7 +476,7 @@
case 'f':
- freeze_threshold = atoi(optarg);
+ freeze_threshold = atoi(optarg)*1000;
break;
default:
@@ -520,7 +527,10 @@
setlinebuf(stdout);
- printf("== Sampling period: %Ld us\n",period_ns / 1000);
+ printf("== Sampling period: %Ld us\n"
+ "== Test mode: %s\n",
+ period_ns / 1000,
+ test_mode_names[test_mode]);
mlockall(MCL_CURRENT|MCL_FUTURE);
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Xenomai-core] [PATCH] in-kernel timer benchmark -v3
2006-01-02 19:20 ` Jan Kiszka
@ 2006-01-03 14:43 ` Jan Kiszka
0 siblings, 0 replies; 4+ messages in thread
From: Jan Kiszka @ 2006-01-03 14:43 UTC (permalink / raw)
To: Philippe Gerum; +Cc: xenomai-core
[-- Attachment #1: Type: text/plain, Size: 199 bytes --]
Jan Kiszka wrote:
> ...as a follow-up, here is a patch to fix some bugs in the new trace
> triggering and to improve (from my POV) the output of this tool in some
> regards.
Applied on my own.
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2006-01-03 14:43 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-01-02 13:14 [Xenomai-core] [PATCH] in-kernel timer benchmark -v3 Jan Kiszka
2006-01-02 18:28 ` Philippe Gerum
2006-01-02 19:20 ` Jan Kiszka
2006-01-03 14:43 ` Jan Kiszka
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.