Module: xenomai-3
Branch: next
Commit: 790836f392dfd2acae4ddbfd926d43a7fabfda08
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=790836f392dfd2acae4ddbfd926d43a7fabfda08

Author: Philippe Gerum <r...@xenomai.org>
Date:   Wed Sep 30 16:13:39 2015 +0200

demo/posix: add cyclictest from stock rt-tests

---

 configure.ac                       |    1 +
 demo/posix/Makefile.am             |    6 +-
 demo/posix/cyclictest/Makefile.am  |   34 +
 demo/posix/cyclictest/README       |    5 +
 demo/posix/cyclictest/cyclictest.c | 2203 ++++++++++++++++++++++++++++++++++++
 demo/posix/cyclictest/error.c      |   96 ++
 demo/posix/cyclictest/error.h      |   19 +
 demo/posix/cyclictest/rt-sched.h   |   76 ++
 demo/posix/cyclictest/rt-utils.c   |  319 ++++++
 demo/posix/cyclictest/rt-utils.h   |   27 +
 demo/posix/cyclictest/rt_numa.h    |  277 +++++
 11 files changed, 3061 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8f2136e..b613515 100644
--- a/configure.ac
+++ b/configure.ac
@@ -904,6 +904,7 @@ AC_CONFIG_FILES([ \
        utils/net/Makefile \
        demo/Makefile \
        demo/posix/Makefile \
+       demo/posix/cyclictest/Makefile \
        demo/posix/cobalt/Makefile \
        demo/alchemy/Makefile \
        demo/alchemy/cobalt/Makefile \
diff --git a/demo/posix/Makefile.am b/demo/posix/Makefile.am
index aa0f7f7..0dd66a5 100644
--- a/demo/posix/Makefile.am
+++ b/demo/posix/Makefile.am
@@ -1,6 +1,8 @@
 
+SUBDIRS = cyclictest
+
 if XENO_COBALT
-SUBDIRS = cobalt
+SUBDIRS += cobalt
 endif
 
-DIST_SUBDIRS = cobalt
+DIST_SUBDIRS = cyclictest cobalt
diff --git a/demo/posix/cyclictest/Makefile.am 
b/demo/posix/cyclictest/Makefile.am
new file mode 100644
index 0000000..ff62b37
--- /dev/null
+++ b/demo/posix/cyclictest/Makefile.am
@@ -0,0 +1,34 @@
+demodir = @XENO_DEMO_DIR@
+
+CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
+
+VERSION_STRING = 0.92
+
+demo_PROGRAMS = cyclictest
+
+cyclictest_CPPFLAGS =                          \
+       $(XENO_USER_CFLAGS)                     \
+       -I$(top_srcdir)/include                 \
+       -DVERSION_STRING=$(VERSION_STRING)      \
+       -Wno-strict-prototypes                  \
+       -Wno-implicit-function-declaration      \
+       -Wno-missing-prototypes                 \
+       -Wno-nonnull                            \
+       -Wno-unused-function                    \
+       -Wno-unused-result
+
+cyclictest_SOURCES =   \
+       cyclictest.c    \
+       error.c         \
+       error.h         \
+       rt_numa.h       \
+       rt-sched.h      \
+       rt-utils.c      \
+       rt-utils.h
+
+cyclictest_LDFLAGS = @XENO_AUTOINIT_LDFLAGS@ $(XENO_POSIX_WRAPPERS)
+
+cyclictest_LDADD =                     \
+       ../../../lib/@XENO_CORE_LIB@    \
+        @XENO_USER_LDADD@              \
+       -lpthread -lrt -lm
diff --git a/demo/posix/cyclictest/README b/demo/posix/cyclictest/README
new file mode 100644
index 0000000..8186b04
--- /dev/null
+++ b/demo/posix/cyclictest/README
@@ -0,0 +1,5 @@
+
+This is the original cyclictest program from the PREEMPT-RT test
+suite as of version 0.92.
+
+See git://git.kernel.org/pub/scm/linux/kernel/git/clrkwllms/rt-tests.git
diff --git a/demo/posix/cyclictest/cyclictest.c 
b/demo/posix/cyclictest/cyclictest.c
new file mode 100644
index 0000000..92c7043
--- /dev/null
+++ b/demo/posix/cyclictest/cyclictest.c
@@ -0,0 +1,2203 @@
+/*
+ * High resolution timer test software
+ *
+ * (C) 2013      Clark Williams <willi...@redhat.com>
+ * (C) 2013      John Kacur <jka...@redhat.com>
+ * (C) 2008-2012 Clark Williams <willi...@redhat.com>
+ * (C) 2005-2007 Thomas Gleixner <t...@linutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License Version
+ * 2 as published by the Free Software Foundation.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sched.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <limits.h>
+#include <linux/unistd.h>
+
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/sysinfo.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <sys/mman.h>
+#include "rt_numa.h"
+
+#include "rt-utils.h"
+
+#define DEFAULT_INTERVAL 1000
+#define DEFAULT_DISTANCE 500
+
+#ifndef SCHED_IDLE
+#define SCHED_IDLE 5
+#endif
+#ifndef SCHED_NORMAL
+#define SCHED_NORMAL SCHED_OTHER
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/* Ugly, but .... */
+#define gettid() syscall(__NR_gettid)
+#define sigev_notify_thread_id _sigev_un._tid
+
+#ifdef __UCLIBC__
+#define MAKE_PROCESS_CPUCLOCK(pid, clock) \
+       ((~(clockid_t) (pid) << 3) | (clockid_t) (clock))
+#define CPUCLOCK_SCHED          2
+
+static int clock_nanosleep(clockid_t clock_id, int flags, const struct 
timespec *req,
+                          struct timespec *rem)
+{
+       if (clock_id == CLOCK_THREAD_CPUTIME_ID)
+               return -EINVAL;
+       if (clock_id == CLOCK_PROCESS_CPUTIME_ID)
+               clock_id = MAKE_PROCESS_CPUCLOCK (0, CPUCLOCK_SCHED);
+
+       return syscall(__NR_clock_nanosleep, clock_id, flags, req, rem);
+}
+
+int sched_setaffinity (__pid_t __pid, size_t __cpusetsize,
+                      __const cpu_set_t *__cpuset)
+{
+       return -EINVAL;
+}
+
+#undef CPU_SET
+#undef CPU_ZERO
+#define CPU_SET(cpu, cpusetp)
+#define CPU_ZERO(cpusetp)
+
+#else
+extern int clock_nanosleep(clockid_t __clock_id, int __flags,
+                          __const struct timespec *__req,
+                          struct timespec *__rem);
+#endif
+
+#define USEC_PER_SEC           1000000
+#define NSEC_PER_SEC           1000000000
+
+#define HIST_MAX               1000000
+
+#define MODE_CYCLIC            0
+#define MODE_CLOCK_NANOSLEEP   1
+#define MODE_SYS_ITIMER                2
+#define MODE_SYS_NANOSLEEP     3
+#define MODE_SYS_OFFSET                2
+
+#define TIMER_RELTIME          0
+
+/* Must be power of 2 ! */
+#define VALBUF_SIZE            16384
+
+#define KVARS                  32
+#define KVARNAMELEN            32
+#define KVALUELEN              32
+
+int enable_events;
+
+static char *policyname(int policy);
+
+enum {
+       NOTRACE,
+       CTXTSWITCH,
+       IRQSOFF,
+       PREEMPTOFF,
+       PREEMPTIRQSOFF,
+       WAKEUP,
+       WAKEUPRT,
+       LATENCY,
+       FUNCTION,
+       CUSTOM,
+};
+
+/* Struct to transfer parameters to the thread */
+struct thread_param {
+       int prio;
+       int policy;
+       int mode;
+       int timermode;
+       int signal;
+       int clock;
+       unsigned long max_cycles;
+       struct thread_stat *stats;
+       int bufmsk;
+       unsigned long interval;
+       int cpu;
+       int node;
+       int tnum;
+};
+
+/* Struct for statistics */
+struct thread_stat {
+       unsigned long cycles;
+       unsigned long cyclesread;
+       long min;
+       long max;
+       long act;
+       double avg;
+       long *values;
+       long *hist_array;
+       long *outliers;
+       pthread_t thread;
+       int threadstarted;
+       int tid;
+       long reduce;
+       long redmax;
+       long cycleofmax;
+       long hist_overflow;
+       long num_outliers;
+};
+
+static int shutdown;
+static int tracelimit = 0;
+static int notrace = 0;
+static int ftrace = 0;
+static int kernelversion;
+static int verbose = 0;
+static int oscope_reduction = 1;
+static int lockall = 0;
+static int tracetype = NOTRACE;
+static int histogram = 0;
+static int histofall = 0;
+static int duration = 0;
+static int use_nsecs = 0;
+static int refresh_on_max;
+static int force_sched_other;
+static int priospread = 0;
+static int check_clock_resolution;
+static int ct_debug;
+static int use_fifo = 0;
+static pthread_t fifo_threadid;
+static int aligned = 0;
+static int secaligned = 0;
+static int offset = 0;
+static int laptop = 0;
+
+static pthread_cond_t refresh_on_max_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t refresh_on_max_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static pthread_mutex_t break_thread_id_lock = PTHREAD_MUTEX_INITIALIZER;
+static pid_t break_thread_id = 0;
+static uint64_t break_thread_value = 0;
+
+static pthread_barrier_t align_barr;
+static pthread_barrier_t globalt_barr;
+static struct timespec globalt;
+
+/* Backup of kernel variables that we modify */
+static struct kvars {
+       char name[KVARNAMELEN];
+       char value[KVALUELEN];
+} kv[KVARS];
+
+static char *procfileprefix = "/proc/sys/kernel/";
+static char *fileprefix;
+static char tracer[MAX_PATH];
+static char fifopath[MAX_PATH];
+static char **traceptr;
+static int traceopt_count;
+static int traceopt_size;
+
+static struct thread_param **parameters;
+static struct thread_stat **statistics;
+
+static void print_stat(FILE *fp, struct thread_param *par, int index, int 
verbose, int quiet);
+
+static int latency_target_fd = -1;
+static int32_t latency_target_value = 0;
+
+/* Latency trick
+ * if the file /dev/cpu_dma_latency exists,
+ * open it and write a zero into it. This will tell
+ * the power management system not to transition to
+ * a high cstate (in fact, the system acts like idle=poll)
+ * When the fd to /dev/cpu_dma_latency is closed, the behavior
+ * goes back to the system default.
+ *
+ * Documentation/power/pm_qos_interface.txt
+ */
+static void set_latency_target(void)
+{
+       struct stat s;
+       int err;
+
+       if (laptop) {
+               warn("not setting cpu_dma_latency to save battery power\n");
+               return;
+       }
+
+       errno = 0;
+       err = stat("/dev/cpu_dma_latency", &s);
+       if (err == -1) {
+               err_msg_n(errno, "WARN: stat /dev/cpu_dma_latency failed");
+               return;
+       }
+
+       errno = 0;
+       latency_target_fd = open("/dev/cpu_dma_latency", O_RDWR);
+       if (latency_target_fd == -1) {
+               err_msg_n(errno, "WARN: open /dev/cpu_dma_latency");
+               return;
+       }
+
+       errno = 0;
+       err = write(latency_target_fd, &latency_target_value, 4);
+       if (err < 1) {
+               err_msg_n(errno, "# error setting cpu_dma_latency to %d!", 
latency_target_value);
+               close(latency_target_fd);
+               return;
+       }
+       printf("# /dev/cpu_dma_latency set to %dus\n", latency_target_value);
+}
+
+
+enum kernelversion {
+       KV_NOT_SUPPORTED,
+       KV_26_LT18,
+       KV_26_LT24,
+       KV_26_33,
+       KV_30
+};
+
+enum {
+       ERROR_GENERAL   = -1,
+       ERROR_NOTFOUND  = -2,
+};
+
+static char functiontracer[MAX_PATH];
+static char traceroptions[MAX_PATH];
+
+static int trace_fd     = -1;
+static int tracemark_fd = -1;
+
+static int kernvar(int mode, const char *name, char *value, size_t sizeofvalue)
+{
+       char filename[128];
+       int retval = 1;
+       int path;
+       size_t len_prefix = strlen(fileprefix), len_name = strlen(name);
+
+       if (len_prefix + len_name + 1 > sizeof(filename)) {
+               errno = ENOMEM;
+               return 1;
+       }
+
+       memcpy(filename, fileprefix, len_prefix);
+       memcpy(filename + len_prefix, name, len_name + 1);
+
+       path = open(filename, mode);
+       if (path >= 0) {
+               if (mode == O_RDONLY) {
+                       int got;
+                       if ((got = read(path, value, sizeofvalue)) > 0) {
+                               retval = 0;
+                               value[got-1] = '\0';
+                       }
+               } else if (mode == O_WRONLY) {
+                       if (write(path, value, sizeofvalue) == sizeofvalue)
+                               retval = 0;
+               }
+               close(path);
+       }
+       return retval;
+}
+
+static void setkernvar(const char *name, char *value)
+{
+       int i;
+       char oldvalue[KVALUELEN];
+
+       if (kernelversion < KV_26_33) {
+               if (kernvar(O_RDONLY, name, oldvalue, sizeof(oldvalue)))
+                       fprintf(stderr, "could not retrieve %s\n", name);
+               else {
+                       for (i = 0; i < KVARS; i++) {
+                               if (!strcmp(kv[i].name, name))
+                                       break;
+                               if (kv[i].name[0] == '\0') {
+                                       strncpy(kv[i].name, name,
+                                               sizeof(kv[i].name));
+                                       strncpy(kv[i].value, oldvalue,
+                                           sizeof(kv[i].value));
+                                       break;
+                               }
+                       }
+                       if (i == KVARS)
+                               fprintf(stderr, "could not backup %s (%s)\n",
+                                       name, oldvalue);
+               }
+       }
+       if (kernvar(O_WRONLY, name, value, strlen(value)))
+               fprintf(stderr, "could not set %s to %s\n", name, value);
+
+}
+
+static void restorekernvars(void)
+{
+       int i;
+
+       for (i = 0; i < KVARS; i++) {
+               if (kv[i].name[0] != '\0') {
+                       if (kernvar(O_WRONLY, kv[i].name, kv[i].value,
+                           strlen(kv[i].value)))
+                               fprintf(stderr, "could not restore %s to %s\n",
+                                       kv[i].name, kv[i].value);
+               }
+       }
+}
+
+static inline void tsnorm(struct timespec *ts)
+{
+       while (ts->tv_nsec >= NSEC_PER_SEC) {
+               ts->tv_nsec -= NSEC_PER_SEC;
+               ts->tv_sec++;
+       }
+}
+
+static inline int tsgreater(struct timespec *a, struct timespec *b)
+{
+       return ((a->tv_sec > b->tv_sec) ||
+               (a->tv_sec == b->tv_sec && a->tv_nsec > b->tv_nsec));
+}
+
+static inline int64_t calcdiff(struct timespec t1, struct timespec t2)
+{
+       int64_t diff;
+       diff = USEC_PER_SEC * (long long)((int) t1.tv_sec - (int) t2.tv_sec);
+       diff += ((int) t1.tv_nsec - (int) t2.tv_nsec) / 1000;
+       return diff;
+}
+
+static inline int64_t calcdiff_ns(struct timespec t1, struct timespec t2)
+{
+       int64_t diff;
+       diff = NSEC_PER_SEC * (int64_t)((int) t1.tv_sec - (int) t2.tv_sec);
+       diff += ((int) t1.tv_nsec - (int) t2.tv_nsec);
+       return diff;
+}
+
+void traceopt(char *option)
+{
+       char *ptr;
+       if (traceopt_count + 1 > traceopt_size) {
+               traceopt_size += 16;
+               printf("expanding traceopt buffer to %d entries\n", 
traceopt_size);
+               traceptr = realloc(traceptr, sizeof(char*) * traceopt_size);
+               if (traceptr == NULL)
+                       fatal ("Error allocating space for %d trace options\n",
+                              traceopt_count+1);
+       }
+       ptr = malloc(strlen(option)+1);
+       if (ptr == NULL)
+               fatal("error allocating space for trace option %s\n", option);
+       printf("adding traceopt %s\n", option);
+       strcpy(ptr, option);
+       traceptr[traceopt_count++] = ptr;
+}
+
+static int trace_file_exists(char *name)
+{
+       struct stat sbuf;
+       char *tracing_prefix = get_debugfileprefix();
+       char path[MAX_PATH];
+       strcat(strcpy(path, tracing_prefix), name);
+       return stat(path, &sbuf) ? 0 : 1;
+}
+
+#define TRACEBUFSIZ 1024
+static __thread char tracebuf[TRACEBUFSIZ];
+
+static void tracemark(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+static void tracemark(char *fmt, ...)
+{
+       va_list ap;
+       int len;
+
+       /* bail out if we're not tracing */
+       /* or if the kernel doesn't support trace_mark */
+       if (tracemark_fd < 0)
+               return;
+
+       va_start(ap, fmt);
+       len = vsnprintf(tracebuf, TRACEBUFSIZ, fmt, ap);
+       va_end(ap);
+       write(tracemark_fd, tracebuf, len);
+}
+
+
+
+void tracing(int on)
+{
+       if (on) {
+               switch (kernelversion) {
+               case KV_26_LT18: gettimeofday(0,(struct timezone *)1); break;
+               case KV_26_LT24: prctl(0, 1); break;
+               case KV_26_33:
+               case KV_30:
+                       write(trace_fd, "1", 1);
+                       break;
+               default:         break;
+               }
+       } else {
+               switch (kernelversion) {
+               case KV_26_LT18: gettimeofday(0,0); break;
+               case KV_26_LT24: prctl(0, 0); break;
+               case KV_26_33:
+               case KV_30:
+                       write(trace_fd, "0", 1);
+                       break;
+               default:        break;
+               }
+       }
+}
+
+static int settracer(char *tracer)
+{
+       if (valid_tracer(tracer)) {
+               setkernvar("current_tracer", tracer);
+               return 0;
+       }
+       return -1;
+}
+
+static void setup_tracer(void)
+{
+       if (!tracelimit || notrace)
+               return;
+
+       if (mount_debugfs(NULL))
+               fatal("could not mount debugfs");
+
+       if (kernelversion >= KV_26_33) {
+               char testname[MAX_PATH];
+
+               fileprefix = get_debugfileprefix();
+               if (!trace_file_exists("tracing_enabled") &&
+                   !trace_file_exists("tracing_on"))
+                       warn("tracing_enabled or tracing_on not found\n"
+                           "debug fs not mounted, "
+                           "TRACERs not configured?\n", testname);
+       } else
+               fileprefix = procfileprefix;
+
+       if (kernelversion >= KV_26_33) {
+               int ret;
+
+               if (trace_file_exists("tracing_enabled") &&
+                   !trace_file_exists("tracing_on"))
+                       setkernvar("tracing_enabled", "1");
+
+               /* ftrace_enabled is a sysctl variable */
+               /* turn it on if you're doing anything but nop or event tracing 
*/
+
+               fileprefix = procfileprefix;
+               if (tracetype)
+                       setkernvar("ftrace_enabled", "1");
+               else
+                       setkernvar("ftrace_enabled", "0");
+               fileprefix = get_debugfileprefix();
+
+               /*
+                * Set default tracer to nop.
+                * this also has the nice side effect of clearing out
+                * old traces.
+                */
+               ret = settracer("nop");
+
+               switch (tracetype) {
+               case NOTRACE:
+                       /* no tracer specified, use events */
+                       enable_events = 1;
+                       break;
+               case FUNCTION:
+                       ret = settracer("function");
+                       break;
+               case IRQSOFF:
+                       ret = settracer("irqsoff");
+                       break;
+               case PREEMPTOFF:
+                       ret = settracer("preemptoff");
+                       break;
+               case PREEMPTIRQSOFF:
+                       ret = settracer("preemptirqsoff");
+                       break;
+               case CTXTSWITCH:
+                       if (valid_tracer("sched_switch"))
+                           ret = settracer("sched_switch");
+                       else {
+                               if ((ret = event_enable("sched/sched_wakeup")))
+                                       break;
+                               ret = event_enable("sched/sched_switch");
+                       }
+                       break;
+               case WAKEUP:
+                       ret = settracer("wakeup");
+                       break;
+               case WAKEUPRT:
+                       ret = settracer("wakeup_rt");
+                       break;
+               default:
+                       if (strlen(tracer)) {
+                               ret = settracer(tracer);
+                               if (strcmp(tracer, "events") == 0 && ftrace)
+                                       ret = settracer(functiontracer);
+                       }
+                       else {
+                               printf("cyclictest: unknown tracer!\n");
+                               ret = 0;
+                       }
+                       break;
+               }
+
+               if (enable_events)
+                       /* turn on all events */
+                       event_enable_all();
+
+               if (ret)
+                       fprintf(stderr, "Requested tracer '%s' not 
available\n", tracer);
+
+               setkernvar(traceroptions, "print-parent");
+               setkernvar(traceroptions, "latency-format");
+               if (verbose) {
+                       setkernvar(traceroptions, "sym-offset");
+                       setkernvar(traceroptions, "sym-addr");
+                       setkernvar(traceroptions, "verbose");
+               } else {
+                       setkernvar(traceroptions, "nosym-offset");
+                       setkernvar(traceroptions, "nosym-addr");
+                       setkernvar(traceroptions, "noverbose");
+               }
+               if (traceopt_count) {
+                       int i;
+                       for (i = 0; i < traceopt_count; i++)
+                               setkernvar(traceroptions, traceptr[i]);
+               }
+               setkernvar("tracing_max_latency", "0");
+               if (trace_file_exists("latency_hist"))
+                       setkernvar("latency_hist/wakeup/reset", "1");
+
+               /* open the tracing on file descriptor */
+               if (trace_fd == -1) {
+                       char path[MAX_PATH];
+                       strcpy(path, fileprefix);
+                       if (trace_file_exists("tracing_on"))
+                               strcat(path, "tracing_on");
+                       else
+                               strcat(path, "tracing_enabled");
+                       if ((trace_fd = open(path, O_WRONLY)) == -1)
+                               fatal("unable to open %s for tracing", path);
+               }
+
+               /* open the tracemark file descriptor */
+               if (tracemark_fd == -1) {
+                       char path[MAX_PATH];
+                       strcat(strcpy(path, fileprefix), "trace_marker");
+                       if ((tracemark_fd = open(path, O_WRONLY)) == -1)
+                               warn("unable to open trace_marker file: %s\n", 
path);
+               }
+
+       } else {
+               setkernvar("trace_all_cpus", "1");
+               setkernvar("trace_freerunning", "1");
+               setkernvar("trace_print_on_crash", "0");
+               setkernvar("trace_user_triggered", "1");
+               setkernvar("trace_user_trigger_irq", "-1");
+               setkernvar("trace_verbose", "0");
+               setkernvar("preempt_thresh", "0");
+               setkernvar("wakeup_timing", "0");
+               setkernvar("preempt_max_latency", "0");
+               if (ftrace)
+                       setkernvar("mcount_enabled", "1");
+               setkernvar("trace_enabled", "1");
+               setkernvar("latency_hist/wakeup_latency/reset", "1");
+       }
+
+       tracing(1);
+}
+
+/*
+ * parse an input value as a base10 value followed by an optional
+ * suffix. The input value is presumed to be in seconds, unless
+ * followed by a modifier suffix: m=minutes, h=hours, d=days
+ *
+ * the return value is a value in seconds
+ */
+int parse_time_string(char *val)
+{
+       char *end;
+       int t = strtol(val, &end, 10);
+       if (end) {
+               switch (*end) {
+               case 'm':
+               case 'M':
+                       t *= 60;
+                       break;
+
+               case 'h':
+               case 'H':
+                       t *= 60*60;
+                       break;
+
+               case 'd':
+               case 'D':
+                       t *= 24*60*60;
+                       break;
+
+               }
+       }
+       return t;
+}
+
+/*
+ * Raise the soft priority limit up to prio, if that is less than or equal
+ * to the hard limit
+ * if a call fails, return the error
+ * if successful return 0
+ * if fails, return -1
+*/
+static int raise_soft_prio(int policy, const struct sched_param *param)
+{
+       int err;
+       int policy_max; /* max for scheduling policy such as SCHED_FIFO */
+       int soft_max;
+       int hard_max;
+       int prio;
+       struct rlimit rlim;
+
+       prio = param->sched_priority;
+
+       policy_max = sched_get_priority_max(policy);
+       if (policy_max == -1) {
+               err = errno;
+               err_msg("WARN: no such policy\n");
+               return err;
+       }
+
+       err = getrlimit(RLIMIT_RTPRIO, &rlim);
+       if (err) {
+               err = errno;
+               err_msg_n(err, "WARN: getrlimit failed");
+               return err;
+       }
+
+       soft_max = (rlim.rlim_cur == RLIM_INFINITY) ? policy_max : 
rlim.rlim_cur;
+       hard_max = (rlim.rlim_max == RLIM_INFINITY) ? policy_max : 
rlim.rlim_max;
+
+       if (prio > soft_max && prio <= hard_max) {
+               rlim.rlim_cur = prio;
+               err = setrlimit(RLIMIT_RTPRIO, &rlim);
+               if (err) {
+                       err = errno;
+                       err_msg_n(err, "WARN: setrlimit failed");
+                       /* return err; */
+               }
+       } else {
+               err = -1;
+       }
+
+       return err;
+}
+
+/*
+ * Check the error status of sched_setscheduler
+ * If an error can be corrected by raising the soft limit priority to
+ * a priority less than or equal to the hard limit, then do so.
+ */
+static int setscheduler(pid_t pid, int policy, const struct sched_param *param)
+{
+       int err = 0;
+
+try_again:
+       err = sched_setscheduler(pid, policy, param);
+       if (err) {
+               err = errno;
+               if (err == EPERM) {
+                       int err1;
+                       err1 = raise_soft_prio(policy, param);
+                       if (!err1) goto try_again;
+               }
+       }
+
+       return err;
+}
+
+/*
+ * timer thread
+ *
+ * Modes:
+ * - clock_nanosleep based
+ * - cyclic timer based
+ *
+ * Clock:
+ * - CLOCK_MONOTONIC
+ * - CLOCK_REALTIME
+ *
+ */
+void *timerthread(void *param)
+{
+       struct thread_param *par = param;
+       struct sched_param schedp;
+       struct sigevent sigev;
+       sigset_t sigset;
+       timer_t timer;
+       struct timespec now, next, interval, stop;
+       struct itimerval itimer;
+       struct itimerspec tspec;
+       struct thread_stat *stat = par->stats;
+       int stopped = 0;
+       cpu_set_t mask;
+       pthread_t thread;
+
+       /* if we're running in numa mode, set our memory node */
+       if (par->node != -1)
+               rt_numa_set_numa_run_on_node(par->node, par->cpu);
+
+       if (par->cpu != -1) {
+               CPU_ZERO(&mask);
+               CPU_SET(par->cpu, &mask);
+               thread = pthread_self();
+               if(pthread_setaffinity_np(thread, sizeof(mask), &mask) == -1)
+                       warn("Could not set CPU affinity to CPU #%d\n", 
par->cpu);
+       }
+
+       interval.tv_sec = par->interval / USEC_PER_SEC;
+       interval.tv_nsec = (par->interval % USEC_PER_SEC) * 1000;
+
+       stat->tid = gettid();
+
+       sigemptyset(&sigset);
+       sigaddset(&sigset, par->signal);
+       sigprocmask(SIG_BLOCK, &sigset, NULL);
+
+       if (par->mode == MODE_CYCLIC) {
+               sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
+               sigev.sigev_signo = par->signal;
+               sigev.sigev_notify_thread_id = stat->tid;
+               timer_create(par->clock, &sigev, &timer);
+               tspec.it_interval = interval;
+       }
+
+       memset(&schedp, 0, sizeof(schedp));
+       schedp.sched_priority = par->prio;
+       if (pthread_setschedparam(pthread_self(), par->policy, &schedp))
+               fatal("timerthread%d: failed to set priority to %d\n", 
par->cpu, par->prio);
+
+       /* Get current time */
+       if (aligned || secaligned) {
+               pthread_barrier_wait(&globalt_barr);
+               if (par->tnum == 0) {
+                       clock_gettime(par->clock, &globalt);
+                       if (secaligned) {
+                               /* Ensure that the thread start timestamp is not
+                                  in the past */
+                               if (globalt.tv_nsec > 900000000)
+                                       globalt.tv_sec += 2;
+                               else
+                                       globalt.tv_sec++;
+                               globalt.tv_nsec = 0;
+                       }
+               }
+               pthread_barrier_wait(&align_barr);
+               now = globalt;
+               if(offset) {
+                       if (aligned)
+                               now.tv_nsec += offset * par->tnum;
+                       else
+                               now.tv_nsec += offset;
+                       tsnorm(&now);
+               }
+       }
+       else
+               clock_gettime(par->clock, &now);
+
+       next = now;
+       next.tv_sec += interval.tv_sec;
+       next.tv_nsec += interval.tv_nsec;
+       tsnorm(&next);
+
+       if (duration) {
+               memset(&stop, 0, sizeof(stop)); /* grrr */
+               stop = now;
+               stop.tv_sec += duration;
+       }
+       if (par->mode == MODE_CYCLIC) {
+               if (par->timermode == TIMER_ABSTIME)
+                       tspec.it_value = next;
+               else {
+                       tspec.it_value = interval;
+               }
+               timer_settime(timer, par->timermode, &tspec, NULL);
+       }
+
+       if (par->mode == MODE_SYS_ITIMER) {
+               itimer.it_interval.tv_sec = interval.tv_sec;
+               itimer.it_interval.tv_usec = interval.tv_nsec / 1000;
+               itimer.it_value = itimer.it_interval;
+               setitimer (ITIMER_REAL, &itimer, NULL);
+       }
+
+       stat->threadstarted++;
+
+       while (!shutdown) {
+
+               uint64_t diff;
+               int sigs, ret;
+
+               /* Wait for next period */
+               switch (par->mode) {
+               case MODE_CYCLIC:
+               case MODE_SYS_ITIMER:
+                       if (sigwait(&sigset, &sigs) < 0)
+                               goto out;
+                       break;
+
+               case MODE_CLOCK_NANOSLEEP:
+                       if (par->timermode == TIMER_ABSTIME) {
+                               if ((ret = clock_nanosleep(par->clock, 
TIMER_ABSTIME, &next, NULL))) {
+                                       if (ret != EINTR)
+                                               warn("clock_nanosleep failed. 
errno: %d\n", errno);
+                                       goto out;
+                               }
+                       } else {
+                               if ((ret = clock_gettime(par->clock, &now))) {
+                                       if (ret != EINTR)
+                                               warn("clock_gettime() failed: 
%s", strerror(errno));
+                                       goto out;
+                               }
+                               if ((ret = clock_nanosleep(par->clock, 
TIMER_RELTIME, &interval, NULL))) {
+                                       if (ret != EINTR)
+                                               warn("clock_nanosleep() failed. 
errno: %d\n", errno);
+                                       goto out;
+                               }
+                               next.tv_sec = now.tv_sec + interval.tv_sec;
+                               next.tv_nsec = now.tv_nsec + interval.tv_nsec;
+                               tsnorm(&next);
+                       }
+                       break;
+
+               case MODE_SYS_NANOSLEEP:
+                       if ((ret = clock_gettime(par->clock, &now))) {
+                               if (ret != EINTR)
+                                       warn("clock_gettime() failed: errno 
%d\n", errno);
+                               goto out;
+                       }
+                       if (nanosleep(&interval, NULL)) {
+                               if (errno != EINTR)
+                                       warn("nanosleep failed. errno: %d\n", 
errno);
+                               goto out;
+                       }
+                       next.tv_sec = now.tv_sec + interval.tv_sec;
+                       next.tv_nsec = now.tv_nsec + interval.tv_nsec;
+                       tsnorm(&next);
+                       break;
+               }
+
+               if ((ret = clock_gettime(par->clock, &now))) {
+                       if (ret != EINTR)
+                               warn("clock_getttime() failed. errno: %d\n", 
errno);
+                       goto out;
+               }
+
+               if (use_nsecs)
+                       diff = calcdiff_ns(now, next);
+               else
+                       diff = calcdiff(now, next);
+               if (diff < stat->min)
+                       stat->min = diff;
+               if (diff > stat->max) {
+                       stat->max = diff;
+                       if (refresh_on_max)
+                               pthread_cond_signal(&refresh_on_max_cond);
+               }
+               stat->avg += (double) diff;
+
+               if (duration && (calcdiff(now, stop) >= 0))
+                       shutdown++;
+
+               if (!stopped && tracelimit && (diff > tracelimit)) {
+                       stopped++;
+                       tracemark("hit latency threshold (%llu > %d)",
+                                 (unsigned long long) diff, tracelimit);
+                       tracing(0);
+                       shutdown++;
+                       pthread_mutex_lock(&break_thread_id_lock);
+                       if (break_thread_id == 0)
+                               break_thread_id = stat->tid;
+                       break_thread_value = diff;
+                       pthread_mutex_unlock(&break_thread_id_lock);
+               }
+               stat->act = diff;
+
+               if (par->bufmsk)
+                       stat->values[stat->cycles & par->bufmsk] = diff;
+
+               /* Update the histogram */
+               if (histogram) {
+                       if (diff >= histogram) {
+                               stat->hist_overflow++;
+                               if (stat->num_outliers < histogram)
+                                       stat->outliers[stat->num_outliers++] = 
stat->cycles;
+                       }
+                       else
+                               stat->hist_array[diff]++;
+               }
+
+               stat->cycles++;
+
+               next.tv_sec += interval.tv_sec;
+               next.tv_nsec += interval.tv_nsec;
+               if (par->mode == MODE_CYCLIC) {
+                       int overrun_count = timer_getoverrun(timer);
+                       next.tv_sec += overrun_count * interval.tv_sec;
+                       next.tv_nsec += overrun_count * interval.tv_nsec;
+               }
+               tsnorm(&next);
+
+               while (tsgreater(&now, &next)) {
+                       next.tv_sec += interval.tv_sec;
+                       next.tv_nsec += interval.tv_nsec;
+                       tsnorm(&next);
+               }
+
+               if (par->max_cycles && par->max_cycles == stat->cycles)
+                       break;
+       }
+
+out:
+       if (par->mode == MODE_CYCLIC)
+               timer_delete(timer);
+
+       if (par->mode == MODE_SYS_ITIMER) {
+               itimer.it_value.tv_sec = 0;
+               itimer.it_value.tv_usec = 0;
+               itimer.it_interval.tv_sec = 0;
+               itimer.it_interval.tv_usec = 0;
+               setitimer (ITIMER_REAL, &itimer, NULL);
+       }
+
+       /* switch to normal */
+       schedp.sched_priority = 0;
+       sched_setscheduler(0, SCHED_OTHER, &schedp);
+
+       stat->threadstarted = -1;
+
+       return NULL;
+}
+
+
+/* Print usage information */
+static void display_help(int error)
+{
+       char tracers[MAX_PATH];
+       char *prefix;
+
+       prefix = get_debugfileprefix();
+       if (prefix[0] == '\0')
+               strcpy(tracers, "unavailable (debugfs not mounted)");
+       else {
+               fileprefix = prefix;
+               if (kernvar(O_RDONLY, "available_tracers", tracers, 
sizeof(tracers)))
+                       strcpy(tracers, "none");
+       }
+
+       printf("cyclictest V %1.2f\n", VERSION_STRING);
+       printf("Usage:\n"
+              "cyclictest <options>\n\n"
+#if LIBNUMA_API_VERSION >= 2
+              "-a [CPUSET] --affinity     Run thread #N on processor #N, if 
possible, or if CPUSET\n"
+              "                           given, pin threads to that set of 
processors in round-\n"
+              "                           robin order.  E.g. -a 2 pins all 
threads to CPU 2,\n"
+              "                           but -a 3-5,0 -t 5 will run the first 
and fifth\n"
+              "                           threads on CPU (0),thread #2 on CPU 
3, thread #3\n"
+              "                           on CPU 4, and thread #5 on CPU 5.\n"
+#else
+              "-a [NUM] --affinity        run thread #N on processor #N, if 
possible\n"
+              "                           with NUM pin all threads to the 
processor NUM\n"
+#endif
+              "-A USEC  --aligned=USEC    align thread wakeups to a specific 
offset\n"
+              "-b USEC  --breaktrace=USEC send break trace command when 
latency > USEC\n"
+              "-B       --preemptirqs     both preempt and irqsoff tracing 
(used with -b)\n"
+              "-c CLOCK --clock=CLOCK     select clock\n"
+              "                           0 = CLOCK_MONOTONIC (default)\n"
+              "                           1 = CLOCK_REALTIME\n"
+              "-C       --context         context switch tracing (used with 
-b)\n"
+              "-d DIST  --distance=DIST   distance of thread intervals in us 
default=500\n"
+              "-D       --duration=t      specify a length for the test run\n"
+              "                           default is in seconds, but 'm', 'h', 
or 'd' maybe added\n"
+              "                           to modify value to minutes, hours or 
days\n"
+              "         --latency=PM_QOS  write PM_QOS to 
/dev/cpu_dma_latency\n"
+              "-E       --event           event tracing (used with -b)\n"
+              "-f       --ftrace          function trace (when -b is active)\n"
+              "-F       --fifo=<path>     create a named pipe at path and 
write stats to it\n"
+              "-h       --histogram=US    dump a latency histogram to stdout 
after the run\n"
+              "                           (with same priority about many 
threads)\n"
+              "                           US is the max time to be be tracked 
in microseconds\n"
+              "-H       --histofall=US    same as -h except with an additional 
summary column\n"
+              "-i INTV  --interval=INTV   base interval of thread in us 
default=1000\n"
+              "-I       --irqsoff         Irqsoff tracing (used with -b)\n"
+              "-l LOOPS --loops=LOOPS     number of loops: 
default=0(endless)\n"
+              "         --laptop          Save battery when running 
cyclictest\n"
+              "                           This will give you poorer realtime 
results\n"
+              "                           but will not drain your battery so 
quickly\n"
+              "-m       --mlockall        lock current and future memory 
allocations\n"
+              "-M       --refresh_on_max  delay updating the screen until a 
new max latency is hit\n"
+              "-n       --nanosleep       use clock_nanosleep\n"
+              "         --notrace         suppress tracing\n"
+              "-N       --nsecs           print results in ns instead of us 
(default us)\n"
+              "-o RED   --oscope=RED      oscilloscope mode, reduce verbose 
output by RED\n"
+              "-O TOPT  --traceopt=TOPT   trace option\n"
+              "-p PRIO  --prio=PRIO       priority of highest prio thread\n"
+              "-P       --preemptoff      Preempt off tracing (used with -b)\n"
+              "-q       --quiet           print only a summary on exit\n"
+              "         --priospread       spread priority levels starting at 
specified value\n"
+              "-r       --relative        use relative timer instead of 
absolute\n"
+              "-R       --resolution      check clock resolution, calling 
clock_gettime() many\n"
+              "                           times.  list of clock_gettime() 
values will be\n"
+              "                           reported with -X\n"
+              "         --secaligned [USEC] align thread wakeups to the next 
full second,\n"
+              "                           and apply the optional offset\n"
+              "-s       --system          use sys_nanosleep and 
sys_setitimer\n"
+              "-S       --smp             Standard SMP testing: options -a -t 
-n and\n"
+              "                           same priority of all threads\n"
+              "-t       --threads         one thread per available processor\n"
+              "-t [NUM] --threads=NUM     number of threads:\n"
+              "                           without NUM, threads = max_cpus\n"
+              "                           without -t default = 1\n"
+              "-T TRACE --tracer=TRACER   set tracing function\n"
+              "    configured tracers: %s\n"
+              "-u       --unbuffered      force unbuffered output for live 
processing\n"
+#ifdef NUMA
+              "-U       --numa            Standard NUMA testing (similar to 
SMP option)\n"
+              "                           thread data structures allocated 
from local node\n"
+#endif
+              "-v       --verbose         output values on stdout for 
statistics\n"
+              "                           format: n:c:v n=tasknum c=count 
v=value in us\n"
+              "-w       --wakeup          task wakeup tracing (used with -b)\n"
+              "-W       --wakeuprt        rt task wakeup tracing (used with 
-b)\n"
+              "         --dbg_cyclictest  print info useful for debugging 
cyclictest\n"
+              "         --policy=POLI     policy of realtime thread, POLI may 
be fifo(default) or rr\n"
+              "                           format: --policy=fifo(default) or 
--policy=rr\n",
+              tracers
+               );
+       if (error)
+               exit(EXIT_FAILURE);
+       exit(EXIT_SUCCESS);
+}
+
+static int use_nanosleep;
+static int timermode = TIMER_ABSTIME;
+static int use_system;
+static int priority;
+static int policy = SCHED_OTHER;       /* default policy if not specified */
+static int num_threads = 1;
+static int max_cycles;
+static int clocksel = 0;
+static int quiet;
+static int interval = DEFAULT_INTERVAL;
+static int distance = -1;
+static struct bitmask *affinity_mask = NULL;
+static int smp = 0;
+
+enum {
+       AFFINITY_UNSPECIFIED,
+       AFFINITY_SPECIFIED,
+       AFFINITY_USEALL
+};
+static int setaffinity = AFFINITY_UNSPECIFIED;
+
+static int clocksources[] = {
+       CLOCK_MONOTONIC,
+       CLOCK_REALTIME,
+};
+
+static unsigned int is_cpumask_zero(const struct bitmask *mask)
+{
+       return (rt_numa_bitmask_count(mask) == 0);
+}
+
+static int cpu_for_thread(int thread_num, int max_cpus)
+{
+       unsigned int m, cpu, i, num_cpus;
+       num_cpus = rt_numa_bitmask_count(affinity_mask);
+
+       m = thread_num % num_cpus;
+
+       /* there are num_cpus bits set, we want position of m'th one */
+       for (i = 0, cpu = 0; i < max_cpus; i++) {
+               if (rt_numa_bitmask_isbitset(affinity_mask, i)) {
+                       if (cpu == m)
+                               return i;
+                       cpu++;
+               }
+       }
+       fprintf(stderr, "Bug in cpu mask handling code.\n");
+       return 0;
+}
+
+
+static void parse_cpumask(const char *option, const int max_cpus)
+{
+       affinity_mask = rt_numa_parse_cpustring(option, max_cpus);
+       if (affinity_mask) {
+               if (is_cpumask_zero(affinity_mask)) {
+                       rt_bitmask_free(affinity_mask);
+                       affinity_mask = NULL;
+               }
+       }
+       if (!affinity_mask)
+               display_help(1);
+
+       if (verbose) {
+               printf("%s: Using %u cpus.\n", __func__,
+                       rt_numa_bitmask_count(affinity_mask));
+       }
+}
+
+
+static void handlepolicy(char *polname)
+{
+       if (strncasecmp(polname, "other", 5) == 0)
+               policy = SCHED_OTHER;
+       else if (strncasecmp(polname, "batch", 5) == 0)
+               policy = SCHED_BATCH;
+       else if (strncasecmp(polname, "idle", 4) == 0)
+               policy = SCHED_IDLE;
+       else if (strncasecmp(polname, "fifo", 4) == 0)
+               policy = SCHED_FIFO;
+       else if (strncasecmp(polname, "rr", 2) == 0)
+               policy = SCHED_RR;
+       else    /* default policy if we don't recognize the request */
+               policy = SCHED_OTHER;
+}
+
+static char *policyname(int policy)
+{
+       char *policystr = "";
+
+       switch(policy) {
+       case SCHED_OTHER:
+               policystr = "other";
+               break;
+       case SCHED_FIFO:
+               policystr = "fifo";
+               break;
+       case SCHED_RR:
+               policystr = "rr";
+               break;
+       case SCHED_BATCH:
+               policystr = "batch";
+               break;
+       case SCHED_IDLE:
+               policystr = "idle";
+               break;
+       }
+       return policystr;
+}
+
+
+enum option_values {
+       OPT_AFFINITY=1, OPT_NOTRACE, OPT_BREAKTRACE, OPT_PREEMPTIRQ, OPT_CLOCK,
+       OPT_CONTEXT, OPT_DISTANCE, OPT_DURATION, OPT_LATENCY, OPT_EVENT,
+       OPT_FTRACE, OPT_FIFO, OPT_HISTOGRAM, OPT_HISTOFALL, OPT_INTERVAL,
+       OPT_IRQSOFF, OPT_LOOPS, OPT_MLOCKALL, OPT_REFRESH, OPT_NANOSLEEP,
+       OPT_NSECS, OPT_OSCOPE, OPT_TRACEOPT, OPT_PRIORITY, OPT_PREEMPTOFF,
+       OPT_QUIET, OPT_PRIOSPREAD, OPT_RELATIVE, OPT_RESOLUTION, OPT_SYSTEM,
+       OPT_SMP, OPT_THREADS, OPT_TRACER, OPT_UNBUFFERED, OPT_NUMA, OPT_VERBOSE,
+       OPT_WAKEUP, OPT_WAKEUPRT, OPT_DBGCYCLIC, OPT_POLICY, OPT_HELP, 
OPT_NUMOPTS,
+       OPT_ALIGNED, OPT_LAPTOP, OPT_SECALIGNED,
+};
+
+/* Process commandline options */
+static void process_options (int argc, char *argv[], int max_cpus)
+{
+       int error = 0;
+       int option_affinity = 0;
+
+       for (;;) {
+               int option_index = 0;
+               /*
+                * Options for getopt
+                * Ordered alphabetically by single letter name
+                */
+               static struct option long_options[] = {
+                       {"affinity",         optional_argument, NULL, 
OPT_AFFINITY},
+                       {"notrace",          no_argument,       NULL, 
OPT_NOTRACE },
+                       {"aligned",          optional_argument, NULL, 
OPT_ALIGNED },
+                       {"breaktrace",       required_argument, NULL, 
OPT_BREAKTRACE },
+                       {"preemptirqs",      no_argument,       NULL, 
OPT_PREEMPTIRQ },
+                       {"clock",            required_argument, NULL, OPT_CLOCK 
},
+                       {"context",          no_argument,       NULL, 
OPT_CONTEXT },
+                       {"distance",         required_argument, NULL, 
OPT_DISTANCE },
+                       {"duration",         required_argument, NULL, 
OPT_DURATION },
+                       {"latency",          required_argument, NULL, 
OPT_LATENCY },
+                       {"event",            no_argument,       NULL, OPT_EVENT 
},
+                       {"ftrace",           no_argument,       NULL, 
OPT_FTRACE },
+                       {"fifo",             required_argument, NULL, OPT_FIFO 
},
+                       {"histogram",        required_argument, NULL, 
OPT_HISTOGRAM },
+                       {"histofall",        required_argument, NULL, 
OPT_HISTOFALL },
+                       {"interval",         required_argument, NULL, 
OPT_INTERVAL },
+                       {"irqsoff",          no_argument,       NULL, 
OPT_IRQSOFF },
+                       {"laptop",           no_argument,       NULL, 
OPT_LAPTOP },
+                       {"loops",            required_argument, NULL, OPT_LOOPS 
},
+                       {"mlockall",         no_argument,       NULL, 
OPT_MLOCKALL },
+                       {"refresh_on_max",   no_argument,       NULL, 
OPT_REFRESH },
+                       {"nanosleep",        no_argument,       NULL, 
OPT_NANOSLEEP },
+                       {"nsecs",            no_argument,       NULL, OPT_NSECS 
},
+                       {"oscope",           required_argument, NULL, 
OPT_OSCOPE },
+                       {"traceopt",         required_argument, NULL, 
OPT_TRACEOPT },
+                       {"priority",         required_argument, NULL, 
OPT_PRIORITY },
+                       {"preemptoff",       no_argument,       NULL, 
OPT_PREEMPTOFF },
+                       {"quiet",            no_argument,       NULL, OPT_QUIET 
},
+                       {"priospread",       no_argument,       NULL, 
OPT_PRIOSPREAD },
+                       {"relative",         no_argument,       NULL, 
OPT_RELATIVE },
+                       {"resolution",       no_argument,       NULL, 
OPT_RESOLUTION },
+                       {"secaligned",       optional_argument, NULL, 
OPT_SECALIGNED },
+                       {"system",           no_argument,       NULL, 
OPT_SYSTEM },
+                       {"smp",              no_argument,       NULL, OPT_SMP },
+                       {"threads",          optional_argument, NULL, 
OPT_THREADS },
+                       {"tracer",           required_argument, NULL, 
OPT_TRACER },
+                       {"unbuffered",       no_argument,       NULL, 
OPT_UNBUFFERED },
+                       {"numa",             no_argument,       NULL, OPT_NUMA 
},
+                       {"verbose",          no_argument,       NULL, 
OPT_VERBOSE },
+                       {"wakeup",           no_argument,       NULL, 
OPT_WAKEUP },
+                       {"wakeuprt",         no_argument,       NULL, 
OPT_WAKEUPRT },
+                       {"dbg_cyclictest",   no_argument,       NULL, 
OPT_DBGCYCLIC },
+                       {"policy",           required_argument, NULL, 
OPT_POLICY },
+                       {"help",             no_argument,       NULL, OPT_HELP 
},
+                       {NULL, 0, NULL, 0}
+               };
+               int c = getopt_long(argc, argv, 
"a::A::b:Bc:Cd:D:Efh:H:i:Il:MnNo:O:p:PmqrRsSt::uUvD:wWT:",
+                                   long_options, &option_index);
+               if (c == -1)
+                       break;
+               switch (c) {
+               case 'a':
+               case OPT_AFFINITY:
+                       option_affinity = 1;
+                       if (smp || numa)
+                               break;
+                       if (optarg != NULL) {
+                               parse_cpumask(optarg, max_cpus);
+                               setaffinity = AFFINITY_SPECIFIED;
+                       } else if (optind<argc && atoi(argv[optind])) {
+                               parse_cpumask(argv[optind], max_cpus);
+                               setaffinity = AFFINITY_SPECIFIED;
+                       } else {
+                               setaffinity = AFFINITY_USEALL;
+                       }
+                       break;
+               case 'A':
+               case OPT_ALIGNED:
+                       aligned=1;
+                       if (optarg != NULL)
+                               offset = atoi(optarg) * 1000;
+                       else if (optind<argc && atoi(argv[optind]))
+                               offset = atoi(argv[optind]) * 1000;
+                       else
+                               offset = 0;
+                       break;
+               case 'b':
+               case OPT_BREAKTRACE:
+                       tracelimit = atoi(optarg); break;
+               case 'B':
+               case OPT_PREEMPTIRQ:
+                       tracetype = PREEMPTIRQSOFF; break;
+               case 'c':
+               case OPT_CLOCK:
+                       clocksel = atoi(optarg); break;
+               case 'C':
+               case OPT_CONTEXT:
+                       tracetype = CTXTSWITCH; break;
+               case 'd':
+               case OPT_DISTANCE:
+                       distance = atoi(optarg); break;
+               case 'D':
+               case OPT_DURATION:
+                       duration = parse_time_string(optarg); break;
+               case 'E':
+               case OPT_EVENT:
+                       enable_events = 1; break;
+               case 'f':
+               case OPT_FTRACE:
+                       tracetype = FUNCTION; ftrace = 1; break;
+               case 'F':
+               case OPT_FIFO:
+                       use_fifo = 1;
+                       strncpy(fifopath, optarg, strlen(optarg));
+                       break;
+
+               case 'H':
+               case OPT_HISTOFALL:
+                       histofall = 1; /* fall through */
+               case 'h':
+               case OPT_HISTOGRAM:
+                       histogram = atoi(optarg); break;
+               case 'i':
+               case OPT_INTERVAL:
+                       interval = atoi(optarg); break;
+               case 'I':
+               case OPT_IRQSOFF:
+                       if (tracetype == PREEMPTOFF) {
+                               tracetype = PREEMPTIRQSOFF;
+                               strncpy(tracer, "preemptirqsoff", 
sizeof(tracer));
+                       } else {
+                               tracetype = IRQSOFF;
+                               strncpy(tracer, "irqsoff", sizeof(tracer));
+                       }
+                       break;
+               case 'l':
+               case OPT_LOOPS:
+                       max_cycles = atoi(optarg); break;
+               case 'm':
+               case OPT_MLOCKALL:
+                       lockall = 1; break;
+               case 'M':
+               case OPT_REFRESH:
+                       refresh_on_max = 1; break;
+               case 'n':
+               case OPT_NANOSLEEP:
+                       use_nanosleep = MODE_CLOCK_NANOSLEEP; break;
+               case 'N':
+               case OPT_NSECS:
+                       use_nsecs = 1; break;
+               case 'o':
+               case OPT_OSCOPE:
+                       oscope_reduction = atoi(optarg); break;
+               case 'O':
+               case OPT_TRACEOPT:
+                       traceopt(optarg); break;
+               case 'p':
+               case OPT_PRIORITY:
+                       priority = atoi(optarg);
+                       if (policy != SCHED_FIFO && policy != SCHED_RR)
+                               policy = SCHED_FIFO;
+                       break;
+               case 'P':
+               case OPT_PREEMPTOFF:
+                       if (tracetype == IRQSOFF) {
+                               tracetype = PREEMPTIRQSOFF;
+                               strncpy(tracer, "preemptirqsoff", 
sizeof(tracer));
+                       } else {
+                               tracetype = PREEMPTOFF;
+                               strncpy(tracer, "preemptoff", sizeof(tracer));
+                       }
+                       break;
+               case 'q':
+               case OPT_QUIET:
+                       quiet = 1; break;
+               case 'r':
+               case OPT_RELATIVE:
+                       timermode = TIMER_RELTIME; break;
+               case 'R':
+               case OPT_RESOLUTION:
+                       check_clock_resolution = 1; break;
+               case 's':
+               case OPT_SECALIGNED:
+                       secaligned = 1;
+                       if (optarg != NULL)
+                               offset = atoi(optarg) * 1000;
+                       else if (optind < argc && atoi(argv[optind]))
+                               offset = atoi(argv[optind]) * 1000;
+                       else
+                               offset = 0;
+                       break;
+               case OPT_SYSTEM:
+                       use_system = MODE_SYS_OFFSET; break;
+               case 'S':
+               case OPT_SMP: /* SMP testing */
+                       if (numa)
+                               fatal("numa and smp options are mutually 
exclusive\n");
+                       smp = 1;
+                       num_threads = max_cpus;
+                       setaffinity = AFFINITY_USEALL;
+                       use_nanosleep = MODE_CLOCK_NANOSLEEP;
+                       break;
+               case 't':
+               case OPT_THREADS:
+                       if (smp) {
+                               warn("-t ignored due to --smp\n");
+                               break;
+                       }
+                       if (optarg != NULL)
+                               num_threads = atoi(optarg);
+                       else if (optind<argc && atoi(argv[optind]))
+                               num_threads = atoi(argv[optind]);
+                       else
+                               num_threads = max_cpus;
+                       break;
+               case 'T':
+               case OPT_TRACER:
+                       tracetype = CUSTOM;
+                       strncpy(tracer, optarg, sizeof(tracer));
+                       break;
+               case 'u':
+               case OPT_UNBUFFERED:
+                       setvbuf(stdout, NULL, _IONBF, 0); break;
+               case 'U':
+               case OPT_NUMA: /* NUMA testing */
+                       if (smp)
+                               fatal("numa and smp options are mutually 
exclusive\n");
+#ifdef NUMA
+                       if (numa_available() == -1)
+                               fatal("NUMA functionality not available!");
+                       numa = 1;
+                       num_threads = max_cpus;
+                       setaffinity = AFFINITY_USEALL;
+                       use_nanosleep = MODE_CLOCK_NANOSLEEP;
+#else
+                       warn("cyclictest was not built with the numa option\n");
+                       warn("ignoring --numa or -U\n");
+#endif
+                       break;
+               case 'v':
+               case OPT_VERBOSE: verbose = 1; break;
+               case 'w':
+               case OPT_WAKEUP:
+                       tracetype = WAKEUP; break;
+               case 'W':
+               case OPT_WAKEUPRT:
+                       tracetype = WAKEUPRT; break;
+               case '?':
+               case OPT_HELP:
+                       display_help(0); break;
+
+               /* long only options */
+               case OPT_PRIOSPREAD:
+                       priospread = 1; break;
+               case OPT_LATENCY:
+                          /* power management latency target value */
+                         /* note: default is 0 (zero) */
+                       latency_target_value = atoi(optarg);
+                       if (latency_target_value < 0)
+                               latency_target_value = 0;
+                       break;
+               case OPT_NOTRACE:
+                       notrace = 1; break;
+               case OPT_POLICY:
+                       handlepolicy(optarg); break;
+               case OPT_DBGCYCLIC:
+                       ct_debug = 1; break;
+               case OPT_LAPTOP:
+                       laptop = 1; break;
+               }
+       }
+
+       if (option_affinity) {
+               if (smp) {
+                       warn("-a ignored due to --smp\n");
+               } else if (numa) {
+                       warn("-a ignored due to --numa\n");
+               }
+       }
+
+       if (tracelimit)
+               fileprefix = procfileprefix;
+
+       if (clocksel < 0 || clocksel > ARRAY_SIZE(clocksources))
+               error = 1;
+
+       if (oscope_reduction < 1)
+               error = 1;
+
+       if (oscope_reduction > 1 && !verbose) {
+               warn("-o option only meaningful, if verbose\n");
+               error = 1;
+       }
+
+       if (histogram < 0)
+               error = 1;
+
+       if (histogram > HIST_MAX)
+               histogram = HIST_MAX;
+
+       if (histogram && distance != -1)
+               warn("distance is ignored and set to 0, if histogram 
enabled\n");
+       if (distance == -1)
+               distance = DEFAULT_DISTANCE;
+
+       if (priority < 0 || priority > 99)
+               error = 1;
+
+       if (priospread && priority == 0) {
+               fprintf(stderr, "defaulting realtime priority to %d\n",
+                       num_threads+1);
+               priority = num_threads+1;
+       }
+
+       if (priority && (policy != SCHED_FIFO && policy != SCHED_RR)) {
+               fprintf(stderr, "policy and priority don't match: setting 
policy to SCHED_FIFO\n");
+               policy = SCHED_FIFO;
+       }
+
+       if ((policy == SCHED_FIFO || policy == SCHED_RR) && priority == 0) {
+               fprintf(stderr, "defaulting realtime priority to %d\n",
+                       num_threads+1);
+               priority = num_threads+1;
+       }
+
+       if (num_threads < 1)
+               error = 1;
+
+       if (aligned && secaligned)
+               error = 1;
+
+       if (aligned || secaligned) {
+               pthread_barrier_init(&globalt_barr, NULL, num_threads);
+               pthread_barrier_init(&align_barr, NULL, num_threads);
+       }
+
+       if (error) {
+               if (affinity_mask)
+                       rt_bitmask_free(affinity_mask);
+               display_help(1);
+       }
+}
+
+static int check_kernel(void)
+{
+       struct utsname kname;
+       int maj, min, sub, kv, ret;
+
+       ret = uname(&kname);
+       if (ret) {
+               fprintf(stderr, "uname failed: %s. Assuming not 2.6\n",
+                               strerror(errno));
+               return KV_NOT_SUPPORTED;
+       }
+       sscanf(kname.release, "%d.%d.%d", &maj, &min, &sub);
+       if (maj == 2 && min == 6) {
+               if (sub < 18)
+                       kv = KV_26_LT18;
+               else if (sub < 24)
+                       kv = KV_26_LT24;
+               else if (sub < 28) {
+                       kv = KV_26_33;
+                       strcpy(functiontracer, "ftrace");
+                       strcpy(traceroptions, "iter_ctrl");
+               } else {
+                       kv = KV_26_33;
+                       strcpy(functiontracer, "function");
+                       strcpy(traceroptions, "trace_options");
+               }
+       } else if (maj >= 3) {
+               kv = KV_30;
+               strcpy(functiontracer, "function");
+               strcpy(traceroptions, "trace_options");
+
+       } else
+               kv = KV_NOT_SUPPORTED;
+
+       return kv;
+}
+
+static int check_timer(void)
+{
+       struct timespec ts;
+
+       if (clock_getres(CLOCK_MONOTONIC, &ts))
+               return 1;
+
+       return (ts.tv_sec != 0 || ts.tv_nsec != 1);
+}
+
+static void sighand(int sig)
+{
+       if (sig == SIGUSR1) {
+               int i;
+               int oldquiet = quiet;
+
+               quiet = 0;
+               fprintf(stderr, "#---------------------------\n");
+               fprintf(stderr, "# cyclictest current status:\n");
+               for (i = 0; i < num_threads; i++)
+                       print_stat(stderr, parameters[i], i, 0, 0);
+               fprintf(stderr, "#---------------------------\n");
+               quiet = oldquiet;
+               return;
+       }
+       shutdown = 1;
+       if (refresh_on_max)
+               pthread_cond_signal(&refresh_on_max_cond);
+       if (tracelimit && !notrace)
+               tracing(0);
+}
+
+static void print_tids(struct thread_param *par[], int nthreads)
+{
+       int i;
+
+       printf("# Thread Ids:");
+       for (i = 0; i < nthreads; i++)
+               printf(" %05d", par[i]->stats->tid);
+       printf("\n");
+}
+
+static void print_hist(struct thread_param *par[], int nthreads)
+{
+       int i, j;
+       unsigned long long int log_entries[nthreads+1];
+       unsigned long maxmax, alloverflows;
+
+       bzero(log_entries, sizeof(log_entries));
+
+       printf("# Histogram\n");
+       for (i = 0; i < histogram; i++) {
+               unsigned long long int allthreads = 0;
+
+               printf("%06d ", i);
+
+               for (j = 0; j < nthreads; j++) {
+                       unsigned long curr_latency=par[j]->stats->hist_array[i];
+                       printf("%06lu", curr_latency);
+                       if (j < nthreads - 1)
+                               printf("\t");
+                       log_entries[j] += curr_latency;
+                       allthreads += curr_latency;
+               }
+               if (histofall && nthreads > 1) {
+                       printf("\t%06llu", allthreads);
+                       log_entries[nthreads] += allthreads;
+               }
+               printf("\n");
+       }
+       printf("# Total:");
+       for (j = 0; j < nthreads; j++)
+               printf(" %09llu", log_entries[j]);
+       if (histofall && nthreads > 1)
+               printf(" %09llu", log_entries[nthreads]);
+       printf("\n");
+       printf("# Min Latencies:");
+       for (j = 0; j < nthreads; j++)
+               printf(" %05lu", par[j]->stats->min);
+       printf("\n");
+       printf("# Avg Latencies:");
+       for (j = 0; j < nthreads; j++)
+               printf(" %05lu", par[j]->stats->cycles ?
+                      (long)(par[j]->stats->avg/par[j]->stats->cycles) : 0);
+       printf("\n");
+       printf("# Max Latencies:");
+       maxmax = 0;
+       for (j = 0; j < nthreads; j++) {
+               printf(" %05lu", par[j]->stats->max);
+               if (par[j]->stats->max > maxmax)
+                       maxmax = par[j]->stats->max;
+       }
+       if (histofall && nthreads > 1)
+               printf(" %05lu", maxmax);
+       printf("\n");
+       printf("# Histogram Overflows:");
+       alloverflows = 0;
+       for (j = 0; j < nthreads; j++) {
+               printf(" %05lu", par[j]->stats->hist_overflow);
+               alloverflows += par[j]->stats->hist_overflow;
+       }
+       if (histofall && nthreads > 1)
+               printf(" %05lu", alloverflows);
+       printf("\n");
+
+       printf("# Histogram Overflow at cycle number:\n");
+       for (i = 0; i < nthreads; i++) {
+               printf("# Thread %d:", i);
+               for (j = 0; j < par[i]->stats->num_outliers; j++)
+                       printf(" %05lu", par[i]->stats->outliers[j]);
+               if (par[i]->stats->num_outliers < par[i]->stats->hist_overflow)
+                       printf(" # %05lu others", par[i]->stats->hist_overflow 
- par[i]->stats->num_outliers);
+               printf("\n");
+       }
+       printf("\n");
+}
+
+static void print_stat(FILE *fp, struct thread_param *par, int index, int 
verbose, int quiet)
+{
+       struct thread_stat *stat = par->stats;
+
+       if (!verbose) {
+               if (quiet != 1) {
+                       char *fmt;
+                       if (use_nsecs)
+                               fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
+                                       "Min:%7ld Act:%8ld Avg:%8ld Max:%8ld\n";
+                       else
+                               fmt = "T:%2d (%5d) P:%2d I:%ld C:%7lu "
+                                       "Min:%7ld Act:%5ld Avg:%5ld Max:%8ld\n";
+                       fprintf(fp, fmt, index, stat->tid, par->prio,
+                               par->interval, stat->cycles, stat->min, 
stat->act,
+                               stat->cycles ?
+                               (long)(stat->avg/stat->cycles) : 0, stat->max);
+               }
+       } else {
+               while (stat->cycles != stat->cyclesread) {
+                       long diff = stat->values
+                           [stat->cyclesread & par->bufmsk];
+
+                       if (diff > stat->redmax) {
+                               stat->redmax = diff;
+                               stat->cycleofmax = stat->cyclesread;
+                       }
+                       if (++stat->reduce == oscope_reduction) {
+                               fprintf(fp, "%8d:%8lu:%8ld\n", index,
+                                       stat->cycleofmax, stat->redmax);
+                               stat->reduce = 0;
+                               stat->redmax = 0;
+                       }
+                       stat->cyclesread++;
+               }
+       }
+}
+
+
+/*
+ * thread that creates a named fifo and hands out run stats when someone
+ * reads from the fifo.
+ */
+void *fifothread(void *param)
+{
+       int ret;
+       int fd;
+       FILE *fp;
+       int i;
+
+       if (use_fifo == 0)
+               return NULL;
+
+       unlink(fifopath);
+       ret = mkfifo(fifopath, 0666);
+       if (ret) {
+               fprintf(stderr, "Error creating fifo %s: %s\n", fifopath, 
strerror(errno));
+               return NULL;
+       }
+       while (!shutdown) {
+               fd = open(fifopath, O_WRONLY|O_NONBLOCK);
+               if (fd < 0) {
+                       usleep(500000);
+                       continue;
+               }
+               fp = fdopen(fd, "w");
+               for (i=0; i < num_threads; i++)
+                       print_stat(fp, parameters[i], i, 0, 0);
+               fclose(fp);
+               usleep(250);
+       }
+       unlink(fifopath);
+       return NULL;
+}
+
+
+int main(int argc, char **argv)
+{
+       sigset_t sigset;
+       int signum = SIGALRM;
+       int mode;
+       int max_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+       int i, ret = -1;
+       int status;
+
+       process_options(argc, argv, max_cpus);
+
+       if (check_privs())
+               exit(EXIT_FAILURE);
+
+       if (verbose)
+               printf("Max CPUs = %d\n", max_cpus);
+
+       /* Checks if numa is on, program exits if numa on but not available */
+       numa_on_and_available();
+
+       /* lock all memory (prevent swapping) */
+       if (lockall)
+               if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) {
+                       perror("mlockall");
+                       goto out;
+               }
+
+       /* use the /dev/cpu_dma_latency trick if it's there */
+       set_latency_target();
+
+       kernelversion = check_kernel();
+
+       if (kernelversion == KV_NOT_SUPPORTED)
+               warn("Running on unknown kernel version...YMMV\n");
+
+       setup_tracer();
+
+       if (check_timer())
+               warn("High resolution timers not available\n");
+
+       if (check_clock_resolution) {
+               int clock;
+               uint64_t diff;
+               int k;
+               uint64_t min_non_zero_diff = UINT64_MAX;
+               struct timespec now;
+               struct timespec prev;
+               uint64_t reported_resolution = UINT64_MAX;
+               struct timespec res;
+               struct timespec *time;
+               int times;
+
+               clock = clocksources[clocksel];
+
+               if (clock_getres(clock, &res)) {
+                       warn("clock_getres failed");
+               } else {
+                       reported_resolution = (NSEC_PER_SEC * res.tv_sec) + 
res.tv_nsec;
+               }
+
+
+               /*
+                * Calculate how many calls to clock_gettime are needed.
+                * Then call it that many times.
+                * Goal is to collect timestamps for ~ 0.001 sec.
+                * This will reliably capture resolution <= 500 usec.
+                */
+               times = 1000;
+               clock_gettime(clock, &prev);
+               for (k=0; k < times; k++) {
+                       clock_gettime(clock, &now);
+               }
+
+               diff = calcdiff_ns(now, prev);
+               if (diff == 0) {
+                       /*
+                        * No clock rollover occurred.
+                        * Use the default value for times.
+                        */
+                       times = -1;
+               } else {
+                       int call_time;
+                       call_time = diff / times;         /* duration 1 call */
+                       times = NSEC_PER_SEC / call_time; /* calls per second */
+                       times /= 1000;                    /* calls per msec */
+                       if (times < 1000)
+                               times = 1000;
+               }
+               /* sanity check */
+               if ((times <= 0) || (times > 100000))
+                       times = 100000;
+
+               time = calloc(times, sizeof(*time));
+
+               for (k=0; k < times; k++) {
+                       clock_gettime(clock, &time[k]);
+               }
+
+               if (ct_debug) {
+                       info("For %d consecutive calls to clock_gettime():\n", 
times);
+                       info("time, delta time (nsec)\n");
+               }
+
+               prev = time[0];
+               for (k=1; k < times; k++) {
+
+                       diff = calcdiff_ns(time[k], prev);
+                       prev = time[k];
+
+                       if (diff && (diff < min_non_zero_diff)) {
+                               min_non_zero_diff = diff;
+                       }
+
+                       if (ct_debug)
+                               info("%ld.%06ld  %5llu\n",
+                                    time[k].tv_sec, time[k].tv_nsec,
+                                    (unsigned long long)diff);
+               }
+
+               free(time);
+
+
+               if (verbose ||
+                   (min_non_zero_diff && (min_non_zero_diff > 
reported_resolution))) {
+                       /*
+                        * Measured clock resolution includes the time to call
+                        * clock_gettime(), so it will be slightly larger than
+                        * actual resolution.
+                        */
+                       warn("reported clock resolution: %llu nsec\n",
+                            (unsigned long long)reported_resolution);
+                       warn("measured clock resolution approximately: %llu 
nsec\n",
+                            (unsigned long long)min_non_zero_diff);
+               }
+
+       }
+
+       mode = use_nanosleep + use_system;
+
+       sigemptyset(&sigset);
+       sigaddset(&sigset, signum);
+       sigprocmask (SIG_BLOCK, &sigset, NULL);
+
+       signal(SIGINT, sighand);
+       signal(SIGTERM, sighand);
+       signal(SIGUSR1, sighand);
+
+       parameters = calloc(num_threads, sizeof(struct thread_param *));
+       if (!parameters)
+               goto out;
+       statistics = calloc(num_threads, sizeof(struct thread_stat *));
+       if (!statistics)
+               goto outpar;
+
+       for (i = 0; i < num_threads; i++) {
+               pthread_attr_t attr;
+               int node;
+               struct thread_param *par;
+               struct thread_stat *stat;
+
+               status = pthread_attr_init(&attr);
+               if (status != 0)
+                       fatal("error from pthread_attr_init for thread %d: 
%s\n", i, strerror(status));
+
+               node = -1;
+               if (numa) {
+                       void *stack;
+                       void *currstk;
+                       size_t stksize;
+
+                       /* find the memory node associated with the cpu i */
+                       node = rt_numa_numa_node_of_cpu(i);
+
+                       /* get the stack size set for for this thread */
+                       if (pthread_attr_getstack(&attr, &currstk, &stksize))
+                               fatal("failed to get stack size for thread 
%d\n", i);
+
+                       /* if the stack size is zero, set a default */
+                       if (stksize == 0)
+                               stksize = PTHREAD_STACK_MIN * 2;
+
+                       /*  allocate memory for a stack on appropriate node */
+                       stack = rt_numa_numa_alloc_onnode(stksize, node, i);
+
+                       /* set the thread's stack */
+                       if (pthread_attr_setstack(&attr, stack, stksize))
+                               fatal("failed to set stack addr for thread %d 
to 0x%x\n",
+                                     i, stack+stksize);
+               }
+
+               /* allocate the thread's parameter block  */
+               parameters[i] = par = threadalloc(sizeof(struct thread_param), 
node);
+               if (par == NULL)
+                       fatal("error allocating thread_param struct for thread 
%d\n", i);
+               memset(par, 0, sizeof(struct thread_param));
+
+               /* allocate the thread's statistics block */
+               statistics[i] = stat = threadalloc(sizeof(struct thread_stat), 
node);
+               if (stat == NULL)
+                       fatal("error allocating thread status struct for thread 
%d\n", i);
+               memset(stat, 0, sizeof(struct thread_stat));
+
+               /* allocate the histogram if requested */
+               if (histogram) {
+                       int bufsize = histogram * sizeof(long);
+
+                       stat->hist_array = threadalloc(bufsize, node);
+                       stat->outliers = threadalloc(bufsize, node);
+                       if (stat->hist_array == NULL || stat->outliers == NULL)
+                               fatal("failed to allocate histogram of size %d 
on node %d\n",
+                                     histogram, i);
+                       memset(stat->hist_array, 0, bufsize);
+                       memset(stat->outliers, 0, bufsize);
+               }
+
+               if (verbose) {
+                       int bufsize = VALBUF_SIZE * sizeof(long);
+                       stat->values = threadalloc(bufsize, node);
+                       if (!stat->values)
+                               goto outall;
+                       memset(stat->values, 0, bufsize);
+                       par->bufmsk = VALBUF_SIZE - 1;
+               }
+
+               par->prio = priority;
+               if (priority && (policy == SCHED_FIFO || policy == SCHED_RR))
+                       par->policy = policy;
+               else {
+                       par->policy = SCHED_OTHER;
+                       force_sched_other = 1;
+               }
+               if (priospread)
+                       priority--;
+               par->clock = clocksources[clocksel];
+               par->mode = mode;
+               par->timermode = timermode;
+               par->signal = signum;
+               par->interval = interval;
+               if (!histogram) /* same interval on CPUs */
+                       interval += distance;
+               if (verbose)
+                       printf("Thread %d Interval: %d\n", i, interval);
+               par->max_cycles = max_cycles;
+               par->stats = stat;
+               par->node = node;
+               par->tnum = i;
+               switch (setaffinity) {
+               case AFFINITY_UNSPECIFIED: par->cpu = -1; break;
+               case AFFINITY_SPECIFIED:
+                       par->cpu = cpu_for_thread(i, max_cpus);
+                       if (verbose)
+                               printf("Thread %d using cpu %d.\n", i,
+                                       par->cpu);
+                       break;
+               case AFFINITY_USEALL: par->cpu = i % max_cpus; break;
+               }
+               stat->min = 1000000;
+               stat->max = 0;
+               stat->avg = 0.0;
+               stat->threadstarted = 1;
+               status = pthread_create(&stat->thread, &attr, timerthread, par);
+               if (status)
+                       fatal("failed to create thread %d: %s\n", i, 
strerror(status));
+
+       }
+       if (use_fifo)
+               status = pthread_create(&fifo_threadid, NULL, fifothread, NULL);
+
+       while (!shutdown) {
+               char lavg[256];
+               int fd, len, allstopped = 0;
+               static char *policystr = NULL;
+               static char *slash = NULL;
+               static char *policystr2;
+
+               if (!policystr)
+                       policystr = policyname(policy);
+
+               if (!slash) {
+                       if (force_sched_other) {
+                               slash = "/";
+                               policystr2 = policyname(SCHED_OTHER);
+                       } else
+                               slash = policystr2 = "";
+               }
+               if (!verbose && !quiet) {
+                       fd = open("/proc/loadavg", O_RDONLY, 0666);
+                       len = read(fd, &lavg, 255);
+                       close(fd);
+                       lavg[len-1] = 0x0;
+                       printf("policy: %s%s%s: loadavg: %s          \n\n",
+                              policystr, slash, policystr2, lavg);
+               }
+
+               for (i = 0; i < num_threads; i++) {
+
+                       print_stat(stdout, parameters[i], i, verbose, quiet);
+                       if(max_cycles && statistics[i]->cycles >= max_cycles)
+                               allstopped++;
+               }
+
+               usleep(10000);
+               if (shutdown || allstopped)
+                       break;
+               if (!verbose && !quiet)
+                       printf("\033[%dA", num_threads + 2);
+
+               if (refresh_on_max) {
+                       pthread_mutex_lock(&refresh_on_max_lock);
+                       pthread_cond_wait(&refresh_on_max_cond,
+                                         &refresh_on_max_lock);
+                       pthread_mutex_unlock(&refresh_on_max_lock);
+               }
+       }
+       ret = EXIT_SUCCESS;
+
+ outall:
+       shutdown = 1;
+       usleep(50000);
+
+       if (quiet)
+               quiet = 2;
+       for (i = 0; i < num_threads; i++) {
+               if (statistics[i]->threadstarted > 0)
+                       pthread_kill(statistics[i]->thread, SIGTERM);
+               if (statistics[i]->threadstarted) {
+                       pthread_join(statistics[i]->thread, NULL);
+                       if (quiet && !histogram)
+                               print_stat(stdout, parameters[i], i, 0, 0);
+               }
+               if (statistics[i]->values)
+                       threadfree(statistics[i]->values, 
VALBUF_SIZE*sizeof(long), parameters[i]->node);
+       }
+
+       if (histogram) {
+               print_hist(parameters, num_threads);
+               for (i = 0; i < num_threads; i++) {
+                       threadfree(statistics[i]->hist_array, 
histogram*sizeof(long), parameters[i]->node);
+                       threadfree(statistics[i]->outliers, 
histogram*sizeof(long), parameters[i]->node);
+               }
+       }
+
+       if (tracelimit) {
+               print_tids(parameters, num_threads);
+               if (break_thread_id) {
+                       printf("# Break thread: %d\n", break_thread_id);
+                       printf("# Break value: %llu\n", (unsigned long 
long)break_thread_value);
+               }
+       }
+
+
+       for (i=0; i < num_threads; i++) {
+               if (!statistics[i])
+                       continue;
+               threadfree(statistics[i], sizeof(struct thread_stat), 
parameters[i]->node);
+       }
+
+ outpar:
+       for (i = 0; i < num_threads; i++) {
+               if (!parameters[i])
+                       continue;
+               threadfree(parameters[i], sizeof(struct thread_param), 
parameters[i]->node);
+       }
+ out:
+       /* ensure that the tracer is stopped */
+       if (tracelimit && !notrace)
+               tracing(0);
+
+
+       /* close any tracer file descriptors */
+       if (tracemark_fd >= 0)
+               close(tracemark_fd);
+       if (trace_fd >= 0)
+               close(trace_fd);
+
+       if (enable_events)
+               /* turn off all events */
+               event_disable_all();
+
+       /* turn off the function tracer */
+       fileprefix = procfileprefix;
+       if (tracetype && !notrace)
+               setkernvar("ftrace_enabled", "0");
+       fileprefix = get_debugfileprefix();
+
+       /* unlock everything */
+       if (lockall)
+               munlockall();
+
+       /* Be a nice program, cleanup */
+       if (kernelversion < KV_26_33)
+               restorekernvars();
+
+       /* close the latency_target_fd if it's open */
+       if (latency_target_fd >= 0)
+               close(latency_target_fd);
+
+       if (affinity_mask)
+               rt_bitmask_free(affinity_mask);
+
+       exit(ret);
+}
diff --git a/demo/posix/cyclictest/error.c b/demo/posix/cyclictest/error.c
new file mode 100644
index 0000000..b32aa02
--- /dev/null
+++ b/demo/posix/cyclictest/error.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2009 John Kacur <jka...@redhat.com>
+ *
+ * error routines, similar to those found in
+ * Advanced Programming in the UNIX Environment 2nd ed.
+ */
+#include "error.h"
+
+/* Print an error message, plus a message for err and exit with error err */
+void err_exit(int err, char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       err_doit(err, fmt, ap);
+       va_end(ap);
+       exit(err);
+}
+
+/* print an error message and return */
+void err_msg(char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       err_doit(0, fmt, ap);
+       va_end(ap);
+       return;
+}
+
+/* Print an error message, plus a message for err, and return */
+void err_msg_n(int err, char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       err_doit(err, fmt, ap);
+       va_end(ap);
+       return;
+}
+
+/* print an error message and quit */
+void err_quit(char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       err_doit(0, fmt, ap);
+       va_end(ap);
+       exit(1);
+}
+
+void debug(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs("DEBUG: ", stderr);
+       err_doit(0, fmt, ap);
+       va_end(ap);
+}
+
+void info(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs("INFO: ", stderr);
+       err_doit(0, fmt, ap);
+       va_end(ap);
+}
+
+void warn(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs("WARN: ", stderr);
+       err_doit(0, fmt, ap);
+       va_end(ap);
+}
+
+void fatal(char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fputs("FATAL: ", stderr);
+       err_doit(0, fmt, ap);
+       va_end(ap);
+       exit(EXIT_FAILURE);
+}
+
+void err_doit(int err, const char *fmt, va_list ap)
+{
+       vfprintf(stderr, fmt, ap);
+       if (err)
+               fprintf(stderr, ": %s\n", strerror(err));
+       return;
+}
diff --git a/demo/posix/cyclictest/error.h b/demo/posix/cyclictest/error.h
new file mode 100644
index 0000000..ae05a2e
--- /dev/null
+++ b/demo/posix/cyclictest/error.h
@@ -0,0 +1,19 @@
+#ifndef __ERROR_H
+#define __ERROR_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+void err_exit(int err, char *fmt, ...);
+void err_msg(char *fmt, ...);
+void err_msg_n(int err, char *fmt, ...);
+void err_quit(char *fmt, ...);
+void debug(char *fmt, ...);
+void info(char *fmt, ...);
+void warn(char *fmt, ...);
+void fatal(char *fmt, ...);
+void err_doit(int err, const char *fmt, va_list ap);
+
+#endif /* __ERROR_H */
diff --git a/demo/posix/cyclictest/rt-sched.h b/demo/posix/cyclictest/rt-sched.h
new file mode 100644
index 0000000..6c45f7a
--- /dev/null
+++ b/demo/posix/cyclictest/rt-sched.h
@@ -0,0 +1,76 @@
+/*
+   rt-sched.h - sched_setattr() and sched_getattr() API
+
+   (C) Dario Faggioli <raist...@linux.it>, 2009, 2010
+   Copyright (C) 2014 BMW Car IT GmbH, Daniel Wagner 
<daniel.wag...@bmw-carit.de
+
+   This program 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.
+
+   This program 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 this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
+   USA */
+
+/* This file is based on Dario Faggioli's libdl. Eventually it will be
+   replaced by a proper implemenation of this API. */
+
+#ifndef __RT_SCHED_H__
+#define __RT_SCHED_H__
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#ifndef SCHED_DEADLINE
+#define SCHED_DEADLINE 6
+#endif
+
+#ifdef __x86_64__
+#define __NR_sched_setattr             314
+#define __NR_sched_getattr             315
+#endif
+
+#ifdef __i386__
+#define __NR_sched_setattr             351
+#define __NR_sched_getattr             352
+#endif
+
+#ifdef __arm__
+#define __NR_sched_setattr             380
+#define __NR_sched_getattr             381
+#endif
+
+struct sched_attr {
+       uint32_t size;
+       uint32_t sched_policy;
+       uint64_t sched_flags;
+
+       /* SCHED_NORMAL, SCHED_BATCH */
+       int32_t sched_nice;
+
+       /* SCHED_FIFO, SCHED_RR */
+       uint32_t sched_priority;
+
+       /* SCHED_DEADLINE */
+       uint64_t sched_runtime;
+       uint64_t sched_deadline;
+       uint64_t sched_period;
+};
+
+int sched_setattr(pid_t pid,
+                 const struct sched_attr *attr,
+                 unsigned int flags);
+
+int sched_getattr(pid_t pid,
+                 struct sched_attr *attr,
+                 unsigned int size,
+                 unsigned int flags);
+
+#endif /* __RT_SCHED_H__ */
diff --git a/demo/posix/cyclictest/rt-utils.c b/demo/posix/cyclictest/rt-utils.c
new file mode 100644
index 0000000..3882d23
--- /dev/null
+++ b/demo/posix/cyclictest/rt-utils.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2009 Carsten Emde <carsten.e...@osadl.org>
+ * Copyright (C) 2010 Clark Williams <willi...@redhat.com>
+ *
+ * based on functions from cyclictest that has
+ * (C) 2008-2009 Clark Williams <willi...@redhat.com>
+ * (C) 2005-2007 Thomas Gleixner <t...@linutronix.de>
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sched.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/syscall.h> /* For SYS_gettid definitions */
+#include "rt-utils.h"
+#include "rt-sched.h"
+#include "error.h"
+
+static char debugfileprefix[MAX_PATH];
+
+/*
+ * Finds the tracing directory in a mounted debugfs
+ */
+char *get_debugfileprefix(void)
+{
+       char type[100];
+       FILE *fp;
+       int size;
+       int found = 0;
+       struct stat s;
+
+       if (debugfileprefix[0] != '\0')
+               goto out;
+
+       /* look in the "standard" mount point first */
+       if ((stat("/sys/kernel/debug/tracing", &s) == 0) && S_ISDIR(s.st_mode)) 
{
+               strcpy(debugfileprefix, "/sys/kernel/debug/tracing/");
+               goto out;
+       }
+
+       /* now look in the "other standard" place */
+       if ((stat("/debug/tracing", &s) == 0) && S_ISDIR(s.st_mode)) {
+               strcpy(debugfileprefix, "/debug/tracing/");
+               goto out;
+       }
+       
+       /* oh well, parse /proc/mounts and see if it's there */
+       if ((fp = fopen("/proc/mounts","r")) == NULL)
+               goto out;
+
+       while (fscanf(fp, "%*s %"
+                     STR(MAX_PATH)
+                     "s %99s %*s %*d %*d\n",
+                     debugfileprefix, type) == 2) {
+               if (strcmp(type, "debugfs") == 0) {
+                       found = 1;
+                       break;
+               }
+               /* stupid check for systemd-style autofs mount */
+               if ((strcmp(debugfileprefix, "/sys/kernel/debug") == 0) &&
+                   (strcmp(type, "systemd") == 0)) {
+                       found = 1;
+                       break;
+               }
+       }
+       fclose(fp);
+
+       if (!found) {
+               debugfileprefix[0] = '\0';
+               goto out;
+       }
+
+       size = sizeof(debugfileprefix) - strlen(debugfileprefix);
+       strncat(debugfileprefix, "/tracing/", size);
+
+out:
+       return debugfileprefix;
+}
+
+int mount_debugfs(char *path)
+{
+       char *mountpoint = path;
+       char cmd[MAX_PATH];
+       char *prefix;
+       int ret;
+
+       /* if it's already mounted just return */
+       prefix = get_debugfileprefix();
+       if (strlen(prefix) != 0) {
+               info("debugfs mountpoint: %s\n", prefix);
+               return 0;
+       }
+       if (!mountpoint)
+               mountpoint = "/sys/kernel/debug";
+       
+       sprintf(cmd, "mount -t debugfs debugfs %s", mountpoint);
+       ret = system(cmd);
+       if (ret != 0) {
+               fprintf(stderr, "Error mounting debugfs at %s: %s\n", 
mountpoint, strerror(errno));
+               return -1;
+       }
+       return 0;
+               
+}
+
+static char **tracer_list;
+static char *tracer_buffer;
+static int num_tracers;
+#define CHUNKSZ   1024
+
+/*
+ * return a list of the tracers configured into the running kernel
+ */
+
+int get_tracers(char ***list)
+{
+       int ret;
+       FILE *fp;
+       char buffer[CHUNKSZ];
+       char *prefix = get_debugfileprefix();
+       char *tmpbuf = NULL;
+       char *ptr;
+       int tmpsz = 0;
+
+       /* if we've already parse it, return what we have */
+       if (tracer_list) {
+               *list = tracer_list;
+               return num_tracers;
+       }
+
+       /* open the tracing file available_tracers */
+       sprintf(buffer, "%savailable_tracers", prefix);
+       if ((fp = fopen(buffer, "r")) == NULL)
+               fatal ("Can't open %s for reading\n", buffer);
+
+       /* allocate initial buffer */
+       ptr = tmpbuf = malloc(CHUNKSZ);
+       if (ptr == NULL)
+               fatal("error allocating initial space for tracer list\n");
+
+       /* read in the list of available tracers */
+       while((ret = fread(buffer, sizeof(char), CHUNKSZ, fp))) {
+               if ((ptr+ret+1) > (tmpbuf+tmpsz)) {
+                       tmpbuf = realloc(tmpbuf, tmpsz + CHUNKSZ);
+                       if (tmpbuf == NULL)
+                               fatal("error allocating space for list of valid 
tracers\n");
+                       tmpsz += CHUNKSZ;
+               }
+               strncpy(ptr, buffer, ret);
+               ptr += ret;
+       }
+       fclose(fp);
+       if (tmpsz == 0)
+               fatal("error reading available tracers\n");
+       
+       tracer_buffer = tmpbuf;
+
+       /* get a buffer for the pointers to tracers */
+       if (!(tracer_list = malloc(sizeof(char *))))
+               fatal ("error allocatinging tracer list buffer\n");
+
+       /* parse the buffer */
+       ptr = strtok(tmpbuf, " \t\n\r");
+       do {
+               tracer_list[num_tracers++] = ptr;
+               tracer_list = realloc(tracer_list, 
sizeof(char*)*(num_tracers+1));
+               tracer_list[num_tracers] = NULL;
+       } while ((ptr = strtok(NULL, " \t\n\r")) != NULL);
+
+       /* return the list and number of tracers */
+       *list = tracer_list;
+       return num_tracers;
+}
+
+
+/* 
+ * return zero if tracername is not a valid tracer, non-zero if it is 
+ */
+
+int valid_tracer(char *tracername)
+{
+       char **list;
+       int ntracers;
+       int i;
+
+       ntracers = get_tracers(&list);
+       if (ntracers == 0 || tracername == NULL)
+               return 0;
+       for (i = 0; i < ntracers; i++)
+               if (strncmp(list[i], tracername, strlen(list[i])) == 0)
+                       return 1;
+       return 0;
+}
+
+/*
+ * enable event tracepoint
+ */
+int setevent(char *event, char *val)
+{
+       char *prefix = get_debugfileprefix();
+       char buffer[MAX_PATH];
+       int fd;
+       int ret;
+
+       sprintf(buffer, "%s%s", prefix, event);
+       if ((fd = open(buffer, O_WRONLY)) < 0) {
+               warn("unable to open %s\n", buffer);
+               return -1;
+       }
+       if ((ret = write(fd, val, strlen(val))) < 0) {
+               warn("unable to write %s to %s\n", val, buffer);
+               close(fd);
+               return -1;
+       }
+       close(fd);
+       return 0;
+}
+
+int event_enable_all(void)
+{
+       return setevent("events/enable", "1");
+}
+
+int event_disable_all(void)
+{
+       return setevent("events/enable", "0");
+}
+
+int event_enable(char *event) 
+{
+       char path[MAX_PATH];
+       sprintf(path, "events/%s/enable", event);
+       return setevent(path, "1");
+}
+
+int event_disable(char *event)
+{
+       char path[MAX_PATH];
+       sprintf(path, "events/%s/enable", event);
+       return setevent(path, "0");
+}
+       
+int check_privs(void)
+{
+       int policy = sched_getscheduler(0);
+       struct sched_param param, old_param;
+
+       /* if we're already running a realtime scheduler
+        * then we *should* be able to change things later
+        */
+       if (policy == SCHED_FIFO || policy == SCHED_RR)
+               return 0;
+
+       /* first get the current parameters */
+       if (sched_getparam(0, &old_param)) {
+               fprintf(stderr, "unable to get scheduler parameters\n");
+               return 1;
+       }
+       param = old_param;
+
+       /* try to change to SCHED_FIFO */
+       param.sched_priority = 1;
+       if (sched_setscheduler(0, SCHED_FIFO, &param)) {
+               fprintf(stderr, "Unable to change scheduling policy!\n");
+               fprintf(stderr, "either run as root or join realtime group\n");
+               return 1;
+       }
+
+       /* we're good; change back and return success */
+       return sched_setscheduler(0, policy, &old_param);
+}
+
+const char *policy_to_string(int policy)
+{
+       switch (policy) {
+       case SCHED_OTHER:
+               return "SCHED_OTHER";
+       case SCHED_FIFO:
+               return "SCHED_FIFO";
+       case SCHED_RR:
+               return "SCHED_RR";
+       case SCHED_BATCH:
+               return "SCHED_BATCH";
+       case SCHED_IDLE:
+               return "SCHED_IDLE";
+       case SCHED_DEADLINE:
+               return "SCHED_DEADLINE";
+       }
+
+       return "unknown";
+}
+
+uint32_t string_to_policy(const char *str)
+{
+       if (!strcmp(str, "other"))
+               return SCHED_OTHER;
+       else if (!strcmp(str, "fifo"))
+               return SCHED_FIFO;
+       else if (!strcmp(str, "rr"))
+               return SCHED_RR;
+       else if (!strcmp(str, "batch"))
+               return SCHED_BATCH;
+       else if (!strcmp(str, "idle"))
+               return SCHED_IDLE;
+       else if (!strcmp(str, "deadline"))
+               return SCHED_DEADLINE;
+
+       return 0;
+}
+
+pid_t gettid(void)
+{
+       return syscall(SYS_gettid);
+}
diff --git a/demo/posix/cyclictest/rt-utils.h b/demo/posix/cyclictest/rt-utils.h
new file mode 100644
index 0000000..ef0f6ac
--- /dev/null
+++ b/demo/posix/cyclictest/rt-utils.h
@@ -0,0 +1,27 @@
+#ifndef __RT_UTILS_H
+#define __RT_UTILS_H
+
+#include <stdint.h>
+
+#define _STR(x) #x
+#define STR(x) _STR(x)
+#define MAX_PATH 256
+
+int check_privs(void);
+char *get_debugfileprefix(void);
+int mount_debugfs(char *);
+int get_tracers(char ***);
+int valid_tracer(char *);
+
+int setevent(char *event, char *val);
+int event_enable(char *event);
+int event_disable(char *event);
+int event_enable_all(void);
+int event_disable_all(void);
+
+const char *policy_to_string(int policy);
+uint32_t string_to_policy(const char *str);
+
+pid_t gettid(void);
+
+#endif /* __RT_UTILS.H */
diff --git a/demo/posix/cyclictest/rt_numa.h b/demo/posix/cyclictest/rt_numa.h
new file mode 100644
index 0000000..98e7d0f
--- /dev/null
+++ b/demo/posix/cyclictest/rt_numa.h
@@ -0,0 +1,277 @@
+/*
+ * A numa library for cyclictest.
+ * The functions here are designed to work whether cyclictest has been
+ * compiled with numa support or not, and whether the user uses the --numa
+ * option or not.
+ * They should also work correctly with older versions of the numactl lib
+ * such as the one found on RHEL5, or with the newer version 2 and above.
+ *
+ * The difference in behavior hinges on whether LIBNUMA_API_VERSION >= 2,
+ * in which case we will employ the bitmask affinity behavior -or-
+ * either LIBNUMA_API_VERSION < 2 or NUMA support is missing altogether,
+ * in which case we retain the older affinity behavior which can either
+ * specify a single CPU core or else use all cores.
+ *
+ * (C) 2010 John Kacur <jka...@redhat.com>
+ * (C) 2010 Clark Williams <willi...@redhat.com>
+ *
+ */
+
+#ifndef _RT_NUMA_H
+#define _RT_NUMA_H
+
+#include "rt-utils.h"
+#include "error.h"
+
+static int numa = 0;
+
+#ifdef NUMA
+#include <numa.h>
+
+#ifndef LIBNUMA_API_VERSION
+#define LIBNUMA_API_VERSION 1
+#endif
+
+static void *
+threadalloc(size_t size, int node)
+{
+       if (node == -1)
+               return malloc(size);
+       return numa_alloc_onnode(size, node);
+}
+
+static void
+threadfree(void *ptr, size_t size, int node)
+{
+       if (node == -1)
+               free(ptr);
+       else
+               numa_free(ptr, size);
+}
+
+static void rt_numa_set_numa_run_on_node(int node, int cpu)
+{
+       int res;
+       res = numa_run_on_node(node);
+       if (res)
+               warn("Could not set NUMA node %d for thread %d: %s\n",
+                               node, cpu, strerror(errno));
+       return;
+}
+
+static void *rt_numa_numa_alloc_onnode(size_t size, int node, int cpu)
+{
+       void *stack;
+       stack = numa_alloc_onnode(size, node);
+       if (stack == NULL)
+               fatal("failed to allocate %d bytes on node %d for cpu %d\n",
+                               size, node, cpu);
+       return stack;
+}
+
+#if LIBNUMA_API_VERSION >= 2
+
+/*
+ * Use new bit mask CPU affinity behavior
+ */
+static int rt_numa_numa_node_of_cpu(int cpu)
+{
+       int node;
+       node = numa_node_of_cpu(cpu);
+       if (node == -1)
+               fatal("invalid cpu passed to numa_node_of_cpu(%d)\n", cpu);
+       return node;
+}
+
+static inline unsigned int rt_numa_bitmask_isbitset( const struct bitmask 
*mask,
+       unsigned long i)
+{
+       return numa_bitmask_isbitset(mask,i);
+}
+
+static inline struct bitmask* rt_numa_parse_cpustring(const char* s,
+       int max_cpus)
+{
+#ifdef HAVE_PARSE_CPUSTRING_ALL                /* Currently not defined 
anywhere.  No
+                                          autotools build. */
+       return numa_parse_cpustring_all(s);
+#else
+       /* We really need numa_parse_cpustring_all(), so we can assign threads
+        * to cores which are part of an isolcpus set, but early 2.x versions of
+        * libnuma do not have this function.  A work around should be to run
+        * your command with e.g. taskset -c 9-15 <command>
+        */
+       return numa_parse_cpustring((char *)s);
+#endif
+}
+
+static inline void rt_bitmask_free(struct bitmask *mask)
+{
+       numa_bitmask_free(mask);
+}
+
+#else  /* LIBNUMA_API_VERSION == 1 */
+
+struct bitmask {
+       unsigned long size; /* number of bits in the map */
+       unsigned long *maskp;
+};
+#define BITS_PER_LONG  (8*sizeof(long))
+
+/*
+ * Map legacy CPU affinity behavior onto bit mask infrastructure
+ */
+static int rt_numa_numa_node_of_cpu(int cpu)
+{
+       unsigned char cpumask[256];
+       int node, idx, bit;
+       int max_node, max_cpus;
+
+       max_node = numa_max_node();
+       max_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+       if (cpu > max_cpus) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       /* calculate bitmask index and relative bit position of cpu */
+       idx = cpu / 8;
+       bit = cpu % 8;
+
+       for (node = 0; node <= max_node; node++) {
+               if (numa_node_to_cpus(node, (void *) cpumask, sizeof(cpumask)))
+                       return -1;
+
+               if (cpumask[idx] & (1<<bit))
+                       return node;
+       }
+       errno = EINVAL;
+       return -1;
+}
+
+static inline unsigned int rt_numa_bitmask_isbitset( const struct bitmask 
*mask,
+       unsigned long i)
+{
+       long bit = mask->maskp[i/BITS_PER_LONG] & (1<<(i % BITS_PER_LONG));
+       return (bit != 0);
+}
+
+static inline struct bitmask* rt_numa_parse_cpustring(const char* s,
+       int max_cpus)
+{
+       int cpu;
+       struct bitmask *mask = NULL;
+       cpu = atoi(s);
+       if (0 <= cpu && cpu < max_cpus) {
+               mask = malloc(sizeof(*mask));
+               if (mask) {
+                       /* Round up to integral number of longs to contain
+                        * max_cpus bits */
+                       int nlongs = (max_cpus+BITS_PER_LONG-1)/BITS_PER_LONG;
+
+                       mask->maskp = calloc(nlongs, sizeof(long));
+                       if (mask->maskp) {
+                               mask->maskp[cpu/BITS_PER_LONG] |=
+                                       (1UL << (cpu % BITS_PER_LONG));
+                               mask->size = max_cpus;
+                       } else {
+                               free(mask);
+                               mask = NULL;
+                       }
+               }
+       }
+       return mask;
+}
+
+static inline void rt_bitmask_free(struct bitmask *mask)
+{
+       free(mask->maskp);
+       free(mask);
+}
+
+#endif /* LIBNUMA_API_VERSION */
+
+static void numa_on_and_available()
+{
+       if (numa && (numa_available() == -1))
+               fatal("--numa specified and numa functions not available.\n");
+}
+
+#else /* ! NUMA */
+
+struct bitmask {
+    unsigned long size; /* number of bits in the map */
+    unsigned long *maskp;
+};
+#define BITS_PER_LONG    (8*sizeof(long))
+
+static inline void *threadalloc(size_t size, int n) { return malloc(size); }
+static inline void threadfree(void *ptr, size_t s, int n) { free(ptr); }
+static inline void rt_numa_set_numa_run_on_node(int n, int c) { }
+static inline int rt_numa_numa_node_of_cpu(int cpu) { return -1; }
+static void *rt_numa_numa_alloc_onnode(size_t s, int n, int c) { return NULL; }
+
+/*
+ * Map legacy CPU affinity behavior onto bit mask infrastructure
+ */
+static inline unsigned int rt_numa_bitmask_isbitset( const struct bitmask 
*mask,
+       unsigned long i)
+{
+       long bit = mask->maskp[i/BITS_PER_LONG] & (1<<(i % BITS_PER_LONG));
+       return (bit != 0);
+}
+
+static inline struct bitmask* rt_numa_parse_cpustring(const char* s,
+       int max_cpus)
+{
+       int cpu;
+       struct bitmask *mask = NULL;
+       cpu = atoi(s);
+       if (0 <= cpu && cpu < max_cpus) {
+               mask = malloc(sizeof(*mask));
+               if (mask) {
+                       /* Round up to integral number of longs to contain
+                        * max_cpus bits */
+                       int nlongs = (max_cpus+BITS_PER_LONG-1)/BITS_PER_LONG;
+
+                       mask->maskp = calloc(nlongs, sizeof(long));
+                       if (mask->maskp) {
+                               mask->maskp[cpu/BITS_PER_LONG] |=
+                                       (1UL << (cpu % BITS_PER_LONG));
+                               mask->size = max_cpus;
+                       } else {
+                               free(mask);
+                               mask = NULL;
+                       }
+               }
+       }
+       return mask;
+}
+
+static inline void rt_bitmask_free(struct bitmask *mask)
+{
+       free(mask->maskp);
+       free(mask);
+}
+
+static inline void numa_on_and_available(void) { }
+
+#endif /* NUMA */
+
+/*
+ * Any behavioral differences above are transparent to these functions
+ */
+/** Returns number of bits set in mask. */
+static inline unsigned int rt_numa_bitmask_count(const struct bitmask *mask)
+{
+       unsigned int num_bits = 0, i;
+       for (i = 0; i < mask->size; i++) {
+               if (rt_numa_bitmask_isbitset(mask, i))
+                       num_bits++;
+       }
+       /* Could stash this instead of recomputing every time. */
+       return num_bits;
+}
+
+#endif /* _RT_NUMA_H */


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to