Commit 3973d289 authored by Philippe Gerum's avatar Philippe Gerum

testsuite/smokey: add test checking Cobalt's cpu affinity control

parent 38df524a
......@@ -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 \
......
......@@ -8,6 +8,7 @@ smokey_SOURCES = main.c
COBALT_SUBDIRS = \
arith \
bufp \
cpu-affinity \
iddp \
leaks \
net_packet_dgram\
......
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
/*
* Test CPU affinity control mechanisms.
*
* Copyright (C) Philippe Gerum <rpm@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, &param);
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, &param);
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment