diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-12 11:57:42 -0400 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-12 12:02:20 -0400 |
| commit | 93ffe5be8fd1954bbfe5a04e55b81ac1d83d2de7 (patch) | |
| tree | d77875e14dd822680ed168816286d994d2d3d93e /src | |
| parent | 1ff4fc699f01f0ad1359fad48b00c9d3be1b28b4 (diff) | |
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().)
Diffstat (limited to 'src')
| -rw-r--r-- | src/litmus.c | 12 | ||||
| -rw-r--r-- | src/migration.c | 162 |
2 files changed, 163 insertions, 11 deletions
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) | |||
| 91 | 91 | ||
| 92 | #define NS_PER_MS 1000000 | 92 | #define NS_PER_MS 1000000 |
| 93 | 93 | ||
| 94 | /* only for best-effort execution: migrate to target_cpu */ | ||
| 95 | int be_migrate_to(int target_cpu) | ||
| 96 | { | ||
| 97 | cpu_set_t cpu_set; | ||
| 98 | |||
| 99 | CPU_ZERO(&cpu_set); | ||
| 100 | CPU_SET(target_cpu, &cpu_set); | ||
| 101 | return sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set); | ||
| 102 | } | ||
| 103 | |||
| 104 | int sporadic_task(lt_t e, lt_t p, lt_t phase, | 94 | int sporadic_task(lt_t e, lt_t p, lt_t phase, |
| 105 | int cpu, unsigned int priority, | 95 | int cpu, unsigned int priority, |
| 106 | task_class_t cls, | 96 | task_class_t cls, |
| @@ -133,7 +123,7 @@ int sporadic_task_ns(lt_t e, lt_t p, lt_t phase, | |||
| 133 | param.priority = priority; | 123 | param.priority = priority; |
| 134 | 124 | ||
| 135 | if (set_cpu_set) { | 125 | if (set_cpu_set) { |
| 136 | ret = be_migrate_to(cpu); | 126 | ret = be_migrate_to_cpu(cpu); |
| 137 | check("migrate to cpu"); | 127 | check("migrate to cpu"); |
| 138 | } | 128 | } |
| 139 | return set_rt_task_param(gettid(), ¶m); | 129 | 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 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include <sched.h> /* for cpu sets */ | ||
| 5 | #include <unistd.h> | ||
| 6 | |||
| 7 | #include "migration.h" | ||
| 8 | |||
| 9 | extern ssize_t read_file(const char* fname, void* buf, size_t maxlen); | ||
| 10 | |||
| 11 | int release_master() | ||
| 12 | { | ||
| 13 | static const char NO_CPU[] = "NO_CPU"; | ||
| 14 | char buf[5] = {0}; /* up to 9999 CPUs */ | ||
| 15 | int master = -1; | ||
| 16 | |||
| 17 | int ret = read_file("/proc/litmus/release_master", &buf, sizeof(buf)-1); | ||
| 18 | |||
| 19 | if ((ret > 0) && (strncmp(buf, NO_CPU, sizeof(NO_CPU)-1) != 0)) | ||
| 20 | master = atoi(buf); | ||
| 21 | |||
| 22 | return master; | ||
| 23 | } | ||
| 24 | |||
| 25 | int num_online_cpus() | ||
| 26 | { | ||
| 27 | return sysconf(_SC_NPROCESSORS_ONLN); | ||
| 28 | } | ||
| 29 | |||
| 30 | int partition_to_cpu(int partition) | ||
| 31 | { | ||
| 32 | int cpu = partition; | ||
| 33 | int master = release_master(); | ||
| 34 | if (master != -1 && master <= cpu) { | ||
| 35 | ++cpu; /* skip over the release master */ | ||
| 36 | } | ||
| 37 | return cpu; | ||
| 38 | } | ||
| 39 | |||
| 40 | int cluster_to_first_cpu(int cluster, int cluster_sz) | ||
| 41 | { | ||
| 42 | int first_cpu; | ||
| 43 | int master; | ||
| 44 | |||
| 45 | if (cluster_sz == 1) | ||
| 46 | return partition_to_cpu(cluster); | ||
| 47 | |||
| 48 | master = release_master(); | ||
| 49 | first_cpu = cluster * cluster_sz; | ||
| 50 | |||
| 51 | if (master == first_cpu) | ||
| 52 | ++first_cpu; | ||
| 53 | |||
| 54 | return first_cpu; | ||
| 55 | } | ||
| 56 | |||
| 57 | int be_migrate_thread_to_cpu(pid_t tid, int target_cpu) | ||
| 58 | { | ||
| 59 | cpu_set_t *cpu_set; | ||
| 60 | size_t sz; | ||
| 61 | int num_cpus; | ||
| 62 | int ret; | ||
| 63 | |||
| 64 | /* TODO: Error check to make sure that tid is not a real-time task. */ | ||
| 65 | |||
| 66 | if (target_cpu < 0) | ||
| 67 | return -1; | ||
| 68 | |||
| 69 | num_cpus = num_online_cpus(); | ||
| 70 | if (num_cpus == -1) | ||
| 71 | return -1; | ||
| 72 | |||
| 73 | if (target_cpu >= num_cpus) | ||
| 74 | return -1; | ||
| 75 | |||
| 76 | cpu_set = CPU_ALLOC(num_cpus); | ||
| 77 | sz = CPU_ALLOC_SIZE(num_cpus); | ||
| 78 | CPU_ZERO_S(sz, cpu_set); | ||
| 79 | CPU_SET_S(target_cpu, sz, cpu_set); | ||
| 80 | |||
| 81 | /* apply to caller */ | ||
| 82 | if (tid == 0) | ||
| 83 | tid = gettid(); | ||
| 84 | |||
| 85 | ret = sched_setaffinity(tid, sz, cpu_set); | ||
| 86 | |||
| 87 | CPU_FREE(cpu_set); | ||
| 88 | |||
| 89 | return ret; | ||
| 90 | } | ||
| 91 | |||
| 92 | int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz) | ||
| 93 | { | ||
| 94 | return __be_migrate_thread_to_cluster(tid, cluster, cluster_sz, 0); | ||
| 95 | } | ||
| 96 | |||
| 97 | int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz, | ||
| 98 | int ignore_rm) | ||
| 99 | { | ||
| 100 | int first_cpu = cluster * cluster_sz; /* first CPU in cluster */ | ||
| 101 | int last_cpu = first_cpu + cluster_sz - 1; | ||
| 102 | int master; | ||
| 103 | int num_cpus; | ||
| 104 | cpu_set_t *cpu_set; | ||
| 105 | size_t sz; | ||
| 106 | int i; | ||
| 107 | int ret; | ||
| 108 | |||
| 109 | /* TODO: Error check to make sure that tid is not a real-time task. */ | ||
| 110 | |||
| 111 | if (cluster_sz == 1) { | ||
| 112 | /* we're partitioned */ | ||
| 113 | return be_migrate_thread_to_partition(tid, cluster); | ||
| 114 | } | ||
| 115 | |||
| 116 | master = (ignore_rm) ? -1 : release_master(); | ||
| 117 | num_cpus = num_online_cpus(); | ||
| 118 | |||
| 119 | if (num_cpus == -1 || last_cpu >= num_cpus || first_cpu < 0) | ||
| 120 | return -1; | ||
| 121 | |||
| 122 | cpu_set = CPU_ALLOC(num_cpus); | ||
| 123 | sz = CPU_ALLOC_SIZE(num_cpus); | ||
| 124 | CPU_ZERO_S(sz, cpu_set); | ||
| 125 | |||
| 126 | for (i = first_cpu; i <= last_cpu; ++i) { | ||
| 127 | if (i != master) { | ||
| 128 | CPU_SET_S(i, sz, cpu_set); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | /* apply to caller */ | ||
| 133 | if (tid == 0) | ||
| 134 | tid = gettid(); | ||
| 135 | |||
| 136 | ret = sched_setaffinity(tid, sz, cpu_set); | ||
| 137 | |||
| 138 | CPU_FREE(cpu_set); | ||
| 139 | |||
| 140 | return ret; | ||
| 141 | } | ||
| 142 | |||
| 143 | int be_migrate_thread_to_partition(pid_t tid, int partition) | ||
| 144 | { | ||
| 145 | return be_migrate_thread_to_cpu(tid, partition_to_cpu(partition)); | ||
| 146 | } | ||
| 147 | |||
| 148 | |||
| 149 | int be_migrate_to_cpu(int target_cpu) | ||
| 150 | { | ||
| 151 | return be_migrate_thread_to_cpu(0, target_cpu); | ||
| 152 | } | ||
| 153 | |||
| 154 | int be_migrate_to_cluster(int cluster, int cluster_sz) | ||
| 155 | { | ||
| 156 | return be_migrate_thread_to_cluster(0, cluster, cluster_sz); | ||
| 157 | } | ||
| 158 | |||
| 159 | int be_migrate_to_partition(int partition) | ||
| 160 | { | ||
| 161 | return be_migrate_thread_to_partition(0, partition); | ||
| 162 | } | ||
