diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-13 17:24:27 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-13 17:24:27 -0400 |
commit | 020dc974933f4e9459f699625a138c33811eadf6 (patch) | |
tree | d45dbe70b7fc3ce0655baeda609ad452a2840ac2 /src | |
parent | 944a78c21028da69fb53c0aec3e9dfdb048d47e4 (diff) | |
parent | 0e71f86251307a37161cf3de2704a59882e25258 (diff) |
Merge branch 'prop/rt_task-init-final' into temp
Conflicts:
bin/base_mt_task.c
bin/rt_launch.c
bin/rtspin.c
include/litmus.h
src/litmus.c
src/task.c
Diffstat (limited to 'src')
-rw-r--r-- | src/litmus.c | 103 | ||||
-rw-r--r-- | src/migration.c | 162 | ||||
-rw-r--r-- | src/task.c | 15 |
3 files changed, 233 insertions, 47 deletions
diff --git a/src/litmus.c b/src/litmus.c index 7cdffcc..213ac3f 100644 --- a/src/litmus.c +++ b/src/litmus.c | |||
@@ -88,6 +88,34 @@ void show_rt_param(struct rt_task* tp) | |||
88 | tp->exec_cost, tp->period, tp->cpu); | 88 | tp->exec_cost, tp->period, tp->cpu); |
89 | } | 89 | } |
90 | 90 | ||
91 | void init_rt_task_param(struct rt_task* tp) | ||
92 | { | ||
93 | /* Defaults: | ||
94 | * - implicit deadline (t->relative_deadline == 0) | ||
95 | * - phase = 0 | ||
96 | * - class = RT_CLASS_SOFT | ||
97 | * - budget policy = NO_ENFORCEMENT | ||
98 | * - fixed priority = LITMUS_LOWEST_PRIORITY | ||
99 | * - release policy = SPORADIC | ||
100 | * - cpu assignment = 0 | ||
101 | * | ||
102 | * User must still set the following fields to non-zero values: | ||
103 | * - tp->exec_cost | ||
104 | * - tp->period | ||
105 | * | ||
106 | * User must set tp->cpu to the appropriate value for non-global | ||
107 | * schedulers. For clusters, set tp->cpu to the first CPU in the | ||
108 | * assigned cluster. | ||
109 | */ | ||
110 | |||
111 | memset(tp, 0, sizeof(*tp)); | ||
112 | |||
113 | tp->cls = RT_CLASS_SOFT; | ||
114 | tp->priority = LITMUS_LOWEST_PRIORITY; | ||
115 | tp->budget_policy = NO_ENFORCEMENT; | ||
116 | tp->release_policy = SPORADIC; | ||
117 | } | ||
118 | |||
91 | task_class_t str2class(const char* str) | 119 | task_class_t str2class(const char* str) |
92 | { | 120 | { |
93 | if (!strcmp(str, "hrt")) | 121 | if (!strcmp(str, "hrt")) |
@@ -102,57 +130,50 @@ task_class_t str2class(const char* str) | |||
102 | 130 | ||
103 | #define NS_PER_MS 1000000 | 131 | #define NS_PER_MS 1000000 |
104 | 132 | ||
105 | /* only for best-effort execution: migrate to target_cpu */ | 133 | int sporadic_global(lt_t e_ns, lt_t p_ns) |
106 | int be_migrate_to(int target_cpu) | ||
107 | { | 134 | { |
108 | cpu_set_t cpu_set; | 135 | struct rt_task param; |
136 | |||
137 | init_rt_task_param(¶m); | ||
138 | param.exec_cost = e_ns; | ||
139 | param.period = p_ns; | ||
109 | 140 | ||
110 | CPU_ZERO(&cpu_set); | 141 | return set_rt_task_param(gettid(), ¶m); |
111 | CPU_SET(target_cpu, &cpu_set); | ||
112 | return sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set); | ||
113 | } | 142 | } |
114 | 143 | ||
115 | int sporadic_task(lt_t e, lt_t p, lt_t phase, | 144 | int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition) |
116 | int cpu, unsigned int priority, | ||
117 | task_class_t cls, | ||
118 | budget_policy_t budget_policy, | ||
119 | budget_signal_policy_t budget_signal_policy, | ||
120 | int set_cpu_set) | ||
121 | { | 145 | { |
122 | return sporadic_task_ns(e * NS_PER_MS, p * NS_PER_MS, phase * NS_PER_MS, | 146 | int ret; |
123 | cpu, priority, cls, budget_policy, budget_signal_policy, | 147 | struct rt_task param; |
124 | set_cpu_set); | 148 | |
149 | ret = be_migrate_to_partition(partition); | ||
150 | check("be_migrate_to_partition()"); | ||
151 | if (ret != 0) | ||
152 | return ret; | ||
153 | |||
154 | init_rt_task_param(¶m); | ||
155 | param.exec_cost = e_ns; | ||
156 | param.period = p_ns; | ||
157 | param.cpu = partition_to_cpu(partition); | ||
158 | |||
159 | return set_rt_task_param(gettid(), ¶m); | ||
125 | } | 160 | } |
126 | 161 | ||
127 | int sporadic_task_ns(lt_t e, lt_t p, lt_t phase, | 162 | int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size) |
128 | int cpu, unsigned int priority, | ||
129 | task_class_t cls, | ||
130 | budget_policy_t budget_policy, | ||
131 | budget_signal_policy_t budget_signal_policy, | ||
132 | int set_cpu_set) | ||
133 | { | 163 | { |
134 | struct rt_task param; | ||
135 | int ret; | 164 | int ret; |
165 | struct rt_task param; | ||
166 | |||
167 | ret = be_migrate_to_cluster(cluster, cluster_size); | ||
168 | check("be_migrate_to_cluster()"); | ||
169 | if (ret != 0) | ||
170 | return ret; | ||
171 | |||
172 | init_rt_task_param(¶m); | ||
173 | param.exec_cost = e_ns; | ||
174 | param.period = p_ns; | ||
175 | param.cpu = cluster_to_first_cpu(cluster, cluster_size); | ||
136 | 176 | ||
137 | /* Zero out first --- this is helpful when we add plugin-specific | ||
138 | * parameters during development. | ||
139 | */ | ||
140 | memset(¶m, 0, sizeof(param)); | ||
141 | |||
142 | param.exec_cost = e; | ||
143 | param.period = p; | ||
144 | param.relative_deadline = p; /* implicit deadline */ | ||
145 | param.cpu = cpu; | ||
146 | param.cls = cls; | ||
147 | param.phase = phase; | ||
148 | param.budget_policy = budget_policy; | ||
149 | param.budget_signal_policy = budget_signal_policy; | ||
150 | param.priority = priority; | ||
151 | |||
152 | if (set_cpu_set) { | ||
153 | ret = be_migrate_to(cpu); | ||
154 | check("migrate to cpu"); | ||
155 | } | ||
156 | return set_rt_task_param(gettid(), ¶m); | 177 | return set_rt_task_param(gettid(), ¶m); |
157 | } | 178 | } |
158 | 179 | ||
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 | } | ||
@@ -40,11 +40,12 @@ int __launch_rt_task(rt_fn_t rt_prog, void *rt_arg, rt_setup_fn_t setup, | |||
40 | return rt_task; | 40 | return rt_task; |
41 | } | 41 | } |
42 | 42 | ||
43 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, lt_t wcet, lt_t period, | 43 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, |
44 | unsigned int priority, task_class_t cls) | 44 | lt_t wcet, lt_t period, unsigned int priority, task_class_t cls) |
45 | { | 45 | { |
46 | struct rt_task params; | 46 | struct rt_task params; |
47 | params.cpu = cpu; | 47 | init_rt_task_param(¶ms); |
48 | params.cpu = cluster_to_first_cpu(cluster, cluster_size); | ||
48 | params.period = period; | 49 | params.period = period; |
49 | params.exec_cost = wcet; | 50 | params.exec_cost = wcet; |
50 | params.cls = cls; | 51 | params.cls = cls; |
@@ -57,9 +58,11 @@ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, lt_t wcet, lt_t period | |||
57 | (rt_setup_fn_t) set_rt_task_param, ¶ms); | 58 | (rt_setup_fn_t) set_rt_task_param, ¶ms); |
58 | } | 59 | } |
59 | 60 | ||
60 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cpu, lt_t wcet, lt_t period, | 61 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, |
61 | unsigned int priority) { | 62 | lt_t wcet, lt_t period, unsigned int prio) |
62 | return __create_rt_task(rt_prog, arg, cpu, wcet, period, priority, RT_CLASS_HARD); | 63 | { |
64 | return __create_rt_task(rt_prog, arg, cluster, cluster_size, wcet, period, | ||
65 | prio, RT_CLASS_HARD); | ||
63 | } | 66 | } |
64 | 67 | ||
65 | 68 | ||