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().) --- src/litmus.c | 12 +---- src/migration.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 11 deletions(-) create mode 100644 src/migration.c (limited to 'src') 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); +} -- cgit v1.2.2