* [Xenomai-core] [RFC] in-kernel timer benchmark
@ 2005-12-18 18:44 Jan Kiszka
2005-12-22 10:32 ` Philippe Gerum
2005-12-22 18:43 ` Gilles Chanteperdrix
0 siblings, 2 replies; 5+ messages in thread
From: Jan Kiszka @ 2005-12-18 18:44 UTC (permalink / raw)
To: xenomai-core
[-- Attachment #1.1: Type: text/plain, Size: 1233 bytes --]
Hi all,
this is fully working proposal how to re-enable in-kernel timer latency
benchmarks.
More precisely, it adds a new RTDM device "rtbenchmark<X>" (and also a
new RTDM class) which can execute either a kernel task or timer
periodically. The benchmark device generates all the usual latency data
which can be retrieved from userspace via IOCTLs. I patched the existing
latency tool to open the device and read the data from there instead of
running its own latency task.
README for a quick test:
o apply patch and rebuild everything (don't forget to re-prepare the
kernel and also call scripts/bootstrap, I added some files)
o load xeno_timerbench (+ xeno_native, xeno_rtdm, ...)
o run "latency -D0" to start in-kernel timer task test on device
"rtbenchmark0"
o run "latency -D0 -t" to start in-kernel timer handler test (i.e.
without scheduling latency) on device "rtbenchmark0"
This is rather fresh code, handle with care! ;) Moreover, I would like
to hear your comments if the extension of the latency tool is the right
way to got or if we better split things up. The problem I see is that
this patch makes latency depend on xeno_rtdm being loaded.
Jan
PS: I likely broke src/testsuite/latency/runinfo.
[-- Attachment #1.2: timerbench.patch --]
[-- Type: text/x-patch, Size: 32683 bytes --]
Index: include/rtdm/rtbenchmark.h
===================================================================
--- include/rtdm/rtbenchmark.h (Revision 0)
+++ include/rtdm/rtbenchmark.h (Revision 0)
@@ -0,0 +1,121 @@
+/**
+ * @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;
+} 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)
+
+/** @} */
+
+#endif /* _RTBENCHMARK_H */
Index: include/rtdm/rtdm.h
===================================================================
--- include/rtdm/rtdm.h (Revision 288)
+++ 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 288)
+++ 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,6 +30,9 @@
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 = -1;
+int benchdev = -1;
+int test_mode = RTBNCH_TIMER_TASK;
time_t test_start, test_end; /* report test duration */
int test_loops = 0; /* outer loop count */
@@ -60,14 +64,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)
@@ -156,14 +152,33 @@
int err, n = 0;
time_t start;
- err = rt_sem_create(&display_sem,"dispsem",0,S_FIFO);
+ if (benchdev >= 0) {
+ struct rtbnch_timerconfig config;
- if (err)
- {
- fprintf(stderr,"latency: cannot create semaphore: %s\n",strerror(-err));
- return;
- }
+ config.mode = test_mode;
+ config.period = period_ns;
+ config.warmup_loops = WARMUP_TIME;
+ config.histogram_size = (do_histogram || do_stats) ? histogram_size : 0;
+ config.histogram_bucketsize = bucketsize;
+ 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;
+ }
+
+ } else {
+ err = rt_sem_create(&display_sem,"dispsem",0,S_FIFO);
+
+ if (err)
+ {
+ fprintf(stderr,"latency: cannot create semaphore: %s\n",strerror(-err));
+ return;
+ }
+ }
+
time(&start);
if (quiet)
@@ -172,23 +187,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 (benchdev >= 0) {
+ struct rtbnch_interm_result result;
- rt_task_delete(NULL);
- }
+ err = rt_dev_ioctl(benchdev, RTBNCH_RTIOC_INTERM_RESULT, &result);
- /* 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);
+ 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;
+
+ } else {
+ 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);
+
+ 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);
+ }
+
if (!quiet)
{
if (data_lines && (n++ % data_lines)==0)
@@ -295,20 +333,38 @@
finished = 1;
rt_timer_stop();
- rt_sem_delete(&display_sem);
+ if (benchdev >= 0) {
+ 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);
+ rt_dev_close(benchdev);
+
+ gminj = overall.result.min;
+ gmaxj = overall.result.max;
+ gavgj = overall.result.avg;
+ goverrun = overall.result.overruns;
+ } else {
+ 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);
+ }
+
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 +389,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")) != EOF)
switch (c)
{
case 'h':
@@ -377,6 +433,16 @@
quiet = 1;
break;
+ case 'D':
+
+ benchdev_no = atoi(optarg);
+ break;
+
+ case 't':
+
+ test_mode = RTBNCH_TIMER_HANDLER;
+ break;
+
default:
fprintf(stderr, "usage: latency [options]\n"
@@ -387,7 +453,9 @@
" [-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>] # use in-kernel benchmark of given device\n"
+ " [-t] # run in-kernel timer handler test, default: task\n");
exit(2);
}
@@ -397,6 +465,12 @@
quiet = 0;
}
+ if ((benchdev_no < 0) && (test_mode == RTBNCH_TIMER_HANDLER))
+ {
+ fprintf(stderr, "latency: -t only works if -D has been given.\n");
+ exit(2);
+ }
+
time(&test_start);
histogram_avg = calloc(histogram_size, sizeof(long));
@@ -420,38 +494,61 @@
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 (benchdev_no >= 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);
- err = rt_task_create(&latency_task,"sampling",0,99,T_FPU);
+ if (benchdev)
+ {
+ fprintf(stderr,"latency: failed to open benchmark device, code %d\n",benchdev);
+ return 0;
+ }
+ }
+ 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 (benchdev_no < 0) {
+ 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/Makefile.am
===================================================================
--- src/testsuite/latency/Makefile.am (Revision 288)
+++ 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 288)
+++ 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 288)
+++ 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,498 @@
+/*
+ * 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 <xenomai/rtdm/rtbenchmark.h>
+#include <xenomai/rtdm/rtdm_driver.h>
+
+struct rt_tmbench_context {
+ int mode;
+ unsigned long period;
+ 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;
+
+ 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;
+}
+
+
+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;
+
+
+ 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;
+
+ 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;
+
+
+ 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 288)
+++ 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_benchmark) += benchmark
+
include $(TOPDIR)/Rules.make
endif
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [Xenomai-core] [RFC] in-kernel timer benchmark
2005-12-18 18:44 [Xenomai-core] [RFC] in-kernel timer benchmark Jan Kiszka
@ 2005-12-22 10:32 ` Philippe Gerum
2005-12-22 18:43 ` Gilles Chanteperdrix
1 sibling, 0 replies; 5+ messages in thread
From: Philippe Gerum @ 2005-12-22 10:32 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai-core
Jan Kiszka wrote:
> Hi all,
>
> this is fully working proposal how to re-enable in-kernel timer latency
> benchmarks.
>
> More precisely, it adds a new RTDM device "rtbenchmark<X>" (and also a
> new RTDM class) which can execute either a kernel task or timer
> periodically. The benchmark device generates all the usual latency data
> which can be retrieved from userspace via IOCTLs. I patched the existing
> latency tool to open the device and read the data from there instead of
> running its own latency task.
>
> README for a quick test:
>
> o apply patch and rebuild everything (don't forget to re-prepare the
> kernel and also call scripts/bootstrap, I added some files)
>
> o load xeno_timerbench (+ xeno_native, xeno_rtdm, ...)
>
> o run "latency -D0" to start in-kernel timer task test on device
> "rtbenchmark0"
>
> o run "latency -D0 -t" to start in-kernel timer handler test (i.e.
> without scheduling latency) on device "rtbenchmark0"
>
Worked like a charm here.
> This is rather fresh code, handle with care! ;) Moreover, I would like
> to hear your comments if the extension of the latency tool is the right
> way to got or if we better split things up. The problem I see is that
> this patch makes latency depend on xeno_rtdm being loaded.
>
IMO, using RTDM here is definitely the right thing, and depending on it
for the purpose of benchmarking is acceptable if we admit that
additional and more complex benchmarks we may provide in the future will
most likely benefit from using RTDM as a mean to exchange data and get
control requests from user-space. Better not having to invent some
braindamage FIFO-based messaging protocol each time we want to enrich
the benchmark/test collection anyway. Production systems will likely
don't care about the benchmark suite, so configuring out RTDM if
otherwise unneeded would still be a no-brainer.
On the split/no-split issue, I'd keep it the way you crafted it, i.e.
both tests integrated. After all, they both measure the same latencies
(pure timer test option put aside) even if they happen to do the
measurements in different exec contexts. I will have two remarks though:
- a clearer message upon failure to start the kernel-based test (likely
due to the absence of the benchmark module) should be sent. Some hint
telling the user that "modprobe xeno_timerbench?" would not be a bad
idea to issue would likely be useful.
- some information when starting/running? the current test that tells us
which benchmark is currently running.
> PS: I likely broke src/testsuite/latency/runinfo.
This patch should do it, whether the listed features are available as
modules or statically bound to the kernel:
-latency:rtdm+native:!./latency;popall:control_c
+latency:rtdm+native+timerbench:!./latency;popall:control_c
--
Philippe.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Xenomai-core] [RFC] in-kernel timer benchmark
2005-12-18 18:44 [Xenomai-core] [RFC] in-kernel timer benchmark Jan Kiszka
2005-12-22 10:32 ` Philippe Gerum
@ 2005-12-22 18:43 ` Gilles Chanteperdrix
2005-12-22 19:25 ` Jan Kiszka
1 sibling, 1 reply; 5+ messages in thread
From: Gilles Chanteperdrix @ 2005-12-22 18:43 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai-core
Jan Kiszka wrote:
> Hi all,
>
> this is fully working proposal how to re-enable in-kernel timer latency
> benchmarks.
>
> More precisely, it adds a new RTDM device "rtbenchmark<X>" (and also a
> new RTDM class) which can execute either a kernel task or timer
> periodically. The benchmark device generates all the usual latency data
> which can be retrieved from userspace via IOCTLs. I patched the existing
> latency tool to open the device and read the data from there instead of
> running its own latency task.
>
> README for a quick test:
>
> o apply patch and rebuild everything (don't forget to re-prepare the
> kernel and also call scripts/bootstrap, I added some files)
>
> o load xeno_timerbench (+ xeno_native, xeno_rtdm, ...)
>
> o run "latency -D0" to start in-kernel timer task test on device
> "rtbenchmark0"
>
> o run "latency -D0 -t" to start in-kernel timer handler test (i.e.
> without scheduling latency) on device "rtbenchmark0"
>
> This is rather fresh code, handle with care! ;) Moreover, I would like
> to hear your comments if the extension of the latency tool is the right
> way to got or if we better split things up. The problem I see is that
> this patch makes latency depend on xeno_rtdm being loaded.
I agree with Philippe: having a driver for the various benchmarking
needs is a good idea, we could imagine adding ioctls for the various
loads, etc... But I would vote for a split between the user-space
latency measurement tool and the display tool for kernel-space latency.
A minor issue: in the 2.4 portion of ksrc/drivers/Makefile, should not
CONFIG_XENO_DRIVERS_benchmark be replaced with
CONFIG_XENO_DRIVERS_TIMERBENCH ?
It is a very interesting tool indeed (especially since I would need such
a tool to benchmark the various solutions to improve nucleus timers
scalability :). But it would be nice to be able to create several tasks
or several timers without having to open one file descriptor by
timer/task. Or if you want one file descriptor by timer/task,
rt_tmbench_ioctl_nrt should return an error when trying to start the
task or timer twice.
--
Gilles Chanteperdrix.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Xenomai-core] [RFC] in-kernel timer benchmark
2005-12-22 18:43 ` Gilles Chanteperdrix
@ 2005-12-22 19:25 ` Jan Kiszka
2005-12-23 12:15 ` Gilles Chanteperdrix
0 siblings, 1 reply; 5+ messages in thread
From: Jan Kiszka @ 2005-12-22 19:25 UTC (permalink / raw)
To: Gilles Chanteperdrix; +Cc: xenomai-core
[-- Attachment #1: Type: text/plain, Size: 3279 bytes --]
Gilles Chanteperdrix wrote:
> Jan Kiszka wrote:
> > Hi all,
> >
> > this is fully working proposal how to re-enable in-kernel timer latency
> > benchmarks.
> >
> > More precisely, it adds a new RTDM device "rtbenchmark<X>" (and also a
> > new RTDM class) which can execute either a kernel task or timer
> > periodically. The benchmark device generates all the usual latency data
> > which can be retrieved from userspace via IOCTLs. I patched the existing
> > latency tool to open the device and read the data from there instead of
> > running its own latency task.
> >
> > README for a quick test:
> >
> > o apply patch and rebuild everything (don't forget to re-prepare the
> > kernel and also call scripts/bootstrap, I added some files)
> >
> > o load xeno_timerbench (+ xeno_native, xeno_rtdm, ...)
> >
> > o run "latency -D0" to start in-kernel timer task test on device
> > "rtbenchmark0"
> >
> > o run "latency -D0 -t" to start in-kernel timer handler test (i.e.
> > without scheduling latency) on device "rtbenchmark0"
> >
> > This is rather fresh code, handle with care! ;) Moreover, I would like
> > to hear your comments if the extension of the latency tool is the right
> > way to got or if we better split things up. The problem I see is that
> > this patch makes latency depend on xeno_rtdm being loaded.
>
> I agree with Philippe: having a driver for the various benchmarking
> needs is a good idea, we could imagine adding ioctls for the various
> loads, etc... But I would vote for a split between the user-space
> latency measurement tool and the display tool for kernel-space latency.
>
What's your main concern about the current solution? The need to have
RTDM being loaded to start only the userspace test?
If this is the case, do we have some option to only fail when the user
actually requests in-kernel tests without any xeno_rtdm being loaded?
That means we would somehow have to avoid that the librtdm
initialisation fatally fails in this particular use case - hmm, or maybe
even in general...
Let's think about this: If there is no xeno_rtdm, then there is also no
driver loaded. While we can catch to first case during lib-init, the
latter will always trigger later in the program. So, having no xeno_rtdm
could also be interpreted by the lib like not having the (every)
addressed driver being loaded. I think I should prepare a patch,
shouldn't I?
> A minor issue: in the 2.4 portion of ksrc/drivers/Makefile, should not
> CONFIG_XENO_DRIVERS_benchmark be replaced with
> CONFIG_XENO_DRIVERS_TIMERBENCH ?
Yep, someone was not able to handle search&replace correctly.
>
> It is a very interesting tool indeed (especially since I would need such
> a tool to benchmark the various solutions to improve nucleus timers
> scalability :). But it would be nice to be able to create several tasks
> or several timers without having to open one file descriptor by
> timer/task. Or if you want one file descriptor by timer/task,
> rt_tmbench_ioctl_nrt should return an error when trying to start the
> task or timer twice.
>
Ok, I will try to reworks this, generating a ready-for-merge patch which
will also include Philippe's remarks. No promise if this is going to be
a pre-Christmas gift. ;)
Jan
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 256 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Xenomai-core] [RFC] in-kernel timer benchmark
2005-12-22 19:25 ` Jan Kiszka
@ 2005-12-23 12:15 ` Gilles Chanteperdrix
0 siblings, 0 replies; 5+ messages in thread
From: Gilles Chanteperdrix @ 2005-12-23 12:15 UTC (permalink / raw)
To: Jan Kiszka; +Cc: xenomai-core
Jan Kiszka wrote:
> Gilles Chanteperdrix wrote:
> > (...) But I would vote for a split between the user-space
> > latency measurement tool and the display tool for kernel-space latency.
> >
>
> What's your main concern about the current solution? The need to have
> RTDM being loaded to start only the userspace test?
I thought the user-space latency was also an example for the native
skin, and had not much in common with the display task for the
kernel-space benchmark. But these benchmarks have in fact much in
common, and the native skin still has the "satch" demo.
> > It is a very interesting tool indeed (especially since I would need such
> > a tool to benchmark the various solutions to improve nucleus timers
> > scalability :). But it would be nice to be able to create several tasks
> > or several timers without having to open one file descriptor by
> > timer/task. Or if you want one file descriptor by timer/task,
> > rt_tmbench_ioctl_nrt should return an error when trying to start the
> > task or timer twice.
> >
>
> Ok, I will try to reworks this, generating a ready-for-merge patch which
> will also include Philippe's remarks. No promise if this is going to be
> a pre-Christmas gift. ;)
Do not bother, since I am the one who need it, I may change it. I will
follow-up with a new proposal.
--
Gilles Chanteperdrix.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2005-12-23 12:15 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-12-18 18:44 [Xenomai-core] [RFC] in-kernel timer benchmark Jan Kiszka
2005-12-22 10:32 ` Philippe Gerum
2005-12-22 18:43 ` Gilles Chanteperdrix
2005-12-22 19:25 ` Jan Kiszka
2005-12-23 12:15 ` Gilles Chanteperdrix
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.