All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@domain.hid>
To: xenomai-core <xenomai@xenomai.org>
Subject: [Xenomai-core] [PATCH] testsuite: add clock test
Date: Mon, 30 Apr 2007 11:25:19 +0200	[thread overview]
Message-ID: <4635B5FF.4000306@domain.hid> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 774 bytes --]

Hi,

here comes a new testsuite tool to add the required [1] clock validation
against unsynchronised TSCs on SMP boxes. It can also be used to detect
certain classes of broken clocks (TSCs...) on UP and to measure the
drift against the Linux clock (gettimeofday). The latter is interesting
to check the potential impact of new tsc-to-ns conversion functions and
- once we provide such a feature - the synchronisation of Xenomai's time
base with Linux (or other clocks).

Feedback welcome!

Once everyone is fine with it, I would like to apply it to trunk. IMO we
should also add this test to the xeno_test script (if someone feels like
providing an add-on patch, don't hesitate).

Jan


[1] https://mail.gna.org/public/xenomai-core/2007-04/msg00022.html

[-- Attachment #1.2: clocktest.patch --]
[-- Type: text/plain, Size: 9068 bytes --]

---
 configure.in                        |    1 
 src/testsuite/Makefile.am           |    2 
 src/testsuite/clocktest/Makefile.am |   26 ++++
 src/testsuite/clocktest/clocktest.c |  230 ++++++++++++++++++++++++++++++++++++
 src/testsuite/clocktest/runinfo.in  |    1 
 5 files changed, 259 insertions(+), 1 deletion(-)

Index: xenomai/configure.in
===================================================================
--- xenomai.orig/configure.in
+++ xenomai/configure.in
@@ -641,6 +641,7 @@ AC_CONFIG_FILES([ \
        	src/testsuite/cyclic/Makefile \
        	src/testsuite/switchtest/Makefile \
 	src/testsuite/irqbench/Makefile \
+	src/testsuite/clocktest/Makefile \
 	src/utils/Makefile \
 	src/utils/can/Makefile \
        	include/Makefile \
Index: xenomai/src/testsuite/Makefile.am
===================================================================
--- xenomai.orig/src/testsuite/Makefile.am
+++ xenomai/src/testsuite/Makefile.am
@@ -1 +1 @@
-SUBDIRS = latency switchbench cyclic switchtest irqbench
+SUBDIRS = latency switchbench cyclic switchtest irqbench clocktest
Index: xenomai/src/testsuite/clocktest/Makefile.am
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/clocktest/Makefile.am
@@ -0,0 +1,26 @@
+testdir = $(exec_prefix)/share/xenomai/testsuite/clocktest
+
+bin_PROGRAMS = clocktest
+
+clocktest_SOURCES = clocktest.c
+
+clocktest_CPPFLAGS = -I$(top_srcdir)/include/posix $(XENO_USER_CFLAGS) -I$(top_srcdir)/include
+
+clocktest_LDFLAGS = $(XENO_POSIX_WRAPPERS) $(XENO_USER_LDFLAGS)
+
+clocktest_LDADD = \
+	../../skins/posix/libpthread_rt.la -lpthread -lrt
+
+install-data-local:
+	$(mkinstalldirs) $(DESTDIR)$(testdir)
+	@sed -e's,@exec_prefix\@,$(exec_prefix),g' $(srcdir)/runinfo.in > $(DESTDIR)$(testdir)/.runinfo
+	@echo "\$${DESTDIR}$(exec_prefix)/bin/xeno-load \`dirname \$$0\` \$$*" > $(DESTDIR)$(testdir)/run
+	@chmod +x $(DESTDIR)$(testdir)/run
+
+uninstall-local:
+	$(RM) $(DESTDIR)$(testdir)/.runinfo $(DESTDIR)$(testdir)/run
+
+run: all
+	@$(top_srcdir)/scripts/xeno-load --verbose
+
+EXTRA_DIST = runinfo.in
Index: xenomai/src/testsuite/clocktest/clocktest.c
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/clocktest/clocktest.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2007 Jan Kiszka <jan.kiszka@web.de>.
+ *
+ * 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 <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#ifndef HAVE_RECENT_SETAFFINITY
+#ifdef HAVE_OLD_SETAFFINITY
+#define sched_setaffinity(pid, len, mask)	sched_setaffinity(pid, mask)
+#else /* !HAVE_OLD_SETAFFINITY */
+#ifndef __cpu_set_t_defined
+typedef unsigned long cpu_set_t;
+#endif
+#define sched_setaffinity(pid, len, mask)	do { } while (0)
+#define CPU_ZERO(set)				memset(set, 0, sizeof(*set))
+#define CPU_SET(n, set)				do { } while (0)
+#endif /* !HAVE_OLD_SETAFFINITY */
+#endif /* !HAVE_RECENT_SETAFFINITY */
+
+pthread_spinlock_t lock;
+unsigned long long last_common = 0;
+clockid_t clock_id = CLOCK_REALTIME;
+
+struct per_cpu_data {
+    unsigned long long first_tod, first_clock;
+    int first_round;
+    long long offset;
+    double drift;
+    unsigned long warps;
+    unsigned long long max_warp;
+    pthread_t thread;
+} *per_cpu_data;
+
+static inline unsigned long long read_clock(clockid_t clock_id)
+{
+    struct timespec ts;
+
+    clock_gettime(clock_id, &ts);
+    return ts.tv_nsec + ts.tv_sec * 1000000000ULL;
+}
+
+static inline unsigned long long read_reference_clock(void)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    return tv.tv_usec * 1000ULL + tv.tv_sec * 1000000000ULL;
+}
+
+void check_reference(struct per_cpu_data *per_cpu_data)
+{
+    unsigned long long clock_val[10], tod_val[10];
+    long long delta, min_delta;
+    int i, idx;
+
+    for (i = 0; i < 10; i++) {
+        tod_val[i] = read_reference_clock();
+        clock_val[i] = read_clock(clock_id);
+    }
+
+    min_delta = tod_val[1] - tod_val[0];
+    idx = 1;
+
+    for (i = 2; i < 10; i++) {
+        delta = tod_val[i] - tod_val[i-1];
+        if (delta < min_delta) {
+            min_delta = delta;
+            idx = i;
+        }
+    }
+
+    if (per_cpu_data->first_round) {
+        per_cpu_data->first_round = 0;
+
+        per_cpu_data->first_tod = tod_val[idx];
+        per_cpu_data->first_clock = clock_val[idx];
+    } else
+        per_cpu_data->drift =
+            (clock_val[idx] - per_cpu_data->first_clock) /
+            (double)(tod_val[idx] - per_cpu_data->first_tod) - 1;
+
+    per_cpu_data->offset = clock_val[idx] - tod_val[idx];
+}
+
+void check_time_warps(struct per_cpu_data *per_cpu_data)
+{
+    int i;
+    unsigned long long last, now;
+    long long incr;
+
+    for (i = 0; i < 100; i++) {
+        pthread_spin_lock(&lock);
+        now = read_clock(clock_id);
+        last = last_common;
+        last_common = now;
+        pthread_spin_unlock(&lock);
+
+        incr = now - last;
+        if (incr < 0) {
+            per_cpu_data->warps++;
+            if (incr > per_cpu_data->max_warp)
+                per_cpu_data->max_warp = incr;
+        }
+    }
+}
+
+void *cpu_thread(void *arg)
+{
+    int cpuid = (long)arg;
+    struct sched_param param = { .sched_priority = 1 };
+    struct timespec delay = { 0, 0 };
+    cpu_set_t cpu_set;
+
+    srandom(read_reference_clock());
+
+    CPU_ZERO(&cpu_set);
+    CPU_SET(cpuid, &cpu_set);
+    sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+
+    while (1) {
+        check_reference(&per_cpu_data[cpuid]);
+
+        check_time_warps(&per_cpu_data[cpuid]);
+
+        delay.tv_nsec = 1000000 + random() * 4000000;
+        nanosleep(&delay, NULL);
+    }
+}
+
+void sighand(int signal)
+{
+    exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+    int cpus = sysconf(_SC_NPROCESSORS_ONLN);
+    int i;
+    char c;
+
+    while ((c = getopt(argc,argv,"C:T:")) != EOF)
+        switch (c) {
+            case 'C':
+                clock_id = atoi(optarg);
+                break;
+
+            case 'T':
+                alarm(atoi(optarg));
+                break;
+
+            default:
+                fprintf(stderr, "usage: clocktest [options]\n"
+                        "  [-C <clock_id>]              # tested clock, default=%d (CLOCK_REALTIME)\n"
+                        "  [-T <test_duration_seconds>] # default=0, so ^C to end\n",
+                        CLOCK_REALTIME);
+                exit(2);
+        }
+
+    mlockall(MCL_CURRENT | MCL_FUTURE);
+
+    signal(SIGALRM, sighand);
+
+    pthread_spin_init(&lock, 0);
+
+    per_cpu_data = malloc(sizeof(*per_cpu_data) * cpus);
+    if (!per_cpu_data) {
+        fprintf(stderr, "%s\n", strerror(ENOMEM));
+        exit(1);
+    }
+    memset(per_cpu_data, 0, sizeof(*per_cpu_data) * cpus);
+
+    for (i = 0; i < cpus; i++) {
+        per_cpu_data[i].first_round = 1;
+        pthread_create(&per_cpu_data[i].thread, NULL, cpu_thread,
+                    (void *)i);
+    }
+
+    printf("== Tested clock: %d (", clock_id);
+    switch (clock_id) {
+        case CLOCK_REALTIME:
+            printf("CLOCK_REALTIME");
+            break;
+
+        case CLOCK_MONOTONIC:
+            printf("CLOCK_MONOTONIC");
+            break;
+
+        default:
+            printf("<unknown>");
+            break;
+    }
+    printf(")\nCPU      ToD offset [us] ToD drift [us/s]      warps max delta [us]\n"
+              "--- -------------------- ---------------- ---------- --------------\n");
+
+    while (1) {
+        for (i = 0; i < cpus; i++)
+            printf("%3d %20.1f %16.3f %10lu %14.1f\n",
+                   i,
+                   per_cpu_data[i].offset/1000.0,
+                   per_cpu_data[i].drift * 1000000.0,
+                   per_cpu_data[i].warps,
+                   per_cpu_data[i].max_warp/1000.0);
+        usleep(250000);
+        printf("\033[%dA", cpus);
+    }
+}
Index: xenomai/src/testsuite/clocktest/runinfo.in
===================================================================
--- /dev/null
+++ xenomai/src/testsuite/clocktest/runinfo.in
@@ -0,0 +1 @@
+clocktest:posix:!@exec_prefix@/bin/clocktest;popall:control_c

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 250 bytes --]

                 reply	other threads:[~2007-04-30  9:25 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4635B5FF.4000306@domain.hid \
    --to=jan.kiszka@domain.hid \
    --cc=xenomai@xenomai.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.