Reduce migrations and unnecessary spreading of load to multiple CPUs
Subsystems (3)
cover Reduce migrations and unnecessary spreading of load to multiple CPUs
It has been observed recently that problems with interaction between scheduler decisions and cpufreq decisions have been unfavourable. The scheduler decisions are biased towards reducing latency of searches which is great on one hand but tends to spread load across an entire socket unnecessarily. On low utilisation, this means the load on each individual CPU is low which can be good but cpufreq decides that utilisation on individual CPUs is too low to increase P-state and overall throughput suffers.
When a cpufreq driver is completely under the control of the OS, it can be compensated for. For example, intel_pstate can decide to boost apparent utilisation if a task recently slept on a CPU for idle. However, if hardware-based cpufreq is in play (e.g. HWP) then very poor decisions can be made and the OS cannot do much about it. This only gets worse as HWP becomes more prevalent, sockets get larger and the p-state for individual cores can be controlled. Just setting the performance governor is not an answer given that plenty of people really do worry about power utilisation and still want a reasonable balance between performance and power.
Patches 0-3 of this series reduce the number of migrations due to interrupts.
Specifically, if prev CPU and the current CPU share cache and prev CPU is idle then use it in preference to migrating the load. The full reasoning why is in the changelog.
Patch 4 observes that co-operating tasks, particularly between an application
and a kworker can push a load around a socket very quickly. This is particularly true if interrupts are involved (e.g. IO completions) and are delivered round-robin (e.g. due to MSI-X). It tracks what CPU was used for a recent wakeup and reuses that CPU if it's still idle when woken later. This reduces the number of cores that are active for a workload and can have a big boost in throughput without a hit to wakeup latency or stacking multiple tasks on one CPU when a machine is lightly loaded.
include/linux/sched.h | 8 ++++++ kernel/sched/core.c | 1 + kernel/sched/fair.c | 69 +++++++++++++++++++++++++++++++++------------------ 3 files changed, 54 insertions(+), 24 deletions(-)
Signature · 1 line
2.15.1
PATCH 1/4 sched/fair: Remove unnecessary parameters from wake_affine_idle
wake_affine_idle takes parameters it never uses so clean it up.
--- kernel/sched/fair.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
kernel/sched/fair.c +3 -5
@@ -5696,10 +5696,8 @@ static int wake_wide(struct task_struct *p)* scheduling latency of the CPUs. This seems to work * for the overloaded case. */ -static bool -wake_affine_idle (struct sched_domain *sd,struct task_struct *p, -int this_cpu,int prev_cpu,int sync) +wake_affine_idle (int this_cpu,int prev_cpu,int sync) {/* * If this_cpu is idle, it implies the wakeup is from interrupt
@@ -5756,8 +5754,8 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p,int this_cpu =smp_processor_id ();bool affine = false; -if (sched_feat (WA_IDLE ) && !affine) - affine =wake_affine_idle (sd, p, this_cpu, prev_cpu, sync); +if (sched_feat (WA_IDLE )) + affine =wake_affine_idle (this_cpu, prev_cpu, sync);if (sched_feat (WA_WEIGHT ) && !affine) affine =wake_affine_weight (sd, p, this_cpu, prev_cpu, sync);
Signature · 1 line
2.15.1
tip-bot for Mel Gorman
merge bot[tip:sched/urgent] sched/fair: Remove unnecessary parameters from wake_affine_idle()
sched/fair: Remove unnecessary parameters from wake_affine_idle()
Commit-ID: 89a55f56fd1cdbe7e69d4693fc5790af9a6e1501 Gitweb: https://git.kernel.org/tip/89a55f56fd1cdbe7e69d4693fc5790af9a6e1501 Author: Mel Gorman <[email protected]> AuthorDate: Tue, 30 Jan 2018 10:45:52 +0000 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 6 Feb 2018 10:20:35 +0100
sched/fair: Remove unnecessary parameters from wake_affine_idle()
wake_affine_idle() takes parameters it never uses so clean it up.
--- kernel/sched/fair.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
kernel/sched/fair.c +3 -5
@@ -5692,10 +5692,8 @@ static int wake_wide(struct task_struct *p)* scheduling latency of the CPUs. This seems to work * for the overloaded case. */ -static bool -wake_affine_idle (struct sched_domain *sd,struct task_struct *p, -int this_cpu,int prev_cpu,int sync) +wake_affine_idle (int this_cpu,int prev_cpu,int sync) {/* * If this_cpu is idle, it implies the wakeup is from interrupt
@@ -5752,8 +5750,8 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p,int this_cpu =smp_processor_id ();bool affine = false; -if (sched_feat (WA_IDLE ) && !affine) - affine =wake_affine_idle (sd, p, this_cpu, prev_cpu, sync); +if (sched_feat (WA_IDLE )) + affine =wake_affine_idle (this_cpu, prev_cpu, sync);if (sched_feat (WA_WEIGHT ) && !affine) affine =wake_affine_weight (sd, p, this_cpu, prev_cpu, sync);
PATCH 2/4 sched/fair: Restructure wake_affine to return a CPU id
In reply to Mel GormanThis is a preparation patch that has wake_affine return a CPU ID instead of a boolean. The intent is to allow the wake_affine() helpers to be avoided if a decision is already made. This patch has no functional change.
--- kernel/sched/fair.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-)
kernel/sched/fair.c +17 -18
@@ -5696,7 +5696,7 @@ static int wake_wide(struct task_struct *p)* scheduling latency of the CPUs. This seems to work * for the overloaded case. */ -static bool +static int wake_affine_idle (int this_cpu,int prev_cpu,int sync) {/*
@@ -5706,15 +5706,15 @@ wake_affine_idle(int this_cpu, int prev_cpu, int sync)* node depending on the IO topology or IRQ affinity settings. */ if (idle_cpu (this_cpu) &&cpus_share_cache (this_cpu, prev_cpu)) -return true; +return this_cpu;if (sync &&cpu_rq (this_cpu)->nr_running ==1 ) -return true; +return this_cpu; -return false; +return nr_cpumask_bits; } -static bool +static int wake_affine_weight (struct sched_domain *sd,struct task_struct *p,int this_cpu,int prev_cpu,int sync) {
@@ -5728,7 +5728,7 @@ wake_affine_weight(struct sched_domain *sd, struct task_struct *p,unsigned long current_load =task_h_load (current);if (current_load > this_eff_load) -return true; +return this_cpu; this_eff_load -= current_load; }
@@ -5745,28 +5745,28 @@ wake_affine_weight(struct sched_domain *sd, struct task_struct *p, prev_eff_load *=100 + (sd->imbalance_pct -100 ) /2 ; prev_eff_load *=capacity_of (this_cpu); -return this_eff_load <= prev_eff_load; +return this_eff_load <= prev_eff_load ? this_cpu : nr_cpumask_bits; }static int wake_affine (struct sched_domain *sd,struct task_struct *p,int prev_cpu,int sync) {int this_cpu =smp_processor_id (); -bool affine = false; +int target = nr_cpumask_bits;if (sched_feat (WA_IDLE )) - affine =wake_affine_idle (this_cpu, prev_cpu, sync); + target =wake_affine_idle (this_cpu, prev_cpu, sync); -if (sched_feat (WA_WEIGHT ) && !affine) - affine =wake_affine_weight (sd, p, this_cpu, prev_cpu, sync); +if (sched_feat (WA_WEIGHT ) && target == nr_cpumask_bits) + target =wake_affine_weight (sd, p, this_cpu, prev_cpu, sync);schedstat_inc (p->se.statistics.nr_wakeups_affine_attempts); -if (affine) { -schedstat_inc (sd->ttwu_move_affine); -schedstat_inc (p->se.statistics.nr_wakeups_affine); - } +if (target == nr_cpumask_bits) +return prev_cpu; -return affine; +schedstat_inc (sd->ttwu_move_affine); +schedstat_inc (p->se.statistics.nr_wakeups_affine); +return target; }static inline int task_util (struct task_struct *p);
@@ -6359,8 +6359,7 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_fif (cpu == prev_cpu) goto pick_cpu; -if (wake_affine (affine_sd, p, prev_cpu, sync)) - new_cpu = cpu; + new_cpu =wake_affine (affine_sd, p, prev_cpu, sync); }if (sd && !(sd_flag &SD_BALANCE_FORK )) {
Signature · 1 line
2.15.1
tip-bot for Mel Gorman
merge bot[tip:sched/urgent] sched/fair: Restructure wake_affine*() to return a CPU id
sched/fair: Restructure wake_affine*() to return a CPU id
Commit-ID: 3b76c4a33959ca98a573cd9c94c8690d123912ca Gitweb: https://git.kernel.org/tip/3b76c4a33959ca98a573cd9c94c8690d123912ca Author: Mel Gorman <[email protected]> AuthorDate: Tue, 30 Jan 2018 10:45:53 +0000 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 6 Feb 2018 10:20:35 +0100
sched/fair: Restructure wake_affine*() to return a CPU id
This is a preparation patch that has wake_affine*() return a CPU ID instead of a boolean. The intent is to allow the wake_affine() helpers to be avoided if a decision is already made. This patch has no functional change.
--- kernel/sched/fair.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-)
kernel/sched/fair.c +17 -18
@@ -5692,7 +5692,7 @@ static int wake_wide(struct task_struct *p)* scheduling latency of the CPUs. This seems to work * for the overloaded case. */ -static bool +static int wake_affine_idle (int this_cpu,int prev_cpu,int sync) {/*
@@ -5702,15 +5702,15 @@ wake_affine_idle(int this_cpu, int prev_cpu, int sync)* node depending on the IO topology or IRQ affinity settings. */ if (idle_cpu (this_cpu) &&cpus_share_cache (this_cpu, prev_cpu)) -return true; +return this_cpu;if (sync &&cpu_rq (this_cpu)->nr_running ==1 ) -return true; +return this_cpu; -return false; +return nr_cpumask_bits; } -static bool +static int wake_affine_weight (struct sched_domain *sd,struct task_struct *p,int this_cpu,int prev_cpu,int sync) {
@@ -5724,7 +5724,7 @@ wake_affine_weight(struct sched_domain *sd, struct task_struct *p,unsigned long current_load =task_h_load (current);if (current_load > this_eff_load) -return true; +return this_cpu; this_eff_load -= current_load; }
@@ -5741,28 +5741,28 @@ wake_affine_weight(struct sched_domain *sd, struct task_struct *p, prev_eff_load *=100 + (sd->imbalance_pct -100 ) /2 ; prev_eff_load *=capacity_of (this_cpu); -return this_eff_load <= prev_eff_load; +return this_eff_load <= prev_eff_load ? this_cpu : nr_cpumask_bits; }static int wake_affine (struct sched_domain *sd,struct task_struct *p,int prev_cpu,int sync) {int this_cpu =smp_processor_id (); -bool affine = false; +int target = nr_cpumask_bits;if (sched_feat (WA_IDLE )) - affine =wake_affine_idle (this_cpu, prev_cpu, sync); + target =wake_affine_idle (this_cpu, prev_cpu, sync); -if (sched_feat (WA_WEIGHT ) && !affine) - affine =wake_affine_weight (sd, p, this_cpu, prev_cpu, sync); +if (sched_feat (WA_WEIGHT ) && target == nr_cpumask_bits) + target =wake_affine_weight (sd, p, this_cpu, prev_cpu, sync);schedstat_inc (p->se.statistics.nr_wakeups_affine_attempts); -if (affine) { -schedstat_inc (sd->ttwu_move_affine); -schedstat_inc (p->se.statistics.nr_wakeups_affine); - } +if (target == nr_cpumask_bits) +return prev_cpu; -return affine; +schedstat_inc (sd->ttwu_move_affine); +schedstat_inc (p->se.statistics.nr_wakeups_affine); +return target; }static inline unsigned long task_util (struct task_struct *p);
@@ -6355,8 +6355,7 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_fif (cpu == prev_cpu) goto pick_cpu; -if (wake_affine (affine_sd, p, prev_cpu, sync)) - new_cpu = cpu; + new_cpu =wake_affine (affine_sd, p, prev_cpu, sync); }if (sd && !(sd_flag &SD_BALANCE_FORK )) {
PATCH 3/4 sched/fair: Do not migrate if the prev_cpu is idle
In reply to Mel Gormanwake_affine_idle prefers to move a task to the current CPU if the wakeup is due to an interrupt. The expectation is that the interrupt data is cache hot and relevant to the waking task as well as avoiding a search. However, there is no way to determine if there was cache hot data on the previous CPU that may exceed the interrupt data. Furthermore, round-robin delivery of interrupts can migrate tasks around a socket where each CPU is under-utilised. This can interact badly with cpufreq which makes decisions based on per-cpu data. It has been observed on machines with HWP that p-states are not boosted to their maximum levels even though the workload is latency and throughput sensitive.
This patch uses the previous CPU for the task if it's idle and cache-affine with the current CPU even if the current CPU is idle due to the wakup being related to the interrupt. This reduces migrations at the cost of the interrupt data not being cache hot when the task wakes.
A variety of workloads were tested on various machines and no adverse impact was noticed that was outside noise. dbench on ext4 on UMA showed roughly 10% reduction in the number of CPU migrations and it is a case where interrupts are frequent for IO competions. In most cases, the difference in performance is quite small but variability is often reduced. For example, this is the result for pgbench running on a UMA machine with different numbers of clients.
4.15.0-rc9 4.15.0-rc9
baseline waprev-v1
Hmean 1 22096.28 ( 0.00%) 22734.86 ( 2.89%)
Hmean 4 74633.42 ( 0.00%) 75496.77 ( 1.16%)
Hmean 7 115017.50 ( 0.00%) 113030.81 ( -1.73%)
Hmean 12 126209.63 ( 0.00%) 126613.40 ( 0.32%)
Hmean 16 131886.91 ( 0.00%) 130844.35 ( -0.79%)
Stddev 1 636.38 ( 0.00%) 417.11 ( 34.46%)
Stddev 4 614.64 ( 0.00%) 583.24 ( 5.11%)
Stddev 7 542.46 ( 0.00%) 435.45 ( 19.73%)
Stddev 12 173.93 ( 0.00%) 171.50 ( 1.40%)
Stddev 16 671.42 ( 0.00%) 680.30 ( -1.32%)
CoeffVar 1 2.88 ( 0.00%) 1.83 ( 36.26%)Note that the different in performance is marginal but for low utilisation, there is less variability.
--- kernel/sched/fair.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
kernel/sched/fair.c +7 -1
@@ -5704,9 +5704,15 @@ wake_affine_idle(int this_cpu, int prev_cpu, int sync)* context. Only allow the move if cache is shared. Otherwise an * interrupt intensive workload could force all tasks onto one * node depending on the IO topology or IRQ affinity settings. +* +* If the prev_cpu is idle and cache affine then avoid a migration. +* There is no guarantee that the cache hot data from an interrupt +* is more important than cache hot data on the prev_cpu and from +* a cpufreq perspective, it's better to have higher utilisation +* on one CPU. */ if (idle_cpu (this_cpu) &&cpus_share_cache (this_cpu, prev_cpu)) -return this_cpu; +return idle_cpu (prev_cpu) ? prev_cpu : this_cpu;if (sync &&cpu_rq (this_cpu)->nr_running ==1 )return this_cpu;
Signature · 1 line
2.15.1
tip-bot for Mel Gorman
merge bot[tip:sched/urgent] sched/fair: Do not migrate if the prev_cpu is idle
sched/fair: Do not migrate if the prev_cpu is idle
Commit-ID: 806486c377e33ab662de6d47902e9e2a32b79368 Gitweb: https://git.kernel.org/tip/806486c377e33ab662de6d47902e9e2a32b79368 Author: Mel Gorman <[email protected]> AuthorDate: Tue, 30 Jan 2018 10:45:54 +0000 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 6 Feb 2018 10:20:36 +0100
sched/fair: Do not migrate if the prev_cpu is idle
wake_affine_idle() prefers to move a task to the current CPU if the wakeup is due to an interrupt. The expectation is that the interrupt data is cache hot and relevant to the waking task as well as avoiding a search. However, there is no way to determine if there was cache hot data on the previous CPU that may exceed the interrupt data. Furthermore, round-robin delivery of interrupts can migrate tasks around a socket where each CPU is under-utilised. This can interact badly with cpufreq which makes decisions based on per-cpu data. It has been observed on machines with HWP that p-states are not boosted to their maximum levels even though the workload is latency and throughput sensitive.
This patch uses the previous CPU for the task if it's idle and cache-affine with the current CPU even if the current CPU is idle due to the wakup being related to the interrupt. This reduces migrations at the cost of the interrupt data not being cache hot when the task wakes.
A variety of workloads were tested on various machines and no adverse impact was noticed that was outside noise. dbench on ext4 on UMA showed roughly 10% reduction in the number of CPU migrations and it is a case where interrupts are frequent for IO competions. In most cases, the difference in performance is quite small but variability is often reduced. For example, this is the result for pgbench running on a UMA machine with different numbers of clients.
4.15.0-rc9 4.15.0-rc9
baseline waprev-v1
Hmean 1 22096.28 ( 0.00%) 22734.86 ( 2.89%)
Hmean 4 74633.42 ( 0.00%) 75496.77 ( 1.16%)
Hmean 7 115017.50 ( 0.00%) 113030.81 ( -1.73%)
Hmean 12 126209.63 ( 0.00%) 126613.40 ( 0.32%)
Hmean 16 131886.91 ( 0.00%) 130844.35 ( -0.79%)
Stddev 1 636.38 ( 0.00%) 417.11 ( 34.46%)
Stddev 4 614.64 ( 0.00%) 583.24 ( 5.11%)
Stddev 7 542.46 ( 0.00%) 435.45 ( 19.73%)
Stddev 12 173.93 ( 0.00%) 171.50 ( 1.40%)
Stddev 16 671.42 ( 0.00%) 680.30 ( -1.32%)
CoeffVar 1 2.88 ( 0.00%) 1.83 ( 36.26%)Note that the different in performance is marginal but for low utilisation, there is less variability.
--- kernel/sched/fair.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
kernel/sched/fair.c +7 -1
@@ -5700,9 +5700,15 @@ wake_affine_idle(int this_cpu, int prev_cpu, int sync)* context. Only allow the move if cache is shared. Otherwise an * interrupt intensive workload could force all tasks onto one * node depending on the IO topology or IRQ affinity settings. +* +* If the prev_cpu is idle and cache affine then avoid a migration. +* There is no guarantee that the cache hot data from an interrupt +* is more important than cache hot data on the prev_cpu and from +* a cpufreq perspective, it's better to have higher utilisation +* on one CPU. */ if (idle_cpu (this_cpu) &&cpus_share_cache (this_cpu, prev_cpu)) -return this_cpu; +return idle_cpu (prev_cpu) ? prev_cpu : this_cpu;if (sync &&cpu_rq (this_cpu)->nr_running ==1 )return this_cpu;
PATCH 4/4 sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Mel GormanThe select_idle_sibling (SIS) rewrite in commit 10e2f1acd010 ("sched/core:
Rewrite and improve select_idle_siblings()") replaced a domain iteration with a search that broadly speaking does a wrapped walk of the scheduler domain sharing a last-level-cache. While this had a number of improvements, one consequence is that two tasks that share a waker/wakee relationship push each other around a socket. Even though two tasks may be active, all cores are evenly used. This is great from a search perspective and spreads a load across individual cores but it has adverse consequences for cpufreq. As each CPU has relatively low utilisation, cpufreq may decide the utilisation is too low to used a higher P-state and overall computation throughput suffers. While individual cpufreq and cpuidle drivers may compensate by artifically boosting P-state (at c0) or avoiding lower C-states (during idle), it does not help if hardware-based cpufreq (e.g. HWP) is used.
This patch tracks a recently used CPU based on what CPU a task was running on when it last was a waker a CPU it was recently using when a task is a wakee. During SIS, the recently used CPU is used as a target if it's still allowed by the task and is idle.
The benefit may be non-obvious so consider an example of two tasks communicating back and forth. Task A may be an application doing IO where task B is a kworker or kthread like journald. Task A may issue IO, wake B and B wakes up A on completion. With the existing scheme this may look like the following (potentially different IDs if SMT is in use but similar principal applies).
A (cpu 0) wake B (wakes on cpu 1)
B (cpu 1) wake A (wakes on cpu 2)
A (cpu 2) wake B (wakes on cpu 3)
etc.
A careful reader may wonder why cpu 0 was not idle when B wakes A the first time and it's simply due to the fact that A can be rescheduled to another CPU and the pattern is that prev == target when B tries to wakeup A and the information about CPU 0 has been lost.
With this patch, the pattern is more likely to be
A (cpu 0) wake B (wakes on cpu 1)
B (cpu 1) wake A (wakes on cpu 0)
A (cpu 0) wake B (wakes on cpu 1)
etc
i.e. two communicating casts are more likely to use just two cores instead of all available cores sharing a LLC.
The most dramatic speedup was noticed on dbench using the XFS filesystem on UMA as clients interact heavily with workqueues in that configuration. Note that a similar speedup is not observed on ext4 as the wakeup pattern is different
4.15.0-rc9 4.15.0-rc9
waprev-v1 biasancestor-v1
Hmean 1 287.54 ( 0.00%) 817.01 ( 184.14%)
Hmean 2 1268.12 ( 0.00%) 1781.24 ( 40.46%)
Hmean 4 1739.68 ( 0.00%) 1594.47 ( -8.35%)
Hmean 8 2464.12 ( 0.00%) 2479.56 ( 0.63%)
Hmean 64 1455.57 ( 0.00%) 1434.68 ( -1.44%)The results can be less dramatic on NUMA where automatic balancing interferes with the test. It's also known that network benchmarks running on localhost also benefit quite a bit from this patch (roughly 10% on netperf RR for UDP and TCP depending on the machine). Hackbench also seens small improvements (6-11% depending on machine and thread count). The facebook schbench was also tested but in most cases showed little or no different to wakeup latencies.
--- include/linux/sched.h | 8 ++++++++ kernel/sched/core.c | 1 + kernel/sched/fair.c | 22 ++++++++++++++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-)
include/linux/sched.h +8 -0
@@ -551,6 +551,14 @@ struct task_struct {unsigned long wakee_flip_decay_ts;struct task_struct *last_wakee; +/* +* recent_used_cpu is initially set as the last CPU used by a task +* that wakes affine another task. Waker/wakee relationships can +* push tasks around a CPU where each wakeup moves to the next one. +* Tracking a recently used CPU allows a quick search for a recently +* used CPU that may be idle. +*/ +int recent_used_cpu;int wake_cpu;#endif int on_rq;
kernel/sched/core.c +1 -0
@@ -2460,6 +2460,7 @@ void wake_up_new_task(struct task_struct *p)* Use __set_task_cpu() to avoid calling sched_class::migrate_task_rq, * as we're not fully set-up yet. */ + p->recent_used_cpu =task_cpu (p);__set_task_cpu (p,select_task_rq (p,task_cpu (p),SD_BALANCE_FORK ,0 ));#endif rq =__task_rq_lock (p, &rf);
kernel/sched/fair.c +20 -2
@@ -6201,7 +6201,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int tstatic int select_idle_sibling (struct task_struct *p,int prev,int target) {struct sched_domain *sd; -int i; +int i, recent_used_cpu;if (idle_cpu (target))return target;
@@ -6212,6 +6212,21 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)if (prev != target &&cpus_share_cache (prev, target) &&idle_cpu (prev))return prev; +/* Check a recently used CPU as a potential idle candidate */ + recent_used_cpu = p->recent_used_cpu; +if (recent_used_cpu != prev && + recent_used_cpu != target && +cpus_share_cache (recent_used_cpu, target) && +idle_cpu (recent_used_cpu) && +cpumask_test_cpu (p->recent_used_cpu, &p->cpus_allowed)) { +/* +* Replace recent_used_cpu with prev as it is a potential +* candidate for the next wake. +*/ + p->recent_used_cpu = prev; +return recent_used_cpu; + } + sd =rcu_dereference (per_cpu (sd_llc, target));if (!sd)return target;
@@ -6379,9 +6394,12 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_fif (!sd) { pick_cpu: -if (sd_flag &SD_BALANCE_WAKE )/* XXX always ? */ +if (sd_flag &SD_BALANCE_WAKE ) {/* XXX always ? */ new_cpu =select_idle_sibling (p, prev_cpu, new_cpu); +if (want_affine) + current->recent_used_cpu = cpu; + } }else { new_cpu =find_idlest_cpu (sd, p, cpu, prev_cpu, sd_flag); }
Signature · 1 line
2.15.1
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 11 lines · Mel Gorman
The
select_idle_sibling(SIS) rewrite in commit10e2f1acd010("sched/core:
Rewrite and improveselect_idle_siblings()") replaced a domain iteration with a search that broadly speaking does a wrapped walk of the scheduler domain sharing a last-level-cache. While this had a number of improvements, one consequence is that two tasks that share a waker/wakee relationship push each other around a socket. Even though two tasks may be active, all cores are evenly used. This is great from a search perspective and spreads a load across individual cores but it has adverse consequences for cpufreq. As each CPU has relatively low utilisation, cpufreq may decide the utilisation is too low to used a higher P-state and overall computation throughput suffers.
Quoted 3 lines
While individual cpufreq and cpuidle drivers may compensate by artifically boosting P-state (at c0) or avoiding lower C-states (during idle), it does not help if hardware-based cpufreq (e.g. HWP) is used.
Not saying this patch is bad; but Rafael / Srinivas we really should do better. Why isn't cpufreq (esp. sugov) fixing this? HWP or not, we can still give it hints, and it looks like we're not doing that.
Mel, what hardware are you testing this on?
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 12 lines · Peter Zijlstra
Quoted 10 lines · Mel Gorman
The
select_idle_sibling(SIS) rewrite in commit10e2f1acd010("sched/core:
Rewrite and improveselect_idle_siblings()") replaced a domain iteration with a search that broadly speaking does a wrapped walk of the scheduler domain sharing a last-level-cache. While this had a number of improvements, one consequence is that two tasks that share a waker/wakee relationship push each other around a socket. Even though two tasks may be active, all cores are evenly used. This is great from a search perspective and spreads a load across individual cores but it has adverse consequences for cpufreq. As each CPU has relatively low utilisation, cpufreq may decide the utilisation is too low to used a higher P-state and overall computation throughput suffers.
Quoted 8 lines
Quoted 3 lines
While individual cpufreq and cpuidle drivers may compensate by artifically boosting P-state (at c0) or avoiding lower C-states (during idle), it does not help if hardware-based cpufreq (e.g. HWP) is used.
Not saying this patch is bad; but Rafael / Srinivas we really should do better. Why isn't cpufreq (esp. sugov) fixing this? HWP or not, we can still give it hints, and it looks like we're not doing that.
I'm not sure if HWP can fix it because of the per-cpu nature of its decisions. I believe it can only give the most basic of hints to hardware like an energy performance profile or bias (EPP and EPB respectively). Of course HWP can be turned off but not many people can detect that it's an appropriate decision, or even desirable, and there is always the caveat that disabling it increases the system CPU footprint.
Quoted 1 line
Mel, what hardware are you testing this on?
The primary one was a single socket skylake machine with 8 threads (HT enabled). However, 11 machines were used in total across multiple generations to reduce the chance of a regression slipping in that was machine-specific.
Signature · 2 lines
Mel Gorman SUSE Labs
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 7 lines · Mel Gorman
Quoted 4 lines · Peter Zijlstra
Not saying this patch is bad; but Rafael / Srinivas we really should do better. Why isn't cpufreq (esp. sugov) fixing this? HWP or not, we can still give it hints, and it looks like we're not doing that.
Quoted 6 lines
I'm not sure if HWP can fix it because of the per-cpu nature of its decisions. I believe it can only give the most basic of hints to hardware like an energy performance profile or bias (EPP and EPB respectively). Of course HWP can be turned off but not many people can detect that it's an appropriate decision, or even desirable, and there is always the caveat that disabling it increases the system CPU footprint.
IA32_HWP_REQUEST has "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.
Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 15 lines · Peter Zijlstra
Quoted 7 lines · Mel Gorman
Quoted 4 lines · Peter Zijlstra
Not saying this patch is bad; but Rafael / Srinivas we really should do better. Why isn't cpufreq (esp. sugov) fixing this? HWP or not, we can still give it hints, and it looks like we're not doing that.
Quoted 6 lines
I'm not sure if HWP can fix it because of the per-cpu nature of its decisions. I believe it can only give the most basic of hints to hardware like an energy performance profile or bias (EPP and EPB respectively). Of course HWP can be turned off but not many people can detect that it's an appropriate decision, or even desirable, and there is always the caveat that disabling it increases the system CPU footprint.
Quoted 4 lines
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.
They can be although these are usually set by the bios or setup early in boot and then left alone. It's not clear how or if these should be tuned on the fly or what variables would drive dynamic tuning. The data collected would still be per-cpu so if all CPUs have low utilisation, the decisions will still be poor except maybe for things like IO boosting.
Quoted 3 lines
Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
Potentially yes. One option without HWP would be to track utilisation for a task or artifically boost it for a short period after migration so a higher p-state is potentially selected. With HWP, a hint would have to be given to the hardware to try select a higher frequency but I've no idea how expensive that is or how it would behave on different implementations of HWP. It may also be a game of whack-a-mole trying to get every cpufreq configuration correct. One advantage of using fewer cores is that it should work regardless of cpufreq driver.
Signature · 2 lines
Mel Gorman SUSE Labs
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 10 lines · Mel Gorman
Quoted 2 lines
Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
Potentially yes. One option without HWP would be to track utilisation for a task or artifically boost it for a short period after migration so a higher p-state is potentially selected. With HWP, a hint would have to be given to the hardware to try select a higher frequency but I've no idea how expensive that is or how it would behave on different implementations of HWP. It may also be a game of whack-a-mole trying to get every cpufreq configuration correct.
We have much of this infrastructure and have been working on improving it [1]. We already track per task utilization and feed it into a cpufreq governor (schedutil).
Quoted 2 lines
One advantage of using fewer cores is that it should work regardless of cpufreq driver.
Sure, and I started out by saying this patch isn't necessarily bad; but I think our 'use' [2] of HWP _is_.
[1] https://lkml.kernel.org/r/[email protected]
[2] IIRC we basically don't do _anything_ when HWP.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 12 lines · Peter Zijlstra
Quoted 10 lines · Mel Gorman
Quoted 2 lines
Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
Potentially yes. One option without HWP would be to track utilisation for a task or artifically boost it for a short period after migration so a higher p-state is potentially selected. With HWP, a hint would have to be given to the hardware to try select a higher frequency but I've no idea how expensive that is or how it would behave on different implementations of HWP. It may also be a game of whack-a-mole trying to get every cpufreq configuration correct.
Quoted 4 lines
We have much of this infrastructure and have been working on improving it [1]. We already track per task utilization and feed it into a cpufreq governor (schedutil).
Which is potentially great without HWP but ...
Quoted 6 lines
Quoted 2 lines
One advantage of using fewer cores is that it should work regardless of cpufreq driver.
Sure, and I started out by saying this patch isn't necessarily bad; but I think our 'use' [2] of HWP _is_.
This is where we get caught -- HWP means we had full responsibility to the hardware with limited feedback options. As far as I can tell, any recent intel CPU is going to have HWP and we've enabled it by default if available since 4.6.
Even if further hints can be given from the OS, it does not necessarily mean this patch is unhelpful. On low utilisation, it's still somewhat sensible to use the minimum number of CPUs necessary (less cache traffic, higher p-states, maybe beneficial to turbo boost etc).
Signature · 2 lines
Mel Gorman SUSE Labs
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Peter ZijlstraQuoted 15 lines · CET Peter Zijlstra
Quoted 7 lines · Mel Gorman
Quoted 4 lines · Peter Zijlstra
Not saying this patch is bad; but Rafael / Srinivas we really should do better. Why isn't cpufreq (esp. sugov) fixing this? HWP or not, we can still give it hints, and it looks like we're not doing that.
Quoted 6 lines
I'm not sure if HWP can fix it because of the per-cpu nature of its decisions. I believe it can only give the most basic of hints to hardware like an energy performance profile or bias (EPP and EPB respectively). Of course HWP can be turned off but not many people can detect that it's an appropriate decision, or even desirable, and there is always the caveat that disabling it increases the system CPU footprint.
Quoted 6 lines
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
But IA32_HWP_REQUEST is not a cheap MSR to write to.
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 10 lines · Rafael J. Wysocki
Quoted 6 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
But
IA32_HWP_REQUESTis not a cheap MSR to write to.
That just means we might need to throttle writing to it, like it already does for the regular pstate (PERF_CTRL) msr in any case (also, is that a cheap msr?)
Not touching it at all seems silly.
But now that you made me look, intel_pstate_hwp_set() is horrible crap. You should _never_ do things like:
rdmsr_on_cpu()
/* frob value */
wrmsr_on_cpu()
That's insane.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 10 lines · Peter Zijlstra
Quoted 9 lines · Rafael J. Wysocki
Quoted 6 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
Quoted 8 lines
Quoted 1 line
But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it already does for the regular pstate (
PERF_CTRL) msr in any case (also, is that a cheap msr?)Not touching it at all seems silly.
Note that even if we do such programming, it would still be desirable to minimise the number of times we have to reprogram it so the series as it stands would still be useful.
Signature · 2 lines
Mel Gorman SUSE Labs
Srinivas Pandruvada
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Peter ZijlstraQuoted 11 lines · Peter Zijlstra
Quoted 10 lines · Rafael J. Wysocki
Quoted 8 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and
"Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really
can't do anything sensible, whereas the OS _knows_.
Quoted 7 lines
Quoted 1 line
But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it already
does for the regular pstate (PERF_CTRL) msr in any case (also, is that a
cheap msr?)
Much more throttling required compared to PERF_CTL. MSR_HWP_REQUEST is much slower compared to PERF_CTL (as high as 10:1).
Quoted 7 lines
Not touching it at all seems silly.
But now that you made me look,
intel_pstate_hwp_set()is horrible crap.
You should _never_ do things like:
Quoted 5 lines
rdmsr_on_cpu()
/* frob value */
wrmsr_on_cpu()That's insane.
Since the cpufreq callback is not guaranteed to be called on the same CPU, we have to use rd/wrmsr_on_cpu().
But we can use smp_call_function_single() and optimize this. This function is called only during init, when usermode changes frequency limits and from thermal, so very few times.
Thanks,
Srinivas
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 2 lines · Srinivas Pandruvada
Much more throttling required compared to
PERF_CTL.MSR_HWP_REQUESTis much slower compared toPERF_CTL(as high as 10:1).
Still much better than what other architectures have to deal with ;-)
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Peter ZijlstraQuoted 10 lines · CET Peter Zijlstra
Quoted 9 lines · Rafael J. Wysocki
Quoted 6 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
Quoted 7 lines
Quoted 1 line
But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it already does for the regular pstate (
PERF_CTRL) msr in any case (also, is that a cheap msr?)Not touching it at all seems silly.
OK
So what field precisely would you touch? "desired"? If so, does that actually guarantee anything to happen?
Quoted 8 lines
But now that you made me look,
intel_pstate_hwp_set()is horrible crap. You should _never_ do things like:
rdmsr_on_cpu()
/* frob value */
wrmsr_on_cpu()That's insane.
I guess you mean it does too many IPIs? Or that it shouldn't do any IPIs at all?
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 17 lines · Rafael J. Wysocki
Quoted 16 lines · CET Peter Zijlstra
Quoted 10 lines · Rafael J. Wysocki
Quoted 6 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it already does for the regular pstate (
PERF_CTRL) msr in any case (also, is that a cheap msr?)
Quoted 6 lines
Quoted 1 line
Not touching it at all seems silly.
OK
So what field precisely would you touch? "desired"? If so, does that actually guarantee anything to happen?
No idea, desired would be the one I would start with, it matches with the intent here. But I've no idea what our current HWP implementation actually does with it.
Quoted 11 lines
Quoted 8 lines
But now that you made me look,
intel_pstate_hwp_set()is horrible crap. You should _never_ do things like:
rdmsr_on_cpu()
/* frob value */
wrmsr_on_cpu()That's insane.
I guess you mean it does too many IPIs? Or that it shouldn't do any IPIs at all?
Yes, too many synchronous IPIs, which themselves are typically already more expensive than the MSR access.
At one point I looked to getting rid of the *msr_on_cpu() crud entirely, but there's just too much users out there I didn't feel like touching.
If you really care you can do async IPIs and do a custom serialization that only waits when you do back-to-back things, which should be fairly uncommon I'd think.
Srinivas Pandruvada
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 29 lines · Peter Zijlstra
Quoted 28 lines · Rafael J. Wysocki
Quoted 25 lines · CET Peter Zijlstra
Quoted 11 lines · Rafael J. Wysocki
Quoted 7 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit
frequency hints. And we really _should_ be doing that.Quoted 4 lines
Quoted 3 lines
Because, esp. in this scenario; a task migrating; the hardware really
can't do anything sensible, whereas the OS _knows_.But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it already
does for the regular pstate (PERF_CTRL) msr in any case (also, is that a
cheap msr?)Not touching it at all seems silly.
Quoted 8 lines
Quoted 5 lines
OK
So what field precisely would you touch? "desired"? If so, does that actually
guarantee anything to happen?No idea, desired would be the one I would start with, it matches with the intent here. But I've no idea what our current HWP implementation actually does with it.
Desired !=0 will disable HWP autonomous mode of frequency selection.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 32 lines · CET Srinivas Pandruvada
Quoted 31 lines · Peter Zijlstra
Quoted 30 lines · Rafael J. Wysocki
Quoted 17 lines · CET Peter Zijlstra
Quoted 14 lines · Rafael J. Wysocki
Quoted 10 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit
frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really
can't do anything sensible, whereas the OS _knows_.Quoted 8 lines
Quoted 1 line
But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it already
does for the regular pstate (PERF_CTRL) msr in any case (also, is that a
cheap msr?)Not touching it at all seems silly.
OK
Quoted 7 lines
Quoted 6 lines
Quoted 3 lines
So what field precisely would you touch? "desired"? If so, does that actually
guarantee anything to happen?No idea, desired would be the one I would start with, it matches with the intent here. But I've no idea what our current HWP implementation actually does with it.
Desired !=0 will disable HWP autonomous mode of frequency selection.
But I don't think it will just run at "desired" then, will it?
Srinivas Pandruvada
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 47 lines · Rafael J. Wysocki
Quoted 45 lines · CET Srinivas Pandruvada
Quoted 43 lines · Peter Zijlstra
Quoted 40 lines · Rafael J. Wysocki
Quoted 29 lines · CET Peter Zijlstra
Quoted 13 lines · Rafael J. Wysocki
Quoted 8 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit
frequency hints. And we really _should_ be doing that.Quoted 4 lines
Quoted 3 lines
Because, esp. in this scenario; a task migrating; the hardware really
can't do anything sensible, whereas the OS _knows_.But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it
already
does for the regular pstate (PERF_CTRL) msr in any case (also, is
that a
cheap msr?)Quoted 1 line
Not touching it at all seems silly.
OK
So what field precisely would you touch? "desired"? If so, does
that actually
guarantee anything to happen?
Quoted 8 lines
Quoted 7 lines
Quoted 5 lines
No idea, desired would be the one I would start with, it matches with
the intent here. But I've no idea what our current HWP implementation
actually does with it.Desired !=0 will disable HWP autonomous mode of frequency selection.
But I don't think it will just run at "desired" then, will it?
HWP all are these hints only not a guarantee.
There are totally different way HWP is handled in client an servers. If you set desired all heuristics they collected will be dumped, so they suggest don't set desired when you are in autonomous mode. If we really want a boost set the EPP. We know that EPP makes lots of measurable difference.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 9 lines · Srinivas Pandruvada
Quoted 8 lines
Quoted 7 lines
Quoted 5 lines
No idea, desired would be the one I would start with, it matches with
the intent here. But I've no idea what our current HWP implementation
actually does with it.Desired !=0 will disable HWP autonomous mode of frequency selection.
But I don't think it will just run at "desired" then, will it?
HWP all are these hints only not a guarantee.
Sure, but the lack on detection when tasks are low utilisation but still latency/throughput sensitive is problematic. Users shouldn't have to know they need to disable HWP or set performance goernor out of the box. It's only going to get worse as sockets get larger.
Quoted 6 lines
There are totally different way HWP is handled in client an servers. If you set desired all heuristics they collected will be dumped, so they suggest don't set desired when you are in autonomous mode. If we really want a boost set the EPP. We know that EPP makes lots of measurable difference.
Sure boosting EPP makes a difference -- it's essentially what the performance goveror does and I know that can be done by a user but it's still basically a cop-out. Default performance for low utilisation or lightly loaded machines is poor. Maybe it should be set based on the ACPI preferred profile but that information is not always available. It would be nice if *some* sort of hint about new migrations or tasks waking from IO would be desirable.
Signature · 2 lines
Mel Gorman SUSE Labs
Srinivas Pandruvada
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 13 lines · Mel Gorman
Quoted 12 lines · Srinivas Pandruvada
Quoted 11 lines
Quoted 9 lines
Quoted 6 lines
No idea, desired would be the one I would start with, it matches
with
the intent here. But I've no idea what our current HWP implementation
actually does with it.Desired !=0 will disable HWP autonomous mode of frequency selection.
But I don't think it will just run at "desired" then, will it?
Quoted 8 lines
Quoted 1 line
HWP all are these hints only not a guarantee.
Sure, but the lack on detection when tasks are low utilisation but still
latency/throughput sensitive is problematic. Users shouldn't have to know they need to disable HWP or set performance goernor out of the box.
It's only going to get worse as sockets get larger.
I am not saying that we shouldn't do anything. Can you give me some workloads which you care the most?
Quoted 10 lines
Quoted 9 lines
There are totally different way HWP is handled in client an servers.
If you set desired all heuristics they collected will be dumped, so they suggest don't set desired when you are in autonomous mode. If we
really want a boost set the EPP. We know that EPP makes lots of measurable difference.
Quoted 11 lines
Sure boosting EPP makes a difference -- it's essentially what the performance
goveror does and I know that can be done by a user but it's still basically a
cop-out. Default performance for low utilisation or lightly loaded machines
is poor. Maybe it should be set based on the ACPI preferred profile but
that information is not always available. It would be nice if *some* sort of hint about new migrations or tasks waking from IO would be desirable.
EPP is a range not a single value. So you don't need to make EPP=0 as a performance governor. PeterZ gave me some scheduler change to experiment, which can be used as hint to play with EPP.
Thanks,
Srinivas
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 10 lines · Srinivas Pandruvada
Quoted 6 lines
Sure, but the lack on detection when tasks are low utilisation but still
latency/throughput sensitive is problematic. Users shouldn't have to know they need to disable HWP or set performance goernor out of the box.
It's only going to get worse as sockets get larger.I am not saying that we shouldn't do anything. Can you give me some workloads which you care the most?
The proprietary workloads I'm aware of are useless to the discussion as they cannot be trivially reproduced and are typically only available under NDA. However, hints can be gotten by looking at the number of cases where recommended tunings limits C-states, set the performance governor, alter intel_pstate setpoint (if not HWP) etc.
For the purposes of illustration, dbench at low thread counts does a reasonable job even though it's not that interesting a workload in general. With ext4 in particular, the journalling thread interactions bounce tasks around the machine and the short sleeps for IO both combine to have relatively low utilisation on individual CPUs. It's less pronounced on xfs as it bounces less due to using kworkers instead of kthreads.
Quoted 21 lines
Quoted 10 lines
Quoted 9 lines
There are totally different way HWP is handled in client an servers.
If you set desired all heuristics they collected will be dumped, so they suggest don't set desired when you are in autonomous mode. If we
really want a boost set the EPP. We know that EPP makes lots of measurable difference.Quoted 11 lines
Sure boosting EPP makes a difference -- it's essentially what the performance
goveror does and I know that can be done by a user but it's still basically a
cop-out. Default performance for low utilisation or lightly loaded machines
is poor. Maybe it should be set based on the ACPI preferred profile but
that information is not always available. It would be nice if *some* sort of hint about new migrations or tasks waking from IO would be desirable.
Quoted 4 lines
EPP is a range not a single value. So you don't need to make EPP=0 as a performance governor. PeterZ gave me some scheduler change to experiment, which can be used as hint to play with EPP.
I know EPP is a range, default from bios usually appear to be 6 or 7 but I didn't do much experiementation to see if there is another value that works better. Even if there is, the default may need to change as not many people even know what EPP is or how it should be tuned.
Signature · 2 lines
Mel Gorman SUSE Labs
Srinivas Pandruvada
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 67 lines · Mel Gorman
Quoted 10 lines · Srinivas Pandruvada
Quoted 9 lines
Sure, but the lack on detection when tasks are low utilisation but
still
latency/throughput sensitive is problematic. Users shouldn't have to
know they need to disable HWP or set performance goernor out of the
box.
It's only going to get worse as sockets get larger.Quoted 3 lines
I am not saying that we shouldn't do anything. Can you give me some workloads which you care the most?
The proprietary workloads I'm aware of are useless to the discussion as they cannot be trivially reproduced and are typically only available
under NDA. However, hints can be gotten by looking at the number of cases
where recommended tunings limits C-states, set the performance governor,
alterintel_pstatesetpoint (if not HWP) etc.For the purposes of illustration, dbench at low thread counts does a reasonable job even though it's not that interesting a workload in general. With ext4 in particular, the journalling thread interactions bounce tasks around the machine and the short sleeps for IO both combine
to have relatively low utilisation on individual CPUs. It's less pronounced
on xfs as it bounces less due to using kworkers instead of kthreads.Quoted 28 lines
Quoted 12 lines
Quoted 11 lines
There are totally different way HWP is handled in client an servers.
If you set desired all heuristics they collected will be dumped, so
they suggest don't set desired when you are in autonomous mode. If
we
really want a boost set the EPP. We know that EPP makes lots of measurable difference.Quoted 15 lines
Sure boosting EPP makes a difference -- it's essentially what the performance
goveror does and I know that can be done by a user but it's still basically a
cop-out. Default performance for low utilisation or lightly loaded
machines
is poor. Maybe it should be set based on the ACPI preferred profile
but
that information is not always available. It would be nice if *some*
sort of hint about new migrations or tasks waking from IO would be
desirable.Quoted 5 lines
EPP is a range not a single value. So you don't need to make EPP=0 as a
performance governor. PeterZ gave me some scheduler change to experiment, which can be used as hint to play with EPP.
Quoted 7 lines
I know EPP is a range, default from bios usually appear to be 6 or 7 but
I didn't do much experiementation to see if there is another value that
works better. Even if there is, the default may need to change as not many
people even know what EPP is or how it should be tuned.
I think you are talking about EPB not EPP because of ranges you mentioned here. EPP is a value from 0 to 255. EPP is part of HWP_REQUEST MSR.
EPB with HWP is used only in Broadwell server. I think you are using Skylake here.
Thanks,
Srinivas
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 7 lines · Srinivas Pandruvada
Quoted 7 lines
I know EPP is a range, default from bios usually appear to be 6 or 7 but
I didn't do much experiementation to see if there is another value that
works better. Even if there is, the default may need to change as not many
people even know what EPP is or how it should be tuned.
Quoted 6 lines
I think you are talking about EPB not EPP because of ranges you mentioned here. EPP is a value from 0 to 255. EPP is part of
HWP_REQUESTMSR.
EPB with HWP is used only in Broadwell server. I think you are using Skylake here.
You're right in that I mixed up EPB (0-15 IIRC) and EPP which has a different range whose exact meaning and semantics are not super-clear to me. The machine in question is Skylake but for the purposes of the current discussion, the issue is the same. There appears to be a lack of giving decent hints to the hardware based on knowledge of migrations or short periods of idleness that the processor may be very busy for very short bursts that are important even if overall utilisation is low.
Signature · 2 lines
Mel Gorman SUSE Labs
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Mel GormanQuoted 8 lines · CET Mel Gorman
Quoted 7 lines · Srinivas Pandruvada
Quoted 7 lines
Quoted 7 lines
Quoted 5 lines
No idea, desired would be the one I would start with, it matches with
the intent here. But I've no idea what our current HWP implementation
actually does with it.Desired !=0 will disable HWP autonomous mode of frequency selection.
Quoted 7 lines
Quoted 2 lines
Quoted 1 line
But I don't think it will just run at "desired" then, will it?
HWP all are these hints only not a guarantee.
Sure, but the lack on detection when tasks are low utilisation but still latency/throughput sensitive is problematic. Users shouldn't have to know they need to disable HWP or set performance goernor out of the box. It's only going to get worse as sockets get larger.
OK, so that's the case I was thinking about when the kernel actually knows more about what's going on than the HW-based logic. That's when it makes sense to provide hints, of course.
Quoted 7 lines
Quoted 6 lines
There are totally different way HWP is handled in client an servers. If you set desired all heuristics they collected will be dumped, so they suggest don't set desired when you are in autonomous mode. If we really want a boost set the EPP. We know that EPP makes lots of measurable difference.
Quoted 6 lines
Sure boosting EPP makes a difference -- it's essentially what the performance goveror does and I know that can be done by a user but it's still basically a cop-out. Default performance for low utilisation or lightly loaded machines is poor. Maybe it should be set based on the ACPI preferred profile but that information is not always available. It would be nice if *some* sort of hint about new migrations or tasks waking from IO would be desirable.
Agreed, we only need to figure out a clean way to do that.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Srinivas PandruvadaQuoted 55 lines · CET Srinivas Pandruvada
Quoted 54 lines · Rafael J. Wysocki
Quoted 52 lines · CET Srinivas Pandruvada
Quoted 43 lines · Peter Zijlstra
Quoted 33 lines · Rafael J. Wysocki
Quoted 29 lines · CET Peter Zijlstra
Quoted 13 lines · Rafael J. Wysocki
Quoted 8 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit
frequency hints. And we really _should_ be doing that.Quoted 4 lines
Quoted 3 lines
Because, esp. in this scenario; a task migrating; the hardware really
can't do anything sensible, whereas the OS _knows_.But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it
already
does for the regular pstate (PERF_CTRL) msr in any case (also, is
that a
cheap msr?)Quoted 7 lines
Quoted 1 line
Not touching it at all seems silly.
OK
So what field precisely would you touch? "desired"? If so, does
that actually
guarantee anything to happen?Quoted 5 lines
No idea, desired would be the one I would start with, it matches with
the intent here. But I've no idea what our current HWP implementation
actually does with it.Desired !=0 will disable HWP autonomous mode of frequency selection.
Quoted 7 lines
Quoted 1 line
But I don't think it will just run at "desired" then, will it?
HWP all are these hints only not a guarantee.
There are totally different way HWP is handled in client an servers. If you set desired all heuristics they collected will be dumped, so they suggest don't set desired when you are in autonomous mode. If we really want a boost set the EPP. We know that EPP makes lots of measurable difference.
Yeah, we've been consistently told to use EPP rather than "desired" for hints like that.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Peter ZijlstraQuoted 36 lines · CET Peter Zijlstra
Quoted 17 lines · Rafael J. Wysocki
Quoted 16 lines · CET Peter Zijlstra
Quoted 10 lines · Rafael J. Wysocki
Quoted 6 lines · CET Peter Zijlstra
IA32_HWP_REQUESThas "Minimum_Performance", "Maximum_Performance" and "Desired_Performance" fields which can be used to give explicit frequency hints. And we really _should_ be doing that.Because, esp. in this scenario; a task migrating; the hardware really can't do anything sensible, whereas the OS _knows_.
But
IA32_HWP_REQUESTis not a cheap MSR to write to.That just means we might need to throttle writing to it, like it already does for the regular pstate (
PERF_CTRL) msr in any case (also, is that a cheap msr?)Quoted 6 lines
Quoted 1 line
Not touching it at all seems silly.
OK
So what field precisely would you touch? "desired"? If so, does that actually guarantee anything to happen?
No idea, desired would be the one I would start with, it matches with the intent here. But I've no idea what our current HWP implementation actually does with it.
Quoted 7 lines
Quoted 7 lines
But now that you made me look,
intel_pstate_hwp_set()is horrible crap. You should _never_ do things like:
rdmsr_on_cpu()
/* frob value */
wrmsr_on_cpu()
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
That's insane.
I guess you mean it does too many IPIs? Or that it shouldn't do any IPIs at all?
Yes, too many synchronous IPIs, which themselves are typically already more expensive than the MSR access.
We could do all of the updates in one IPI (as Srinivas said), but it would be more code, and custom code for that matter.
Is this really worth it for a slow path like this one?
Quoted 6 lines
At one point I looked to getting rid of the
*msr_on_cpu()crud entirely, but there's just too much users out there I didn't feel like touching.If you really care you can do async IPIs and do a custom serialization that only waits when you do back-to-back things, which should be fairly uncommon I'd think.
In this particular case we don't want to return to user space before the MSR is actually written with the new value.
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 6 lines · Rafael J. Wysocki
Quoted 3 lines
If you really care you can do async IPIs and do a custom serialization that only waits when you do back-to-back things, which should be fairly uncommon I'd think.
In this particular case we don't want to return to user space before the MSR is actually written with the new value.
Why not?
I was thinking of something like the below, which would in fact do exactly that.
---
drivers/cpufreq/intel_pstate.c +35 -0
@@ -29,6 +29,7 @@#include <linux/debugfs.h> #include <linux/acpi.h> #include <linux/vmalloc.h> +#include <linux/smp.h> #include <trace/events/power.h> #include <asm/div64.h>
@@ -767,6 +768,40 @@ static void intel_pstate_hwp_set(unsigned int cpu)wrmsrl_on_cpu (cpu,MSR_HWP_REQUEST , value); } +static void __intel_pstate_hwp_set_desired (int val) +{ +u64 value; + + value =rdmsrl (MSR_HWP_REQUEST ); + value &= ~GENMASK_ULL (23 ,16 ); + value |= (val &0xff ) <<16 ; +wrmsrl (MSR_HWP_REQUEST , val); +} + +static void __intel_pstate_hwp_func (void *data) +{ +__intel_pstate_hwp_set_desired ((int )data); +} + +static DEFINE_PER_CPU_SHARED_ALIGNED(struct __call_single_data, csd_data); + +static void intel_pstate_hwp_set_desired (int cpu,int val) +{ +struct call_function_data *csd; + +preempt_disable (); + csd =this_cpu_ptr (&csd_data); +/* wait for previous invocation to complete */ +csd_lock_wait (csd); + + csd->func = __intel_pstate_hwp_func; + csd->info = (unsigned long )val; + +smp_call_function_single_async (cpu, csd); +preempt_enable (); +} + +static int intel_pstate_hwp_save_state (struct cpufreq_policy *policy) {struct cpudata *cpu_data = all_cpu_data[policy->cpu];
include/linux/smp.h +10 -0
@@ -14,6 +14,11 @@#include <linux/init.h> #include <linux/llist.h> +enum { +CSD_FLAG_LOCK =0x01 , +CSD_FLAG_SYNCHRONOUS =0x02 , +}; +typedef void (*smp_call_func_t )(void *info);struct __call_single_data {struct llist_node llist;
@@ -26,6 +31,11 @@ struct __call_single_data {typedef struct __call_single_data call_single_data_t __aligned(sizeof(struct __call_single_data)) ; +static __always_inline void csd_lock_wait(call_single_data_t *csd) +{ +smp_cond_load_acquire (&csd->flags, !(VAL &CSD_FLAG_LOCK )); +} +/* total number of cpus in this system (may exceed NR_CPUS) */ extern unsigned int total_cpus;
kernel/smp.c +0 -10
@@ -22,11 +22,6 @@#include "smpboot.h" -enum { -CSD_FLAG_LOCK =0x01 , -CSD_FLAG_SYNCHRONOUS =0x02 , -}; -struct call_function_data {call_single_data_t __percpu *csd;cpumask_var_t cpumask;
@@ -103,11 +98,6 @@ void __init call_function_init(void)* previous function call. For multi-cpu calls its even more interesting * as we'll have to ensure no other cpu is observing our csd. */ -static __always_inline void csd_lock_wait(call_single_data_t *csd) -{ -smp_cond_load_acquire (&csd->flags, !(VAL &CSD_FLAG_LOCK )); -} - static __always_inline void csd_lock(call_single_data_t *csd) {csd_lock_wait (csd);
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
drivers/cpufreq/intel_pstate.c static void intel_pstate_hwp_set(unsigned int cpu) · line 778
Quoted 8 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c +8
-0+static void __intel_pstate_hwp_set_desired (int val) +{ +u64 value; + + value =rdmsrl (MSR_HWP_REQUEST ); + value &= ~GENMASK_ULL (23 ,16 ); + value |= (val &0xff ) <<16 ; +wrmsrl (MSR_HWP_REQUEST , val);
D'0h: s/val/value/
Quoted 1 line
+}
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Peter Zijlstradrivers/cpufreq/intel_pstate.c static void intel_pstate_hwp_set(unsigned int cpu) · line 779
Quoted 9 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c +9
-0+static void __intel_pstate_hwp_set_desired (int val) +{ +u64 value; + + value =rdmsrl (MSR_HWP_REQUEST ); + value &= ~GENMASK_ULL (23 ,16 ); + value |= (val &0xff ) <<16 ; +wrmsrl (MSR_HWP_REQUEST , val); +}
Also, if we keep a software shadow of that MSR, we can avoid the rdmsr, which might also help.
Srinivas Pandruvada
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 14 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c static void intel_pstate_hwp_set(unsigned int cpu) · line 779
Quoted 9 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c +9
-0+static void __intel_pstate_hwp_set_desired (int val) +{ +u64 value; + + value =rdmsrl (MSR_HWP_REQUEST ); + value &= ~GENMASK_ULL (23 ,16 ); + value |= (val &0xff ) <<16 ; +wrmsrl (MSR_HWP_REQUEST , val); +}Also, if we keep a software shadow of that MSR, we can avoid the rdmsr, which might also help.
The reason we don't keep a software shadow as users can use x86-energy- perf utility or via BMC to adjust. CCed to Len.
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 15 lines · Srinivas Pandruvada
Quoted 14 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c static void intel_pstate_hwp_set(unsigned int cpu) · line 779
Quoted 9 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c +9
-0+static void __intel_pstate_hwp_set_desired (int val) +{ +u64 value; + + value =rdmsrl (MSR_HWP_REQUEST ); + value &= ~GENMASK_ULL (23 ,16 ); + value |= (val &0xff ) <<16 ; +wrmsrl (MSR_HWP_REQUEST , val); +}Also, if we keep a software shadow of that MSR, we can avoid the rdmsr, which might also help.
Quoted 2 lines
The reason we don't keep a software shadow as users can use x86-energy- perf utility or via BMC to adjust. CCed to Len.
Total NAK on that. People using /dev/msr to prod at state get to keep whatever pieces they end up with.
We _really_ should make /dev/msr taint the kernel on write. Ingo, Thomas, can we pretty please just do that?
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 16 lines · Peter Zijlstra
Quoted 15 lines · Srinivas Pandruvada
Quoted 14 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c static void intel_pstate_hwp_set(unsigned int cpu) · line 779
Quoted 9 lines · Peter Zijlstra
drivers/cpufreq/intel_pstate.c +9
-0+static void __intel_pstate_hwp_set_desired (int val) +{ +u64 value; + + value =rdmsrl (MSR_HWP_REQUEST ); + value &= ~GENMASK_ULL (23 ,16 ); + value |= (val &0xff ) <<16 ; +wrmsrl (MSR_HWP_REQUEST , val); +}Also, if we keep a software shadow of that MSR, we can avoid the rdmsr, which might also help.
Quoted 8 lines
Quoted 2 lines
The reason we don't keep a software shadow as users can use x86-energy- perf utility or via BMC to adjust. CCed to Len.
Total NAK on that. People using
/dev/msrto prod at state get to keep whatever pieces they end up with.We _really_ should make
/dev/msrtaint the kernel on write. Ingo, Thomas, can we pretty please just do that?
Sure - mind sending a patch?
Thanks,
Ingo
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Rafael J. WysockiQuoted 7 lines · Rafael J. Wysocki
Quoted 2 lines
Yes, too many synchronous IPIs, which themselves are typically already more expensive than the MSR access.
We could do all of the updates in one IPI (as Srinivas said), but it would be more code, and custom code for that matter.
Is this really worth it for a slow path like this one?
Probably not, still, the pattern really annoys me ;-)
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Rafael J. WysockiQuoted 12 lines · Rafael J. Wysocki
Quoted 12 lines
Quoted 11 lines
Quoted 8 lines
But now that you made me look,
intel_pstate_hwp_set()is horrible crap. You should _never_ do things like:
rdmsr_on_cpu()
/* frob value */
wrmsr_on_cpu()That's insane.
I guess you mean it does too many IPIs? Or that it shouldn't do any IPIs at all?
Quoted 8 lines
Quoted 2 lines
Yes, too many synchronous IPIs, which themselves are typically already more expensive than the MSR access.
We could do all of the updates in one IPI (as Srinivas said), but it would be more code, and custom code for that matter.
Is this really worth it for a slow path like this one?
Maybe it's a slow path at the moment but don't forget that one motivation for this series is that HWP does not properly react when utilisation of a CPU is artifically low because a task recently slept for IO or recently migrated. In both cases, the task may be busy and sensitive to either latency, throughput or both but HWP will use a low p-state. A standard driver can do io-boost and while it currently does not do so, it could also trivially do idle-boosting -- HWP does neither.
Signature · 2 lines
Mel Gorman SUSE Labs
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Mel GormanQuoted 6 lines · Mel Gorman
Quoted 1 line · Peter Zijlstra
Mel, what hardware are you testing this on?
The primary one was a single socket skylake machine with 8 threads (HT enabled).
I took it for a spin in a 2 x Gold 6152 box.
-Mike
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 9 lines · Mike Galbraith
Quoted 6 lines · Mel Gorman
Quoted 1 line · Peter Zijlstra
Mel, what hardware are you testing this on?
The primary one was a single socket skylake machine with 8 threads (HT enabled).
I took it for a spin in a 2 x Gold 6152 box.
Can you translate that marketing speak for a simpleton like me? That's what we should've called SKL-EP, right?
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 6 lines · Peter Zijlstra
Quoted 5 lines · Mike Galbraith
Quoted 4 lines · Mel Gorman
Quoted 1 line · Peter Zijlstra
Mel, what hardware are you testing this on?
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
The primary one was a single socket skylake machine with 8 threads (HT enabled).
I took it for a spin in a 2 x Gold 6152 box.
Can you translate that marketing speak for a simpleton like me? That's what we should've called SKL-EP, right?
Um um.. danged if I know. It's SKL, w. 22 cores each + SMT.
-Mike
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Mel GormanQuoted 6 lines · Mel Gorman
The results can be less dramatic on NUMA where automatic balancing interferes with the test. It's also known that network benchmarks running on localhost also benefit quite a bit from this patch (roughly 10% on netperf RR for UDP and TCP depending on the machine). Hackbench also seens small improvements (6-11% depending on machine and thread count). The facebook schbench was also tested but in most cases showed little or no different to wakeup latencies.
What cpufreq setting were you using for these tests?
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 9 lines · Peter Zijlstra
Quoted 6 lines · Mel Gorman
The results can be less dramatic on NUMA where automatic balancing interferes with the test. It's also known that network benchmarks running on localhost also benefit quite a bit from this patch (roughly 10% on netperf RR for UDP and TCP depending on the machine). Hackbench also seens small improvements (6-11% depending on machine and thread count). The facebook schbench was also tested but in most cases showed little or no different to wakeup latencies.
What cpufreq setting were you using for these tests?
Default powersave settings in general -- intel_pstate driver is the one used most often but HWP was not always available. By and large, no special tuning was applied. Two sets of tests were run, one with turbostat and perf keeping track of p-states and migrations and one without to make sure the measured increase was real. The irony when hitting cpufreq-related problems is that monitoring can mask the issue by increasing overall utilisation.
Signature · 2 lines
Mel Gorman SUSE Labs
Peter Zijlstra
maintainerRe: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Peter ZijlstraQuoted 9 lines · Peter Zijlstra
Quoted 6 lines · Mel Gorman
The results can be less dramatic on NUMA where automatic balancing interferes with the test. It's also known that network benchmarks running on localhost also benefit quite a bit from this patch (roughly 10% on netperf RR for UDP and TCP depending on the machine). Hackbench also seens small improvements (6-11% depending on machine and thread count). The facebook schbench was also tested but in most cases showed little or no different to wakeup latencies.
What cpufreq setting were you using for these tests?
I cannot measure any hackbench variation one way or the other with these patches using 'performance' mode. So I'll assume you've been running things with HWP or something.
Re: [PATCH 4/4] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Quoted 9 lines · Peter Zijlstra
Quoted 8 lines · Peter Zijlstra
Quoted 6 lines · Mel Gorman
The results can be less dramatic on NUMA where automatic balancing interferes with the test. It's also known that network benchmarks running on localhost also benefit quite a bit from this patch (roughly 10% on netperf RR for UDP and TCP depending on the machine). Hackbench also seens small improvements (6-11% depending on machine and thread count). The facebook schbench was also tested but in most cases showed little or no different to wakeup latencies.
Quoted 5 lines
Quoted 1 line
What cpufreq setting were you using for these tests?
I cannot measure any hackbench variation one way or the other with these patches using 'performance' mode. So I'll assume you've been running things with HWP or something.
Correct, I am not using the performance governor as it's not the default and not necessarily desirable as a default. HWP in some cases is enabled but even machines using the intel_pstate driver on machines without HWP benefit.
Signature · 2 lines
Mel Gorman SUSE Labs
tip-bot for Mel Gorman
merge bot[tip:sched/urgent] sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
In reply to Mel Gormansched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
Commit-ID: 32e839dda3ba576943365f0f5817ce5c843137dc Gitweb: https://git.kernel.org/tip/32e839dda3ba576943365f0f5817ce5c843137dc Author: Mel Gorman <[email protected]> AuthorDate: Tue, 30 Jan 2018 10:45:55 +0000 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 6 Feb 2018 10:20:37 +0100
sched/fair: Use a recently used CPU as an idle candidate and the basis for SIS
The select_idle_sibling() (SIS) rewrite in commit:
10e2f1acd010 ("sched/core: Rewrite and improve select_idle_siblings()")
... replaced a domain iteration with a search that broadly speaking does a wrapped walk of the scheduler domain sharing a last-level-cache.
While this had a number of improvements, one consequence is that two tasks that share a waker/wakee relationship push each other around a socket. Even though two tasks may be active, all cores are evenly used. This is great from a search perspective and spreads a load across individual cores, but it has adverse consequences for cpufreq. As each CPU has relatively low utilisation, cpufreq may decide the utilisation is too low to used a higher P-state and overall computation throughput suffers.
While individual cpufreq and cpuidle drivers may compensate by artifically boosting P-state (at c0) or avoiding lower C-states (during idle), it does not help if hardware-based cpufreq (e.g. HWP) is used.
This patch tracks a recently used CPU based on what CPU a task was running on when it last was a waker a CPU it was recently using when a task is a wakee. During SIS, the recently used CPU is used as a target if it's still allowed by the task and is idle.
The benefit may be non-obvious so consider an example of two tasks communicating back and forth. Task A may be an application doing IO where task B is a kworker or kthread like journald. Task A may issue IO, wake B and B wakes up A on completion. With the existing scheme this may look like the following (potentially different IDs if SMT is in use but similar principal applies).
A (cpu 0) wake B (wakes on cpu 1)
B (cpu 1) wake A (wakes on cpu 2)
A (cpu 2) wake B (wakes on cpu 3)
etc.
A careful reader may wonder why CPU 0 was not idle when B wakes A the first time and it's simply due to the fact that A can be rescheduled to another CPU and the pattern is that prev == target when B tries to wakeup A and the information about CPU 0 has been lost.
With this patch, the pattern is more likely to be:
A (cpu 0) wake B (wakes on cpu 1)
B (cpu 1) wake A (wakes on cpu 0)
A (cpu 0) wake B (wakes on cpu 1)
etc
i.e. two communicating casts are more likely to use just two cores instead of all available cores sharing a LLC.
The most dramatic speedup was noticed on dbench using the XFS filesystem on UMA as clients interact heavily with workqueues in that configuration. Note that a similar speedup is not observed on ext4 as the wakeup pattern is different:
4.15.0-rc9 4.15.0-rc9
waprev-v1 biasancestor-v1
Hmean 1 287.54 ( 0.00%) 817.01 ( 184.14%)
Hmean 2 1268.12 ( 0.00%) 1781.24 ( 40.46%)
Hmean 4 1739.68 ( 0.00%) 1594.47 ( -8.35%)
Hmean 8 2464.12 ( 0.00%) 2479.56 ( 0.63%)
Hmean 64 1455.57 ( 0.00%) 1434.68 ( -1.44%)The results can be less dramatic on NUMA where automatic balancing interferes with the test. It's also known that network benchmarks running on localhost also benefit quite a bit from this patch (roughly 10% on netperf RR for UDP and TCP depending on the machine). Hackbench also seens small improvements (6-11% depending on machine and thread count). The facebook schbench was also tested but in most cases showed little or no different to wakeup latencies.
--- include/linux/sched.h | 8 ++++++++ kernel/sched/core.c | 1 + kernel/sched/fair.c | 22 ++++++++++++++++++++-- 3 files changed, 29 insertions(+), 2 deletions(-)
include/linux/sched.h +8 -0
@@ -555,6 +555,14 @@ struct task_struct {unsigned long wakee_flip_decay_ts;struct task_struct *last_wakee; +/* +* recent_used_cpu is initially set as the last CPU used by a task +* that wakes affine another task. Waker/wakee relationships can +* push tasks around a CPU where each wakeup moves to the next one. +* Tracking a recently used CPU allows a quick search for a recently +* used CPU that may be idle. +*/ +int recent_used_cpu;int wake_cpu;#endif int on_rq;
kernel/sched/core.c +1 -0
@@ -2461,6 +2461,7 @@ void wake_up_new_task(struct task_struct *p)* Use __set_task_cpu() to avoid calling sched_class::migrate_task_rq, * as we're not fully set-up yet. */ + p->recent_used_cpu =task_cpu (p);__set_task_cpu (p,select_task_rq (p,task_cpu (p),SD_BALANCE_FORK ,0 ));#endif rq =__task_rq_lock (p, &rf);
kernel/sched/fair.c +20 -2
@@ -6197,7 +6197,7 @@ static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int tstatic int select_idle_sibling (struct task_struct *p,int prev,int target) {struct sched_domain *sd; -int i; +int i, recent_used_cpu;if (idle_cpu (target))return target;
@@ -6208,6 +6208,21 @@ static int select_idle_sibling(struct task_struct *p, int prev, int target)if (prev != target &&cpus_share_cache (prev, target) &&idle_cpu (prev))return prev; +/* Check a recently used CPU as a potential idle candidate */ + recent_used_cpu = p->recent_used_cpu; +if (recent_used_cpu != prev && + recent_used_cpu != target && +cpus_share_cache (recent_used_cpu, target) && +idle_cpu (recent_used_cpu) && +cpumask_test_cpu (p->recent_used_cpu, &p->cpus_allowed)) { +/* +* Replace recent_used_cpu with prev as it is a potential +* candidate for the next wake. +*/ + p->recent_used_cpu = prev; +return recent_used_cpu; + } + sd =rcu_dereference (per_cpu (sd_llc, target));if (!sd)return target;
@@ -6375,9 +6390,12 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_fif (!sd) { pick_cpu: -if (sd_flag &SD_BALANCE_WAKE )/* XXX always ? */ +if (sd_flag &SD_BALANCE_WAKE ) {/* XXX always ? */ new_cpu =select_idle_sibling (p, prev_cpu, new_cpu); +if (want_affine) + current->recent_used_cpu = cpu; + } }else { new_cpu =find_idlest_cpu (sd, p, cpu, prev_cpu, sd_flag); }