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 | |
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().)
-rw-r--r-- | bin/rt_launch.c | 2 | ||||
-rw-r--r-- | bin/rtspin.c | 2 | ||||
-rw-r--r-- | include/litmus.h | 8 | ||||
-rw-r--r-- | include/migration.h | 24 | ||||
-rw-r--r-- | src/litmus.c | 12 | ||||
-rw-r--r-- | src/migration.c | 162 | ||||
-rw-r--r-- | tests/core_api.c | 4 | ||||
-rw-r--r-- | tests/pcp.c | 16 | ||||
-rw-r--r-- | tests/sched.c | 4 |
9 files changed, 202 insertions, 32 deletions
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) | |||
109 | info.argv = argv + optind + 2; | 109 | info.argv = argv + optind + 2; |
110 | info.wait = wait; | 110 | info.wait = wait; |
111 | if (migrate) { | 111 | if (migrate) { |
112 | ret = be_migrate_to(cpu); | 112 | ret = be_migrate_to_cpu(cpu); |
113 | if (ret < 0) | 113 | if (ret < 0) |
114 | bail_out("could not migrate to target partition"); | 114 | bail_out("could not migrate to target partition"); |
115 | } | 115 | } |
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) | |||
321 | duration += period_ms * 0.001 * (num_jobs - 1); | 321 | duration += period_ms * 0.001 * (num_jobs - 1); |
322 | 322 | ||
323 | if (migrate) { | 323 | if (migrate) { |
324 | ret = be_migrate_to(cpu); | 324 | ret = be_migrate_to_cpu(cpu); |
325 | if (ret < 0) | 325 | if (ret < 0) |
326 | bail_out("could not migrate to target partition"); | 326 | bail_out("could not migrate to target partition"); |
327 | } | 327 | } |
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" { | |||
16 | 16 | ||
17 | #include "asm/cycles.h" /* for null_call() */ | 17 | #include "asm/cycles.h" /* for null_call() */ |
18 | 18 | ||
19 | typedef int pid_t; /* PID of a task */ | 19 | #include "migration.h" |
20 | |||
21 | /* obtain the PID of a thread */ | ||
22 | pid_t gettid(void); | ||
23 | |||
24 | /* migrate to partition */ | ||
25 | int be_migrate_to(int target_cpu); | ||
26 | 20 | ||
27 | int set_rt_task_param(pid_t pid, struct rt_task* param); | 21 | int set_rt_task_param(pid_t pid, struct rt_task* param); |
28 | int get_rt_task_param(pid_t pid, struct rt_task* param); | 22 | 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 @@ | |||
1 | |||
2 | typedef int pid_t; | ||
3 | |||
4 | /* obtain the PID of a thread */ | ||
5 | pid_t gettid(); | ||
6 | |||
7 | /* Assign a task to a cpu/partition/cluster. | ||
8 | * PRECOND: tid is not yet in real-time mode (it's a best effort task). | ||
9 | * Set tid == 0 to migrate the caller */ | ||
10 | int be_migrate_thread_to_cpu(pid_t tid, int target_cpu); | ||
11 | int be_migrate_thread_to_partition(pid_t tid, int partition); | ||
12 | /* If using release master, set cluster_sz to size of largest cluster. tid | ||
13 | * will not be scheduled on release master. */ | ||
14 | int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz); | ||
15 | |||
16 | /* set ignore_rm == 1 to include release master in tid's cpu affinity */ | ||
17 | int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz, int ignore_rm); | ||
18 | |||
19 | int be_migrate_to_cpu(int target_cpu); | ||
20 | int be_migrate_to_partition(int partition); | ||
21 | int be_migrate_to_cluster(int cluster, int cluster_sz); | ||
22 | |||
23 | int num_online_cpus(); | ||
24 | 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) | |||
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 | } | ||
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, | |||
61 | params.cls = RT_CLASS_HARD; | 61 | params.cls = RT_CLASS_HARD; |
62 | params.budget_policy = NO_ENFORCEMENT; | 62 | params.budget_policy = NO_ENFORCEMENT; |
63 | 63 | ||
64 | SYSCALL( be_migrate_to(params.cpu) ); | 64 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
65 | 65 | ||
66 | /* too high */ | 66 | /* too high */ |
67 | params.priority = 0; | 67 | params.priority = 0; |
@@ -87,7 +87,7 @@ TESTCASE(accept_valid_priorities, P_FP, | |||
87 | params.cls = RT_CLASS_HARD; | 87 | params.cls = RT_CLASS_HARD; |
88 | params.budget_policy = NO_ENFORCEMENT; | 88 | params.budget_policy = NO_ENFORCEMENT; |
89 | 89 | ||
90 | SYSCALL( be_migrate_to(params.cpu) ); | 90 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
91 | 91 | ||
92 | /* acceptable */ | 92 | /* acceptable */ |
93 | params.priority = LITMUS_LOWEST_PRIORITY; | 93 | 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, | |||
64 | params.priority = LITMUS_LOWEST_PRIORITY; | 64 | params.priority = LITMUS_LOWEST_PRIORITY; |
65 | params.phase = 0; | 65 | params.phase = 0; |
66 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 66 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
67 | SYSCALL( be_migrate_to(params.cpu) ); | 67 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
68 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 68 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
69 | 69 | ||
70 | SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); | 70 | SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); |
@@ -85,7 +85,7 @@ TESTCASE(pcp_inheritance, P_FP, | |||
85 | params.phase = ms2lt(100); | 85 | params.phase = ms2lt(100); |
86 | 86 | ||
87 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 87 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
88 | SYSCALL( be_migrate_to(params.cpu) ); | 88 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
89 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 89 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
90 | 90 | ||
91 | 91 | ||
@@ -102,7 +102,7 @@ TESTCASE(pcp_inheritance, P_FP, | |||
102 | params.phase = ms2lt(50); | 102 | params.phase = ms2lt(50); |
103 | 103 | ||
104 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 104 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
105 | SYSCALL( be_migrate_to(params.cpu) ); | 105 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
106 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 106 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
107 | 107 | ||
108 | SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); | 108 | SYSCALL( od = open_pcp_sem(fd, 0, cpu) ); |
@@ -130,7 +130,7 @@ TESTCASE(pcp_inheritance, P_FP, | |||
130 | ASSERT( waiters >= 0 ); | 130 | ASSERT( waiters >= 0 ); |
131 | } while (waiters != 3); | 131 | } while (waiters != 3); |
132 | 132 | ||
133 | SYSCALL( be_migrate_to(1) ); | 133 | SYSCALL( be_migrate_to_cpu(1) ); |
134 | 134 | ||
135 | waiters = release_ts(&delay); | 135 | waiters = release_ts(&delay); |
136 | 136 | ||
@@ -169,7 +169,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, | |||
169 | params.priority = LITMUS_LOWEST_PRIORITY; | 169 | params.priority = LITMUS_LOWEST_PRIORITY; |
170 | params.phase = 0; | 170 | params.phase = 0; |
171 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 171 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
172 | SYSCALL( be_migrate_to(params.cpu) ); | 172 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
173 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 173 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
174 | 174 | ||
175 | SYSCALL( od = open_srp_sem(fd, 0) ); | 175 | SYSCALL( od = open_srp_sem(fd, 0) ); |
@@ -189,7 +189,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, | |||
189 | params.relative_deadline -= ms2lt(110); | 189 | params.relative_deadline -= ms2lt(110); |
190 | 190 | ||
191 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 191 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
192 | SYSCALL( be_migrate_to(params.cpu) ); | 192 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
193 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 193 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
194 | 194 | ||
195 | 195 | ||
@@ -206,7 +206,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, | |||
206 | params.relative_deadline -= ms2lt(200); | 206 | params.relative_deadline -= ms2lt(200); |
207 | 207 | ||
208 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 208 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
209 | SYSCALL( be_migrate_to(params.cpu) ); | 209 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
210 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 210 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
211 | 211 | ||
212 | SYSCALL( od = open_srp_sem(fd, 0) ); | 212 | SYSCALL( od = open_srp_sem(fd, 0) ); |
@@ -231,7 +231,7 @@ TESTCASE(srp_ceiling_blocking, P_FP | PSN_EDF, | |||
231 | ASSERT( waiters >= 0 ); | 231 | ASSERT( waiters >= 0 ); |
232 | } while (waiters != 3); | 232 | } while (waiters != 3); |
233 | 233 | ||
234 | SYSCALL( be_migrate_to(1) ); | 234 | SYSCALL( be_migrate_to_cpu(1) ); |
235 | 235 | ||
236 | waiters = release_ts(&delay); | 236 | waiters = release_ts(&delay); |
237 | 237 | ||
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, | |||
24 | child_lo = FORK_TASK( | 24 | child_lo = FORK_TASK( |
25 | params.priority = LITMUS_LOWEST_PRIORITY; | 25 | params.priority = LITMUS_LOWEST_PRIORITY; |
26 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 26 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
27 | SYSCALL( be_migrate_to(params.cpu) ); | 27 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
28 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 28 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
29 | 29 | ||
30 | SYSCALL( wait_for_ts_release() ); | 30 | SYSCALL( wait_for_ts_release() ); |
@@ -40,7 +40,7 @@ TESTCASE(preempt_on_resume, P_FP | PSN_EDF, | |||
40 | params.priority = LITMUS_HIGHEST_PRIORITY; | 40 | params.priority = LITMUS_HIGHEST_PRIORITY; |
41 | params.relative_deadline -= 1000000; | 41 | params.relative_deadline -= 1000000; |
42 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); | 42 | SYSCALL( set_rt_task_param(gettid(), ¶ms) ); |
43 | SYSCALL( be_migrate_to(params.cpu) ); | 43 | SYSCALL( be_migrate_to_cpu(params.cpu) ); |
44 | SYSCALL( task_mode(LITMUS_RT_TASK) ); | 44 | SYSCALL( task_mode(LITMUS_RT_TASK) ); |
45 | 45 | ||
46 | SYSCALL( wait_for_ts_release() ); | 46 | SYSCALL( wait_for_ts_release() ); |