sched: unified sched_powersavings tunables
Subsystems (4)
cover sched: unified sched_powersavings tunables
Hi,
I have created the following RFC patch based on the recent discussions and consensus on simplifying the power aware scheduler in the kernel.
Ref: LWN: Rethinking power-aware scheduling
http://lwn.net/Articles/474915/
The goal of the unified tunable are as follows:
* Simple and single tunable for different (all) topology
* Good default powersavings for kernel
* Potential to map this setting to other subsystems like cpufreq and cpuidle
What this patch does: (first step)
* Create a single sched_powersavings tunable in sysfs
* Enable current sched_mc and sched_smt features based on value of this single tunable
What this patch is yet to do:
* Tune the default power savings to pack packages only till a threshold of say 50%
* Add notifiers to change setting on battery/AC transitions
* Feed the thresholds from arch specific code so that different archs can do 'optimal' packing based on topology
* May be move this to /sys/device/system/powersavings and add additional platform tunables like x86_energy_perf_policy?
This RFC has only x86 changes and has been tested on dual-socket, quad-core,HT configuration.
Please let me know your comments and feedback.
Thanks,
Vaidy
---
Vaidyanathan Srinivasan (2):
sched: unified sched_powersavings sysfs tunable
sched: fix group_capacity for thread level consolidation
arch/x86/Kconfig | 20 ++++-------- arch/x86/kernel/smpboot.c | 2 + block/blk.h | 11 ++++--- drivers/base/cpu.c | 2 + include/linux/sched.h | 29 +++++++++-------- include/linux/topology.h | 9 +---- kernel/sched/core.c | 75 +++++++++++---------------------------------- kernel/sched/fair.c | 38 ++++++++++++++++------- 8 files changed, 77 insertions(+), 109 deletions(-)
RFC PATCH 1/2 sched: unified sched_powersavings sysfs tunable
Combine the sched_mc_powersavings and sched_smt_powersavings sysfs tunables into a single sysfs tunable:
/sys/devices/system/cpu/sched_powersavings={0,1,2}
0 - Power savings disabled (performance mode) 1 - Default kernel settings. Automatic powersave
vs performance tradeoff by the kernel
2 - Maximum power savings
The kernel will default to '1' which is equivalent to sched_mc_powersavings=1 or consolidate at package level.
Max power saving setting '2' would consolidate to sibling threads and also do aggressive active balancing.
--- arch/x86/Kconfig | 20 ++++-------- arch/x86/kernel/smpboot.c | 2 + block/blk.h | 11 ++++--- drivers/base/cpu.c | 2 + include/linux/sched.h | 29 +++++++++-------- include/linux/topology.h | 9 +---- kernel/sched/core.c | 75 +++++++++++---------------------------------- kernel/sched/fair.c | 23 +++++++------- 8 files changed, 62 insertions(+), 109 deletions(-)
arch/x86/Kconfig +6 -14
@@ -788,23 +788,15 @@ config NR_CPUS This is purely to save memory - each supported CPU adds approximately eight kilobytes to the kernel image. -config SCHED_SMT - bool "SMT (Hyperthreading) scheduler support" - depends on X86_HT - ---help--- - SMT scheduler support improves the CPU scheduler's decision making - when dealing with Intel Pentium 4 chips with HyperThreading at a - cost of slightly increased overhead in some places. If unsure say - N here. - -config SCHED_MC +config SCHED_POWERSAVE def_bool y - prompt "Multi-core scheduler support" + prompt "Power save support in scheduler" depends on X86_HT ---help--- - Multi-core scheduler support improves the CPU scheduler's decision - making when dealing with multi-core CPU chips at a cost of slightly - increased overhead in some places. If unsure say N here. + Power saving feature in scheduler optimizes task placement + in a multi-core or mulit-threaded system whenever possible. + Default kernel settings would suit most applications, while + sysfs tunables can be used to control this feature at runtime. config IRQ_TIME_ACCOUNTING bool "Fine granularity task level IRQ time accounting"
arch/x86/kernel/smpboot.c +1 -1
@@ -414,7 +414,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu)* For perf, we return last level cache shared map. * And for power savings, we return cpu_core_map */ -if ((sched_mc_power_savings || sched_smt_power_savings) && +if ((sched_power_savings) && !(cpu_has (c,X86_FEATURE_AMD_DCM )))return cpu_core_mask (cpu);else
block/blk.h +6 -5
@@ -167,14 +167,15 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)static inline int blk_cpu_to_group (int cpu) {int group =NR_CPUS ; -#ifdef CONFIG_SCHED_MC -const struct cpumask *mask =cpu_coregroup_mask (cpu); - group =cpumask_first (mask); -#elif defined(CONFIG_SCHED_SMT ) - group =cpumask_first (topology_thread_cpumask (cpu)); +#ifdef CONFIG_SCHED_POWERSAVE +if (smt_capable ()) + group =cpumask_first (topology_thread_cpumask (cpu)); +else + group =cpumask_first (cpu_coregroup_mask (cpu));#else return cpu;#endif +/* Possible dead code?? */ if (likely (group <NR_CPUS ))return group;return cpu;
drivers/base/cpu.c +1 -1
@@ -299,7 +299,7 @@ void __init cpu_dev_init(void)cpu_dev_register_generic (); -#if defined(CONFIG_SCHED_MC ) || defined(CONFIG_SCHED_SMT ) +#ifdef CONFIG_SCHED_POWERSAVE sched_create_sysfs_power_savings_entries (cpu_subsys.dev_root);#endif }
include/linux/sched.h +15 -14
@@ -850,33 +850,34 @@ enum cpu_idle_type {#define SD_PREFER_SIBLING 0x1000/* Prefer to place tasks in a sibling domain */ #define SD_OVERLAP 0x2000/* sched_domains of this level overlap */ -enum powersavings_balance_level { -POWERSAVINGS_BALANCE_NONE =0 ,/* No power saving load balance */ -POWERSAVINGS_BALANCE_BASIC ,/* Fill one thread/core/package -* first for long running threads -*/ -POWERSAVINGS_BALANCE_WAKEUP ,/* Also bias task wakeups to semi-idle -* cpu package for power savings -*/ -MAX_POWERSAVINGS_BALANCE_LEVELS +enum powersavings_level { +POWERSAVINGS_DISABLED =0 ,/* Max performance */ +POWERSAVINGS_DEFAULT ,/* Kernel default policy, automatic powersave */ +/* vs performance tradeoff */ +POWERSAVINGS_MAX /* Favour power savings over peformance */ }; -extern int sched_mc_power_savings, sched_smt_power_savings; +extern int sched_power_savings;static inline int sd_balance_for_mc_power (void ) { -if (sched_smt_power_savings) +switch (sched_power_savings) { +case POWERSAVINGS_MAX :return SD_POWERSAVINGS_BALANCE ; -if (!sched_mc_power_savings) +case POWERSAVINGS_DISABLED :return SD_PREFER_SIBLING ; +default : +break ; + } +return 0 ; }static inline int sd_balance_for_package_power (void ) { -if (sched_mc_power_savings | sched_smt_power_savings) +if (sched_power_savings !=POWERSAVINGS_DISABLED )return SD_POWERSAVINGS_BALANCE ;return SD_PREFER_SIBLING ;
@@ -892,7 +893,7 @@ extern int __weak arch_sd_sibiling_asym_packing(void);static inline int sd_power_saving_flags (void ) { -if (sched_mc_power_savings | sched_smt_power_savings) +if (sched_power_savings !=POWERSAVINGS_DISABLED )return SD_BALANCE_NEWIDLE ;return 0 ;
include/linux/topology.h +2 -7
@@ -79,10 +79,7 @@ int arch_update_cpu_topology(void);* (Only non-zero and non-null fields need be specified.) */ -#ifdef CONFIG_SCHED_SMT -/* MCD - Do we really need this? It is always on if CONFIG_SCHED_SMT is, -* so can't we drop this in favor of CONFIG_SCHED_SMT? -*/ +#ifdef CONFIG_SCHED_POWERSAVE #define ARCH_HAS_SCHED_WAKE_IDLE /* Common values for SMT siblings */ #ifndef SD_SIBLING_INIT
@@ -110,9 +107,7 @@ int arch_update_cpu_topology(void); .smt_gain = 1178, /* 15% */ \ }#endif -#endif /* CONFIG_SCHED_SMT */ -#ifdef CONFIG_SCHED_MC /* Common values for MC siblings. for now mostly derived from SD_CPU_INIT */ #ifndef SD_MC_INIT #define SD_MC_INIT (struct sched_domain) { \
@@ -142,7 +137,7 @@ int arch_update_cpu_topology(void); .balance_interval = 1, \ }#endif -#endif /* CONFIG_SCHED_MC */ +#endif /* CONFIG_SCHED_POWERSAVE */ /* Common values for CPUs */ #ifndef SD_CPU_INIT
kernel/sched/core.c +19 -56
142 lines not on this page · raw message
kernel/sched/fair.c +12 -11
@@ -3497,7 +3497,7 @@ struct sd_lb_stats {unsigned int busiest_group_weight;int group_imb;/* Is there imbalance in this sd */ -#if defined(CONFIG_SCHED_MC ) || defined(CONFIG_SCHED_SMT ) +#ifdef CONFIG_SCHED_POWERSAVE int power_savings_balance;/* Is powersave balance needed for this sd */ struct sched_group *group_min;/* Least loaded group in sd */ struct sched_group *group_leader;/* Group which relieves group_min */
@@ -3549,7 +3549,7 @@ static inline int get_sd_load_idx(struct sched_domain *sd, } -#if defined(CONFIG_SCHED_MC ) || defined(CONFIG_SCHED_SMT ) +#ifdef CONFIG_SCHED_POWERSAVE /** * init_sd_power_savings_stats - Initialize power savings statistics for * the given sched_domain, during load balancing.
@@ -3669,7 +3669,7 @@ static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, return 1; } -#else /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ +#else /* CONFIG_SCHED_POWERSAVE */ static inline void init_sd_power_savings_stats (struct sched_domain *sd,struct sd_lb_stats *sds,enum cpu_idle_type idle) {
@@ -3687,7 +3687,7 @@ static inline int check_power_save_busiest_group(struct sd_lb_stats *sds, {return 0 ; } -#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */ +#endif /* CONFIG_SCHED_POWERSAVE */ unsigned long default_scale_freq_power (struct sched_domain *sd,int cpu)
@@ -4422,9 +4422,10 @@ static int need_active_balance(struct sched_domain *sd, int idle,* * The package power saving logic comes from * find_busiest_group(). If there are no imbalance, then -* f_b_g() will return NULL. However when sched_mc={1,2} then -* f_b_g() will select a group from which a running task may be -* pulled to this cpu in order to make the other package idle. +* f_b_g() will return NULL. However when +* sched_powersavings={1,2} then f_b_g() will select a group +* from which a running task may be pulled to this cpu +* in order to make the other package idle. * If there is no opportunity to make a package idle and if * there are no imbalance, then f_b_g() will return NULL and no * action will be taken in load_balance_newidle().
@@ -4434,7 +4435,7 @@ static int need_active_balance(struct sched_domain *sd, int idle,* move_tasks() will succeed. ld_moved will be true and this * active balance code will not be triggered. */ -if (sched_mc_power_savings <POWERSAVINGS_BALANCE_WAKEUP ) +if (sched_power_savings <POWERSAVINGS_MAX )return 0 ; }
@@ -4739,7 +4740,7 @@ static struct {unsigned long next_balance;/* in jiffy units */ } nohz____cacheline_aligned ; -#if defined(CONFIG_SCHED_MC ) || defined(CONFIG_SCHED_SMT ) +#ifdef CONFIG_SCHED_POWERSAVE /** * lowest_flag_domain - Return lowest sched_domain containing flag. * @cpu: The cpu whose lowest level of sched domain is to
@@ -4796,7 +4797,7 @@ static int find_new_ilb(int cpu)* Have idle load balancer selection from semi-idle packages only * when power-aware load balancing is enabled */ -if (!(sched_smt_power_savings || sched_mc_power_savings)) +if (!(sched_power_savings)) goto out_done;/*
@@ -4831,7 +4832,7 @@ out_done: return nr_cpu_ids; } -#else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */ +#else /* (CONFIG_SCHED_POWERSAVE) */ static inline int find_new_ilb (int call_cpu) {return nr_cpu_ids;
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 12 lines · Vaidyanathan Srinivasan
+++
b/block/blk.hblock/blk.h +2
-5@@ -167,14 +167,15 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)static inline int blk_cpu_to_group (int cpu) {int group =NR_CPUS ; -#ifdef CONFIG_SCHED_MC -const struct cpumask *mask =cpu_coregroup_mask (cpu); - group =cpumask_first (mask); -#elif defined(CONFIG_SCHED_SMT ) - group =cpumask_first (topology_thread_cpumask (cpu)); +#ifdef CONFIG_SCHED_POWERSAVE +if (smt_capable ())
block/blk.h static inline int queue_congestion_off_threshold(struct request_queue *q) · line 181
Quoted 10 lines
block/blk.h +4
-0+ group =cpumask_first (topology_thread_cpumask (cpu)); + else + group =cpumask_first (cpu_coregroup_mask (cpu));#else return cpu;#endif +/* Possible dead code?? */ if (likely (group <NR_CPUS ))return group;return cpu;
After going, WTF is block doing! I had a closer look and this doesn't seem right at all. The old code would use coregroup_mask when SCHED_MC && SCHED_SMT, the new code does something else.
Jens, what is this thing trying to do?
Jens Axboe
maintainerRe: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 28 lines · Peter Zijlstra
Quoted 12 lines · Vaidyanathan Srinivasan
+++
b/block/blk.hblock/blk.h +2
-5@@ -167,14 +167,15 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)static inline int blk_cpu_to_group (int cpu) {int group =NR_CPUS ; -#ifdef CONFIG_SCHED_MC -const struct cpumask *mask =cpu_coregroup_mask (cpu); - group =cpumask_first (mask); -#elif defined(CONFIG_SCHED_SMT ) - group =cpumask_first (topology_thread_cpumask (cpu)); +#ifdef CONFIG_SCHED_POWERSAVE +if (smt_capable ())block/blk.h static inline int queue_congestion_off_threshold(struct request_queue *q) · line 181
Quoted 10 lines
block/blk.h +4
-0+ group =cpumask_first (topology_thread_cpumask (cpu)); + else + group =cpumask_first (cpu_coregroup_mask (cpu));#else return cpu;#endif +/* Possible dead code?? */ if (likely (group <NR_CPUS ))return group;return cpu;After going, WTF is block doing! I had a closer look and this doesn't seem right at all. The old code would use
coregroup_maskwhenSCHED_MC&&SCHED_SMT, the new code does something else.
Quoted 1 line
Jens, what is this thing trying to do?
Not surprised that it's broken for some configs. The intent of the code is to return the first CPU in the "group" that the passed in core/thread belongs to. This is used to decide whether to perform a completion locally, or to send it off to a different "group".
Signature · 1 line
Jens Axboe
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 8 lines · Jens Axboe
Quoted 1 line · Peter Zijlstra
Jens, what is this thing trying to do?
The intent of the code
is to return the first CPU in the "group" that the passed in core/thread belongs to. This is used to decide whether to perform a completion locally, or to send it off to a different "group".
Would you perhaps have meant to identify some shared cache domain?
In the scheduler core code we have (for CONFIG_SMP):
static int ttwu_share_cache(int this_cpu, int that_cpu);
which returns true if this and that share a cache and false otherwise. Would that suffice or do you need a slightly different form? That is, we should provide you with some API and avoid you having to poke around with CONFIG_SCHED* and topology bits methinks.
Jens Axboe
maintainerRe: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 12 lines · Peter Zijlstra
Quoted 8 lines · Jens Axboe
Quoted 1 line · Peter Zijlstra
Jens, what is this thing trying to do?
The intent of the code
is to return the first CPU in the "group" that the passed in core/thread belongs to. This is used to decide whether to perform a completion locally, or to send it off to a different "group".Would you perhaps have meant to identify some shared cache domain?
Quoted 8 lines
In the scheduler core code we have (for
CONFIG_SMP):static int ttwu_share_cache(int this_cpu, int that_cpu);which returns true if this and that share a cache and false otherwise. Would that suffice or do you need a slightly different form? That is, we should provide you with some API and avoid you having to poke around with CONFIG_SCHED* and topology bits methinks.
Yeah, I think that would suit my purpose nicely, in fact. What level of cache sharing is being used here? The block code wanted a per-socket type operation, but since it's a heuristic, perhaps the above is even better (or equivelant, perhaps).
Signature · 1 line
Jens Axboe
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 5 lines · Jens Axboe
O
Yeah, I think that would suit my purpose nicely, in fact. What level of cache sharing is being used here? The block code wanted a per-socket type operation, but since it's a heuristic, perhaps the above is even better (or equivelant, perhaps).
It uses the biggest shared cache exposed in the topology information the scheduler has (which is currently somewhat funny but is on the todo list for improvements).
Effectively it ends up being the socket wide LLC for modern Intel chips though.
Would something like the below work for you (compile tested only).
---
Subject: sched, block: Unify cache detection
From: Peter Zijlstra <[email protected]>
Date: Thu Jan 26 12:44:34 CET 2012
The block layer has some code trying to determine if two CPUs share a cache, the scheduler has a similar function. Expose the function used by the scheduler and make the block layer use it, thereby removing the block layers usage of CONFIG_SCHED* and topology bits.
--- block/blk-softirq.c | 16 ++++++++-------- block/blk.h | 16 ---------------- include/linux/sched.h | 8 ++++++++ kernel/sched/core.c | 6 +++--- 4 files changed, 19 insertions(+), 27 deletions(-)
block/blk-softirq.c +8 -8
@@ -8,6 +8,7 @@#include <linux/blkdev.h> #include <linux/interrupt.h> #include <linux/cpu.h> +#include <linux/sched.h> #include "blk.h"
@@ -103,9 +104,10 @@ static struct notifier_block __cpuinitdavoid __blk_complete_request (struct request *req) { -int ccpu, cpu, group_cpu =NR_CPUS ; +int ccpu, cpu;struct request_queue *q = req->q;unsigned long flags; +bool shared = false;BUG_ON (!q->softirq_done_fn);
@@ -117,22 +119,20 @@ void __blk_complete_request(struct reque*/ if (req->cpu !=-1 ) { ccpu = req->cpu; -if (!test_bit (QUEUE_FLAG_SAME_FORCE , &q->queue_flags)) { - ccpu =blk_cpu_to_group (ccpu); - group_cpu =blk_cpu_to_group (cpu); - } +if (!test_bit (QUEUE_FLAG_SAME_FORCE , &q->queue_flags)) + shared =cpus_share_cache (cpu, ccpu); }else ccpu = cpu;/* -* If current CPU and requested CPU are in the same group, running -* softirq in current CPU. One might concern this is just like +* If current CPU and requested CPU share a cache, run the softirq on +* the current CPU. One might concern this is just like * QUEUE_FLAG_SAME_FORCE, but actually not. blk_complete_request() is * running in interrupt handler, and currently I/O controller doesn't * support multiple interrupts, so current CPU is unique actually. This * avoids IPI sending from current CPU to the first CPU of a group. */ -if (ccpu == cpu || ccpu == group_cpu) { +if (ccpu == cpu || shared) {struct list_head *list; do_local: list = &__get_cpu_var (blk_cpu_done);
block/blk.h +0 -16
@@ -164,22 +164,6 @@ static inline int queue_congestion_off_treturn q->nr_congestion_off; } -static inline int blk_cpu_to_group (int cpu) -{ -int group =NR_CPUS ; -#ifdef CONFIG_SCHED_MC -const struct cpumask *mask =cpu_coregroup_mask (cpu); - group =cpumask_first (mask); -#elif defined(CONFIG_SCHED_SMT ) - group =cpumask_first (topology_thread_cpumask (cpu)); -#else -return cpu; -#endif -if (likely (group <NR_CPUS )) -return group; -return cpu; -} -/* * Contribute to IO statistics IFF: *
include/linux/sched.h +8 -0
@@ -1052,6 +1052,8 @@ static inline int test_sd_parent(structunsigned long default_scale_freq_power (struct sched_domain *sd,int cpu);unsigned long default_scale_smt_power (struct sched_domain *sd,int cpu); +bool cpus_share_cache (int this_cpu,int that_cpu); +#else /* CONFIG_SMP */ struct sched_domain_attr ;
@@ -1061,6 +1063,12 @@ partition_sched_domains(int ndoms_new, c struct sched_domain_attr *dattr_new) { } + +static inline bool cpus_share_cache (int this_cpu,int that_cpu) +{ +return true; +} +#endif /* !CONFIG_SMP */
kernel/sched/core.c +3 -3
@@ -1512,7 +1512,7 @@ static int ttwu_activate_remote(struct t }#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ -static inline int ttwu_share_cache (int this_cpu,int that_cpu) +bool cpus_share_cache (int this_cpu,int that_cpu) {return per_cpu (sd_llc_id, this_cpu) ==per_cpu (sd_llc_id, that_cpu); }
@@ -1523,7 +1523,7 @@ static void ttwu_queue(struct task_strucstruct rq *rq =cpu_rq (cpu);#if defined(CONFIG_SMP ) -if (sched_feat (TTWU_QUEUE ) && !ttwu_share_cache (smp_processor_id (), cpu)) { +if (sched_feat (TTWU_QUEUE ) && !cpus_share_cache (smp_processor_id (), cpu)) {sched_clock_cpu (cpu);/* sync clocks x-cpu */ ttwu_queue_remote (p, cpu);return ;
@@ -5759,7 +5759,7 @@ static void destroy_sched_domains(struct* * Also keep a unique ID per domain (we use the first cpu number in * the cpumask of the domain), this allows us to quickly tell if -* two cpus are in the same cache domain, see ttwu_share_cache(). +* two cpus are in the same cache domain, see cpus_share_cache(). */ DEFINE_PER_CPU(struct sched_domain *, sd_llc);DEFINE_PER_CPU (int, sd_llc_id);
Jens Axboe
maintainerRe: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 7 lines · Peter Zijlstra
Quoted 5 lines · Jens Axboe
O
Yeah, I think that would suit my purpose nicely, in fact. What level of cache sharing is being used here? The block code wanted a per-socket type operation, but since it's a heuristic, perhaps the above is even better (or equivelant, perhaps).
Quoted 8 lines
It uses the biggest shared cache exposed in the topology information the scheduler has (which is currently somewhat funny but is on the todo list for improvements).
Effectively it ends up being the socket wide LLC for modern Intel chips though.
Would something like the below work for you (compile tested only).
Yep, looks good to me, and an improvement for me not to carry this code that doesn't really belong there.
Signature · 1 line
Jens Axboe
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 3 lines · Jens Axboe
Yep, looks good to me, and an improvement for me not to carry this code
that doesn't really belong there.
I'll take this as an ACK from you and slam the patch in my 3.4 queue. Yell if I misconstrued your intent.
Thanks!
Jens Axboe
maintainerRe: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 7 lines · Peter Zijlstra
Quoted 3 lines · Jens Axboe
Yep, looks good to me, and an improvement for me not to carry this code
that doesn't really belong there.I'll take this as an ACK from you and slam the patch in my 3.4 queue. Yell if I misconstrued your intent.
Sorry, should have been clearer. Yes, you can add my acked-by. Thanks Peter!
Signature · 1 line
Jens Axboe
[tip:sched/core] sched, block: Unify cache detection
In reply to Peter ZijlstraCommit-ID: 39be350127ec60a078edffe5b4915dafba4ba514 Gitweb: http://git.kernel.org/tip/39be350127ec60a078edffe5b4915dafba4ba514 Author: Peter Zijlstra <[email protected]> AuthorDate: Thu, 26 Jan 2012 12:44:34 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 27 Jan 2012 13:28:48 +0100
sched, block: Unify cache detection
The block layer has some code trying to determine if two CPUs share a cache, the scheduler has a similar function. Expose the function used by the scheduler and make the block layer use it, thereby removing the block layers usage of CONFIG_SCHED* and topology bits.
--- block/blk-softirq.c | 16 ++++++++-------- block/blk.h | 16 ---------------- include/linux/sched.h | 8 ++++++++ kernel/sched/core.c | 6 +++--- 4 files changed, 19 insertions(+), 27 deletions(-)
block/blk-softirq.c +8 -8
@@ -8,6 +8,7 @@#include <linux/blkdev.h> #include <linux/interrupt.h> #include <linux/cpu.h> +#include <linux/sched.h> #include "blk.h"
@@ -103,9 +104,10 @@ static struct notifier_block __cpuinitdata blk_cpu_notifier = {void __blk_complete_request (struct request *req) { -int ccpu, cpu, group_cpu =NR_CPUS ; +int ccpu, cpu;struct request_queue *q = req->q;unsigned long flags; +bool shared = false;BUG_ON (!q->softirq_done_fn);
@@ -117,22 +119,20 @@ void __blk_complete_request(struct request *req)*/ if (req->cpu !=-1 ) { ccpu = req->cpu; -if (!test_bit (QUEUE_FLAG_SAME_FORCE , &q->queue_flags)) { - ccpu =blk_cpu_to_group (ccpu); - group_cpu =blk_cpu_to_group (cpu); - } +if (!test_bit (QUEUE_FLAG_SAME_FORCE , &q->queue_flags)) + shared =cpus_share_cache (cpu, ccpu); }else ccpu = cpu;/* -* If current CPU and requested CPU are in the same group, running -* softirq in current CPU. One might concern this is just like +* If current CPU and requested CPU share a cache, run the softirq on +* the current CPU. One might concern this is just like * QUEUE_FLAG_SAME_FORCE, but actually not. blk_complete_request() is * running in interrupt handler, and currently I/O controller doesn't * support multiple interrupts, so current CPU is unique actually. This * avoids IPI sending from current CPU to the first CPU of a group. */ -if (ccpu == cpu || ccpu == group_cpu) { +if (ccpu == cpu || shared) {struct list_head *list; do_local: list = &__get_cpu_var (blk_cpu_done);
block/blk.h +0 -16
@@ -164,22 +164,6 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)return q->nr_congestion_off; } -static inline int blk_cpu_to_group (int cpu) -{ -int group =NR_CPUS ; -#ifdef CONFIG_SCHED_MC -const struct cpumask *mask =cpu_coregroup_mask (cpu); - group =cpumask_first (mask); -#elif defined(CONFIG_SCHED_SMT ) - group =cpumask_first (topology_thread_cpumask (cpu)); -#else -return cpu; -#endif -if (likely (group <NR_CPUS )) -return group; -return cpu; -} -/* * Contribute to IO statistics IFF: *
include/linux/sched.h +8 -0
@@ -1052,6 +1052,8 @@ static inline int test_sd_parent(struct sched_domain *sd, int flag)unsigned long default_scale_freq_power (struct sched_domain *sd,int cpu);unsigned long default_scale_smt_power (struct sched_domain *sd,int cpu); +bool cpus_share_cache (int this_cpu,int that_cpu); +#else /* CONFIG_SMP */ struct sched_domain_attr ;
@@ -1061,6 +1063,12 @@ partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], struct sched_domain_attr *dattr_new) { } + +static inline bool cpus_share_cache (int this_cpu,int that_cpu) +{ +return true; +} +#endif /* !CONFIG_SMP */
kernel/sched/core.c +3 -3
@@ -1507,7 +1507,7 @@ static int ttwu_activate_remote(struct task_struct *p, int wake_flags) }#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */ -static inline int ttwu_share_cache (int this_cpu,int that_cpu) +bool cpus_share_cache (int this_cpu,int that_cpu) {return per_cpu (sd_llc_id, this_cpu) ==per_cpu (sd_llc_id, that_cpu); }
@@ -1518,7 +1518,7 @@ static void ttwu_queue(struct task_struct *p, int cpu)struct rq *rq =cpu_rq (cpu);#if defined(CONFIG_SMP ) -if (sched_feat (TTWU_QUEUE ) && !ttwu_share_cache (smp_processor_id (), cpu)) { +if (sched_feat (TTWU_QUEUE ) && !cpus_share_cache (smp_processor_id (), cpu)) {sched_clock_cpu (cpu);/* sync clocks x-cpu */ ttwu_queue_remote (p, cpu);return ;
@@ -5754,7 +5754,7 @@ static void destroy_sched_domains(struct sched_domain *sd, int cpu)* * Also keep a unique ID per domain (we use the first cpu number in * the cpumask of the domain), this allows us to quickly tell if -* two cpus are in the same cache domain, see ttwu_share_cache(). +* two cpus are in the same cache domain, see cpus_share_cache(). */ DEFINE_PER_CPU(struct sched_domain *, sd_llc);DEFINE_PER_CPU (int, sd_llc_id);
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
In reply to Peter ZijlstraQuoted 28 lines · Peter Zijlstra
Quoted 12 lines · Vaidyanathan Srinivasan
+++
b/block/blk.hblock/blk.h +2
-5@@ -167,14 +167,15 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)static inline int blk_cpu_to_group (int cpu) {int group =NR_CPUS ; -#ifdef CONFIG_SCHED_MC -const struct cpumask *mask =cpu_coregroup_mask (cpu); - group =cpumask_first (mask); -#elif defined(CONFIG_SCHED_SMT ) - group =cpumask_first (topology_thread_cpumask (cpu)); +#ifdef CONFIG_SCHED_POWERSAVE +if (smt_capable ())block/blk.h static inline int queue_congestion_off_threshold(struct request_queue *q) · line 181
Quoted 10 lines
block/blk.h +4
-0+ group =cpumask_first (topology_thread_cpumask (cpu)); + else + group =cpumask_first (cpu_coregroup_mask (cpu));#else return cpu;#endif +/* Possible dead code?? */ if (likely (group <NR_CPUS ))return group;return cpu;After going, WTF is block doing! I had a closer look and this doesn't seem right at all. The old code would use
coregroup_maskwhenSCHED_MC&&SCHED_SMT, the new code does something else.
Quoted 1 line
Jens, what is this thing trying to do?
I understood the requirement as get first cpu in the 'core' on a hyper-threaded system and first cpu in the 'socket' on a non-threaded system for best cache affinity. Based on Jens explanation and Peter's patch, identifying last-level shared cache works best for this case.
--Vaidy
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
In reply to Vaidyanathan Srinivasaninclude/linux/sched.h enum cpu_idle_type { · line 858
Quoted 6 lines · Vaidyanathan Srinivasan
include/linux/sched.h +5
-0+enum powersavings_level { +POWERSAVINGS_DISABLED =0 ,/* Max performance */ +POWERSAVINGS_DEFAULT ,/* Kernel default policy, automatic powersave */ +/* vs performance tradeoff */ +POWERSAVINGS_MAX /* Favour power savings over peformance */ };
I don't like that, I can get, OFF, AUTO, ON, but to overload that with different policies for AUTO and ON just reeks.
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 10 lines · Peter Zijlstra
include/linux/sched.h enum cpu_idle_type { · line 858
Quoted 6 lines · Vaidyanathan Srinivasan
include/linux/sched.h +5
-0+enum powersavings_level { +POWERSAVINGS_DISABLED =0 ,/* Max performance */ +POWERSAVINGS_DEFAULT ,/* Kernel default policy, automatic powersave */ +/* vs performance tradeoff */ +POWERSAVINGS_MAX /* Favour power savings over peformance */ };I don't like that, I can get, OFF, AUTO, ON, but to overload that with different policies for AUTO and ON just reeks.
How about this:
enum powersavings_level {
POWERSAVINGS_OFF = 0, /* Max performance */
POWERSAVINGS_AUTO, /* Kernel default policy, automatic powersave */
/* vs performance tradeoff */
POWERSAVINGS_ON /* Max power savings */
};
Basically AUTO is where we have a 'policy' or heuristics, but simple straight forward decisions for OFF and ON case.
--Vaidy
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
In reply to Vaidyanathan SrinivasanQuoted 23 lines · Vaidyanathan Srinivasan
kernel/sched/core.c +2
-4@@ -6150,10 +6150,8 @@ SD_INIT_FUNC(CPU) SD_INIT_FUNC(ALLNODES) SD_INIT_FUNC(NODE) #endif -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE SD_INIT_FUNC(SIBLING) -#endif -#ifdef CONFIG_SCHED_MC SD_INIT_FUNC(MC)#endif #ifdef CONFIG_SCHED_BOOK @@ -6250,7 +6248,7 @@ static void claim_allocations(int cpu, struct sched_domain *sd) *per_cpu_ptr (sdd->sgp, cpu) =NULL ; } -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE static const struct cpumask *cpu_smt_mask (int cpu) {return topology_thread_cpumask (cpu);@@ -6261,10 +6259,8 @@ static const struct cpumask *cpu_smt_mask(int cpu)* Topology list, bottom-up.
kernel/sched/core.c static const struct cpumask *cpu_smt_mask(int cpu) · line 6266
Quoted 10 lines
kernel/sched/core.c +1
-3*/ static struct sched_domain_topology_level default_topology[] = { -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE { sd_init_SIBLING, cpu_smt_mask, }, -#endif -#ifdef CONFIG_SCHED_MC { sd_init_MC, cpu_coregroup_mask, }, #endif #ifdef CONFIG_SCHED_BOOK
I don't like this either, SCHED_{MC,SMT} here have nothing to do with powersavings, its topology support.
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
On 1/25/2012 7:10 AM, Peter Zijlstra wrote:
btw... any reason why this feature is a config option with tons of ifdefs... why not just have this available all the time? it shouldn't be all that much code in the first place.
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 6 lines · Arjan van de Ven
On 1/25/2012 7:10 AM, Peter Zijlstra wrote:
btw... any reason why this feature is a config option with tons of ifdefs... why not just have this available all the time? it shouldn't be all that much code in the first place.
I guess its because SCHED_SMT and SCHED_MC also indicate the availability of the topology functions like cpu_coregroup_mask() etc.
The whole powersave stuff got intermixed with all that.
But yes, I agree, we should kill all that and sort the topology stuff differently.
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
In reply to Peter ZijlstraQuoted 29 lines · Peter Zijlstra
Quoted 28 lines · Vaidyanathan Srinivasan
kernel/sched/core.c +3
-5@@ -6150,10 +6150,8 @@ SD_INIT_FUNC(CPU) SD_INIT_FUNC(ALLNODES) SD_INIT_FUNC(NODE) #endif -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE SD_INIT_FUNC(SIBLING) -#endif -#ifdef CONFIG_SCHED_MC SD_INIT_FUNC(MC)#endif #ifdef CONFIG_SCHED_BOOK @@ -6250,7 +6248,7 @@ static void claim_allocations(int cpu, struct sched_domain *sd) *per_cpu_ptr (sdd->sgp, cpu) =NULL ; } -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE static const struct cpumask *cpu_smt_mask (int cpu) {return topology_thread_cpumask (cpu);@@ -6261,10 +6259,8 @@ static const struct cpumask *cpu_smt_mask(int cpu)* Topology list, bottom-up. */ static struct sched_domain_topology_level default_topology[] = { -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE { sd_init_SIBLING, cpu_smt_mask, },
Quoted 8 lines
kernel/sched/core.c static const struct cpumask *cpu_smt_mask(int cpu) · line 6266
Quoted 5 lines
kernel/sched/core.c +0
-2-#endif -#ifdef CONFIG_SCHED_MC { sd_init_MC, cpu_coregroup_mask, }, #endif #ifdef CONFIG_SCHED_BOOKI don't like this either, SCHED_{MC,SMT} here have nothing to do with powersavings, its topology support.
Yes, but we don't need these domains for any other purpose other than powersave balance. The code overheads are not high, I will remove the config option and check.
--Vaidy
Re: [RFC PATCH v1 1/2] sched: unified sched_powersavings sysfs tunable
Quoted 40 lines · Vaidyanathan Srinivasan
Quoted 29 lines · Peter Zijlstra
Quoted 28 lines · Vaidyanathan Srinivasan
kernel/sched/core.c +3
-5@@ -6150,10 +6150,8 @@ SD_INIT_FUNC(CPU) SD_INIT_FUNC(ALLNODES) SD_INIT_FUNC(NODE) #endif -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE SD_INIT_FUNC(SIBLING) -#endif -#ifdef CONFIG_SCHED_MC SD_INIT_FUNC(MC)#endif #ifdef CONFIG_SCHED_BOOK @@ -6250,7 +6248,7 @@ static void claim_allocations(int cpu, struct sched_domain *sd) *per_cpu_ptr (sdd->sgp, cpu) =NULL ; } -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE static const struct cpumask *cpu_smt_mask (int cpu) {return topology_thread_cpumask (cpu);@@ -6261,10 +6259,8 @@ static const struct cpumask *cpu_smt_mask(int cpu)* Topology list, bottom-up. */ static struct sched_domain_topology_level default_topology[] = { -#ifdef CONFIG_SCHED_SMT +#ifdef CONFIG_SCHED_POWERSAVE { sd_init_SIBLING, cpu_smt_mask, },Quoted 8 lines
kernel/sched/core.c static const struct cpumask *cpu_smt_mask(int cpu) · line 6266
Quoted 5 lines
kernel/sched/core.c +0
-2-#endif -#ifdef CONFIG_SCHED_MC { sd_init_MC, cpu_coregroup_mask, }, #endif #ifdef CONFIG_SCHED_BOOKI don't like this either, SCHED_{MC,SMT} here have nothing to do with powersavings, its topology support.
Quoted 3 lines
Yes, but we don't need these domains for any other purpose other than powersave balance. The code overheads are not high, I will remove the config option and check.
Yes we do, SMT perf skips siblings and only loads them when there's only siblings left idle. Similarly for MC, we prefer to run tasks on separate sockets when possible.
RFC PATCH 2/2 sched: fix group_capacity for thread level consolidation
In reply to Vaidyanathan Srinivasansched_powersavings for threaded systems need this fix for consolidation to sibling threads to work. Since threads have fractional capacity, group_capacity will turn out to be one always and not accommodate another task in the sibling thread.
This fix makes group_capacity a function of cpumask_weight that will enable the power saving load balancer to pack tasks among sibling threads and keep more cores idle.
--- kernel/sched/fair.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-)
kernel/sched/fair.c +15 -0
@@ -4012,6 +4012,21 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,*/ if (prefer_sibling && !local_group && sds->this_has_capacity) sgs.group_capacity =min (sgs.group_capacity,1UL ); +/* +* If power savings balance is set at this domain, then +* make capacity equal to number of hardware threads to +* accommodate more tasks until capacity is reached. +*/ +else if (sd->flags &SD_POWERSAVINGS_BALANCE ) + sgs.group_capacity = +cpumask_weight (sched_group_cpus (sg)); + +/* +* The default group_capacity is rounded from sum of +* fractional cpu_powers of sibling hardware threads +* in order to enable fair use of available hardware +* resources. +*/ if (local_group) { sds->this_load = sgs.avg_load;
Re: [RFC PATCH v1 2/2] sched: fix group_capacity for thread level consolidation
kernel/sched/fair.c static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, · line 4022
Quoted 8 lines · Vaidyanathan Srinivasan
kernel/sched/fair.c +8
-0+/* +* If power savings balance is set at this domain, then +* make capacity equal to number of hardware threads to +* accommodate more tasks until capacity is reached. +*/ + else if (sd->flags & SD_POWERSAVINGS_BALANCE) + sgs.group_capacity = +cpumask_weight (sched_group_cpus (sg));
sg->group_weight perhaps?
Re: [RFC PATCH v1 2/2] sched: fix group_capacity for thread level consolidation
Quoted 11 lines · Peter Zijlstra
kernel/sched/fair.c static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu, · line 4022
Quoted 8 lines · Vaidyanathan Srinivasan
kernel/sched/fair.c +8
-0+/* +* If power savings balance is set at this domain, then +* make capacity equal to number of hardware threads to +* accommodate more tasks until capacity is reached. +*/ + else if (sd->flags & SD_POWERSAVINGS_BALANCE) + sgs.group_capacity = +cpumask_weight (sched_group_cpus (sg));
sg->group_weightperhaps?
Yes, I will correct this. sg->group_weight is updated to the correct value on sched_domain rebuild in init_sched_groups_power().
--Vaidy
Quoted 7 lines · Vaidyanathan Srinivasan
Hi,
I have created the following RFC patch based on the recent discussions and consensus on simplifying the power aware scheduler in the kernel.
Ref: LWN: Rethinking power-aware scheduling
http://lwn.net/Articles/474915/
https://lkml.org/lkml/2012/1/10/61