s390/topology: alternative topology for topology-less machines
If running on machines that do not provide topology information we currently generate a "fake" topology which defines the maximum distance between each cpu: each cpu will be put into an own drawer. Historically this used to be the best option for (virtual) machines in overcommited hypervisors. For some workloads however it is better to generate a different topology where all cpus are siblings within a package (all cpus are core siblings). This shows performance improvements of up to 10%, depending on the workload. In order to keep the current behaviour, but also allow to switch to the different core sibling topology use the existing "topology=" kernel parameter: Specifying "topology=on" on machines without topology information will generate the core siblings (fake) topology information, instead of the default topology information where all cpus have the maximum distance. On machines which provide topology information specifying "topology=on" does not have any effect. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
ba385c0594
commit
1b25fda053
|
@ -404,18 +404,6 @@ static inline void save_vector_registers(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init topology_setup(char *str)
|
|
||||||
{
|
|
||||||
bool enabled;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = kstrtobool(str, &enabled);
|
|
||||||
if (!rc && !enabled)
|
|
||||||
S390_lowcore.machine_flags &= ~MACHINE_FLAG_TOPOLOGY;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
early_param("topology", topology_setup);
|
|
||||||
|
|
||||||
static int __init disable_vector_extension(char *str)
|
static int __init disable_vector_extension(char *str)
|
||||||
{
|
{
|
||||||
S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
|
S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
|
||||||
|
|
|
@ -29,12 +29,20 @@
|
||||||
#define PTF_VERTICAL (1UL)
|
#define PTF_VERTICAL (1UL)
|
||||||
#define PTF_CHECK (2UL)
|
#define PTF_CHECK (2UL)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TOPOLOGY_MODE_HW,
|
||||||
|
TOPOLOGY_MODE_SINGLE,
|
||||||
|
TOPOLOGY_MODE_PACKAGE,
|
||||||
|
TOPOLOGY_MODE_UNINITIALIZED
|
||||||
|
};
|
||||||
|
|
||||||
struct mask_info {
|
struct mask_info {
|
||||||
struct mask_info *next;
|
struct mask_info *next;
|
||||||
unsigned char id;
|
unsigned char id;
|
||||||
cpumask_t mask;
|
cpumask_t mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int topology_mode = TOPOLOGY_MODE_UNINITIALIZED;
|
||||||
static void set_topology_timer(void);
|
static void set_topology_timer(void);
|
||||||
static void topology_work_fn(struct work_struct *work);
|
static void topology_work_fn(struct work_struct *work);
|
||||||
static struct sysinfo_15_1_x *tl_info;
|
static struct sysinfo_15_1_x *tl_info;
|
||||||
|
@ -59,11 +67,26 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
|
||||||
cpumask_t mask;
|
cpumask_t mask;
|
||||||
|
|
||||||
cpumask_copy(&mask, cpumask_of(cpu));
|
cpumask_copy(&mask, cpumask_of(cpu));
|
||||||
if (!MACHINE_HAS_TOPOLOGY)
|
switch (topology_mode) {
|
||||||
return mask;
|
case TOPOLOGY_MODE_HW:
|
||||||
for (; info; info = info->next) {
|
while (info) {
|
||||||
if (cpumask_test_cpu(cpu, &info->mask))
|
if (cpumask_test_cpu(cpu, &info->mask)) {
|
||||||
return info->mask;
|
mask = info->mask;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
info = info->next;
|
||||||
|
}
|
||||||
|
if (cpumask_empty(&mask))
|
||||||
|
cpumask_copy(&mask, cpumask_of(cpu));
|
||||||
|
break;
|
||||||
|
case TOPOLOGY_MODE_PACKAGE:
|
||||||
|
cpumask_copy(&mask, cpu_present_mask);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* fallthrough */
|
||||||
|
case TOPOLOGY_MODE_SINGLE:
|
||||||
|
cpumask_copy(&mask, cpumask_of(cpu));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +97,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
cpumask_copy(&mask, cpumask_of(cpu));
|
cpumask_copy(&mask, cpumask_of(cpu));
|
||||||
if (!MACHINE_HAS_TOPOLOGY)
|
if (topology_mode != TOPOLOGY_MODE_HW)
|
||||||
return mask;
|
return mask;
|
||||||
cpu -= cpu % (smp_cpu_mtid + 1);
|
cpu -= cpu % (smp_cpu_mtid + 1);
|
||||||
for (i = 0; i <= smp_cpu_mtid; i++)
|
for (i = 0; i <= smp_cpu_mtid; i++)
|
||||||
|
@ -223,7 +246,7 @@ int topology_set_cpu_management(int fc)
|
||||||
static void update_cpu_masks(void)
|
static void update_cpu_masks(void)
|
||||||
{
|
{
|
||||||
struct cpu_topology_s390 *topo;
|
struct cpu_topology_s390 *topo;
|
||||||
int cpu;
|
int cpu, id;
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
topo = &cpu_topology[cpu];
|
topo = &cpu_topology[cpu];
|
||||||
|
@ -231,12 +254,13 @@ static void update_cpu_masks(void)
|
||||||
topo->core_mask = cpu_group_map(&socket_info, cpu);
|
topo->core_mask = cpu_group_map(&socket_info, cpu);
|
||||||
topo->book_mask = cpu_group_map(&book_info, cpu);
|
topo->book_mask = cpu_group_map(&book_info, cpu);
|
||||||
topo->drawer_mask = cpu_group_map(&drawer_info, cpu);
|
topo->drawer_mask = cpu_group_map(&drawer_info, cpu);
|
||||||
if (!MACHINE_HAS_TOPOLOGY) {
|
if (topology_mode != TOPOLOGY_MODE_HW) {
|
||||||
|
id = topology_mode == TOPOLOGY_MODE_PACKAGE ? 0 : cpu;
|
||||||
topo->thread_id = cpu;
|
topo->thread_id = cpu;
|
||||||
topo->core_id = cpu;
|
topo->core_id = cpu;
|
||||||
topo->socket_id = cpu;
|
topo->socket_id = id;
|
||||||
topo->book_id = cpu;
|
topo->book_id = id;
|
||||||
topo->drawer_id = cpu;
|
topo->drawer_id = id;
|
||||||
if (cpu_present(cpu))
|
if (cpu_present(cpu))
|
||||||
cpumask_set_cpu(cpu, &cpus_with_topology);
|
cpumask_set_cpu(cpu, &cpus_with_topology);
|
||||||
}
|
}
|
||||||
|
@ -459,6 +483,12 @@ void __init topology_init_early(void)
|
||||||
struct sysinfo_15_1_x *info;
|
struct sysinfo_15_1_x *info;
|
||||||
|
|
||||||
set_sched_topology(s390_topology);
|
set_sched_topology(s390_topology);
|
||||||
|
if (topology_mode == TOPOLOGY_MODE_UNINITIALIZED) {
|
||||||
|
if (MACHINE_HAS_TOPOLOGY)
|
||||||
|
topology_mode = TOPOLOGY_MODE_HW;
|
||||||
|
else
|
||||||
|
topology_mode = TOPOLOGY_MODE_SINGLE;
|
||||||
|
}
|
||||||
if (!MACHINE_HAS_TOPOLOGY)
|
if (!MACHINE_HAS_TOPOLOGY)
|
||||||
goto out;
|
goto out;
|
||||||
tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE);
|
tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE);
|
||||||
|
@ -474,6 +504,26 @@ out:
|
||||||
__arch_update_cpu_topology();
|
__arch_update_cpu_topology();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int topology_get_mode(int enabled)
|
||||||
|
{
|
||||||
|
if (!enabled)
|
||||||
|
return TOPOLOGY_MODE_SINGLE;
|
||||||
|
return MACHINE_HAS_TOPOLOGY ? TOPOLOGY_MODE_HW : TOPOLOGY_MODE_PACKAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init topology_setup(char *str)
|
||||||
|
{
|
||||||
|
bool enabled;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = kstrtobool(str, &enabled);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
topology_mode = topology_get_mode(enabled);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
early_param("topology", topology_setup);
|
||||||
|
|
||||||
static int __init topology_init(void)
|
static int __init topology_init(void)
|
||||||
{
|
{
|
||||||
if (MACHINE_HAS_TOPOLOGY)
|
if (MACHINE_HAS_TOPOLOGY)
|
||||||
|
|
Loading…
Reference in New Issue