Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1396938 > unrolled thread
| Started by | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| First post | 2016-05-09 13:00 +0200 |
| Last post | 2016-05-11 16:30 +0200 |
| Articles | 17 — 4 participants |
Back to article view | Back to linux.kernel
[RFC][PATCH 0/7] sched: select_idle_siblings rewrite Peter Zijlstra <peterz@infradead.org> - 2016-05-09 13:00 +0200
[RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-09 13:00 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Matt Fleming <matt@codeblueprint.co.uk> - 2016-05-11 14:00 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-11 14:40 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-11 20:20 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-11 20:30 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Michael Neuling <mikey@neuling.org> - 2016-05-12 04:10 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-12 07:10 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Michael Neuling <mikey@neuling.org> - 2016-05-12 13:10 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-12 13:40 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-11 19:40 +0200
Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared Matt Fleming <matt@codeblueprint.co.uk> - 2016-05-11 20:10 +0200
[RFC][PATCH 1/7] sched: Remove unused @cpu argument from destroy_sched_domain*() Peter Zijlstra <peterz@infradead.org> - 2016-05-09 13:00 +0200
[RFC][PATCH 3/7] sched: Introduce struct sched_domain_shared Peter Zijlstra <peterz@infradead.org> - 2016-05-09 13:00 +0200
[RFC][PATCH 6/7] sched: Optimize SCHED_SMT Peter Zijlstra <peterz@infradead.org> - 2016-05-09 13:00 +0200
Re: [RFC][PATCH 0/7] sched: select_idle_siblings rewrite Chris Mason <clm@fb.com> - 2016-05-10 03:00 +0200
Re: [RFC][PATCH 0/7] sched: select_idle_siblings rewrite Chris Mason <clm@fb.com> - 2016-05-11 16:30 +0200
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-09 13:00 +0200 |
| Subject | [RFC][PATCH 0/7] sched: select_idle_siblings rewrite |
| Message-ID | <rwR4S-3QS-9@gated-at.bofh.it> |
Hai, here be a semi coherent patch series for the recent select_idle_siblings() tinkering. Happy benchmarking.. --- include/linux/sched.h | 10 ++ kernel/sched/core.c | 94 +++++++++++---- kernel/sched/fair.c | 298 ++++++++++++++++++++++++++++++++++++++--------- kernel/sched/idle_task.c | 2 +- kernel/sched/sched.h | 23 +++- kernel/time/tick-sched.c | 10 +- 6 files changed, 348 insertions(+), 89 deletions(-)
[toc] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-09 13:00 +0200 |
| Subject | [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rwR4T-3QS-23@gated-at.bofh.it> |
| In reply to | #1396938 |
Move the nr_busy_cpus thing from its hacky sd->parent->groups->sgc
location into the much more natural sched_domain_shared location.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
include/linux/sched.h | 1 +
kernel/sched/core.c | 10 +++++-----
kernel/sched/fair.c | 22 ++++++++++++----------
kernel/sched/sched.h | 6 +-----
kernel/time/tick-sched.c | 10 +++++-----
5 files changed, 24 insertions(+), 25 deletions(-)
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1059,6 +1059,7 @@ struct sched_group;
struct sched_domain_shared {
atomic_t ref;
+ atomic_t nr_busy_cpus;
};
struct sched_domain {
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5866,14 +5866,14 @@ static void destroy_sched_domains(struct
DEFINE_PER_CPU(struct sched_domain *, sd_llc);
DEFINE_PER_CPU(int, sd_llc_size);
DEFINE_PER_CPU(int, sd_llc_id);
+DEFINE_PER_CPU(struct sched_domain_shared *, sd_llc_shared);
DEFINE_PER_CPU(struct sched_domain *, sd_numa);
-DEFINE_PER_CPU(struct sched_domain *, sd_busy);
DEFINE_PER_CPU(struct sched_domain *, sd_asym);
static void update_top_cache_domain(int cpu)
{
+ struct sched_domain_shared *sds = NULL;
struct sched_domain *sd;
- struct sched_domain *busy_sd = NULL;
int id = cpu;
int size = 1;
@@ -5881,13 +5881,13 @@ static void update_top_cache_domain(int
if (sd) {
id = cpumask_first(sched_domain_span(sd));
size = cpumask_weight(sched_domain_span(sd));
- busy_sd = sd->parent; /* sd_busy */
+ sds = sd->shared;
}
- rcu_assign_pointer(per_cpu(sd_busy, cpu), busy_sd);
rcu_assign_pointer(per_cpu(sd_llc, cpu), sd);
per_cpu(sd_llc_size, cpu) = size;
per_cpu(sd_llc_id, cpu) = id;
+ rcu_assign_pointer(per_cpu(sd_llc_shared, cpu), sds);
sd = lowest_flag_domain(cpu, SD_NUMA);
rcu_assign_pointer(per_cpu(sd_numa, cpu), sd);
@@ -6184,7 +6184,6 @@ static void init_sched_groups_capacity(i
return;
update_group_capacity(sd, cpu);
- atomic_set(&sg->sgc->nr_busy_cpus, sg->group_weight);
}
/*
@@ -6388,6 +6387,7 @@ sd_init(struct sched_domain_topology_lev
sd->shared = *per_cpu_ptr(sdd->sds, sd_id);
atomic_inc(&sd->shared->ref);
+ atomic_set(&sd->shared->nr_busy_cpus, sd_weight);
#ifdef CONFIG_NUMA
} else if (sd->flags & SD_NUMA) {
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -7842,13 +7842,13 @@ static inline void set_cpu_sd_state_busy
int cpu = smp_processor_id();
rcu_read_lock();
- sd = rcu_dereference(per_cpu(sd_busy, cpu));
+ sd = rcu_dereference(per_cpu(sd_llc, cpu));
if (!sd || !sd->nohz_idle)
goto unlock;
sd->nohz_idle = 0;
- atomic_inc(&sd->groups->sgc->nr_busy_cpus);
+ atomic_inc(&sd->shared->nr_busy_cpus);
unlock:
rcu_read_unlock();
}
@@ -7859,13 +7859,13 @@ void set_cpu_sd_state_idle(void)
int cpu = smp_processor_id();
rcu_read_lock();
- sd = rcu_dereference(per_cpu(sd_busy, cpu));
+ sd = rcu_dereference(per_cpu(sd_llc, cpu));
if (!sd || sd->nohz_idle)
goto unlock;
sd->nohz_idle = 1;
- atomic_dec(&sd->groups->sgc->nr_busy_cpus);
+ atomic_dec(&sd->shared->nr_busy_cpus);
unlock:
rcu_read_unlock();
}
@@ -8092,8 +8092,8 @@ static void nohz_idle_balance(struct rq
static inline bool nohz_kick_needed(struct rq *rq)
{
unsigned long now = jiffies;
+ struct sched_domain_shared *sds;
struct sched_domain *sd;
- struct sched_group_capacity *sgc;
int nr_busy, cpu = rq->cpu;
bool kick = false;
@@ -8121,11 +8121,13 @@ static inline bool nohz_kick_needed(stru
return true;
rcu_read_lock();
- sd = rcu_dereference(per_cpu(sd_busy, cpu));
- if (sd) {
- sgc = sd->groups->sgc;
- nr_busy = atomic_read(&sgc->nr_busy_cpus);
-
+ sds = rcu_dereference(per_cpu(sd_llc_shared, cpu));
+ if (sds) {
+ /*
+ * XXX: write a coherent comment on why we do this.
+ * See also: http:lkml.kernel.org/r/20111202010832.602203411@sbsiddha-desk.sc.intel.com
+ */
+ nr_busy = atomic_read(&sds->nr_busy_cpus);
if (nr_busy > 1) {
kick = true;
goto unlock;
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -856,8 +856,8 @@ static inline struct sched_domain *lowes
DECLARE_PER_CPU(struct sched_domain *, sd_llc);
DECLARE_PER_CPU(int, sd_llc_size);
DECLARE_PER_CPU(int, sd_llc_id);
+DECLARE_PER_CPU(struct sched_domain_shared *, sd_llc_shared);
DECLARE_PER_CPU(struct sched_domain *, sd_numa);
-DECLARE_PER_CPU(struct sched_domain *, sd_busy);
DECLARE_PER_CPU(struct sched_domain *, sd_asym);
struct sched_group_capacity {
@@ -869,10 +869,6 @@ struct sched_group_capacity {
unsigned int capacity;
unsigned long next_update;
int imbalance; /* XXX unrelated to capacity but shared group state */
- /*
- * Number of busy cpus in this group.
- */
- atomic_t nr_busy_cpus;
unsigned long cpumask[0]; /* iteration mask */
};
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -933,11 +933,11 @@ void tick_nohz_idle_enter(void)
WARN_ON_ONCE(irqs_disabled());
/*
- * Update the idle state in the scheduler domain hierarchy
- * when tick_nohz_stop_sched_tick() is called from the idle loop.
- * State will be updated to busy during the first busy tick after
- * exiting idle.
- */
+ * Update the idle state in the scheduler domain hierarchy
+ * when tick_nohz_stop_sched_tick() is called from the idle loop.
+ * State will be updated to busy during the first busy tick after
+ * exiting idle.
+ */
set_cpu_sd_state_idle();
local_irq_disable();
[toc] | [prev] | [next] | [standalone]
| From | Matt Fleming <matt@codeblueprint.co.uk> |
|---|---|
| Date | 2016-05-11 14:00 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxAY1-7z7-1@gated-at.bofh.it> |
| In reply to | #1396939 |
On Mon, 09 May, at 12:48:11PM, Peter Zijlstra wrote:
> Move the nr_busy_cpus thing from its hacky sd->parent->groups->sgc
> location into the much more natural sched_domain_shared location.
>
> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> ---
> include/linux/sched.h | 1 +
> kernel/sched/core.c | 10 +++++-----
> kernel/sched/fair.c | 22 ++++++++++++----------
> kernel/sched/sched.h | 6 +-----
> kernel/time/tick-sched.c | 10 +++++-----
> 5 files changed, 24 insertions(+), 25 deletions(-)
>
> --- a/include/linux/sched.h
> +++ b/include/linux/sched.h
> @@ -1059,6 +1059,7 @@ struct sched_group;
>
> struct sched_domain_shared {
> atomic_t ref;
> + atomic_t nr_busy_cpus;
> };
>
> struct sched_domain {
[...]
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -7842,13 +7842,13 @@ static inline void set_cpu_sd_state_busy
> int cpu = smp_processor_id();
>
> rcu_read_lock();
> - sd = rcu_dereference(per_cpu(sd_busy, cpu));
> + sd = rcu_dereference(per_cpu(sd_llc, cpu));
>
> if (!sd || !sd->nohz_idle)
> goto unlock;
> sd->nohz_idle = 0;
>
> - atomic_inc(&sd->groups->sgc->nr_busy_cpus);
> + atomic_inc(&sd->shared->nr_busy_cpus);
> unlock:
> rcu_read_unlock();
> }
This breaks my POWER7 box which presumably doesn't have SD_SHARE_PKG_RESOURCES,
NIP [c00000000012de68] .set_cpu_sd_state_idle+0x58/0x80
LR [c00000000017ded4] .tick_nohz_idle_enter+0x24/0x90
Call Trace:
[c0000007774b7cf0] [c0000007774b4080] 0xc0000007774b4080 (unreliable)
[c0000007774b7d60] [c00000000017ded4] .tick_nohz_idle_enter+0x24/0x90
[c0000007774b7dd0] [c000000000137200] .cpu_startup_entry+0xe0/0x440
[c0000007774b7ee0] [c00000000004739c] .start_secondary+0x35c/0x3a0
[c0000007774b7f90] [c000000000008bfc] start_secondary_prolog+0x10/0x14
The following fixes it,
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 978b3ef2d87e..d27153adee4d 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -7920,7 +7920,8 @@ static inline void set_cpu_sd_state_busy(void)
goto unlock;
sd->nohz_idle = 0;
- atomic_inc(&sd->shared->nr_busy_cpus);
+ if (sd->shared)
+ atomic_inc(&sd->shared->nr_busy_cpus);
unlock:
rcu_read_unlock();
}
@@ -7937,7 +7938,8 @@ void set_cpu_sd_state_idle(void)
goto unlock;
sd->nohz_idle = 1;
- atomic_dec(&sd->shared->nr_busy_cpus);
+ if (sd->shared)
+ atomic_dec(&sd->shared->nr_busy_cpus);
unlock:
rcu_read_unlock();
}
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-11 14:40 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxBAM-8ht-43@gated-at.bofh.it> |
| In reply to | #1398979 |
On Wed, May 11, 2016 at 12:55:56PM +0100, Matt Fleming wrote: > > --- a/kernel/sched/fair.c > > +++ b/kernel/sched/fair.c > > @@ -7842,13 +7842,13 @@ static inline void set_cpu_sd_state_busy > > int cpu = smp_processor_id(); > > > > rcu_read_lock(); > > - sd = rcu_dereference(per_cpu(sd_busy, cpu)); > > + sd = rcu_dereference(per_cpu(sd_llc, cpu)); > > > > if (!sd || !sd->nohz_idle) > > goto unlock; > > sd->nohz_idle = 0; > > > > - atomic_inc(&sd->groups->sgc->nr_busy_cpus); > > + atomic_inc(&sd->shared->nr_busy_cpus); > > unlock: > > rcu_read_unlock(); > > } > > This breaks my POWER7 box which presumably doesn't have SD_SHARE_PKG_RESOURCES, > Hmm, PPC folks; what does your topology look like? Currently your sched_domain_topology, as per arch/powerpc/kernel/smp.c seems to suggest your cores do not share cache at all. https://en.wikipedia.org/wiki/POWER7 seems to agree and states "4 MB L3 cache per C1 core" And http://www-03.ibm.com/systems/resources/systems_power_software_i_perfmgmt_underthehood.pdf also explicitly draws pictures with the L3 per core. _however_, that same document describes L3 inter-core fill and lateral cast-out, which sounds like the L3s work together to form a node wide caching system. Do we want to model this co-operative L3 slices thing as a sort of node-wide LLC for the purpose of the scheduler ? While we should definitely fix the assumption that an LLC exists (and I need to look at why it isn't set to the core domain instead as well), the scheduler does try and scale things by 'assuming' LLC := node. It does this for NOHZ, and these here patches under discussion would be doing the same for idle-core state. Would this make sense for power, or should we somehow think of something else?
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-11 20:20 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxGTN-5ei-19@gated-at.bofh.it> |
| In reply to | #1399024 |
On Wed, May 11, 2016 at 02:33:45PM +0200, Peter Zijlstra wrote: > Do we want to model this co-operative L3 slices thing as a sort of > node-wide LLC for the purpose of the scheduler ? > > the scheduler does try and scale things by 'assuming' LLC := node. So this whole series is about selecting idle CPUs to run stuff on. With the current PPC setup we would never consider placing a task outside of its core. If we were to add a node wide cache domain, the scheduler would look to place a task across cores if there is an idle core to be had. Would something like that be beneficial?
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-11 20:30 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxH3s-5o7-3@gated-at.bofh.it> |
| In reply to | #1399024 |
On Wed, May 11, 2016 at 02:33:45PM +0200, Peter Zijlstra wrote: > Hmm, PPC folks; what does your topology look like? > > Currently your sched_domain_topology, as per arch/powerpc/kernel/smp.c > seems to suggest your cores do not share cache at all. > > https://en.wikipedia.org/wiki/POWER7 seems to agree and states > > "4 MB L3 cache per C1 core" > > And http://www-03.ibm.com/systems/resources/systems_power_software_i_perfmgmt_underthehood.pdf > also explicitly draws pictures with the L3 per core. > > _however_, that same document describes L3 inter-core fill and lateral > cast-out, which sounds like the L3s work together to form a node wide > caching system. > > Do we want to model this co-operative L3 slices thing as a sort of > node-wide LLC for the purpose of the scheduler ? Going back a generation; Power6 seems to have a shared L3 (off package) between the two cores on the package. The current topology does not reflect that at all. And going forward a generation; Power8 seems to share the per-core (chiplet) L3 amonst all cores (chiplets) + is has the centaur (memory controller) 16M L4. So it seems the current topology setup is not describing these chips very well. Also note that the arch topology code can runtime select a topology, so you could make that topo setup micro-arch specific.
[toc] | [prev] | [next] | [standalone]
| From | Michael Neuling <mikey@neuling.org> |
|---|---|
| Date | 2016-05-12 04:10 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxOeC-3YK-5@gated-at.bofh.it> |
| In reply to | #1399403 |
On Wed, 2016-05-11 at 20:24 +0200, Peter Zijlstra wrote: > On Wed, May 11, 2016 at 02:33:45PM +0200, Peter Zijlstra wrote: > > > > Hmm, PPC folks; what does your topology look like? > > > > Currently your sched_domain_topology, as per arch/powerpc/kernel/smp.c > > seems to suggest your cores do not share cache at all. > > > > https://en.wikipedia.org/wiki/POWER7 seems to agree and states > > > > "4 MB L3 cache per C1 core" > > > > And http://www-03.ibm.com/systems/resources/systems_power_software_i_pe > > rfmgmt_underthehood.pdf > > also explicitly draws pictures with the L3 per core. > > > > _however_, that same document describes L3 inter-core fill and lateral > > cast-out, which sounds like the L3s work together to form a node wide > > caching system. > > > > Do we want to model this co-operative L3 slices thing as a sort of > > node-wide LLC for the purpose of the scheduler ? > Going back a generation; Power6 seems to have a shared L3 (off package) > between the two cores on the package. The current topology does not > reflect that at all. > > And going forward a generation; Power8 seems to share the per-core > (chiplet) L3 amonst all cores (chiplets) + is has the centaur (memory > controller) 16M L4. Yep, L1/L2/L3 is per core on POWER8 and POWER7. POWER6 and POWER5 (both dual core chips) had a shared off chip cache The POWER8 L4 is really a bit different as it's out in the memory controller. It's more of a memory DIMM buffer as it can only cache data associated with the physical addresses on those DIMMS. > So it seems the current topology setup is not describing these chips > very well. Also note that the arch topology code can runtime select a > topology, so you could make that topo setup micro-arch specific. We are planning on making some topology changes for the upcoming P9 which will share L2/L3 amongst pairs of cores (24 cores per chip). FWIW our P9 upstreaming is still in it's infancy since P9 is not released yet. Mike
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-12 07:10 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxR2O-7ar-1@gated-at.bofh.it> |
| In reply to | #1399641 |
On Thu, May 12, 2016 at 12:05:37PM +1000, Michael Neuling wrote: > On Wed, 2016-05-11 at 20:24 +0200, Peter Zijlstra wrote: > > On Wed, May 11, 2016 at 02:33:45PM +0200, Peter Zijlstra wrote: > > > > > > Hmm, PPC folks; what does your topology look like? > > > > > > Currently your sched_domain_topology, as per arch/powerpc/kernel/smp.c > > > seems to suggest your cores do not share cache at all. > > > > > > https://en.wikipedia.org/wiki/POWER7 seems to agree and states > > > > > > "4 MB L3 cache per C1 core" > > > > > > And http://www-03.ibm.com/systems/resources/systems_power_software_i_pe > > > rfmgmt_underthehood.pdf > > > also explicitly draws pictures with the L3 per core. > > > > > > _however_, that same document describes L3 inter-core fill and lateral > > > cast-out, which sounds like the L3s work together to form a node wide > > > caching system. > > > > > > Do we want to model this co-operative L3 slices thing as a sort of > > > node-wide LLC for the purpose of the scheduler ? > > Going back a generation; Power6 seems to have a shared L3 (off package) > > between the two cores on the package. The current topology does not > > reflect that at all. > > > > And going forward a generation; Power8 seems to share the per-core > > (chiplet) L3 amonst all cores (chiplets) + is has the centaur (memory > > controller) 16M L4. > > Yep, L1/L2/L3 is per core on POWER8 and POWER7. POWER6 and POWER5 (both > dual core chips) had a shared off chip cache But as per the above, Power7 and Power8 have explicit logic to share the per-core L3 with the other cores. How effective is that? From some of the slides/documents i've looked at the L3s are connected with a high-speed fabric. Suggesting that the cross-core sharing should be fairly efficient. In which case it would make sense to treat/model the combined L3 as a single large LLC covering all cores.
[toc] | [prev] | [next] | [standalone]
| From | Michael Neuling <mikey@neuling.org> |
|---|---|
| Date | 2016-05-12 13:10 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxWFc-4nU-17@gated-at.bofh.it> |
| In reply to | #1399668 |
On Thu, 2016-05-12 at 07:07 +0200, Peter Zijlstra wrote: > On Thu, May 12, 2016 at 12:05:37PM +1000, Michael Neuling wrote: > > > > On Wed, 2016-05-11 at 20:24 +0200, Peter Zijlstra wrote: > > > > > > On Wed, May 11, 2016 at 02:33:45PM +0200, Peter Zijlstra wrote: > > > > > > > > > > > > Hmm, PPC folks; what does your topology look like? > > > > > > > > Currently your sched_domain_topology, as per > > > > arch/powerpc/kernel/smp.c > > > > seems to suggest your cores do not share cache at all. > > > > > > > > https://en.wikipedia.org/wiki/POWER7 seems to agree and states > > > > > > > > "4 MB L3 cache per C1 core" > > > > > > > > And http://www-03.ibm.com/systems/resources/systems_power_software_ > > > > i_pe > > > > rfmgmt_underthehood.pdf > > > > also explicitly draws pictures with the L3 per core. > > > > > > > > _however_, that same document describes L3 inter-core fill and > > > > lateral > > > > cast-out, which sounds like the L3s work together to form a node > > > > wide > > > > caching system. > > > > > > > > Do we want to model this co-operative L3 slices thing as a sort of > > > > node-wide LLC for the purpose of the scheduler ? > > > Going back a generation; Power6 seems to have a shared L3 (off > > > package) > > > between the two cores on the package. The current topology does not > > > reflect that at all. > > > > > > And going forward a generation; Power8 seems to share the per-core > > > (chiplet) L3 amonst all cores (chiplets) + is has the centaur (memory > > > controller) 16M L4. > > Yep, L1/L2/L3 is per core on POWER8 and POWER7. POWER6 and POWER5 > > (both > > dual core chips) had a shared off chip cache > But as per the above, Power7 and Power8 have explicit logic to share the > per-core L3 with the other cores. > > How effective is that? From some of the slides/documents i've looked at > the L3s are connected with a high-speed fabric. Suggesting that the > cross-core sharing should be fairly efficient. I'm not sure. I thought it was mostly private but if another core was sleeping or not experiencing much cache pressure, another core could use it for some things. But I'm fuzzy on the the exact properties, sorry. > In which case it would make sense to treat/model the combined L3 as a > single large LLC covering all cores. Are you thinking it would be much cheaper to migrate a task to another core inside this chip, than to off chip? Mikey
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-12 13:40 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxX8e-4Hz-21@gated-at.bofh.it> |
| In reply to | #1399922 |
On Thu, May 12, 2016 at 09:07:52PM +1000, Michael Neuling wrote: > On Thu, 2016-05-12 at 07:07 +0200, Peter Zijlstra wrote: > > But as per the above, Power7 and Power8 have explicit logic to share the > > per-core L3 with the other cores. > > > > How effective is that? From some of the slides/documents i've looked at > > the L3s are connected with a high-speed fabric. Suggesting that the > > cross-core sharing should be fairly efficient. > > I'm not sure. I thought it was mostly private but if another core was > sleeping or not experiencing much cache pressure, another core could use it > for some things. But I'm fuzzy on the the exact properties, sorry. Right; I'm going by bits and pieces found on the tubes, so I'm just guessing ;-) But it sounds like these L3s are nowhere close to what Intel does with their L3, where each core has an L3 slice, and slices are connected on a ring to form a unified/shared cache across all cores. http://www.realworldtech.com/sandy-bridge/8/ > > In which case it would make sense to treat/model the combined L3 as a > > single large LLC covering all cores. > > Are you thinking it would be much cheaper to migrate a task to another core > inside this chip, than to off chip? Basically; and if so, if its cheap enough to shoot a task to an idle core to avoid queueing. Assuming there still is some cache residency on the old core, the inter-core fill should be much cheaper than fetching it off package (either remote cache or dram). Or at least; so goes my reasoning based on my google results.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-11 19:40 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxGh4-4oy-17@gated-at.bofh.it> |
| In reply to | #1398979 |
On Wed, May 11, 2016 at 12:55:56PM +0100, Matt Fleming wrote:
> This breaks my POWER7 box which presumably doesn't have SD_SHARE_PKG_RESOURCES,
> index 978b3ef2d87e..d27153adee4d 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -7920,7 +7920,8 @@ static inline void set_cpu_sd_state_busy(void)
> goto unlock;
> sd->nohz_idle = 0;
>
> - atomic_inc(&sd->shared->nr_busy_cpus);
> + if (sd->shared)
> + atomic_inc(&sd->shared->nr_busy_cpus);
> unlock:
> rcu_read_unlock();
> }
Ah, no, the problem is that while it does have SHARE_PKG_RESOURCES (in
its SMT domain -- SMT threads share all cache after all), I failed to
connect the sched_domain_shared structure for it.
Does something like this also work?
---
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -6389,10 +6389,6 @@ sd_init(struct sched_domain_topology_lev
sd->cache_nice_tries = 1;
sd->busy_idx = 2;
- sd->shared = *per_cpu_ptr(sdd->sds, sd_id);
- atomic_inc(&sd->shared->ref);
- atomic_set(&sd->shared->nr_busy_cpus, sd_weight);
-
#ifdef CONFIG_NUMA
} else if (sd->flags & SD_NUMA) {
sd->cache_nice_tries = 2;
@@ -6414,6 +6410,16 @@ sd_init(struct sched_domain_topology_lev
sd->idle_idx = 1;
}
+ /*
+ * For all levels sharing cache; connect a sched_domain_shared
+ * instance.
+ */
+ if (sd->flags & SH_SHARED_PKG_RESOURCES) {
+ sd->shared = *per_cpu_ptr(sdd->sds, sd_id);
+ atomic_inc(&sd->shared->ref);
+ atomic_set(&sd->shared->nr_busy_cpus, sd_weight);
+ }
+
sd->private = sdd;
return sd;
[toc] | [prev] | [next] | [standalone]
| From | Matt Fleming <matt@codeblueprint.co.uk> |
|---|---|
| Date | 2016-05-11 20:10 +0200 |
| Subject | Re: [RFC][PATCH 4/7] sched: Replace sd_busy/nr_busy_cpus with sched_domain_shared |
| Message-ID | <rxGK6-57i-3@gated-at.bofh.it> |
| In reply to | #1399387 |
On Wed, 11 May, at 07:37:52PM, Peter Zijlstra wrote: > On Wed, May 11, 2016 at 12:55:56PM +0100, Matt Fleming wrote: > > > This breaks my POWER7 box which presumably doesn't have SD_SHARE_PKG_RESOURCES, > > > index 978b3ef2d87e..d27153adee4d 100644 > > --- a/kernel/sched/fair.c > > +++ b/kernel/sched/fair.c > > @@ -7920,7 +7920,8 @@ static inline void set_cpu_sd_state_busy(void) > > goto unlock; > > sd->nohz_idle = 0; > > > > - atomic_inc(&sd->shared->nr_busy_cpus); > > + if (sd->shared) > > + atomic_inc(&sd->shared->nr_busy_cpus); > > unlock: > > rcu_read_unlock(); > > } > > > Ah, no, the problem is that while it does have SHARE_PKG_RESOURCES (in > its SMT domain -- SMT threads share all cache after all), I failed to > connect the sched_domain_shared structure for it. > > Does something like this also work? Yep, it does.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-09 13:00 +0200 |
| Subject | [RFC][PATCH 1/7] sched: Remove unused @cpu argument from destroy_sched_domain*() |
| Message-ID | <rwR4T-3QS-25@gated-at.bofh.it> |
| In reply to | #1396938 |
Small cleanup; nothing uses the @cpu argument so make it go away.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
kernel/sched/core.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5841,15 +5841,15 @@ static void free_sched_domain(struct rcu
kfree(sd);
}
-static void destroy_sched_domain(struct sched_domain *sd, int cpu)
+static void destroy_sched_domain(struct sched_domain *sd)
{
call_rcu(&sd->rcu, free_sched_domain);
}
-static void destroy_sched_domains(struct sched_domain *sd, int cpu)
+static void destroy_sched_domains(struct sched_domain *sd)
{
for (; sd; sd = sd->parent)
- destroy_sched_domain(sd, cpu);
+ destroy_sched_domain(sd);
}
/*
@@ -5921,7 +5921,7 @@ cpu_attach_domain(struct sched_domain *s
*/
if (parent->flags & SD_PREFER_SIBLING)
tmp->flags |= SD_PREFER_SIBLING;
- destroy_sched_domain(parent, cpu);
+ destroy_sched_domain(parent);
} else
tmp = tmp->parent;
}
@@ -5929,7 +5929,7 @@ cpu_attach_domain(struct sched_domain *s
if (sd && sd_degenerate(sd)) {
tmp = sd;
sd = sd->parent;
- destroy_sched_domain(tmp, cpu);
+ destroy_sched_domain(tmp);
if (sd)
sd->child = NULL;
}
@@ -5939,7 +5939,7 @@ cpu_attach_domain(struct sched_domain *s
rq_attach_root(rq, rd);
tmp = rq->sd;
rcu_assign_pointer(rq->sd, sd);
- destroy_sched_domains(tmp, cpu);
+ destroy_sched_domains(tmp);
update_top_cache_domain(cpu);
}
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-09 13:00 +0200 |
| Subject | [RFC][PATCH 3/7] sched: Introduce struct sched_domain_shared |
| Message-ID | <rwR4T-3QS-29@gated-at.bofh.it> |
| In reply to | #1396938 |
Since struct sched_domain is strictly per cpu; introduce a structure
that is shared between all 'identical' sched_domains.
Limit to SD_SHARE_PKG_RESOURCES domains for now, as we'll only use it
for shared cache state; if another use comes up later we can easily
relax this.
While the sched_group's are normally shared between CPUs, these are
not natural to use when we need some shared state on a domain level --
since that would require the domain to have a parent, which is not a
given.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
include/linux/sched.h | 6 ++++++
kernel/sched/core.c | 40 ++++++++++++++++++++++++++++++++++------
2 files changed, 40 insertions(+), 6 deletions(-)
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1057,6 +1057,10 @@ extern int sched_domain_level_max;
struct sched_group;
+struct sched_domain_shared {
+ atomic_t ref;
+};
+
struct sched_domain {
/* These fields must be setup */
struct sched_domain *parent; /* top domain must be null terminated */
@@ -1125,6 +1129,7 @@ struct sched_domain {
void *private; /* used during construction */
struct rcu_head rcu; /* used during destruction */
};
+ struct sched_domain_shared *shared;
unsigned int span_weight;
/*
@@ -1158,6 +1163,7 @@ typedef int (*sched_domain_flags_f)(void
struct sd_data {
struct sched_domain **__percpu sd;
+ struct sched_domain_shared **__percpu sds;
struct sched_group **__percpu sg;
struct sched_group_capacity **__percpu sgc;
};
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5836,6 +5836,8 @@ static void free_sched_domain(struct sch
kfree(sd->groups->sgc);
kfree(sd->groups);
}
+ if (sd->shared && atomic_dec_and_test(&sd->shared->ref))
+ kfree(sd->shared);
kfree(sd);
}
@@ -6270,6 +6272,9 @@ static void claim_allocations(int cpu, s
WARN_ON_ONCE(*per_cpu_ptr(sdd->sd, cpu) != sd);
*per_cpu_ptr(sdd->sd, cpu) = NULL;
+ if (atomic_read(&(*per_cpu_ptr(sdd->sds, cpu))->ref))
+ *per_cpu_ptr(sdd->sds, cpu) = NULL;
+
if (atomic_read(&(*per_cpu_ptr(sdd->sg, cpu))->ref))
*per_cpu_ptr(sdd->sg, cpu) = NULL;
@@ -6305,10 +6310,12 @@ static int sched_domains_curr_level;
SD_SHARE_POWERDOMAIN)
static struct sched_domain *
-sd_init(struct sched_domain_topology_level *tl, int cpu)
+sd_init(struct sched_domain_topology_level *tl,
+ const struct cpumask *cpu_map, int cpu)
{
- struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu);
- int sd_weight, sd_flags = 0;
+ struct sd_data *sdd = &tl->data;
+ struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu);
+ int sd_id, sd_weight, sd_flags = 0;
#ifdef CONFIG_NUMA
/*
@@ -6362,6 +6369,9 @@ sd_init(struct sched_domain_topology_lev
#endif
};
+ cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu));
+ sd_id = cpumask_first(sched_domain_span(sd));
+
/*
* Convert topological properties into behaviour.
*/
@@ -6376,6 +6386,9 @@ sd_init(struct sched_domain_topology_lev
sd->cache_nice_tries = 1;
sd->busy_idx = 2;
+ sd->shared = *per_cpu_ptr(sdd->sds, sd_id);
+ atomic_inc(&sd->shared->ref);
+
#ifdef CONFIG_NUMA
} else if (sd->flags & SD_NUMA) {
sd->cache_nice_tries = 2;
@@ -6397,7 +6410,7 @@ sd_init(struct sched_domain_topology_lev
sd->idle_idx = 1;
}
- sd->private = &tl->data;
+ sd->private = sdd;
return sd;
}
@@ -6704,6 +6717,10 @@ static int __sdt_alloc(const struct cpum
if (!sdd->sd)
return -ENOMEM;
+ sdd->sds = alloc_percpu(struct sched_domain_shared *);
+ if (!sdd->sds)
+ return -ENOMEM;
+
sdd->sg = alloc_percpu(struct sched_group *);
if (!sdd->sg)
return -ENOMEM;
@@ -6714,6 +6731,7 @@ static int __sdt_alloc(const struct cpum
for_each_cpu(j, cpu_map) {
struct sched_domain *sd;
+ struct sched_domain_shared *sds;
struct sched_group *sg;
struct sched_group_capacity *sgc;
@@ -6724,6 +6742,13 @@ static int __sdt_alloc(const struct cpum
*per_cpu_ptr(sdd->sd, j) = sd;
+ sds = kzalloc_node(sizeof(struct sched_domain_shared),
+ GFP_KERNEL, cpu_to_node(j));
+ if (!sds)
+ return -ENOMEM;
+
+ *per_cpu_ptr(sdd->sds, j) = sds;
+
sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(),
GFP_KERNEL, cpu_to_node(j));
if (!sg)
@@ -6763,6 +6788,8 @@ static void __sdt_free(const struct cpum
kfree(*per_cpu_ptr(sdd->sd, j));
}
+ if (sdd->sds)
+ kfree(*per_cpu_ptr(sdd->sds, j));
if (sdd->sg)
kfree(*per_cpu_ptr(sdd->sg, j));
if (sdd->sgc)
@@ -6770,6 +6797,8 @@ static void __sdt_free(const struct cpum
}
free_percpu(sdd->sd);
sdd->sd = NULL;
+ free_percpu(sdd->sds);
+ sdd->sds = NULL;
free_percpu(sdd->sg);
sdd->sg = NULL;
free_percpu(sdd->sgc);
@@ -6781,11 +6810,10 @@ struct sched_domain *build_sched_domain(
const struct cpumask *cpu_map, struct sched_domain_attr *attr,
struct sched_domain *child, int cpu)
{
- struct sched_domain *sd = sd_init(tl, cpu);
+ struct sched_domain *sd = sd_init(tl, cpu_map, cpu);
if (!sd)
return child;
- cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu));
if (child) {
sd->level = child->level + 1;
sched_domain_level_max = max(sched_domain_level_max, sd->level);
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-05-09 13:00 +0200 |
| Subject | [RFC][PATCH 6/7] sched: Optimize SCHED_SMT |
| Message-ID | <rwR4T-3QS-31@gated-at.bofh.it> |
| In reply to | #1396938 |
Avoid pointless SCHED_SMT code when running on !SMT hardware.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
kernel/sched/core.c | 19 +++++++++++++++++++
kernel/sched/fair.c | 8 +++++++-
kernel/sched/idle_task.c | 2 --
kernel/sched/sched.h | 17 +++++++++++++++++
4 files changed, 43 insertions(+), 3 deletions(-)
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7263,6 +7263,22 @@ int sched_cpu_dying(unsigned int cpu)
}
#endif
+#ifdef CONFIG_SCHED_SMT
+DEFINE_STATIC_KEY_FALSE(sched_smt_present);
+
+static void sched_init_smt(void)
+{
+ /*
+ * We've enumerated all CPUs and will assume that if any CPU
+ * has SMT siblings, CPU0 will too.
+ */
+ if (cpumask_weight(cpu_smt_mask(0)) > 1)
+ static_branch_enable(&sched_smt_present);
+}
+#else
+static inline void sched_init_smt(void) { }
+#endif
+
void __init sched_init_smp(void)
{
cpumask_var_t non_isolated_cpus;
@@ -7292,6 +7308,9 @@ void __init sched_init_smp(void)
init_sched_rt_class();
init_sched_dl_class();
+
+ sched_init_smt();
+
sched_smp_initialized = true;
}
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -5249,7 +5249,7 @@ static inline bool test_idle_cores(int c
* Since SMT siblings share all cache levels, inspecting this limited remote
* state should be fairly cheap.
*/
-void update_idle_core(struct rq *rq)
+void __update_idle_core(struct rq *rq)
{
int core = cpu_of(rq);
int cpu;
@@ -5281,6 +5281,9 @@ static int select_idle_core(struct task_
struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_idle_mask);
int core, cpu, wrap;
+ if (!static_branch_likely(&sched_smt_present))
+ return -1;
+
if (!test_idle_cores(target, false))
return -1;
@@ -5314,6 +5317,9 @@ static int select_idle_smt(struct task_s
{
int cpu;
+ if (!static_branch_likely(&sched_smt_present))
+ return -1;
+
for_each_cpu(cpu, cpu_smt_mask(target)) {
if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)))
continue;
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -23,8 +23,6 @@ static void check_preempt_curr_idle(stru
resched_curr(rq);
}
-extern void update_idle_core(struct rq *rq);
-
static struct task_struct *
pick_next_task_idle(struct rq *rq, struct task_struct *prev, struct pin_cookie cookie)
{
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -1811,3 +1811,20 @@ static inline void account_reset_rq(stru
rq->prev_steal_time_rq = 0;
#endif
}
+
+
+#ifdef CONFIG_SCHED_SMT
+
+extern struct static_key_false sched_smt_present;
+
+extern void __update_idle_core(struct rq *rq);
+
+static inline void update_idle_core(struct rq *rq)
+{
+ if (static_branch_unlikely(&sched_smt_present))
+ __update_idle_core(rq);
+}
+
+#else
+static inline void update_idle_core(struct rq *rq) { }
+#endif
[toc] | [prev] | [next] | [standalone]
| From | Chris Mason <clm@fb.com> |
|---|---|
| Date | 2016-05-10 03:00 +0200 |
| Message-ID | <rx4bM-8tE-3@gated-at.bofh.it> |
| In reply to | #1396938 |
On Mon, May 09, 2016 at 12:48:07PM +0200, Peter Zijlstra wrote:
> Hai,
>
> here be a semi coherent patch series for the recent select_idle_siblings()
> tinkering. Happy benchmarking..
Thanks Peter,
I'll have some production numbers tomorrow, but based on schbench I'm
hoping it'll score better than my original.
You win on the pipe test (1.9MB/s vs 2.1MB/s) when a thread sibling is
pegged, and even when I double the think time on schbench, it holds up
well:
# Peter
# ./schbench -t 23 -m 2 -c 60000 -s 30000
Latency percentiles (usec)
50.0000th: 50
75.0000th: 60
90.0000th: 69
95.0000th: 73
*99.0000th: 85
99.5000th: 135
99.9000th: 4012
min=0, max=10873
# Mason
# ./schbench -t 23 -m 2 -c 60000 -s 30000
Latency percentiles (usec)
50.0000th: 50
75.0000th: 60
90.0000th: 70
95.0000th: 74
*99.0000th: 83
99.5000th: 88
99.9000th: 118
min=0, max=14770
# Mainline
# ./schbench -t 23 -m 2 -c 60000 -s 30000
Latency percentiles (usec)
50.0000th: 47
75.0000th: 60
90.0000th: 70
95.0000th: 79
*99.0000th: 5400
99.5000th: 10352
99.9000th: 10992
min=0, max=19642
[toc] | [prev] | [next] | [standalone]
| From | Chris Mason <clm@fb.com> |
|---|---|
| Date | 2016-05-11 16:30 +0200 |
| Message-ID | <rxDjc-1to-13@gated-at.bofh.it> |
| In reply to | #1396938 |
On Mon, May 09, 2016 at 12:48:07PM +0200, Peter Zijlstra wrote: > Hai, > > here be a semi coherent patch series for the recent select_idle_siblings() > tinkering. Happy benchmarking.. I ran a few more rounds of the production benchmarks, and NO_AVG_CPU is consistently faster by about 5% than AVG_CPU. I think what's happening here is the production runs are ramping up load in a finer grained setup than schbench, and production is able to see the AVG_CPU calculations back off the scan too soon (for us anyway). I'm going to play around with schbench to try and model this better, but so far this is a clear win over unpatched v4.6. -chris
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web