|
46 | 46 | #include <linux/cgroup.h> |
47 | 47 | #include <linux/wait.h> |
48 | 48 | #include <linux/workqueue.h> |
| 49 | +#include <linux/union_find.h> |
49 | 50 |
|
50 | 51 | DEFINE_STATIC_KEY_FALSE(cpusets_pre_enable_key); |
51 | 52 | DEFINE_STATIC_KEY_FALSE(cpusets_enabled_key); |
@@ -175,9 +176,6 @@ struct cpuset { |
175 | 176 | */ |
176 | 177 | int attach_in_progress; |
177 | 178 |
|
178 | | - /* partition number for rebuild_sched_domains() */ |
179 | | - int pn; |
180 | | - |
181 | 179 | /* for custom sched domain */ |
182 | 180 | int relax_domain_level; |
183 | 181 |
|
@@ -211,6 +209,9 @@ struct cpuset { |
211 | 209 |
|
212 | 210 | /* Remote partition silbling list anchored at remote_children */ |
213 | 211 | struct list_head remote_sibling; |
| 212 | + |
| 213 | + /* Used to merge intersecting subsets for generate_sched_domains */ |
| 214 | + struct uf_node node; |
214 | 215 | }; |
215 | 216 |
|
216 | 217 | /* |
@@ -998,33 +999,31 @@ static inline int nr_cpusets(void) |
998 | 999 | * were changed (added or removed.) |
999 | 1000 | * |
1000 | 1001 | * Finding the best partition (set of domains): |
1001 | | - * The triple nested loops below over i, j, k scan over the |
1002 | | - * load balanced cpusets (using the array of cpuset pointers in |
1003 | | - * csa[]) looking for pairs of cpusets that have overlapping |
1004 | | - * cpus_allowed, but which don't have the same 'pn' partition |
1005 | | - * number and gives them in the same partition number. It keeps |
1006 | | - * looping on the 'restart' label until it can no longer find |
1007 | | - * any such pairs. |
| 1002 | + * The double nested loops below over i, j scan over the load |
| 1003 | + * balanced cpusets (using the array of cpuset pointers in csa[]) |
| 1004 | + * looking for pairs of cpusets that have overlapping cpus_allowed |
| 1005 | + * and merging them using a union-find algorithm. |
| 1006 | + * |
| 1007 | + * The union of the cpus_allowed masks from the set of all cpusets |
| 1008 | + * having the same root then form the one element of the partition |
| 1009 | + * (one sched domain) to be passed to partition_sched_domains(). |
1008 | 1010 | * |
1009 | | - * The union of the cpus_allowed masks from the set of |
1010 | | - * all cpusets having the same 'pn' value then form the one |
1011 | | - * element of the partition (one sched domain) to be passed to |
1012 | | - * partition_sched_domains(). |
1013 | 1011 | */ |
1014 | 1012 | static int generate_sched_domains(cpumask_var_t **domains, |
1015 | 1013 | struct sched_domain_attr **attributes) |
1016 | 1014 | { |
1017 | 1015 | struct cpuset *cp; /* top-down scan of cpusets */ |
1018 | 1016 | struct cpuset **csa; /* array of all cpuset ptrs */ |
1019 | 1017 | int csn; /* how many cpuset ptrs in csa so far */ |
1020 | | - int i, j, k; /* indices for partition finding loops */ |
| 1018 | + int i, j; /* indices for partition finding loops */ |
1021 | 1019 | cpumask_var_t *doms; /* resulting partition; i.e. sched domains */ |
1022 | 1020 | struct sched_domain_attr *dattr; /* attributes for custom domains */ |
1023 | 1021 | int ndoms = 0; /* number of sched domains in result */ |
1024 | 1022 | int nslot; /* next empty doms[] struct cpumask slot */ |
1025 | 1023 | struct cgroup_subsys_state *pos_css; |
1026 | 1024 | bool root_load_balance = is_sched_load_balance(&top_cpuset); |
1027 | 1025 | bool cgrpv2 = cgroup_subsys_on_dfl(cpuset_cgrp_subsys); |
| 1026 | + int nslot_update; |
1028 | 1027 |
|
1029 | 1028 | doms = NULL; |
1030 | 1029 | dattr = NULL; |
@@ -1112,31 +1111,25 @@ static int generate_sched_domains(cpumask_var_t **domains, |
1112 | 1111 | if (root_load_balance && (csn == 1)) |
1113 | 1112 | goto single_root_domain; |
1114 | 1113 |
|
1115 | | - for (i = 0; i < csn; i++) |
1116 | | - csa[i]->pn = i; |
1117 | | - ndoms = csn; |
1118 | | - |
1119 | | -restart: |
1120 | | - /* Find the best partition (set of sched domains) */ |
1121 | | - for (i = 0; i < csn; i++) { |
1122 | | - struct cpuset *a = csa[i]; |
1123 | | - int apn = a->pn; |
1124 | | - |
1125 | | - for (j = 0; j < csn; j++) { |
1126 | | - struct cpuset *b = csa[j]; |
1127 | | - int bpn = b->pn; |
1128 | | - |
1129 | | - if (apn != bpn && cpusets_overlap(a, b)) { |
1130 | | - for (k = 0; k < csn; k++) { |
1131 | | - struct cpuset *c = csa[k]; |
| 1114 | + if (!cgrpv2) { |
| 1115 | + for (i = 0; i < csn; i++) |
| 1116 | + uf_node_init(&csa[i]->node); |
1132 | 1117 |
|
1133 | | - if (c->pn == bpn) |
1134 | | - c->pn = apn; |
1135 | | - } |
1136 | | - ndoms--; /* one less element */ |
1137 | | - goto restart; |
| 1118 | + /* Merge overlapping cpusets */ |
| 1119 | + for (i = 0; i < csn; i++) { |
| 1120 | + for (j = i + 1; j < csn; j++) { |
| 1121 | + if (cpusets_overlap(csa[i], csa[j])) |
| 1122 | + uf_union(&csa[i]->node, &csa[j]->node); |
1138 | 1123 | } |
1139 | 1124 | } |
| 1125 | + |
| 1126 | + /* Count the total number of domains */ |
| 1127 | + for (i = 0; i < csn; i++) { |
| 1128 | + if (uf_find(&csa[i]->node) == &csa[i]->node) |
| 1129 | + ndoms++; |
| 1130 | + } |
| 1131 | + } else { |
| 1132 | + ndoms = csn; |
1140 | 1133 | } |
1141 | 1134 |
|
1142 | 1135 | /* |
@@ -1169,44 +1162,25 @@ static int generate_sched_domains(cpumask_var_t **domains, |
1169 | 1162 | } |
1170 | 1163 |
|
1171 | 1164 | for (nslot = 0, i = 0; i < csn; i++) { |
1172 | | - struct cpuset *a = csa[i]; |
1173 | | - struct cpumask *dp; |
1174 | | - int apn = a->pn; |
1175 | | - |
1176 | | - if (apn < 0) { |
1177 | | - /* Skip completed partitions */ |
1178 | | - continue; |
1179 | | - } |
1180 | | - |
1181 | | - dp = doms[nslot]; |
1182 | | - |
1183 | | - if (nslot == ndoms) { |
1184 | | - static int warnings = 10; |
1185 | | - if (warnings) { |
1186 | | - pr_warn("rebuild_sched_domains confused: nslot %d, ndoms %d, csn %d, i %d, apn %d\n", |
1187 | | - nslot, ndoms, csn, i, apn); |
1188 | | - warnings--; |
1189 | | - } |
1190 | | - continue; |
1191 | | - } |
1192 | | - |
1193 | | - cpumask_clear(dp); |
1194 | | - if (dattr) |
1195 | | - *(dattr + nslot) = SD_ATTR_INIT; |
| 1165 | + nslot_update = 0; |
1196 | 1166 | for (j = i; j < csn; j++) { |
1197 | | - struct cpuset *b = csa[j]; |
1198 | | - |
1199 | | - if (apn == b->pn) { |
1200 | | - cpumask_or(dp, dp, b->effective_cpus); |
| 1167 | + if (uf_find(&csa[j]->node) == &csa[i]->node) { |
| 1168 | + struct cpumask *dp = doms[nslot]; |
| 1169 | + |
| 1170 | + if (i == j) { |
| 1171 | + nslot_update = 1; |
| 1172 | + cpumask_clear(dp); |
| 1173 | + if (dattr) |
| 1174 | + *(dattr + nslot) = SD_ATTR_INIT; |
| 1175 | + } |
| 1176 | + cpumask_or(dp, dp, csa[j]->effective_cpus); |
1201 | 1177 | cpumask_and(dp, dp, housekeeping_cpumask(HK_TYPE_DOMAIN)); |
1202 | 1178 | if (dattr) |
1203 | | - update_domain_attr_tree(dattr + nslot, b); |
1204 | | - |
1205 | | - /* Done with this partition */ |
1206 | | - b->pn = -1; |
| 1179 | + update_domain_attr_tree(dattr + nslot, csa[j]); |
1207 | 1180 | } |
1208 | 1181 | } |
1209 | | - nslot++; |
| 1182 | + if (nslot_update) |
| 1183 | + nslot++; |
1210 | 1184 | } |
1211 | 1185 | BUG_ON(nslot != ndoms); |
1212 | 1186 |
|
|
0 commit comments