diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2016-05-25 04:25:50 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2016-06-13 09:58:27 -0400 |
commit | adac0f1e8c08548d82a48c9913ebc9787f946440 (patch) | |
tree | 290e69f3e727a33b0e3a8ed8f012141f4a469b88 | |
parent | a62247e1f5c13b926f535bb64ecbd7f9fdef7b21 (diff) |
s390/topology: add drawer scheduling domain level
The z13 machine added a fourth level to the cpu topology
information. The new top level is called drawer.
A drawer contains two books, which used to be the top level.
Adding this additional scheduling domain did show performance
improvements for some workloads of up to 8%, while there don't
seem to be any workloads impacted in a negative way.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/Kconfig | 4 | ||||
-rw-r--r-- | arch/s390/include/asm/topology.h | 4 | ||||
-rw-r--r-- | arch/s390/kernel/topology.c | 33 | ||||
-rw-r--r-- | arch/s390/numa/mode_emu.c | 25 |
4 files changed, 55 insertions, 11 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 3529a285dda8..ac963903d54f 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -478,6 +478,9 @@ config SCHED_MC | |||
478 | config SCHED_BOOK | 478 | config SCHED_BOOK |
479 | def_bool n | 479 | def_bool n |
480 | 480 | ||
481 | config SCHED_DRAWER | ||
482 | def_bool n | ||
483 | |||
481 | config SCHED_TOPOLOGY | 484 | config SCHED_TOPOLOGY |
482 | def_bool y | 485 | def_bool y |
483 | prompt "Topology scheduler support" | 486 | prompt "Topology scheduler support" |
@@ -485,6 +488,7 @@ config SCHED_TOPOLOGY | |||
485 | select SCHED_SMT | 488 | select SCHED_SMT |
486 | select SCHED_MC | 489 | select SCHED_MC |
487 | select SCHED_BOOK | 490 | select SCHED_BOOK |
491 | select SCHED_DRAWER | ||
488 | help | 492 | help |
489 | Topology scheduler support improves the CPU scheduler's decision | 493 | Topology scheduler support improves the CPU scheduler's decision |
490 | making when dealing with machines that have multi-threading, | 494 | making when dealing with machines that have multi-threading, |
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h index 6b53962e807e..f15f5571ca2b 100644 --- a/arch/s390/include/asm/topology.h +++ b/arch/s390/include/asm/topology.h | |||
@@ -14,10 +14,12 @@ struct cpu_topology_s390 { | |||
14 | unsigned short core_id; | 14 | unsigned short core_id; |
15 | unsigned short socket_id; | 15 | unsigned short socket_id; |
16 | unsigned short book_id; | 16 | unsigned short book_id; |
17 | unsigned short drawer_id; | ||
17 | unsigned short node_id; | 18 | unsigned short node_id; |
18 | cpumask_t thread_mask; | 19 | cpumask_t thread_mask; |
19 | cpumask_t core_mask; | 20 | cpumask_t core_mask; |
20 | cpumask_t book_mask; | 21 | cpumask_t book_mask; |
22 | cpumask_t drawer_mask; | ||
21 | }; | 23 | }; |
22 | 24 | ||
23 | DECLARE_PER_CPU(struct cpu_topology_s390, cpu_topology); | 25 | DECLARE_PER_CPU(struct cpu_topology_s390, cpu_topology); |
@@ -30,6 +32,8 @@ DECLARE_PER_CPU(struct cpu_topology_s390, cpu_topology); | |||
30 | #define topology_core_cpumask(cpu) (&per_cpu(cpu_topology, cpu).core_mask) | 32 | #define topology_core_cpumask(cpu) (&per_cpu(cpu_topology, cpu).core_mask) |
31 | #define topology_book_id(cpu) (per_cpu(cpu_topology, cpu).book_id) | 33 | #define topology_book_id(cpu) (per_cpu(cpu_topology, cpu).book_id) |
32 | #define topology_book_cpumask(cpu) (&per_cpu(cpu_topology, cpu).book_mask) | 34 | #define topology_book_cpumask(cpu) (&per_cpu(cpu_topology, cpu).book_mask) |
35 | #define topology_drawer_id(cpu) (per_cpu(cpu_topology, cpu).drawer_id) | ||
36 | #define topology_drawer_cpumask(cpu) (&per_cpu(cpu_topology, cpu).drawer_mask) | ||
33 | 37 | ||
34 | #define mc_capable() 1 | 38 | #define mc_capable() 1 |
35 | 39 | ||
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index 64298a867589..44745e751c3a 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
@@ -46,6 +46,7 @@ static DECLARE_WORK(topology_work, topology_work_fn); | |||
46 | */ | 46 | */ |
47 | static struct mask_info socket_info; | 47 | static struct mask_info socket_info; |
48 | static struct mask_info book_info; | 48 | static struct mask_info book_info; |
49 | static struct mask_info drawer_info; | ||
49 | 50 | ||
50 | DEFINE_PER_CPU(struct cpu_topology_s390, cpu_topology); | 51 | DEFINE_PER_CPU(struct cpu_topology_s390, cpu_topology); |
51 | EXPORT_PER_CPU_SYMBOL_GPL(cpu_topology); | 52 | EXPORT_PER_CPU_SYMBOL_GPL(cpu_topology); |
@@ -80,6 +81,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) | |||
80 | } | 81 | } |
81 | 82 | ||
82 | static struct mask_info *add_cpus_to_mask(struct topology_core *tl_core, | 83 | static struct mask_info *add_cpus_to_mask(struct topology_core *tl_core, |
84 | struct mask_info *drawer, | ||
83 | struct mask_info *book, | 85 | struct mask_info *book, |
84 | struct mask_info *socket, | 86 | struct mask_info *socket, |
85 | int one_socket_per_cpu) | 87 | int one_socket_per_cpu) |
@@ -97,9 +99,11 @@ static struct mask_info *add_cpus_to_mask(struct topology_core *tl_core, | |||
97 | continue; | 99 | continue; |
98 | for (i = 0; i <= smp_cpu_mtid; i++) { | 100 | for (i = 0; i <= smp_cpu_mtid; i++) { |
99 | topo = &per_cpu(cpu_topology, lcpu + i); | 101 | topo = &per_cpu(cpu_topology, lcpu + i); |
102 | topo->drawer_id = drawer->id; | ||
100 | topo->book_id = book->id; | 103 | topo->book_id = book->id; |
101 | topo->core_id = rcore; | 104 | topo->core_id = rcore; |
102 | topo->thread_id = lcpu + i; | 105 | topo->thread_id = lcpu + i; |
106 | cpumask_set_cpu(lcpu + i, &drawer->mask); | ||
103 | cpumask_set_cpu(lcpu + i, &book->mask); | 107 | cpumask_set_cpu(lcpu + i, &book->mask); |
104 | cpumask_set_cpu(lcpu + i, &socket->mask); | 108 | cpumask_set_cpu(lcpu + i, &socket->mask); |
105 | if (one_socket_per_cpu) | 109 | if (one_socket_per_cpu) |
@@ -128,6 +132,11 @@ static void clear_masks(void) | |||
128 | cpumask_clear(&info->mask); | 132 | cpumask_clear(&info->mask); |
129 | info = info->next; | 133 | info = info->next; |
130 | } | 134 | } |
135 | info = &drawer_info; | ||
136 | while (info) { | ||
137 | cpumask_clear(&info->mask); | ||
138 | info = info->next; | ||
139 | } | ||
131 | } | 140 | } |
132 | 141 | ||
133 | static union topology_entry *next_tle(union topology_entry *tle) | 142 | static union topology_entry *next_tle(union topology_entry *tle) |
@@ -141,12 +150,17 @@ static void __tl_to_masks_generic(struct sysinfo_15_1_x *info) | |||
141 | { | 150 | { |
142 | struct mask_info *socket = &socket_info; | 151 | struct mask_info *socket = &socket_info; |
143 | struct mask_info *book = &book_info; | 152 | struct mask_info *book = &book_info; |
153 | struct mask_info *drawer = &drawer_info; | ||
144 | union topology_entry *tle, *end; | 154 | union topology_entry *tle, *end; |
145 | 155 | ||
146 | tle = info->tle; | 156 | tle = info->tle; |
147 | end = (union topology_entry *)((unsigned long)info + info->length); | 157 | end = (union topology_entry *)((unsigned long)info + info->length); |
148 | while (tle < end) { | 158 | while (tle < end) { |
149 | switch (tle->nl) { | 159 | switch (tle->nl) { |
160 | case 3: | ||
161 | drawer = drawer->next; | ||
162 | drawer->id = tle->container.id; | ||
163 | break; | ||
150 | case 2: | 164 | case 2: |
151 | book = book->next; | 165 | book = book->next; |
152 | book->id = tle->container.id; | 166 | book->id = tle->container.id; |
@@ -156,7 +170,7 @@ static void __tl_to_masks_generic(struct sysinfo_15_1_x *info) | |||
156 | socket->id = tle->container.id; | 170 | socket->id = tle->container.id; |
157 | break; | 171 | break; |
158 | case 0: | 172 | case 0: |
159 | add_cpus_to_mask(&tle->cpu, book, socket, 0); | 173 | add_cpus_to_mask(&tle->cpu, drawer, book, socket, 0); |
160 | break; | 174 | break; |
161 | default: | 175 | default: |
162 | clear_masks(); | 176 | clear_masks(); |
@@ -170,6 +184,7 @@ static void __tl_to_masks_z10(struct sysinfo_15_1_x *info) | |||
170 | { | 184 | { |
171 | struct mask_info *socket = &socket_info; | 185 | struct mask_info *socket = &socket_info; |
172 | struct mask_info *book = &book_info; | 186 | struct mask_info *book = &book_info; |
187 | struct mask_info *drawer = &drawer_info; | ||
173 | union topology_entry *tle, *end; | 188 | union topology_entry *tle, *end; |
174 | 189 | ||
175 | tle = info->tle; | 190 | tle = info->tle; |
@@ -181,7 +196,7 @@ static void __tl_to_masks_z10(struct sysinfo_15_1_x *info) | |||
181 | book->id = tle->container.id; | 196 | book->id = tle->container.id; |
182 | break; | 197 | break; |
183 | case 0: | 198 | case 0: |
184 | socket = add_cpus_to_mask(&tle->cpu, book, socket, 1); | 199 | socket = add_cpus_to_mask(&tle->cpu, drawer, book, socket, 1); |
185 | break; | 200 | break; |
186 | default: | 201 | default: |
187 | clear_masks(); | 202 | clear_masks(); |
@@ -257,11 +272,13 @@ static void update_cpu_masks(void) | |||
257 | topo->thread_mask = cpu_thread_map(cpu); | 272 | topo->thread_mask = cpu_thread_map(cpu); |
258 | topo->core_mask = cpu_group_map(&socket_info, cpu); | 273 | topo->core_mask = cpu_group_map(&socket_info, cpu); |
259 | topo->book_mask = cpu_group_map(&book_info, cpu); | 274 | topo->book_mask = cpu_group_map(&book_info, cpu); |
275 | topo->drawer_mask = cpu_group_map(&drawer_info, cpu); | ||
260 | if (!MACHINE_HAS_TOPOLOGY) { | 276 | if (!MACHINE_HAS_TOPOLOGY) { |
261 | topo->thread_id = cpu; | 277 | topo->thread_id = cpu; |
262 | topo->core_id = cpu; | 278 | topo->core_id = cpu; |
263 | topo->socket_id = cpu; | 279 | topo->socket_id = cpu; |
264 | topo->book_id = cpu; | 280 | topo->book_id = cpu; |
281 | topo->drawer_id = cpu; | ||
265 | } | 282 | } |
266 | } | 283 | } |
267 | numa_update_cpu_topology(); | 284 | numa_update_cpu_topology(); |
@@ -269,10 +286,7 @@ static void update_cpu_masks(void) | |||
269 | 286 | ||
270 | void store_topology(struct sysinfo_15_1_x *info) | 287 | void store_topology(struct sysinfo_15_1_x *info) |
271 | { | 288 | { |
272 | if (topology_max_mnest >= 3) | 289 | stsi(info, 15, 1, min(topology_max_mnest, 4)); |
273 | stsi(info, 15, 1, 3); | ||
274 | else | ||
275 | stsi(info, 15, 1, 2); | ||
276 | } | 290 | } |
277 | 291 | ||
278 | int arch_update_cpu_topology(void) | 292 | int arch_update_cpu_topology(void) |
@@ -442,6 +456,11 @@ static const struct cpumask *cpu_book_mask(int cpu) | |||
442 | return &per_cpu(cpu_topology, cpu).book_mask; | 456 | return &per_cpu(cpu_topology, cpu).book_mask; |
443 | } | 457 | } |
444 | 458 | ||
459 | static const struct cpumask *cpu_drawer_mask(int cpu) | ||
460 | { | ||
461 | return &per_cpu(cpu_topology, cpu).drawer_mask; | ||
462 | } | ||
463 | |||
445 | static int __init early_parse_topology(char *p) | 464 | static int __init early_parse_topology(char *p) |
446 | { | 465 | { |
447 | return kstrtobool(p, &topology_enabled); | 466 | return kstrtobool(p, &topology_enabled); |
@@ -452,6 +471,7 @@ static struct sched_domain_topology_level s390_topology[] = { | |||
452 | { cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, | 471 | { cpu_thread_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, |
453 | { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, | 472 | { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, |
454 | { cpu_book_mask, SD_INIT_NAME(BOOK) }, | 473 | { cpu_book_mask, SD_INIT_NAME(BOOK) }, |
474 | { cpu_drawer_mask, SD_INIT_NAME(DRAWER) }, | ||
455 | { cpu_cpu_mask, SD_INIT_NAME(DIE) }, | 475 | { cpu_cpu_mask, SD_INIT_NAME(DIE) }, |
456 | { NULL, }, | 476 | { NULL, }, |
457 | }; | 477 | }; |
@@ -487,6 +507,7 @@ static int __init s390_topology_init(void) | |||
487 | printk(KERN_CONT " / %d\n", info->mnest); | 507 | printk(KERN_CONT " / %d\n", info->mnest); |
488 | alloc_masks(info, &socket_info, 1); | 508 | alloc_masks(info, &socket_info, 1); |
489 | alloc_masks(info, &book_info, 2); | 509 | alloc_masks(info, &book_info, 2); |
510 | alloc_masks(info, &drawer_info, 3); | ||
490 | set_sched_topology(s390_topology); | 511 | set_sched_topology(s390_topology); |
491 | return 0; | 512 | return 0; |
492 | } | 513 | } |
diff --git a/arch/s390/numa/mode_emu.c b/arch/s390/numa/mode_emu.c index 828d0695d0d4..fbc394e16b2c 100644 --- a/arch/s390/numa/mode_emu.c +++ b/arch/s390/numa/mode_emu.c | |||
@@ -34,7 +34,8 @@ | |||
34 | #define DIST_CORE 1 | 34 | #define DIST_CORE 1 |
35 | #define DIST_MC 2 | 35 | #define DIST_MC 2 |
36 | #define DIST_BOOK 3 | 36 | #define DIST_BOOK 3 |
37 | #define DIST_MAX 4 | 37 | #define DIST_DRAWER 4 |
38 | #define DIST_MAX 5 | ||
38 | 39 | ||
39 | /* Node distance reported to common code */ | 40 | /* Node distance reported to common code */ |
40 | #define EMU_NODE_DIST 10 | 41 | #define EMU_NODE_DIST 10 |
@@ -43,7 +44,7 @@ | |||
43 | #define NODE_ID_FREE -1 | 44 | #define NODE_ID_FREE -1 |
44 | 45 | ||
45 | /* Different levels of toptree */ | 46 | /* Different levels of toptree */ |
46 | enum toptree_level {CORE, MC, BOOK, NODE, TOPOLOGY}; | 47 | enum toptree_level {CORE, MC, BOOK, DRAWER, NODE, TOPOLOGY}; |
47 | 48 | ||
48 | /* The two toptree IDs */ | 49 | /* The two toptree IDs */ |
49 | enum {TOPTREE_ID_PHYS, TOPTREE_ID_NUMA}; | 50 | enum {TOPTREE_ID_PHYS, TOPTREE_ID_NUMA}; |
@@ -114,6 +115,14 @@ static int cores_free(struct toptree *tree) | |||
114 | */ | 115 | */ |
115 | static struct toptree *core_node(struct toptree *core) | 116 | static struct toptree *core_node(struct toptree *core) |
116 | { | 117 | { |
118 | return core->parent->parent->parent->parent; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Return drawer of core | ||
123 | */ | ||
124 | static struct toptree *core_drawer(struct toptree *core) | ||
125 | { | ||
117 | return core->parent->parent->parent; | 126 | return core->parent->parent->parent; |
118 | } | 127 | } |
119 | 128 | ||
@@ -138,6 +147,8 @@ static struct toptree *core_mc(struct toptree *core) | |||
138 | */ | 147 | */ |
139 | static int dist_core_to_core(struct toptree *core1, struct toptree *core2) | 148 | static int dist_core_to_core(struct toptree *core1, struct toptree *core2) |
140 | { | 149 | { |
150 | if (core_drawer(core1)->id != core_drawer(core2)->id) | ||
151 | return DIST_DRAWER; | ||
141 | if (core_book(core1)->id != core_book(core2)->id) | 152 | if (core_book(core1)->id != core_book(core2)->id) |
142 | return DIST_BOOK; | 153 | return DIST_BOOK; |
143 | if (core_mc(core1)->id != core_mc(core2)->id) | 154 | if (core_mc(core1)->id != core_mc(core2)->id) |
@@ -262,6 +273,8 @@ static void toptree_to_numa_first(struct toptree *numa, struct toptree *phys) | |||
262 | struct toptree *core; | 273 | struct toptree *core; |
263 | 274 | ||
264 | /* Always try to move perfectly fitting structures first */ | 275 | /* Always try to move perfectly fitting structures first */ |
276 | move_level_to_numa(numa, phys, DRAWER, true); | ||
277 | move_level_to_numa(numa, phys, DRAWER, false); | ||
265 | move_level_to_numa(numa, phys, BOOK, true); | 278 | move_level_to_numa(numa, phys, BOOK, true); |
266 | move_level_to_numa(numa, phys, BOOK, false); | 279 | move_level_to_numa(numa, phys, BOOK, false); |
267 | move_level_to_numa(numa, phys, MC, true); | 280 | move_level_to_numa(numa, phys, MC, true); |
@@ -335,7 +348,7 @@ static struct toptree *toptree_to_numa(struct toptree *phys) | |||
335 | */ | 348 | */ |
336 | static struct toptree *toptree_from_topology(void) | 349 | static struct toptree *toptree_from_topology(void) |
337 | { | 350 | { |
338 | struct toptree *phys, *node, *book, *mc, *core; | 351 | struct toptree *phys, *node, *drawer, *book, *mc, *core; |
339 | struct cpu_topology_s390 *top; | 352 | struct cpu_topology_s390 *top; |
340 | int cpu; | 353 | int cpu; |
341 | 354 | ||
@@ -344,10 +357,11 @@ static struct toptree *toptree_from_topology(void) | |||
344 | for_each_online_cpu(cpu) { | 357 | for_each_online_cpu(cpu) { |
345 | top = &per_cpu(cpu_topology, cpu); | 358 | top = &per_cpu(cpu_topology, cpu); |
346 | node = toptree_get_child(phys, 0); | 359 | node = toptree_get_child(phys, 0); |
347 | book = toptree_get_child(node, top->book_id); | 360 | drawer = toptree_get_child(node, top->drawer_id); |
361 | book = toptree_get_child(drawer, top->book_id); | ||
348 | mc = toptree_get_child(book, top->socket_id); | 362 | mc = toptree_get_child(book, top->socket_id); |
349 | core = toptree_get_child(mc, top->core_id); | 363 | core = toptree_get_child(mc, top->core_id); |
350 | if (!book || !mc || !core) | 364 | if (!drawer || !book || !mc || !core) |
351 | panic("NUMA emulation could not allocate memory"); | 365 | panic("NUMA emulation could not allocate memory"); |
352 | cpumask_set_cpu(cpu, &core->mask); | 366 | cpumask_set_cpu(cpu, &core->mask); |
353 | toptree_update_mask(mc); | 367 | toptree_update_mask(mc); |
@@ -368,6 +382,7 @@ static void topology_add_core(struct toptree *core) | |||
368 | cpumask_copy(&top->thread_mask, &core->mask); | 382 | cpumask_copy(&top->thread_mask, &core->mask); |
369 | cpumask_copy(&top->core_mask, &core_mc(core)->mask); | 383 | cpumask_copy(&top->core_mask, &core_mc(core)->mask); |
370 | cpumask_copy(&top->book_mask, &core_book(core)->mask); | 384 | cpumask_copy(&top->book_mask, &core_book(core)->mask); |
385 | cpumask_copy(&top->drawer_mask, &core_drawer(core)->mask); | ||
371 | cpumask_set_cpu(cpu, &node_to_cpumask_map[core_node(core)->id]); | 386 | cpumask_set_cpu(cpu, &node_to_cpumask_map[core_node(core)->id]); |
372 | top->node_id = core_node(core)->id; | 387 | top->node_id = core_node(core)->id; |
373 | } | 388 | } |