diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2014-02-05 00:31:08 -0500 |
|---|---|---|
| committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2014-02-24 14:01:11 -0500 |
| commit | 1f323b00f95c4704cdeea7918853f1e9e8d26c2e (patch) | |
| tree | 76a6856b2465ba7d114009f231c0dae9c9e5ef2c /src | |
| parent | 871eef081ff9db7289a6947d0160cd984232c34c (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.c | 10 | ||||
| -rw-r--r-- | src/migration.c | 113 | ||||
| -rw-r--r-- | src/task.c | 8 |
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(¶m); | 143 | init_rt_task_param(¶m); |
| 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(), ¶m); | 148 | return set_rt_task_param(gettid(), ¶m); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | int sporadic_clustered(lt_t e_ns, lt_t p_ns, int cluster, int cluster_size) | 151 | int 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(¶m); | 161 | init_rt_task_param(¶m); |
| 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(), ¶m); | 166 | return set_rt_task_param(gettid(), ¶m); |
| 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 | ||
| 30 | int partition_to_cpu(int partition) | 30 | static 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 | ||
| 40 | int 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(); | 51 | out: |
| 49 | first_cpu = cluster * cluster_sz; | 52 | return ret; |
| 53 | } | ||
| 54 | |||
| 55 | int 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) | 60 | int 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; | 65 | int 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 | ||
| 57 | int be_migrate_thread_to_cpu(pid_t tid, int target_cpu) | 74 | int 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 | ||
| 92 | int be_migrate_thread_to_cluster(pid_t tid, int cluster, int cluster_sz) | 109 | int 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 | |||
| 97 | int __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 | ||
| 143 | int be_migrate_thread_to_partition(pid_t tid, int partition) | 145 | int be_migrate_to_cpu(int target_cpu) |
| 146 | { | ||
| 147 | return be_migrate_thread_to_cpu(0, target_cpu); | ||
| 148 | } | ||
| 149 | |||
| 150 | int 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 | ||
| 149 | int be_migrate_to_cpu(int target_cpu) | 156 | /* deprecated functions. */ |
| 157 | |||
| 158 | int 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 | ||
| 154 | int be_migrate_to_cluster(int cluster, int cluster_sz) | 163 | int 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 | ||
| 159 | int be_migrate_to_partition(int partition) | 168 | int 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 | } |
| @@ -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 | ||
| 43 | int __create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, | 43 | int __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, ¶ms); | 57 | (rt_setup_fn_t) set_rt_task_param, ¶ms); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | int create_rt_task(rt_fn_t rt_prog, void *arg, int cluster, int cluster_size, | 60 | int 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 | ||
