powerpc/smp: Cache CPU to chip lookup
authorSrikar Dronamraju <srikar@linux.vnet.ibm.com>
Thu, 15 Apr 2021 12:09:34 +0000 (17:39 +0530)
committerMichael Ellerman <mpe@ellerman.id.au>
Sat, 17 Apr 2021 00:40:51 +0000 (10:40 +1000)
On systems with large CPUs per node, even with the filtered matching of
related CPUs, there can be large number of calls to cpu_to_chip_id for
the same CPU. For example with 4096 vCPU, 1 node QEMU configuration,
with 4 threads per core, system could be see upto 1024 calls to
cpu_to_chip_id() for the same CPU. On a given system, cpu_to_chip_id()
for a given CPU would always return the same. Hence cache the result in
a lookup table for use in subsequent calls.

Since all CPUs sharing the same core will belong to the same chip, the
lookup_table has an entry for one CPU per core.  chip_id_lookup_table is
not being freed and would be used on subsequent CPU online post CPU
offline.

Reported-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Suggested-by: Michael Ellerman <mpe@ellerman.id.au>
Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Tested-by: Daniel Henrique Barboza <danielhb413@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210415120934.232271-4-srikar@linux.vnet.ibm.com
arch/powerpc/include/asm/smp.h
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/smp.c

index 47081a9e13ca4da0b7b236a31d7bc41f764d272a..03b3d010cbab667a48eef50c535859b468db5fae 100644 (file)
@@ -31,6 +31,7 @@ extern u32 *cpu_to_phys_id;
 extern bool coregroup_enabled;
 
 extern int cpu_to_chip_id(int cpu);
+extern int *chip_id_lookup_table;
 
 #ifdef CONFIG_SMP
 
index a8b2d6bfc1ca7e004f7dd7473f151ba50b2a7fd6..fbe9deebc8e13eff1b844df914cdf9cbb54d0c2d 100644 (file)
@@ -65,6 +65,8 @@
 #define DBG(fmt...)
 #endif
 
+int *chip_id_lookup_table;
+
 #ifdef CONFIG_PPC64
 int __initdata iommu_is_off;
 int __initdata iommu_force_on;
@@ -914,13 +916,22 @@ EXPORT_SYMBOL(of_get_ibm_chip_id);
 int cpu_to_chip_id(int cpu)
 {
        struct device_node *np;
+       int ret = -1, idx;
+
+       idx = cpu / threads_per_core;
+       if (chip_id_lookup_table && chip_id_lookup_table[idx] != -1)
+               return chip_id_lookup_table[idx];
 
        np = of_get_cpu_node(cpu, NULL);
-       if (!np)
-               return -1;
+       if (np) {
+               ret = of_get_ibm_chip_id(np);
+               of_node_put(np);
+
+               if (chip_id_lookup_table)
+                       chip_id_lookup_table[idx] = ret;
+       }
 
-       of_node_put(np);
-       return of_get_ibm_chip_id(np);
+       return ret;
 }
 EXPORT_SYMBOL(cpu_to_chip_id);
 
index f8576a2f34a08dd16962fbb32f535b10532b0b3d..ad3e974726797e5eb821b101ca49b58f0d203fc1 100644 (file)
@@ -1073,6 +1073,20 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
                                cpu_smallcore_mask(boot_cpuid));
        }
 
+       if (cpu_to_chip_id(boot_cpuid) != -1) {
+               int idx = num_possible_cpus() / threads_per_core;
+
+               /*
+                * All threads of a core will all belong to the same core,
+                * chip_id_lookup_table will have one entry per core.
+                * Assumption: if boot_cpuid doesn't have a chip-id, then no
+                * other CPUs, will also not have chip-id.
+                */
+               chip_id_lookup_table = kcalloc(idx, sizeof(int), GFP_KERNEL);
+               if (chip_id_lookup_table)
+                       memset(chip_id_lookup_table, -1, sizeof(int) * idx);
+       }
+
        if (smp_ops && smp_ops->probe)
                smp_ops->probe();
 }
@@ -1468,8 +1482,8 @@ static void add_cpu_to_masks(int cpu)
 {
        struct cpumask *(*submask_fn)(int) = cpu_sibling_mask;
        int first_thread = cpu_first_thread_sibling(cpu);
-       int chip_id = cpu_to_chip_id(cpu);
        cpumask_var_t mask;
+       int chip_id = -1;
        bool ret;
        int i;
 
@@ -1492,7 +1506,10 @@ static void add_cpu_to_masks(int cpu)
        if (has_coregroup_support())
                update_coregroup_mask(cpu, &mask);
 
-       if (chip_id == -1 || !ret) {
+       if (chip_id_lookup_table && ret)
+               chip_id = cpu_to_chip_id(cpu);
+
+       if (chip_id == -1) {
                cpumask_copy(per_cpu(cpu_core_map, cpu), cpu_cpu_mask(cpu));
                goto out;
        }