|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v6 4/6] xen/cpupool: Create different cpupools at boot time
On Fri, 8 Apr 2022, Luca Fancellu wrote:
> Introduce a way to create different cpupools at boot time, this is
> particularly useful on ARM big.LITTLE system where there might be the
> need to have different cpupools for each type of core, but also
> systems using NUMA can have different cpu pools for each node.
>
> The feature on arm relies on a specification of the cpupools from the
> device tree to build pools and assign cpus to them.
>
> ACPI is not supported for this feature.
>
> Documentation is created to explain the feature.
>
> Signed-off-by: Luca Fancellu <luca.fancellu@xxxxxxx>
> Reviewed-by: Juergen Gross <jgross@xxxxxxxx>
Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>
> ---
> Changes in v6:
> - Changed docs, return if booted with ACPI in btcpupools_dtb_parse,
> panic if /chosen does not exists. Changed commit message (Julien)
> - Add Juergen R-by for the xen/common/sched part that didn't change
> Changes in v5:
> - Fixed wrong variable name, swapped schedulers, add scheduler info
> in the printk (Stefano)
> - introduce assert in cpupool_init and btcpupools_get_cpupool_id to
> harden the code
> Changes in v4:
> - modify Makefile to put in *.init.o, fixed stubs and macro (Jan)
> - fixed docs, fix brakets (Stefano)
> - keep cpu0 in Pool-0 (Julien)
> - moved printk from btcpupools_allocate_pools to
> btcpupools_get_cpupool_id
> - Add to docs constraint about cpu0 and Pool-0
> Changes in v3:
> - Add newline to cpupools.txt and removed "default n" from Kconfig (Jan)
> - Fixed comment, moved defines, used global cpu_online_map, use
> HAS_DEVICE_TREE instead of ARM and place arch specific code in header
> (Juergen)
> - Fix brakets, x86 code only panic, get rid of scheduler dt node, don't
> save pool pointer and look for it from the pool list (Stefano)
> - Changed data structures to allow modification to the code.
> Changes in v2:
> - Move feature to common code (Juergen)
> - Try to decouple dtb parse and cpupool creation to allow
> more way to specify cpupools (for example command line)
> - Created standalone dt node for the scheduler so it can
> be used in future work to set scheduler specific
> parameters
> - Use only auto generated ids for cpupools
> ---
> docs/misc/arm/device-tree/cpupools.txt | 140 +++++++++++++++++
> xen/arch/arm/include/asm/smp.h | 3 +
> xen/common/Kconfig | 7 +
> xen/common/Makefile | 1 +
> xen/common/boot_cpupools.c | 207 +++++++++++++++++++++++++
> xen/common/sched/cpupool.c | 12 +-
> xen/include/xen/sched.h | 14 ++
> 7 files changed, 383 insertions(+), 1 deletion(-)
> create mode 100644 docs/misc/arm/device-tree/cpupools.txt
> create mode 100644 xen/common/boot_cpupools.c
>
> diff --git a/docs/misc/arm/device-tree/cpupools.txt
> b/docs/misc/arm/device-tree/cpupools.txt
> new file mode 100644
> index 000000000000..40cc8135c66f
> --- /dev/null
> +++ b/docs/misc/arm/device-tree/cpupools.txt
> @@ -0,0 +1,140 @@
> +Boot time cpupools
> +==================
> +
> +When BOOT_TIME_CPUPOOLS is enabled in the Xen configuration, it is possible
> to
> +create cpupools during boot phase by specifying them in the device tree.
> +ACPI is not supported for this feature.
> +
> +Cpupools specification nodes shall be direct childs of /chosen node.
> +Each cpupool node contains the following properties:
> +
> +- compatible (mandatory)
> +
> + Must always include the compatiblity string: "xen,cpupool".
> +
> +- cpupool-cpus (mandatory)
> +
> + Must be a list of device tree phandle to nodes describing cpus (e.g.
> having
> + device_type = "cpu"), it can't be empty.
> +
> +- cpupool-sched (optional)
> +
> + Must be a string having the name of a Xen scheduler. Check the
> sched=<...>
> + boot argument for allowed values [1]. When this property is omitted, the
> Xen
> + default scheduler will be used.
> +
> +
> +Constraints
> +===========
> +
> +If no cpupools are specified, all cpus will be assigned to one cpupool
> +implicitly created (Pool-0).
> +
> +If cpupools node are specified, but not every cpu brought up by Xen is
> assigned,
> +all the not assigned cpu will be assigned to an additional cpupool.
> +
> +If a cpu is assigned to a cpupool, but it's not brought up correctly, Xen
> will
> +stop.
> +
> +The boot cpu must be assigned to Pool-0, so the cpupool containing that core
> +will become Pool-0 automatically.
> +
> +
> +Examples
> +========
> +
> +A system having two types of core, the following device tree specification
> will
> +instruct Xen to have two cpupools:
> +
> +- The cpupool with id 0 will have 4 cpus assigned.
> +- The cpupool with id 1 will have 2 cpus assigned.
> +
> +The following example can work only if hmp-unsafe=1 is passed to Xen boot
> +arguments, otherwise not all cores will be brought up by Xen and the cpupool
> +creation process will stop Xen.
> +
> +
> +a72_1: cpu@0 {
> + compatible = "arm,cortex-a72";
> + reg = <0x0 0x0>;
> + device_type = "cpu";
> + [...]
> +};
> +
> +a72_2: cpu@1 {
> + compatible = "arm,cortex-a72";
> + reg = <0x0 0x1>;
> + device_type = "cpu";
> + [...]
> +};
> +
> +a53_1: cpu@100 {
> + compatible = "arm,cortex-a53";
> + reg = <0x0 0x100>;
> + device_type = "cpu";
> + [...]
> +};
> +
> +a53_2: cpu@101 {
> + compatible = "arm,cortex-a53";
> + reg = <0x0 0x101>;
> + device_type = "cpu";
> + [...]
> +};
> +
> +a53_3: cpu@102 {
> + compatible = "arm,cortex-a53";
> + reg = <0x0 0x102>;
> + device_type = "cpu";
> + [...]
> +};
> +
> +a53_4: cpu@103 {
> + compatible = "arm,cortex-a53";
> + reg = <0x0 0x103>;
> + device_type = "cpu";
> + [...]
> +};
> +
> +chosen {
> +
> + cpupool_a {
> + compatible = "xen,cpupool";
> + cpupool-cpus = <&a53_1 &a53_2 &a53_3 &a53_4>;
> + };
> + cpupool_b {
> + compatible = "xen,cpupool";
> + cpupool-cpus = <&a72_1 &a72_2>;
> + cpupool-sched = "credit2";
> + };
> +
> + [...]
> +
> +};
> +
> +
> +A system having the cpupools specification below will instruct Xen to have
> three
> +cpupools:
> +
> +- The cpupool Pool-0 will have 2 cpus assigned.
> +- The cpupool Pool-1 will have 2 cpus assigned.
> +- The cpupool Pool-2 will have 2 cpus assigned (created by Xen with all the
> not
> + assigned cpus a53_3 and a53_4).
> +
> +chosen {
> +
> + cpupool_a {
> + compatible = "xen,cpupool";
> + cpupool-cpus = <&a53_1 &a53_2>;
> + };
> + cpupool_b {
> + compatible = "xen,cpupool";
> + cpupool-cpus = <&a72_1 &a72_2>;
> + cpupool-sched = "null";
> + };
> +
> + [...]
> +
> +};
> +
> +[1] docs/misc/xen-command-line.pandoc
> diff --git a/xen/arch/arm/include/asm/smp.h b/xen/arch/arm/include/asm/smp.h
> index af5a2fe65266..83c0cd69767b 100644
> --- a/xen/arch/arm/include/asm/smp.h
> +++ b/xen/arch/arm/include/asm/smp.h
> @@ -34,6 +34,9 @@ extern void init_secondary(void);
> extern void smp_init_cpus(void);
> extern void smp_clear_cpu_maps (void);
> extern int smp_get_max_cpus (void);
> +
> +#define cpu_physical_id(cpu) cpu_logical_map(cpu)
> +
> #endif
>
> /*
> diff --git a/xen/common/Kconfig b/xen/common/Kconfig
> index d921c74d615e..70aac5220e75 100644
> --- a/xen/common/Kconfig
> +++ b/xen/common/Kconfig
> @@ -22,6 +22,13 @@ config GRANT_TABLE
>
> If unsure, say Y.
>
> +config BOOT_TIME_CPUPOOLS
> + bool "Create cpupools at boot time"
> + depends on HAS_DEVICE_TREE
> + help
> + Creates cpupools during boot time and assigns cpus to them. Cpupools
> + options can be specified in the device tree.
> +
> config ALTERNATIVE_CALL
> bool
>
> diff --git a/xen/common/Makefile b/xen/common/Makefile
> index b1e076c30b81..218174ca8b6b 100644
> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -1,5 +1,6 @@
> obj-$(CONFIG_ARGO) += argo.o
> obj-y += bitmap.o
> +obj-$(CONFIG_BOOT_TIME_CPUPOOLS) += boot_cpupools.init.o
> obj-$(CONFIG_HYPFS_CONFIG) += config_data.o
> obj-$(CONFIG_CORE_PARKING) += core_parking.o
> obj-y += cpu.o
> diff --git a/xen/common/boot_cpupools.c b/xen/common/boot_cpupools.c
> new file mode 100644
> index 000000000000..9429a5025fc4
> --- /dev/null
> +++ b/xen/common/boot_cpupools.c
> @@ -0,0 +1,207 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * xen/common/boot_cpupools.c
> + *
> + * Code to create cpupools at boot time.
> + *
> + * Copyright (C) 2022 Arm Ltd.
> + */
> +
> +#include <xen/sched.h>
> +#include <asm/acpi.h>
> +
> +/*
> + * pool_cpu_map: Index is logical cpu number, content is cpupool id, (-1)
> for
> + * unassigned.
> + * pool_sched_map: Index is cpupool id, content is scheduler id, (-1) for
> + * unassigned.
> + */
> +static int __initdata pool_cpu_map[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
> +static int __initdata pool_sched_map[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
> +static unsigned int __initdata next_pool_id;
> +
> +#define BTCPUPOOLS_DT_NODE_NO_REG (-1)
> +#define BTCPUPOOLS_DT_NODE_NO_LOG_CPU (-2)
> +
> +static int __init get_logical_cpu_from_hw_id(unsigned int hwid)
> +{
> + unsigned int i;
> +
> + for ( i = 0; i < nr_cpu_ids; i++ )
> + {
> + if ( cpu_physical_id(i) == hwid )
> + return i;
> + }
> +
> + return -1;
> +}
> +
> +static int __init
> +get_logical_cpu_from_cpu_node(const struct dt_device_node *cpu_node)
> +{
> + int cpu_num;
> + const __be32 *prop;
> + unsigned int cpu_reg;
> +
> + prop = dt_get_property(cpu_node, "reg", NULL);
> + if ( !prop )
> + return BTCPUPOOLS_DT_NODE_NO_REG;
> +
> + cpu_reg = dt_read_number(prop, dt_n_addr_cells(cpu_node));
> +
> + cpu_num = get_logical_cpu_from_hw_id(cpu_reg);
> + if ( cpu_num < 0 )
> + return BTCPUPOOLS_DT_NODE_NO_LOG_CPU;
> +
> + return cpu_num;
> +}
> +
> +static int __init check_and_get_sched_id(const char* scheduler_name)
> +{
> + int sched_id = sched_get_id_by_name(scheduler_name);
> +
> + if ( sched_id < 0 )
> + panic("Scheduler %s does not exists!\n", scheduler_name);
> +
> + return sched_id;
> +}
> +
> +void __init btcpupools_dtb_parse(void)
> +{
> + const struct dt_device_node *chosen, *node;
> +
> + if ( !acpi_disabled )
> + return;
> +
> + chosen = dt_find_node_by_path("/chosen");
> + if ( !chosen )
> + panic("/chosen missing. Boot time cpupools can't be parsed from
> DT.\n");
> +
> + dt_for_each_child_node(chosen, node)
> + {
> + const struct dt_device_node *phandle_node;
> + int sched_id = -1;
> + const char* scheduler_name;
> + unsigned int i = 0;
> +
> + if ( !dt_device_is_compatible(node, "xen,cpupool") )
> + continue;
> +
> + if ( !dt_property_read_string(node, "cpupool-sched",
> &scheduler_name) )
> + sched_id = check_and_get_sched_id(scheduler_name);
> +
> + phandle_node = dt_parse_phandle(node, "cpupool-cpus", i++);
> + if ( !phandle_node )
> + panic("Missing or empty cpupool-cpus property!\n");
> +
> + while ( phandle_node )
> + {
> + int cpu_num;
> +
> + cpu_num = get_logical_cpu_from_cpu_node(phandle_node);
> +
> + if ( cpu_num < 0 )
> + panic("Error retrieving logical cpu from node %s (%d)\n",
> + dt_node_name(node), cpu_num);
> +
> + if ( pool_cpu_map[cpu_num] != -1 )
> + panic("Logical cpu %d already added to a cpupool!\n",
> cpu_num);
> +
> + pool_cpu_map[cpu_num] = next_pool_id;
> +
> + phandle_node = dt_parse_phandle(node, "cpupool-cpus", i++);
> + }
> +
> + /* Save scheduler choice for this cpupool id */
> + pool_sched_map[next_pool_id] = sched_id;
> +
> + /* Let Xen generate pool ids */
> + next_pool_id++;
> + }
> +}
> +
> +void __init btcpupools_allocate_pools(void)
> +{
> + unsigned int i;
> + bool add_extra_cpupool = false;
> + int swap_id = -1;
> +
> + /*
> + * If there are no cpupools, the value of next_pool_id is zero, so the
> code
> + * below will assign every cpu to cpupool0 as the default behavior.
> + * When there are cpupools, the code below is assigning all the not
> + * assigned cpu to a new pool (next_pool_id value is the last id + 1).
> + * In the same loop we check if there is any assigned cpu that is not
> + * online.
> + */
> + for ( i = 0; i < nr_cpu_ids; i++ )
> + {
> + if ( cpumask_test_cpu(i, &cpu_online_map) )
> + {
> + /* Unassigned cpu gets next_pool_id pool id value */
> + if ( pool_cpu_map[i] < 0 )
> + {
> + pool_cpu_map[i] = next_pool_id;
> + add_extra_cpupool = true;
> + }
> +
> + /*
> + * Cpu0 must be in cpupool0, otherwise some operations like
> moving
> + * cpus between cpupools, cpu hotplug, destroying cpupools,
> shutdown
> + * of the host, might not work in a sane way.
> + */
> + if ( !i && (pool_cpu_map[0] != 0) )
> + swap_id = pool_cpu_map[0];
> +
> + if ( swap_id != -1 )
> + {
> + if ( pool_cpu_map[i] == swap_id )
> + pool_cpu_map[i] = 0;
> + else if ( pool_cpu_map[i] == 0 )
> + pool_cpu_map[i] = swap_id;
> + }
> + }
> + else
> + {
> + if ( pool_cpu_map[i] >= 0 )
> + panic("Pool-%d contains cpu%u that is not online!\n",
> + pool_cpu_map[i], i);
> + }
> + }
> +
> + /* A swap happened, swap schedulers between cpupool id 0 and the other */
> + if ( swap_id != -1 )
> + {
> + int swap_sched = pool_sched_map[swap_id];
> +
> + pool_sched_map[swap_id] = pool_sched_map[0];
> + pool_sched_map[0] = swap_sched;
> + }
> +
> + if ( add_extra_cpupool )
> + next_pool_id++;
> +
> + /* Create cpupools with selected schedulers */
> + for ( i = 0; i < next_pool_id; i++ )
> + cpupool_create_pool(i, pool_sched_map[i]);
> +}
> +
> +unsigned int __init btcpupools_get_cpupool_id(unsigned int cpu)
> +{
> + ASSERT((cpu < NR_CPUS) && (pool_cpu_map[cpu] >= 0));
> +
> + printk(XENLOG_INFO "Logical CPU %u in Pool-%d (Scheduler id: %d).\n",
> + cpu, pool_cpu_map[cpu], pool_sched_map[pool_cpu_map[cpu]]);
> +
> + return pool_cpu_map[cpu];
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/common/sched/cpupool.c b/xen/common/sched/cpupool.c
> index 89a891af7076..86a175f99cd5 100644
> --- a/xen/common/sched/cpupool.c
> +++ b/xen/common/sched/cpupool.c
> @@ -1247,12 +1247,22 @@ static int __init cf_check cpupool_init(void)
> cpupool_put(cpupool0);
> register_cpu_notifier(&cpu_nfb);
>
> + btcpupools_dtb_parse();
> +
> + btcpupools_allocate_pools();
> +
> spin_lock(&cpupool_lock);
>
> cpumask_copy(&cpupool_free_cpus, &cpu_online_map);
>
> for_each_cpu ( cpu, &cpupool_free_cpus )
> - cpupool_assign_cpu_locked(cpupool0, cpu);
> + {
> + unsigned int pool_id = btcpupools_get_cpupool_id(cpu);
> + struct cpupool *pool = cpupool_find_by_id(pool_id);
> +
> + ASSERT(pool);
> + cpupool_assign_cpu_locked(pool, cpu);
> + }
>
> spin_unlock(&cpupool_lock);
>
> diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
> index b527f141a1d3..453e98f1cba8 100644
> --- a/xen/include/xen/sched.h
> +++ b/xen/include/xen/sched.h
> @@ -1178,6 +1178,20 @@ extern void cf_check dump_runq(unsigned char key);
>
> void arch_do_physinfo(struct xen_sysctl_physinfo *pi);
>
> +#ifdef CONFIG_BOOT_TIME_CPUPOOLS
> +void btcpupools_allocate_pools(void);
> +unsigned int btcpupools_get_cpupool_id(unsigned int cpu);
> +void btcpupools_dtb_parse(void);
> +
> +#else /* !CONFIG_BOOT_TIME_CPUPOOLS */
> +static inline void btcpupools_allocate_pools(void) {}
> +static inline void btcpupools_dtb_parse(void) {}
> +static inline unsigned int btcpupools_get_cpupool_id(unsigned int cpu)
> +{
> + return 0;
> +}
> +#endif
> +
> #endif /* __SCHED_H__ */
>
> /*
> --
> 2.17.1
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |