Module: xenomai-3 Branch: wip/prioceil Commit: 3973d289e7ea7b0f31054b25a74d5c68617bfd58 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=3973d289e7ea7b0f31054b25a74d5c68617bfd58
Author: Philippe Gerum <r...@xenomai.org> Date: Fri Feb 26 11:44:16 2016 +0100 testsuite/smokey: add test checking Cobalt's cpu affinity control --- configure.ac | 1 + testsuite/smokey/Makefile.am | 1 + testsuite/smokey/cpu-affinity/Makefile.am | 9 + testsuite/smokey/cpu-affinity/cpu-affinity.c | 252 ++++++++++++++++++++++++++ 4 files changed, 263 insertions(+) diff --git a/configure.ac b/configure.ac index 20fa0ec..8bbeeef 100644 --- a/configure.ac +++ b/configure.ac @@ -900,6 +900,7 @@ AC_CONFIG_FILES([ \ testsuite/smokey/net_packet_dgram/Makefile \ testsuite/smokey/net_packet_raw/Makefile \ testsuite/smokey/net_common/Makefile \ + testsuite/smokey/cpu-affinity/Makefile \ testsuite/clocktest/Makefile \ testsuite/xeno-test/Makefile \ utils/Makefile \ diff --git a/testsuite/smokey/Makefile.am b/testsuite/smokey/Makefile.am index e9a0fd2..5ade58b 100644 --- a/testsuite/smokey/Makefile.am +++ b/testsuite/smokey/Makefile.am @@ -8,6 +8,7 @@ smokey_SOURCES = main.c COBALT_SUBDIRS = \ arith \ bufp \ + cpu-affinity \ iddp \ leaks \ net_packet_dgram\ diff --git a/testsuite/smokey/cpu-affinity/Makefile.am b/testsuite/smokey/cpu-affinity/Makefile.am new file mode 100644 index 0000000..0d2e4e6 --- /dev/null +++ b/testsuite/smokey/cpu-affinity/Makefile.am @@ -0,0 +1,9 @@ + +noinst_LIBRARIES = libcpu-affinity.a + +libcpu_affinity_a_SOURCES = cpu-affinity.c + +libcpu_affinity_a_CPPFLAGS = \ + @XENO_USER_CFLAGS@ \ + -I$(top_srcdir) \ + -I$(top_srcdir)/include diff --git a/testsuite/smokey/cpu-affinity/cpu-affinity.c b/testsuite/smokey/cpu-affinity/cpu-affinity.c new file mode 100644 index 0000000..2674f76 --- /dev/null +++ b/testsuite/smokey/cpu-affinity/cpu-affinity.c @@ -0,0 +1,252 @@ +/* + * Test CPU affinity control mechanisms. + * + * Copyright (C) Philippe Gerum <r...@xenomai.org> + * + * Released under the terms of GPLv2. + */ +#include <pthread.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <semaphore.h> +#include <rtdm/testing.h> +#include <smokey/smokey.h> + +smokey_test_plugin(cpu_affinity, + SMOKEY_NOARGS, + "Check CPU affinity control." +); + +static cpu_set_t cpu_realtime_set, cpu_online_set; + +struct test_context { + sem_t done; + int status; + int kfd; + int nrt_cpu; +}; + +static void *test_thread(void *arg) +{ + int cpu, cpu_in_rt_set, status = 0, ncpu, ret; + struct test_context *p = arg; + cpu_set_t set; + + cpu = get_current_cpu(); + if (!__Fassert(cpu < 0)) { + status = cpu; + goto out; + } + + /* + * When emerging, we should be running on a member of the + * real-time CPU set. + */ + cpu_in_rt_set = CPU_ISSET(cpu, &cpu_realtime_set); + if (!__Tassert(cpu_in_rt_set)) { + status = -EINVAL; + goto out; + } + + smokey_trace(".... user thread starts on CPU%d, ok", cpu); + + for (ncpu = 0; ncpu < CPU_SETSIZE; ncpu++) { + if (ncpu == cpu || !CPU_ISSET(ncpu, &cpu_realtime_set)) + continue; + CPU_ZERO(&set); + CPU_SET(ncpu, &set); + if (!__Terrno(ret, sched_setaffinity(0, sizeof(set), &set))) { + status = ret; + goto out; + } + smokey_trace(".... user thread moved to CPU%d, good", ncpu); + } +out: + p->status = status; + __STD(sem_post(&p->done)); + + return NULL; +} + +static int load_test_module(void) +{ + int fd, status; + + status = system("modprobe -q xeno_rtdmtest"); + if (status < 0 || WEXITSTATUS(status)) + return -ENOSYS; + + /* Open the RTDM actor device. */ + fd = open("/dev/rtdm/rtdmx", O_RDWR); + if (fd < 0) + return -errno; + + return fd; +} + +static void unload_test_module(int fd) +{ + close(fd); + system("rmmod xeno_rtdmtest"); +} + +static void *__run_cpu_affinity(void *arg) +{ + struct test_context *context = arg; + struct sched_param param; + struct timespec ts, now; + pthread_attr_t thattr; + cpu_set_t set; + pthread_t tid; + int ret; + + smokey_trace(".. control thread binding to non-RT CPU%d", + context->nrt_cpu); + + __STD(sem_init(&context->done, 0, 0)); + + /* + * Make the child thread inherit a CPU affinity outside of the + * valid RT set from us. Cobalt should migrate the spawned + * threads (kernel and user) to a CPU from the RT set + * automatically. + */ + CPU_ZERO(&set); + CPU_SET(context->nrt_cpu, &set); + if (!__Terrno(ret, sched_setaffinity(0, sizeof(set), &set))) { + context->status = ret; + goto out; + } + + /* Check CPU affinity handling for user-space threads. */ + + smokey_trace(".. starting user thread"); + + pthread_attr_init(&thattr); + param.sched_priority = 1; + pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_DETACHED); + pthread_attr_setschedpolicy(&thattr, SCHED_FIFO); + pthread_attr_setschedparam(&thattr, ¶m); + pthread_attr_setinheritsched(&thattr, PTHREAD_EXPLICIT_SCHED); + + if (!__T(ret, pthread_create(&tid, &thattr, test_thread, context))) { + context->status = ret; + goto out; + } + + __STD(clock_gettime(CLOCK_REALTIME, &now)); + timespec_adds(&ts, &now, 100000000); /* 100ms from now */ + + if (!__Terrno(ret, __STD(sem_timedwait(&context->done, &ts)))) { + context->status = ret; + goto out; + } + + /* + * Prepare for testing CPU affinity handling for RTDM driver + * tasks. We don't actually run the test just yet, since we + * have no real-time context and the RTDM actor wants one, + * but we still load the module, creating the actor task over + * a non-RT CPU, which is the premise of our kernel-based + * test. + */ + + context->kfd = load_test_module(); +out: + __STD(sem_destroy(&context->done)); + + return NULL; +} + +static int run_cpu_affinity(struct smokey_test *t, + int argc, char *const argv[]) +{ + struct test_context context; + int cpu, ret, cpu_in_rt_set; + struct sched_param param; + pthread_attr_t thattr; + pthread_t tid; + __u32 kcpu; + + if (sysconf(_SC_NPROCESSORS_CONF) == 1) { + smokey_trace("uniprocessor system, skipped"); + return 0; + } + + ret = get_realtime_cpu_set(&cpu_realtime_set); + if (ret) + return -ENOSYS; + + ret = get_online_cpu_set(&cpu_online_set); + if (ret) + return -ENOSYS; + + for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { + if (CPU_ISSET(cpu, &cpu_online_set)) + smokey_trace(".. CPU%d is %s", cpu, + CPU_ISSET(cpu, &cpu_realtime_set) ? + "available" : "online, non-RT"); + } + + /* Find a non-RT CPU in the online set. */ + for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) { + if (CPU_ISSET(cpu, &cpu_online_set) && + !CPU_ISSET(cpu, &cpu_realtime_set)) + break; + } + + /* + * If there is no CPU restriction on the bootargs + * (i.e. xenomai.supported_cpus is absent or does not exclude + * any online CPU), pretend that we have no kernel support for + * running this test. + */ + if (cpu < 0) { + smokey_trace("no CPU restriction with xenomai.supported_cpus"); + return -ENOSYS; + } + + pthread_attr_init(&thattr); + param.sched_priority = 0; + pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE); + pthread_attr_setschedpolicy(&thattr, SCHED_OTHER); + pthread_attr_setschedparam(&thattr, ¶m); + pthread_attr_setinheritsched(&thattr, PTHREAD_EXPLICIT_SCHED); + + context.kfd = -1; + context.status = 0; + context.nrt_cpu = cpu; + /* + * Start a regular pthread for running the tests, to bypass + * sanity checks Cobalt does on CPU affinity. We actually want + * to start testing from a non-RT CPU. + */ + if (!__T(ret, __STD(pthread_create(&tid, &thattr, + __run_cpu_affinity, &context)))) + return ret; + + if (!__T(ret, pthread_join(tid, NULL))) + return ret; + + if (context.kfd < 0) + smokey_trace(".. RTDM test module not available, skipping"); + else { + smokey_trace(".. testing kthread affinity handling"); + if (!__Terrno(ret, ioctl(context.kfd, + RTTST_RTIOC_RTDM_ACTOR_GET_CPU, &kcpu))) + context.status = ret; + else { + cpu_in_rt_set = CPU_ISSET(kcpu, &cpu_realtime_set); + if (!__Tassert(cpu_in_rt_set)) + context.status = -EINVAL; + else + smokey_trace(".... kernel thread pinned to CPU%d, fine", + kcpu); + } + unload_test_module(context.kfd); + } + + return context.status; +} _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://xenomai.org/mailman/listinfo/xenomai-git