aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2014-02-05 00:31:08 -0500
committerBjoern Brandenburg <bbb@mpi-sws.org>2014-02-24 14:01:11 -0500
commit1f323b00f95c4704cdeea7918853f1e9e8d26c2e (patch)
tree76a6856b2465ba7d114009f231c0dae9c9e5ef2c /src
parent871eef081ff9db7289a6947d0160cd984232c34c (diff)
Use /proc/litmus/domains to set up affinity masks
This patch replaces the algorithm used to compute CPU affinity masks. The old algorithm was fragile and would break on systems with multiple levels of shared caches. (As found on some older Intel chips, and as one would probably find on a system with hyper-threading enabled.) The bug stems from fact that Linux enumerates consecutive CPUs in a way that distributes them across the physical system, thereby reducing contention resources (e.g., cache). Cluster size no longer needs to be provided now that cluster/CPU mappings are explicit in /proc/litmus/domains/. This keeps the following migration functions, but marks them as deprecated: - be_migrate_to_cluster() - cluster_to_first_cpu() - partition_to_cpu() Although the deprecated interfaces are supported, the implementations for these functions call the new be_migrate_to_domain() and domain_to_first_cpu() functions. [bbb: resolved several merge conflicts]
Diffstat (limited to 'src')
-rw-r--r--src/litmus.c10
-rw-r--r--src/migration.c113
-rw-r--r--src/task.c8
3 files changed, 70 insertions, 61 deletions
diff --git a/src/litmus.c b/src/litmus.c
index dce8e1b..4631eea 100644
--- a/src/litmus.c
+++ b/src/litmus.c
@@ -135,7 +135,7 @@ int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition)
135 int ret; 135 int ret;
136 struct rt_task param; 136 struct rt_task param;
137 137
138 ret = be_migrate_to_partition(partition); 138 ret = be_migrate_to_domain(partition);
139 check("be_migrate_to_partition()"); 139 check("be_migrate_to_partition()");
140 if (ret != 0) 140 if (ret != 0)
141 return ret; 141 return ret;
@@ -143,17 +143,17 @@ int sporadic_partitioned(lt_t e_ns, lt_t p_ns, int partition)
143 init_rt_task_param(&param); 143 init_rt_task_param(&param);
144 param.exec_cost = e_ns; 144 param.exec_cost = e_ns;
145 param.period = p_ns; 145 param.period = p_ns;
146 param.cpu = partition_to_cpu(partition); 146 param.cpu = domain_to_first_cpu(partition);
147 147
148 return set_rt_task_param(gettid(), &param); 148 return set_rt_task_param(gettid(), &param);
149} 149}
150 150
151int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size) 151int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster)
152{ 152{
153 int ret; 153 int ret;
154 struct rt_task param; 154 struct rt_task param;
155 155
156 ret = be_migrate_to_cluster(cluster, cluster_size); 156 ret = be_migrate_to_domain(cluster);
157 check("be_migrate_to_cluster()"); 157 check("be_migrate_to_cluster()");
158 if (ret != 0) 158 if (ret != 0)
159 return ret; 159 return ret;
@@ -161,7 +161,7 @@ int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size)
161 init_rt_task_param(&param); 161 init_rt_task_param(&param);
162 param.exec_cost = e_ns; 162 param.exec_cost = e_ns;
163 param.period = p_ns; 163 param.period = p_ns;
164 param.cpu = cluster_to_first_cpu(cluster, cluster_size); 164 param.cpu = domain_to_first_cpu(cluster);
165 165
166 return set_rt_task_param(gettid(), &param); 166 return set_rt_task_param(gettid(), &param);
167} 167}
diff --git a/src/migration.c b/src/migration.c
index 5de81d5..3bd6d0a 100644
--- a/src/migration.c
+++ b/src/migration.c
@@ -27,31 +27,48 @@ int num_online_cpus()
27 return sysconf(_SC_NPROCESSORS_ONLN); 27 return sysconf(_SC_NPROCESSORS_ONLN);
28} 28}
29 29
30int partition_to_cpu(int partition) 30static int read_mapping(int idx, const char* which, unsigned long long int* mask)
31{ 31{
32 int cpu = partition; 32 int ret = -1;
33 int master = release_master(); 33 char buf[129] = {0};
34 if (master != -1 && master <= cpu) { 34 char fname[80] = {0};
35 ++cpu; /* skip over the release master */ 35
36 if (num_online_cpus() > 64) {
37 /* XXX: Support more than 64 CPUs.
38 * User can still set appropriate values directly. */
39 goto out;
36 } 40 }
37 return cpu;
38}
39 41
40int cluster_to_first_cpu(int cluster, int cluster_sz) 42 snprintf(fname, sizeof(fname), "/proc/litmus/%s/%d", which, idx);
41{ 43
42 int first_cpu; 44 ret = read_file(fname, &buf, sizeof(buf)-1);
43 int master; 45 if (ret <= 0)
46 goto out;
44 47
45 if (cluster_sz == 1) 48 *mask = strtoull(buf, NULL, 16);
46 return partition_to_cpu(cluster); 49 ret = 0;
47 50
48 master = release_master(); 51out:
49 first_cpu = cluster * cluster_sz; 52 return ret;
53}
54
55int domain_to_cpus(int domain, unsigned long long int* mask)
56{
57 return read_mapping(domain, "domains", mask);
58}
50 59
51 if (master == first_cpu) 60int cpu_to_domains(int cpu, unsigned long long int* mask)
52 ++first_cpu; 61{
62 return read_mapping(cpu, "cpus", mask);
63}
53 64
54 return first_cpu; 65int domain_to_first_cpu(int domain)
66{
67 unsigned long long int mask;
68 int ret = domain_to_cpus(domain, &mask);
69 if(ret == 0)
70 return (ffsll(mask)-1);
71 return ret;
55} 72}
56 73
57int be_migrate_thread_to_cpu(pid_t tid, int target_cpu) 74int be_migrate_thread_to_cpu(pid_t tid, int target_cpu)
@@ -89,44 +106,29 @@ int be_migrate_thread_to_cpu(pid_t tid, int target_cpu)
89 return ret; 106 return ret;
90} 107}
91 108
92int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz) 109int be_migrate_thread_to_domain(pid_t tid, int domain)
93{
94 return __be_migrate_thread_to_cluster(tid, cluster, cluster_sz, 0);
95}
96
97int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz,
98 int ignore_rm)
99{ 110{
100 int first_cpu = cluster * cluster_sz; /* first CPU in cluster */ 111 int ret, num_cpus;
101 int last_cpu = first_cpu + cluster_sz - 1;
102 int master;
103 int num_cpus;
104 cpu_set_t *cpu_set; 112 cpu_set_t *cpu_set;
105 size_t sz; 113 size_t sz;
106 int i; 114 unsigned long long int mask;
107 int ret;
108
109 /* TODO: Error check to make sure that tid is not a real-time task. */
110 115
111 if (cluster_sz == 1) { 116 ret = domain_to_cpus(domain, &mask);
112 /* we're partitioned */ 117 if (ret != 0)
113 return be_migrate_thread_to_partition(tid, cluster); 118 return ret;
114 }
115 119
116 master = (ignore_rm) ? -1 : release_master();
117 num_cpus = num_online_cpus(); 120 num_cpus = num_online_cpus();
118 121 if (num_cpus == -1)
119 if (num_cpus == -1 || last_cpu >= num_cpus || first_cpu < 0)
120 return -1; 122 return -1;
121 123
122 cpu_set = CPU_ALLOC(num_cpus); 124 cpu_set = CPU_ALLOC(num_cpus);
123 sz = CPU_ALLOC_SIZE(num_cpus); 125 sz = CPU_ALLOC_SIZE(num_cpus);
124 CPU_ZERO_S(sz, cpu_set); 126 CPU_ZERO_S(sz, cpu_set);
125 127
126 for (i = first_cpu; i <= last_cpu; ++i) { 128 while(mask) {
127 if (i != master) { 129 int idx = ffsll(mask) - 1;
128 CPU_SET_S(i, sz, cpu_set); 130 CPU_SET_S(idx, sz, cpu_set);
129 } 131 mask &= ~(1ull<<idx);
130 } 132 }
131 133
132 /* apply to caller */ 134 /* apply to caller */
@@ -140,23 +142,30 @@ int __be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz,
140 return ret; 142 return ret;
141} 143}
142 144
143int be_migrate_thread_to_partition(pid_t tid, int partition) 145int be_migrate_to_cpu(int target_cpu)
146{
147 return be_migrate_thread_to_cpu(0, target_cpu);
148}
149
150int be_migrate_to_domain(int domain)
144{ 151{
145 return be_migrate_thread_to_cpu(tid, partition_to_cpu(partition)); 152 return be_migrate_thread_to_domain(0, domain);
146} 153}
147 154
148 155
149int be_migrate_to_cpu(int target_cpu) 156/* deprecated functions. */
157
158int be_migrate_to_cluster(int cluster, int cluster_size)
150{ 159{
151 return be_migrate_thread_to_cpu(0, target_cpu); 160 return be_migrate_to_domain(cluster);
152} 161}
153 162
154int be_migrate_to_cluster(int cluster, int cluster_sz) 163int cluster_to_first_cpu(int cluster, int cluster_size)
155{ 164{
156 return be_migrate_thread_to_cluster(0, cluster, cluster_sz); 165 return domain_to_first_cpu(cluster);
157} 166}
158 167
159int be_migrate_to_partition(int partition) 168int partition_to_cpu(int partition)
160{ 169{
161 return be_migrate_thread_to_partition(0, partition); 170 return domain_to_first_cpu(partition);
162} 171}
diff --git a/src/task.c b/src/task.c
index 5f2fa26..35bad66 100644
--- a/src/task.c
+++ b/src/task.c
@@ -40,11 +40,11 @@ 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
43int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, 43int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster,
44 lt_t wcet, lt_t period, unsigned int priority, task_class_t class) 44 lt_t wcet, lt_t period, unsigned int priority, task_class_t class)
45{ 45{
46 struct rt_task params; 46 struct rt_task params;
47 params.cpu = cluster_to_first_cpu(cluster, cluster_size); 47 params.cpu = domain_to_first_cpu(cluster);
48 params.period = period; 48 params.period = period;
49 params.exec_cost = wcet; 49 params.exec_cost = wcet;
50 params.cls = class; 50 params.cls = class;
@@ -57,10 +57,10 @@ int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size,
57 (rt_setup_fn_t) set_rt_task_param, &params); 57 (rt_setup_fn_t) set_rt_task_param, &params);
58} 58}
59 59
60int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, 60int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster,
61 lt_t wcet, lt_t period, unsigned int prio) 61 lt_t wcet, lt_t period, unsigned int prio)
62{ 62{
63 return __create_rt_task(rt_prog, arg, cluster, cluster_size, wcet, period, 63 return __create_rt_task(rt_prog, arg, cluster, wcet, period,
64 prio, RT_CLASS_HARD); 64 prio, RT_CLASS_HARD);
65} 65}
66 66