From 93ffe5be8fd1954bbfe5a04e55b81ac1d83d2de7 Mon Sep 17 00:00:00 2001 From: Glenn Elliott Date: Tue, 12 Mar 2013 11:57:42 -0400 Subject: Auto-CPU-affinity from part./cluster assignment. This patch replaces be_migrate_to() with several be_migrate_*() APIs to automatically assign CPU affinity masks from a task's partition (or cluster) assignment. Routines are release-master-aware such that the release master (if one exists) will NOT be included in the task's affinity mask. (Note that release-master avoidance may be overridden by calling __be_migrate_thread_to_cluster().) --- bin/rt_launch.c | 2 +- bin/rtspin.c | 2 +- include/litmus.h | 8 +-- include/migration.h | 24 ++++++++ src/litmus.c | 12 +--- src/migration.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/core_api.c | 4 +- tests/pcp.c | 16 +++--- tests/sched.c | 4 +- 9 files changed, 202 insertions(+), 32 deletions(-) create mode 100644 include/migration.h create mode 100644 src/migration.c diff --git a/bin/rt_launch.c b/bin/rt_launch.c index 16d6ed7..97d9df9 100644 --- a/bin/rt_launch.c +++ b/bin/rt_launch.c @@ -109,7 +109,7 @@ int main(int argc, char** argv) info.argv = argv + optind + 2; info.wait = wait; if (migrate) { - ret = be_migrate_to(cpu); + ret = be_migrate_to_cpu(cpu); if (ret < 0) bail_out("could not migrate to target partition"); } diff --git a/bin/rtspin.c b/bin/rtspin.c index 657a94c..5f12930 100644 --- a/bin/rtspin.c +++ b/bin/rtspin.c @@ -321,7 +321,7 @@ int main(int argc, char** argv) duration += period_ms * 0.001 * (num_jobs - 1); if (migrate) { - ret = be_migrate_to(cpu); + ret = be_migrate_to_cpu(cpu); if (ret < 0) bail_out("could not migrate to target partition"); } diff --git a/include/litmus.h b/include/litmus.h index 58af6b7..b2e81f2 100644 --- a/include/litmus.h +++ b/include/litmus.h @@ -16,13 +16,7 @@ extern "C" { #include "asm/cycles.h" /* for null_call() */ -typedef int pid_t; /* PID of a task */ - -/* obtain the PID of a thread */ -pid_t gettid(void); - -/* migrate to partition */ -int be_migrate_to(int target_cpu); +#include "migration.h" int set_rt_task_param(pid_t pid, struct rt_task* param); int get_rt_task_param(pid_t pid, struct rt_task* param); diff --git a/include/migration.h b/include/migration.h new file mode 100644 index 0000000..2413e7c --- /dev/null +++ b/include/migration.h @@ -0,0 +1,24 @@ + +typedef int pid_t; + +/* obtain the PID of a thread */ +pid_t gettid(); + +/* Assign a task to a cpu/partition/cluster. + * PRECOND: tid is not yet in real-time mode (it's a best effort task). + * Set tid == 0 to migrate the caller */ +int be_migrate_thread_to_cpu(pid_t tid, int target_cpu); +int be_migrate_thread_to_partition(pid_t tid, int partition); +/* If using release master, set cluster_sz to size of largest cluster. tid + * will not be scheduled on release master. */ +int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz); + +/* set ignore_rm == 1 to include release master in tid's cpu affinity */ +int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz, int ignore_rm); + +int be_migrate_to_cpu(int target_cpu); +int be_migrate_to_partition(int partition); +int be_migrate_to_cluster(int cluster, int cluster_sz); + +int num_online_cpus(); +int release_master(); diff --git a/src/litmus.c b/src/litmus.c index e0d9253..b774c63 100644 --- a/src/litmus.c +++ b/src/litmus.c @@ -91,16 +91,6 @@ task_class_t str2class(const char* str) #define NS_PER_MS 1000000 -/* only for best-effort execution: migrate to target_cpu */ -int be_migrate_to(int target_cpu) -{ - cpu_set_t cpu_set; - - CPU_ZERO(&cpu_set); - CPU_SET(target_cpu, &cpu_set); - return sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set); -} - int sporadic_task(lt_t e, lt_t p, lt_t phase, int cpu, unsigned int priority, task_class_t cls, @@ -133,7 +123,7 @@ int sporadic_task_ns(lt_t e, lt_t p, lt_t phase, param.priority = priority; if (set_cpu_set) { - ret = be_migrate_to(cpu); + ret = be_migrate_to_cpu(cpu); check("migrate to cpu"); } return set_rt_task_param(gettid(), ¶m); diff --git a/src/migration.c b/src/migration.c new file mode 100644 index 0000000..152d81b --- /dev/null +++ b/src/migration.c @@ -0,0 +1,162 @@ +#include +#include +#include +#include /* for cpu sets */ +#include + +#include "migration.h" + +extern ssize_t read_file(const char* fname, void* buf, size_t maxlen); + +int release_master() +{ + static const char NO_CPU[] = "NO_CPU"; + char buf[5] = {0}; /* up to 9999 CPUs */ + int master = -1; + + int ret = read_file("/proc/litmus/release_master", &buf, sizeof(buf)-1); + + if ((ret > 0) && (strncmp(buf, NO_CPU, sizeof(NO_CPU)-1) != 0)) + master = atoi(buf); + + return master; +} + +int num_online_cpus() +{ + return sysconf(_SC_NPROCESSORS_ONLN); +} + +int partition_to_cpu(int partition) +{ + int cpu = partition; + int master = release_master(); + if (master != -1 && master <= cpu) { + ++cpu; /* skip over the release master */ + } + return cpu; +} + +int cluster_to_first_cpu(int cluster, int cluster_sz) +{ + int first_cpu; + int master; + + if (cluster_sz == 1) + return partition_to_cpu(cluster); + + master = release_master(); + first_cpu = cluster * cluster_sz; + + if (master == first_cpu) + ++first_cpu; + + return first_cpu; +} + +int be_migrate_thread_to_cpu(pid_t tid, int target_cpu) +{ + cpu_set_t *cpu_set; + size_t sz; + int num_cpus; + int ret; + + /* TODO: Error check to make sure that tid is not a real-time task. */ + + if (target_cpu < 0) + return -1; + + num_cpus = num_online_cpus(); + if (num_cpus == -1) + return -1; + + if (target_cpu >= num_cpus) + return -1; + + cpu_set = CPU_ALLOC(num_cpus); + sz = CPU_ALLOC_SIZE(num_cpus); + CPU_ZERO_S(sz, cpu_set); + CPU_SET_S(target_cpu, sz, cpu_set); + + /* apply to caller */ + if (tid == 0) + tid = gettid(); + + ret = sched_setaffinity(tid, sz, cpu_set); + + CPU_FREE(cpu_set); + + return ret; +} + +int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz) +{ + return __be_migrate_thread_to_cluster(tid, cluster, cluster_sz, 0); +} + +int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz, + int ignore_rm) +{ + int first_cpu = cluster * cluster_sz; /* first CPU in cluster */ + int last_cpu = first_cpu + cluster_sz - 1; + int master; + int num_cpus; + cpu_set_t *cpu_set; + size_t sz; + int i; + int ret; + + /* TODO: Error check to make sure that tid is not a real-time task. */ + + if (cluster_sz == 1) { + /* we're partitioned */ + return be_migrate_thread_to_partition(tid, cluster); + } + + master = (ignore_rm) ? -1 : release_master(); + num_cpus = num_online_cpus(); + + if (num_cpus == -1 || last_cpu >= num_cpus || first_cpu < 0) + return -1; + + cpu_set = CPU_ALLOC(num_cpus); + sz = CPU_ALLOC_SIZE(num_cpus); + CPU_ZERO_S(sz, cpu_set); + + for (i = first_cpu; i <= last_cpu; ++i) { + if (i != master) { + CPU_SET_S(i, sz, cpu_set); + } + } + + /* apply to caller */ + if (tid == 0) + tid = gettid(); + + ret = sched_setaffinity(tid, sz, cpu_set); + + CPU_FREE(cpu_set); + + return ret; +} + +int be_migrate_thread_to_partition(pid_t tid, int partition) +{ + return be_migrate_thread_to_cpu(tid, partition_to_cpu(partition)); +} + + +int be_migrate_to_cpu(int target_cpu) +{ + return be_migrate_thread_to_cpu(0, target_cpu); +} + +int be_migrate_to_cluster(int cluster, int cluster_sz) +{ + return be_migrate_thread_to_cluster(0, cluster, cluster_sz); +} + +int be_migrate_to_partition(int partition) +{ + return be_migrate_thread_to_partition(0, partition); +} diff --git a/tests/core_api.c b/tests/core_api.c index c0b291e..b57e278 100644 --- a/tests/core_api.c +++ b/tests/core_api.c @@ -61,7 +61,7 @@ TESTCASE(reject_bad_priorities, P_FP, params.cls = RT_CLASS_HARD; params.budget_policy = NO_ENFORCEMENT; - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); /* too high */ params.priority = 0; @@ -87,7 +87,7 @@ TESTCASE(accept_valid_priorities, P_FP, params.cls = RT_CLASS_HARD; params.budget_policy = NO_ENFORCEMENT; - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); /* acceptable */ params.priority = LITMUS_LOWEST_PRIORITY; diff --git a/tests/pcp.c b/tests/pcp.c index 8e1204f..cff4240 100644 --- a/tests/pcp.c +++ b/tests/pcp.c @@ -64,7 +64,7 @@ TESTCASE(pcp_inheritance, P_FP, params.priority = LITMUS_LOWEST_PRIORITY; params.phase = 0; SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); @@ -85,7 +85,7 @@ TESTCASE(pcp_inheritance, P_FP, params.phase = ms2lt(100); SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); @@ -102,7 +102,7 @@ TESTCASE(pcp_inheritance, P_FP, params.phase = ms2lt(50); SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); @@ -130,7 +130,7 @@ TESTCASE(pcp_inheritance, P_FP, ASSERT( waiters >= 0 ); } while (waiters != 3); - SYSCALL( be_migrate_to(1) ); + SYSCALL( be_migrate_to_cpu(1) ); waiters = release_ts(&delay); @@ -169,7 +169,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, params.priority = LITMUS_LOWEST_PRIORITY; params.phase = 0; SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); SYSCALL( od = open_srp_sem(fd, 0) ); @@ -189,7 +189,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, params.relative_deadline -= ms2lt(110); SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); @@ -206,7 +206,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, params.relative_deadline -= ms2lt(200); SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); SYSCALL( od = open_srp_sem(fd, 0) ); @@ -231,7 +231,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, ASSERT( waiters >= 0 ); } while (waiters != 3); - SYSCALL( be_migrate_to(1) ); + SYSCALL( be_migrate_to_cpu(1) ); waiters = release_ts(&delay); diff --git a/tests/sched.c b/tests/sched.c index ab47a91..713fde2 100644 --- a/tests/sched.c +++ b/tests/sched.c @@ -24,7 +24,7 @@ TESTCASE(preempt_on_resume, P_FP | PSN_EDF, child_lo = FORK_TASK( params.priority = LITMUS_LOWEST_PRIORITY; SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); SYSCALL( wait_for_ts_release() ); @@ -40,7 +40,7 @@ TESTCASE(preempt_on_resume, P_FP | PSN_EDF, params.priority = LITMUS_HIGHEST_PRIORITY; params.relative_deadline -= 1000000; SYSCALL( set_rt_task_param(gettid(), ¶ms) ); - SYSCALL( be_migrate_to(params.cpu) ); + SYSCALL( be_migrate_to_cpu(params.cpu) ); SYSCALL( task_mode(LITMUS_RT_TASK) ); SYSCALL( wait_for_ts_release() ); -- cgit v1.2.2