Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1629964 > unrolled thread
| Started by | Tejun Heo <tj@kernel.org> |
|---|---|
| First post | 2017-04-24 22:20 +0200 |
| Last post | 2017-05-02 09:30 +0200 |
| Articles | 20 on this page of 28 — 4 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-04-24 22:20 +0200
[PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-04-24 23:40 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-03 20:10 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-05-03 23:50 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-04 08:00 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-04 08:30 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Dietmar Eggemann <dietmar.eggemann@arm.com> - 2017-05-04 12:00 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-04 13:00 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-05-04 19:40 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Dietmar Eggemann <dietmar.eggemann@arm.com> - 2017-05-05 12:40 +0200
Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Vincent Guittot <vincent.guittot@linaro.org> - 2017-05-04 12:30 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Vincent Guittot <vincent.guittot@linaro.org> - 2017-04-25 10:40 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-04-25 20:20 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Vincent Guittot <vincent.guittot@linaro.org> - 2017-04-26 19:00 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-04-27 00:50 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Vincent Guittot <vincent.guittot@linaro.org> - 2017-04-27 09:10 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-01 16:20 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-01 17:00 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-05-02 00:00 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-02 10:20 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-02 10:40 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-05-02 22:10 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Peter Zijlstra <peterz@infradead.org> - 2017-05-03 11:20 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Vincent Guittot <vincent.guittot@linaro.org> - 2017-04-26 18:20 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-04-27 00:30 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Vincent Guittot <vincent.guittot@linaro.org> - 2017-04-27 11:00 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Tejun Heo <tj@kernel.org> - 2017-04-28 19:50 +0200
Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity Vincent Guittot <vincent.guittot@linaro.org> - 2017-05-02 09:30 +0200
Page 1 of 2 [1] 2 Next page →
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2017-04-24 22:20 +0200 |
| Subject | [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tzSCK-37e-11@gated-at.bofh.it> |
09a43ace1f98 ("sched/fair: Propagate load during synchronous
attach/detach") added immediate load propagation from cfs_rq to its
sched_entity then to the parent cfs_rq; however, what gets propagated
doesn't seem to make sense.
It repeats the tg_weight calculation done in calc_cfs_shares() but
only uses it to compensate for shares being out of date. After that,
it sets the sched_entity's load_avg to the load_avg of the
corresponding cfs_rq.
This doesn't make sense as the cfs_rq's load_avg is some fraction of
its total weight, which the sched_entity's weight has nothing to with.
For example, if the cfs_rq has a single constant load 1 task the
cfs_rq's load_avg would be around 1. If that cfs_rq is the only
active sched_entity in the parent cfs_rq which has the maximum weight,
the sched_entity's load should be around the maximum weight but
update_tg_cfs_load() ends up overriding it to 1.
At the parent's level, the absolute value of load_avg inside a child
cfs_rq doesn't mean anything. Only the ratio against its weight is
meaningful.
This patch changes update_tg_cfs_load() to normalize the
runnable_load_avg of the cfs_rq and then scale it to the matching
sched_entity's freshly calculated shares for propagation. Use of
runnable_load_avg instead of load_avg is intentional and keeps the
parent's runnable_load_avg true to the sum of scaled loads of all
tasks queued under it which is critical for the correction operation
of load balancer. The next patch will depend on it.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Turner <pjt@google.com>
---
kernel/sched/fair.c | 46 +++++++++++++++++++---------------------------
1 file changed, 19 insertions(+), 27 deletions(-)
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3078,37 +3078,29 @@ static inline void
update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
struct cfs_rq *gcfs_rq = group_cfs_rq(se);
- long delta, load = gcfs_rq->avg.load_avg;
+ long load = 0, delta;
/*
- * If the load of group cfs_rq is null, the load of the
- * sched_entity will also be null so we can skip the formula
+ * A cfs_rq's load avg contribution to the parent should be scaled
+ * to the sched_entity's weight. Use freshly calculated shares
+ * instead of @se->load.weight as the latter may not reflect
+ * changes from the current scheduling operation.
+ *
+ * Note that the propagation source is runnable_load_avg instead of
+ * load_avg. This keeps every cfs_rq's runnable_load_avg true to
+ * the sum of the scaled loads of all tasks queued under it, which
+ * is important for the correct operation of the load balancer.
+ *
+ * This can make the sched_entity's load_avg jumpier but that
+ * correctly reflects what would happen without cgroups if each
+ * task's load is scaled across nesting - the load is being
+ * averaged at the task and each cfs_rq.
*/
- if (load) {
- long tg_load;
+ if (gcfs_rq->load.weight) {
+ long shares = calc_cfs_shares(gcfs_rq, gcfs_rq->tg);
- /* Get tg's load and ensure tg_load > 0 */
- tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
-
- /* Ensure tg_load >= load and updated with current load*/
- tg_load -= gcfs_rq->tg_load_avg_contrib;
- tg_load += load;
-
- /*
- * We need to compute a correction term in the case that the
- * task group is consuming more CPU than a task of equal
- * weight. A task with a weight equals to tg->shares will have
- * a load less or equal to scale_load_down(tg->shares).
- * Similarly, the sched_entities that represent the task group
- * at parent level, can't have a load higher than
- * scale_load_down(tg->shares). And the Sum of sched_entities'
- * load must be <= scale_load_down(tg->shares).
- */
- if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
- /* scale gcfs_rq's load into tg's shares*/
- load *= scale_load_down(gcfs_rq->tg->shares);
- load /= tg_load;
- }
+ load = min(gcfs_rq->runnable_load_avg *
+ shares / gcfs_rq->load.weight, shares);
}
delta = load - se->avg.load_avg;
[toc] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2017-04-24 23:40 +0200 |
| Subject | [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tzTSa-3S5-33@gated-at.bofh.it> |
| In reply to | #1629964 |
09a43ace1f98 ("sched/fair: Propagate load during synchronous
attach/detach") added immediate load propagation from cfs_rq to its
sched_entity then to the parent cfs_rq; however, what gets propagated
doesn't seem to make sense.
It repeats the tg_weight calculation done in calc_cfs_shares() but
only uses it to compensate for shares being out of date. After that,
it sets the sched_entity's load_avg to the load_avg of the
corresponding cfs_rq.
This doesn't make sense as the cfs_rq's load_avg is some fraction of
its total weight, which the sched_entity's weight has nothing to with.
For example, if the cfs_rq has a single constant load 1 task the
cfs_rq's load_avg would be around 1. If that cfs_rq is the only
active sched_entity in the parent cfs_rq which has the maximum weight,
the sched_entity's load should be around the maximum weight but
update_tg_cfs_load() ends up overriding it to 1.
At the parent's level, the absolute value of load_avg inside a child
cfs_rq doesn't mean anything. Only the ratio against its weight is
meaningful.
This patch changes update_tg_cfs_load() to normalize the
runnable_load_avg of the cfs_rq and then scale it to the matching
sched_entity's freshly calculated shares for propagation. Use of
runnable_load_avg instead of load_avg is intentional and keeps the
parent's runnable_load_avg true to the sum of scaled loads of all
tasks queued under it which is critical for the correction operation
of load balancer. The next patch will depend on it.
v2: Use min_t() to squash a build warning.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Vincent Guittot <vincent.guittot@linaro.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Turner <pjt@google.com>
---
kernel/sched/fair.c | 47 ++++++++++++++++++++---------------------------
1 file changed, 20 insertions(+), 27 deletions(-)
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3078,37 +3078,30 @@ static inline void
update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
struct cfs_rq *gcfs_rq = group_cfs_rq(se);
- long delta, load = gcfs_rq->avg.load_avg;
+ long load = 0, delta;
/*
- * If the load of group cfs_rq is null, the load of the
- * sched_entity will also be null so we can skip the formula
+ * A cfs_rq's load avg contribution to the parent should be scaled
+ * to the sched_entity's weight. Use freshly calculated shares
+ * instead of @se->load.weight as the latter may not reflect
+ * changes from the current scheduling operation.
+ *
+ * Note that the propagation source is runnable_load_avg instead of
+ * load_avg. This keeps every cfs_rq's runnable_load_avg true to
+ * the sum of the scaled loads of all tasks queued under it, which
+ * is important for the correct operation of the load balancer.
+ *
+ * This can make the sched_entity's load_avg jumpier but that
+ * correctly reflects what would happen without cgroups if each
+ * task's load is scaled across nesting - the load is being
+ * averaged at the task and each cfs_rq.
*/
- if (load) {
- long tg_load;
+ if (gcfs_rq->load.weight) {
+ long shares = calc_cfs_shares(gcfs_rq, gcfs_rq->tg);
- /* Get tg's load and ensure tg_load > 0 */
- tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
-
- /* Ensure tg_load >= load and updated with current load*/
- tg_load -= gcfs_rq->tg_load_avg_contrib;
- tg_load += load;
-
- /*
- * We need to compute a correction term in the case that the
- * task group is consuming more CPU than a task of equal
- * weight. A task with a weight equals to tg->shares will have
- * a load less or equal to scale_load_down(tg->shares).
- * Similarly, the sched_entities that represent the task group
- * at parent level, can't have a load higher than
- * scale_load_down(tg->shares). And the Sum of sched_entities'
- * load must be <= scale_load_down(tg->shares).
- */
- if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
- /* scale gcfs_rq's load into tg's shares*/
- load *= scale_load_down(gcfs_rq->tg->shares);
- load /= tg_load;
- }
+ load = min_t(long, shares,
+ gcfs_rq->runnable_load_avg *
+ shares / gcfs_rq->load.weight);
}
delta = load - se->avg.load_avg;
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2017-05-03 20:10 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tD6SS-tq-11@gated-at.bofh.it> |
| In reply to | #1630054 |
This is on my IVB-EP, 2 sockets, 10 cores / socket, 2 threads / core.
workload is constrained to 1 socket.
root@ivb-ep:~/bench/schbench# numactl -N 0 ./schbench -m 2 -t 10 -s 10000 -c 15000 -r 30
Latency percentiles (usec)
50.0000th: 21
75.0000th: 30
90.0000th: 38
95.0000th: 42
*99.0000th: 49
99.5000th: 53
99.9000th: 15024
min=0, max=15056
root@ivb-ep:~/bench/schbench# echo NO_FUDGE > /debug/sched_features; echo NO_FUDGE2 > /debug/sched_features ; mkdir /cgroup/ponies; echo $$ > /cgroup/ponies/tasks ; numactl -N 0 ./schbench -m 2 -t 10 -s 10000 -c 15000 -r 30 ; echo $$ > /cgroup/tasks ; rmdir /cgroup/ponies
Latency percentiles (usec)
50.0000th: 14
75.0000th: 19
90.0000th: 24
95.0000th: 28
*99.0000th: 57
99.5000th: 15024
99.9000th: 15024
min=0, max=15060
root@ivb-ep:~/bench/schbench# echo NO_FUDGE > /debug/sched_features; echo FUDGE2 > /debug/sched_features ; mkdir /cgroup/ponies; echo $$ > /cgroup/ponies/tasks ; numactl -N 0 ./schbench -m 2 -t 10 -s 10000 -c 15000 -r 30 ; echo $$ > /cgroup/tasks ; rmdir /cgroup/ponies
Latency percentiles (usec)
50.0000th: 14
75.0000th: 19
90.0000th: 24
95.0000th: 26
*99.0000th: 38
99.5000th: 49
99.9000th: 9648
min=0, max=15035
root@ivb-ep:~/bench/schbench# echo FUDGE > /debug/sched_features; echo FUDGE2 > /debug/sched_features ; mkdir /cgroup/ponies; echo $$ > /cgroup/ponies/tasks ; numactl -N 0 ./schbench -m 2 -t 10 -s 10000 -c 15000 -r 30 ; echo $$ > /cgroup/tasks ; rmdir /cgroup/ponies
Latency percentiles (usec)
50.0000th: 14
75.0000th: 19
90.0000th: 24
95.0000th: 27
*99.0000th: 3060
99.5000th: 7848
99.9000th: 15024
min=0, max=15041
root@ivb-ep:~/bench/schbench# echo 0 > /sys/module/fair/parameters/prop_type
root@ivb-ep:~/bench/schbench# echo FUDGE > /debug/sched_features; echo FUDGE2 > /debug/sched_features ; mkdir /cgroup/ponies; echo $$ > /cgroup/ponies/tasks ; numactl -N 0 ./schbench -m 2 -t 10 -s 10000 -c 15000 -r 30 ; echo $$ > /cgroup/tasks ; rmdir /cgroup/ponies
Latency percentiles (usec)
50.0000th: 14
75.0000th: 19
90.0000th: 24
95.0000th: 27
*99.0000th: 52
99.5000th: 4712
99.9000th: 14640
min=0, max=15033
Just FUDGE2 on its own seems to be the best on my system and is a change
that makes sense (and something Paul recently pointed out as well).
The implementation isn't particularly pretty or fast, but should
illustrate the idea.
Poking at the whole update_tg_cfs_load() thing only makes it worse after
that. And while I agree that that code is mind bending; it seems to work
OK-ish.
Tejun, Vincent, could you guys have a poke?
The thing is that if we assume se->avg.load_avg is correct, we should
already compute a correct cfs_rq->runnable_load_avg, we do all that
propagation right.
But because se->avg.load_avg is stuck in the 'past' because it's sum is
based on all its old weight, things don't quite work out. If we otoh
treat it as a runnable_sum and scale with weight, it seems to work out
fine.
Arguably sys_nice and all related crud should do the same, but nobody
really uses nice at any frequency, whereas we constantly change the
weight of our group entities.
---
kernel/sched/fair.c | 184 +++++++++++++++++++++++++++++++-----------------
kernel/sched/features.h | 2 +
2 files changed, 122 insertions(+), 64 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index cd6c3f9..d6a33e6 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -32,6 +32,7 @@
#include <linux/mempolicy.h>
#include <linux/migrate.h>
#include <linux/task_work.h>
+#include <linux/moduleparam.h>
#include <trace/events/sched.h>
@@ -2632,16 +2633,39 @@ account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
#ifdef CONFIG_FAIR_GROUP_SCHED
# ifdef CONFIG_SMP
-static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
+
+enum shares_type {
+ shares_runnable,
+ shares_avg,
+ shares_weight,
+};
+
+static long calc_cfs_shares(struct cfs_rq *cfs_rq, enum shares_type shares_type)
{
- long tg_weight, load, shares;
+ long tg_weight, tg_shares, load, shares;
+ struct task_group *tg = cfs_rq->tg;
- /*
- * This really should be: cfs_rq->avg.load_avg, but instead we use
- * cfs_rq->load.weight, which is its upper bound. This helps ramp up
- * the shares for small weight interactive tasks.
- */
- load = scale_load_down(cfs_rq->load.weight);
+ tg_shares = READ_ONCE(tg->shares);
+
+ switch (shares_type) {
+ case shares_runnable:
+ load = cfs_rq->runnable_load_avg;
+ break;
+
+ default:
+ case shares_avg:
+ load = cfs_rq->avg.load_avg;
+ break;
+
+ case shares_weight:
+ /*
+ * This really should be: cfs_rq->avg.load_avg, but instead we
+ * use cfs_rq->load.weight, which is its upper bound. This
+ * helps ramp up the shares for small weight interactive tasks.
+ */
+ load = scale_load_down(cfs_rq->load.weight);
+ break;
+ }
tg_weight = atomic_long_read(&tg->load_avg);
@@ -2665,23 +2689,33 @@ static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
* case no task is runnable on a CPU MIN_SHARES=2 should be returned
* instead of 0.
*/
- if (shares < MIN_SHARES)
- shares = MIN_SHARES;
- if (shares > tg->shares)
- shares = tg->shares;
-
- return shares;
-}
-# else /* CONFIG_SMP */
-static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
-{
- return tg->shares;
+ return clamp_t(long, shares, MIN_SHARES, tg_shares);
}
# endif /* CONFIG_SMP */
+/*
+ * Unsigned subtract and clamp on underflow.
+ *
+ * Explicitly do a load-store to ensure the intermediate value never hits
+ * memory. This allows lockless observations without ever seeing the negative
+ * values.
+ */
+#define sub_positive(_ptr, _val) do { \
+ typeof(_ptr) ptr = (_ptr); \
+ typeof(*ptr) val = (_val); \
+ typeof(*ptr) res, var = READ_ONCE(*ptr); \
+ res = var - val; \
+ if (res > var) \
+ res = 0; \
+ WRITE_ONCE(*ptr, res); \
+} while (0)
+
static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
unsigned long weight)
{
+ if (se->load.weight == weight)
+ return;
+
if (se->on_rq) {
/* commit outstanding execution time */
if (cfs_rq->curr == se)
@@ -2689,10 +2723,40 @@ static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
account_entity_dequeue(cfs_rq, se);
}
+ if (sched_feat(FUDGE2)) {
+ unsigned long new_weight = max(scale_load_down(weight), 1UL);
+ unsigned long old_weight = max(scale_load_down(se->load.weight), 1UL);
+
+ sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg);
+ sub_positive(&cfs_rq->avg.load_sum, se->avg.load_sum);
+
+ if (se->on_rq) {
+ sub_positive(&cfs_rq->runnable_load_avg, se->avg.load_avg);
+ sub_positive(&cfs_rq->runnable_load_sum, se->avg.load_sum);
+ }
+
+ se->avg.load_avg *= new_weight;
+ se->avg.load_sum *= new_weight;
+
+ se->avg.load_avg /= old_weight;
+ se->avg.load_sum /= old_weight;
+ }
+
update_load_set(&se->load, weight);
- if (se->on_rq)
+ if (se->on_rq) {
account_entity_enqueue(cfs_rq, se);
+ }
+
+ if (sched_feat(FUDGE2)) {
+ cfs_rq->avg.load_avg += se->avg.load_avg;
+ cfs_rq->avg.load_sum += se->avg.load_sum;
+
+ if (se->on_rq) {
+ cfs_rq->runnable_load_avg += se->avg.load_avg;
+ cfs_rq->runnable_load_sum += se->avg.load_sum;
+ }
+ }
}
static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
@@ -2700,7 +2764,6 @@ static inline int throttled_hierarchy(struct cfs_rq *cfs_rq);
static void update_cfs_shares(struct sched_entity *se)
{
struct cfs_rq *cfs_rq = group_cfs_rq(se);
- struct task_group *tg;
long shares;
if (!cfs_rq)
@@ -2709,13 +2772,14 @@ static void update_cfs_shares(struct sched_entity *se)
if (throttled_hierarchy(cfs_rq))
return;
- tg = cfs_rq->tg;
-
#ifndef CONFIG_SMP
- if (likely(se->load.weight == tg->shares))
+ shares = READ_ONCE(cfs_rq->tg->shares);
+
+ if (likely(se->load.weight == shares))
return;
+#else
+ shares = calc_cfs_shares(cfs_rq, shares_weight);
#endif
- shares = calc_cfs_shares(cfs_rq, tg);
reweight_entity(cfs_rq_of(se), se, shares);
}
@@ -3070,42 +3134,51 @@ update_tg_cfs_util(struct cfs_rq *cfs_rq, struct sched_entity *se)
cfs_rq->avg.util_sum = cfs_rq->avg.util_avg * LOAD_AVG_MAX;
}
+static int prop_type = shares_avg;
+
+module_param(prop_type, int, 0644);
+
/* Take into account change of load of a child task group */
static inline void
update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
struct cfs_rq *gcfs_rq = group_cfs_rq(se);
- long delta, load = gcfs_rq->avg.load_avg;
+ long delta, load;
/*
* If the load of group cfs_rq is null, the load of the
* sched_entity will also be null so we can skip the formula
*/
- if (load) {
- long tg_load;
+ if (!sched_feat(FUDGE)) {
+ load = gcfs_rq->avg.load_avg;
+ if (load) {
+ long tg_load;
- /* Get tg's load and ensure tg_load > 0 */
- tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
+ /* Get tg's load and ensure tg_load > 0 */
+ tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
- /* Ensure tg_load >= load and updated with current load*/
- tg_load -= gcfs_rq->tg_load_avg_contrib;
- tg_load += load;
+ /* Ensure tg_load >= load and updated with current load*/
+ tg_load -= gcfs_rq->tg_load_avg_contrib;
+ tg_load += load;
- /*
- * We need to compute a correction term in the case that the
- * task group is consuming more CPU than a task of equal
- * weight. A task with a weight equals to tg->shares will have
- * a load less or equal to scale_load_down(tg->shares).
- * Similarly, the sched_entities that represent the task group
- * at parent level, can't have a load higher than
- * scale_load_down(tg->shares). And the Sum of sched_entities'
- * load must be <= scale_load_down(tg->shares).
- */
- if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
- /* scale gcfs_rq's load into tg's shares*/
- load *= scale_load_down(gcfs_rq->tg->shares);
- load /= tg_load;
+ /*
+ * We need to compute a correction term in the case that the
+ * task group is consuming more CPU than a task of equal
+ * weight. A task with a weight equals to tg->shares will have
+ * a load less or equal to scale_load_down(tg->shares).
+ * Similarly, the sched_entities that represent the task group
+ * at parent level, can't have a load higher than
+ * scale_load_down(tg->shares). And the Sum of sched_entities'
+ * load must be <= scale_load_down(tg->shares).
+ */
+ if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
+ /* scale gcfs_rq's load into tg's shares*/
+ load *= scale_load_down(gcfs_rq->tg->shares);
+ load /= tg_load;
+ }
}
+ } else {
+ load = calc_cfs_shares(gcfs_rq, prop_type);
}
delta = load - se->avg.load_avg;
@@ -3236,23 +3309,6 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq)
}
}
-/*
- * Unsigned subtract and clamp on underflow.
- *
- * Explicitly do a load-store to ensure the intermediate value never hits
- * memory. This allows lockless observations without ever seeing the negative
- * values.
- */
-#define sub_positive(_ptr, _val) do { \
- typeof(_ptr) ptr = (_ptr); \
- typeof(*ptr) val = (_val); \
- typeof(*ptr) res, var = READ_ONCE(*ptr); \
- res = var - val; \
- if (res > var) \
- res = 0; \
- WRITE_ONCE(*ptr, res); \
-} while (0)
-
/**
* update_cfs_rq_load_avg - update the cfs_rq's load/util averages
* @now: current time, as per cfs_rq_clock_task()
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
index dc4d148..4c517b4 100644
--- a/kernel/sched/features.h
+++ b/kernel/sched/features.h
@@ -80,3 +80,5 @@ SCHED_FEAT(RT_RUNTIME_SHARE, true)
SCHED_FEAT(LB_MIN, false)
SCHED_FEAT(ATTACH_AGE_LOAD, true)
+SCHED_FEAT(FUDGE, true)
+SCHED_FEAT(FUDGE2, true)
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2017-05-03 23:50 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDajL-2yX-7@gated-at.bofh.it> |
| In reply to | #1635184 |
Hello, Peter.
On Wed, May 03, 2017 at 08:00:28PM +0200, Peter Zijlstra wrote:
> Just FUDGE2 on its own seems to be the best on my system and is a change
> that makes sense (and something Paul recently pointed out as well).
>
> The implementation isn't particularly pretty or fast, but should
> illustrate the idea.
>
> Poking at the whole update_tg_cfs_load() thing only makes it worse after
> that. And while I agree that that code is mind bending; it seems to work
> OK-ish.
>
> Tejun, Vincent, could you guys have a poke?
So, just preliminary testing.
FUDGE: Does cut down the number of wrong picks by about 70% and p99
latency by about half; however, the resulting p99 is still
worse by 5 - 10 times compared to !cgroup case.
FUDGE2: Changes things a lot (load values go wild) but only because
it's missing scale_load_down(). After adding
scale_load_down(), it doesn't do much. For this to work, it
needs to be always propagated, which btw shouldn't be
prohibitively expensive given other operations which are
performed at the same time.
Thanks.
--
tejun
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2017-05-04 08:00 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDhXX-7Jm-1@gated-at.bofh.it> |
| In reply to | #1635293 |
On Wed, May 03, 2017 at 05:45:46PM -0400, Tejun Heo wrote: > FUDGE2: Changes things a lot (load values go wild) but only because > it's missing scale_load_down(). After adding > scale_load_down(), it doesn't do much. For this to work, it > needs to be always propagated, which btw shouldn't be > prohibitively expensive given other operations which are > performed at the same time. Urgh, and my numbers were so pretty :/ Maybe I need to wake up, but I'm not immediately seeing where the scale_load_down() went missing for FUDGE2. FUDGE does indeed appear to have one missing.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2017-05-04 08:30 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDir0-8aF-11@gated-at.bofh.it> |
| In reply to | #1635423 |
On Thu, May 04, 2017 at 07:51:29AM +0200, Peter Zijlstra wrote: > Urgh, and my numbers were so pretty :/ Just to clarify on how to run schbench, I limited to a single socket (as that is what you have) and set -t to the number of cores in the socket (not the number of threads). Furthermore, my machine is _idle_, if I don't do anything, it doesn't do _anything_.
[toc] | [prev] | [next] | [standalone]
| From | Dietmar Eggemann <dietmar.eggemann@arm.com> |
|---|---|
| Date | 2017-05-04 12:00 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDlId-1IX-1@gated-at.bofh.it> |
| In reply to | #1635430 |
On 04/05/17 07:21, Peter Zijlstra wrote:
> On Thu, May 04, 2017 at 07:51:29AM +0200, Peter Zijlstra wrote:
>
>> Urgh, and my numbers were so pretty :/
>
> Just to clarify on how to run schbench, I limited to a single socket (as
> that is what you have) and set -t to the number of cores in the socket
> (not the number of threads).
>
> Furthermore, my machine is _idle_, if I don't do anything, it doesn't do
> _anything_.
>
I can't recreate this problem running 'numactl -N 0 ./schbench -m 2 -t
10 -s 10000 -c 15000 -r 30' on my E5-2690 v2 (IVB-EP, 2 sockets, 10
cores / socket, 2 threads / core)
I tried tip/sched/core comparing running in 'cpu:/' and 'cpu:/foo' and
using your patch on top with all the combinations of {NO_}FUDGE,
{NO_}FUDGE2 with prop_type=shares_avg or prop_type_runnable.
Where you able to see the issue on tip/sched/core w/o your patch on your
machine?
The workload of n 60% periodic tasks on n logical cpus always creates a
very stable task distribution for me.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2017-05-04 13:00 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDmEh-2js-9@gated-at.bofh.it> |
| In reply to | #1635613 |
On Thu, May 04, 2017 at 10:49:51AM +0100, Dietmar Eggemann wrote:
> On 04/05/17 07:21, Peter Zijlstra wrote:
> > On Thu, May 04, 2017 at 07:51:29AM +0200, Peter Zijlstra wrote:
> >
> >> Urgh, and my numbers were so pretty :/
> >
> > Just to clarify on how to run schbench, I limited to a single socket (as
> > that is what you have) and set -t to the number of cores in the socket
> > (not the number of threads).
> >
> > Furthermore, my machine is _idle_, if I don't do anything, it doesn't do
> > _anything_.
> >
>
> I can't recreate this problem running 'numactl -N 0 ./schbench -m 2 -t
> 10 -s 10000 -c 15000 -r 30' on my E5-2690 v2 (IVB-EP, 2 sockets, 10
> cores / socket, 2 threads / core)
>
> I tried tip/sched/core comparing running in 'cpu:/' and 'cpu:/foo' and
I'm running tip/master (I think, possibly with the numa topology fixes
in, which should be no-op on the EP).
Also, I run debian sysvinit, so nobody creating cgroups I don't know about.
> using your patch on top with all the combinations of {NO_}FUDGE,
> {NO_}FUDGE2 with prop_type=shares_avg or prop_type_runnable.
>
> Where you able to see the issue on tip/sched/core w/o your patch on your
> machine?
I see the 99.5th percentile shoot up when I run it in a cgroup.
With FUDGE2 its all good again like not using cgroups.
But yes, last time I played with schbench (when prodding at
select_idle_sibling) the thing was finicky too, I never quite got the same
numbers Chris did. But in the end we found something that worked
at both ends.
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2017-05-04 19:40 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDsTn-6G6-15@gated-at.bofh.it> |
| In reply to | #1635613 |
Hello, Dietmar.
On Thu, May 04, 2017 at 10:49:51AM +0100, Dietmar Eggemann wrote:
> On 04/05/17 07:21, Peter Zijlstra wrote:
> > On Thu, May 04, 2017 at 07:51:29AM +0200, Peter Zijlstra wrote:
> >
> >> Urgh, and my numbers were so pretty :/
> >
> > Just to clarify on how to run schbench, I limited to a single socket (as
> > that is what you have) and set -t to the number of cores in the socket
> > (not the number of threads).
> >
> > Furthermore, my machine is _idle_, if I don't do anything, it doesn't do
> > _anything_.
> >
>
> I can't recreate this problem running 'numactl -N 0 ./schbench -m 2 -t
> 10 -s 10000 -c 15000 -r 30' on my E5-2690 v2 (IVB-EP, 2 sockets, 10
> cores / socket, 2 threads / core)
>
> I tried tip/sched/core comparing running in 'cpu:/' and 'cpu:/foo' and
>
> using your patch on top with all the combinations of {NO_}FUDGE,
> {NO_}FUDGE2 with prop_type=shares_avg or prop_type_runnable.
>
> Where you able to see the issue on tip/sched/core w/o your patch on your
> machine?
>
> The workload of n 60% periodic tasks on n logical cpus always creates a
> very stable task distribution for me.
It depends heavily on what else is going on in the system. On the
test systems that I'm using, there's always something not-too-heavy
going on. The pattern over time isn't too varied and the latency
results are usually stable and the grouping of results is very clear
as the difference between the load balancer working properly and not
shows up as upto an order of magnitude difference in p99 latencies.
For these differences to matter, you need to push the machine so that
it's right at the point of saturation - e.g. increase duty cycle till
p99 starts to deteriorate w/o cgroup.
Thanks.
--
tejun
[toc] | [prev] | [next] | [standalone]
| From | Dietmar Eggemann <dietmar.eggemann@arm.com> |
|---|---|
| Date | 2017-05-05 12:40 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDIOt-vu-3@gated-at.bofh.it> |
| In reply to | #1635927 |
Hi Tejun,
On 04/05/17 18:39, Tejun Heo wrote:
> Hello, Dietmar.
>
> On Thu, May 04, 2017 at 10:49:51AM +0100, Dietmar Eggemann wrote:
>> On 04/05/17 07:21, Peter Zijlstra wrote:
>>> On Thu, May 04, 2017 at 07:51:29AM +0200, Peter Zijlstra wrote:
[...]
>>
>> I can't recreate this problem running 'numactl -N 0 ./schbench -m 2 -t
>> 10 -s 10000 -c 15000 -r 30' on my E5-2690 v2 (IVB-EP, 2 sockets, 10
>> cores / socket, 2 threads / core)
>>
>> I tried tip/sched/core comparing running in 'cpu:/' and 'cpu:/foo' and
>>
>> using your patch on top with all the combinations of {NO_}FUDGE,
>> {NO_}FUDGE2 with prop_type=shares_avg or prop_type_runnable.
>>
>> Where you able to see the issue on tip/sched/core w/o your patch on your
>> machine?
>>
>> The workload of n 60% periodic tasks on n logical cpus always creates a
>> very stable task distribution for me.
>
> It depends heavily on what else is going on in the system. On the
> test systems that I'm using, there's always something not-too-heavy
> going on. The pattern over time isn't too varied and the latency
> results are usually stable and the grouping of results is very clear
> as the difference between the load balancer working properly and not
> shows up as upto an order of magnitude difference in p99 latencies.
OK, that make sense. You do need the light (independent from schbench)
background noise to create work for the load balancer.
I switched to my Hikey board (hot-plugged out the 2. cluster, so 4
remaining cores with performance governor) because we should see the
effect regardless of the topology. There is no background noise on my
debian fs.
That's why I don't see any effect if I increase the C/S
(cputime/sleeptime) ratio when running 'schbench -m 2 -t 2 -s S -c C -r
30'. The only source of disturbance are some additional schbench threads
which sometimes force one of the worker threads to get co-scheduled with
another worker thread.
https://drive.google.com/file/d/0B2f-ZAwV_YnmTDhWUk5ZRHdBRUU/view shows
such a case where the additional schbench thread 'schbench-2206' (green
marker line in picture) forces the worker thread 'schbench-2209' to
wakeup migrate from cpu3 to cpu0 where he gets co-scheduled with the
worker thread 'schbench-2210' for a while.
> For these differences to matter, you need to push the machine so that
> it's right at the point of saturation - e.g. increase duty cycle till
> p99 starts to deteriorate w/o cgroup.
>
> Thanks.
>
[toc] | [prev] | [next] | [standalone]
| From | Vincent Guittot <vincent.guittot@linaro.org> |
|---|---|
| Date | 2017-05-04 12:30 +0200 |
| Subject | Re: [PATCH v2 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tDmbf-28q-5@gated-at.bofh.it> |
| In reply to | #1635184 |
Le Wednesday 03 May 2017 à 20:00:28 (+0200), Peter Zijlstra a écrit :
>
[snip]
>
> Just FUDGE2 on its own seems to be the best on my system and is a change
> that makes sense (and something Paul recently pointed out as well).
>
> The implementation isn't particularly pretty or fast, but should
> illustrate the idea.
>
> Poking at the whole update_tg_cfs_load() thing only makes it worse after
> that. And while I agree that that code is mind bending; it seems to work
> OK-ish.
>
> Tejun, Vincent, could you guys have a poke?
I have added below patch on to of your:
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -3191,7 +3191,7 @@ update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
}
}
} else {
- load = calc_cfs_shares(gcfs_rq, prop_type);
+ load = scale_load_down(calc_cfs_shares(gcfs_rq, prop_type));
}
delta = load - se->avg.load_avg;
--
The results for each configurations are :
** Config 1**
linaro@linaro-developer:~/schbench$cat /sys/module/fair/parameters/prop_type
1
linaro@linaro-developer:~/schbench$ sudo cat /sys/kernel/debug/sched_features
GENTLE_FAIR_SLEEPERS START_DEBIT NO_NEXT_BUDDY LAST_BUDDY CACHE_HOT_BUDDY WAKEUP_PREEMPTION NO_HRTICK NO_DOUBLE_TICK LB_BIAS NONTASK_CAPACITY TTWU_QUEUE NO_SIS_AVG_CPU RT_PUSH_IPI NO_FORCE_SD_OVERLAP RT_RUNTIME_SHARE NO_LB_MIN ATTACH_AGE_LOAD NO_FUDGE NO_FUDGE2
Latency percentiles (usec)
50.0000th: 252
75.0000th: 346
90.0000th: 438
95.0000th: 485
*99.0000th: 537
99.5000th: 581
99.9000th: 5768
min=0, max=14202
** Config 2 **
linaro@linaro-developer:~/schbench$ cat /sys/module/fair/parameters/prop_type
1
linaro@linaro-developer:~/schbench$ sudo cat /sys/kernel/debug/sched_features
GENTLE_FAIR_SLEEPERS START_DEBIT NO_NEXT_BUDDY LAST_BUDDY CACHE_HOT_BUDDY WAKEUP_PREEMPTION NO_HRTICK NO_DOUBLE_TICK LB_BIAS NONTASK_CAPACITY TTWU_QUEUE NO_SIS_AVG_CPU RT_PUSH_IPI NO_FORCE_SD_OVERLAP RT_RUNTIME_SHARE NO_LB_MIN ATTACH_AGE_LOAD FUDGE NO_FUDGE2
Latency percentiles (usec)
50.0000th: 261
75.0000th: 374
90.0000th: 457
95.0000th: 490
*99.0000th: 533
99.5000th: 585
99.9000th: 9392
min=0, max=13295
**Config 3**
linaro@linaro-developer:~/schbench$ cat /sys/module/fair/parameters/prop_type
1
linaro@linaro-developer:~/schbench$ sudo cat /sys/kernel/debug/sched_features
GENTLE_FAIR_SLEEPERS START_DEBIT NO_NEXT_BUDDY LAST_BUDDY CACHE_HOT_BUDDY WAKEUP_PREEMPTION NO_HRTICK NO_DOUBLE_TICK LB_BIAS NONTASK_CAPACITY TTWU_QUEUE NO_SIS_AVG_CPU RT_PUSH_IPI NO_FORCE_SD_OVERLAP RT_RUNTIME_SHARE NO_LB_MIN ATTACH_AGE_LOAD NO_FUDGE FUDGE2
Latency percentiles (usec)
50.0000th: 233
75.0000th: 309
90.0000th: 456
95.0000th: 498
*99.0000th: 5272
99.5000th: 8184
99.9000th: 12368
min=0, max=14865
I have run several time the test, few were correct but most of them were like
above
**Config 4**
linaro@linaro-developer:~/schbench$ cat /sys/module/fair/parameters/prop_type
1
linaro@linaro-developer:~/schbench$ sudo cat /sys/kernel/debug/sched_features
GENTLE_FAIR_SLEEPERS START_DEBIT NO_NEXT_BUDDY LAST_BUDDY CACHE_HOT_BUDDY WAKEUP_PREEMPTION NO_HRTICK NO_DOUBLE_TICK LB_BIAS NONTASK_CAPACITY TTWU_QUEUE NO_SIS_AVG_CPU RT_PUSH_IPI NO_FORCE_SD_OVERLAP RT_RUNTIME_SHARE NO_LB_MIN ATTACH_AGE_LOAD FUDGE FUDGE2
Latency percentiles (usec)
50.0000th: 211
75.0000th: 290
90.0000th: 380
95.0000th: 451
*99.0000th: 1778
99.5000th: 5048
99.9000th: 12752
min=0, max=15090
I have run several time the test, few were correct but most of them were like
above
** Config 5 **
linaro@linaro-developer:~/schbench$ cat /sys/module/fair/parameters/prop_type
0
linaro@linaro-developer:~/schbench$ sudo cat /sys/kernel/debug/sched_features
GENTLE_FAIR_SLEEPERS START_DEBIT NO_NEXT_BUDDY LAST_BUDDY CACHE_HOT_BUDDY WAKEUP_PREEMPTION NO_HRTICK NO_DOUBLE_TICK LB_BIAS NONTASK_CAPACITY TTWU_QUEUE NO_SIS_AVG_CPU RT_PUSH_IPI NO_FORCE_SD_OVERLAP RT_RUNTIME_SHARE NO_LB_MIN ATTACH_AGE_LOAD FUDGE FUDGE2
Latency percentiles (usec)
50.0000th: 216
75.0000th: 297
90.0000th: 430
95.0000th: 487
*99.0000th: 2748
99.5000th: 7432
99.9000th: 12912
min=0, max=15046
I have run several time the test, few were correct but most of them were like
above
** Config 6 **
linaro@linaro-developer:~/schbench$ cat /sys/module/fair/parameters/prop_type
0
linaro@linaro-developer:~/schbench$ sudo cat /sys/kernel/debug/sched_features
GENTLE_FAIR_SLEEPERS START_DEBIT NO_NEXT_BUDDY LAST_BUDDY CACHE_HOT_BUDDY WAKEUP_PREEMPTION NO_HRTICK NO_DOUBLE_TICK LB_BIAS NONTASK_CAPACITY TTWU_QUEUE NO_SIS_AVG_CPU RT_PUSH_IPI NO_FORCE_SD_OVERLAP RT_RUNTIME_SHARE NO_LB_MIN ATTACH_AGE_LOAD FUDGE NO_FUDGE2
Latency percentiles (usec)
50.0000th: 245
75.0000th: 339
90.0000th: 444
95.0000th: 492
*99.0000th: 3036
99.5000th: 9104
99.9000th: 12496
min=0, max=14098
I have run several time the test, few were correct but most of them were like
above
Config 1 and 2 are the two configuraton which have stable and good results
Regards,
Vincent
[toc] | [prev] | [next] | [standalone]
| From | Vincent Guittot <vincent.guittot@linaro.org> |
|---|---|
| Date | 2017-04-25 10:40 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tA4aS-2hp-23@gated-at.bofh.it> |
| In reply to | #1629964 |
Hi Tejun
On 24 April 2017 at 22:14, Tejun Heo <tj@kernel.org> wrote:
> 09a43ace1f98 ("sched/fair: Propagate load during synchronous
> attach/detach") added immediate load propagation from cfs_rq to its
> sched_entity then to the parent cfs_rq; however, what gets propagated
> doesn't seem to make sense.
>
> It repeats the tg_weight calculation done in calc_cfs_shares() but
> only uses it to compensate for shares being out of date. After that,
> it sets the sched_entity's load_avg to the load_avg of the
> corresponding cfs_rq.
>
> This doesn't make sense as the cfs_rq's load_avg is some fraction of
> its total weight, which the sched_entity's weight has nothing to with.
> For example, if the cfs_rq has a single constant load 1 task the
> cfs_rq's load_avg would be around 1. If that cfs_rq is the only
> active sched_entity in the parent cfs_rq which has the maximum weight,
> the sched_entity's load should be around the maximum weight but
> update_tg_cfs_load() ends up overriding it to 1.
not sure to catch your example:
a task TA with a load_avg = 1 is the only task in a task group GB so
the cfs_rq load_avg = 1 too and the group_entity of this cfs_rq has
got a weight of 1024 (I use 10bits format for readability) which is
the total share of task group GB
Are you saying that the group_entity load_avg should be around 1024 and not 1 ?
I would say it depends of TA weight. I assume that TA weight is the
default value (1024) as you don't specify any value in your example
If TA directly runs at parent level, its sched_entity would have a
load_avg of 1 so why the group entity load_avg should be 1024 ? it
will just temporally show the cfs_rq more loaded than it is really and
at the end the group entity load_avg will go back to 1
>
> At the parent's level, the absolute value of load_avg inside a child
> cfs_rq doesn't mean anything. Only the ratio against its weight is
> meaningful.
>
> This patch changes update_tg_cfs_load() to normalize the
> runnable_load_avg of the cfs_rq and then scale it to the matching
> sched_entity's freshly calculated shares for propagation. Use of
> runnable_load_avg instead of load_avg is intentional and keeps the
> parent's runnable_load_avg true to the sum of scaled loads of all
> tasks queued under it which is critical for the correction operation
> of load balancer. The next patch will depend on it.
>
> Signed-off-by: Tejun Heo <tj@kernel.org>
> Cc: Vincent Guittot <vincent.guittot@linaro.org>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Mike Galbraith <efault@gmx.de>
> Cc: Paul Turner <pjt@google.com>
> ---
> kernel/sched/fair.c | 46 +++++++++++++++++++---------------------------
> 1 file changed, 19 insertions(+), 27 deletions(-)
>
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -3078,37 +3078,29 @@ static inline void
> update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
> {
> struct cfs_rq *gcfs_rq = group_cfs_rq(se);
> - long delta, load = gcfs_rq->avg.load_avg;
> + long load = 0, delta;
>
> /*
> - * If the load of group cfs_rq is null, the load of the
> - * sched_entity will also be null so we can skip the formula
> + * A cfs_rq's load avg contribution to the parent should be scaled
> + * to the sched_entity's weight. Use freshly calculated shares
> + * instead of @se->load.weight as the latter may not reflect
> + * changes from the current scheduling operation.
> + *
> + * Note that the propagation source is runnable_load_avg instead of
> + * load_avg. This keeps every cfs_rq's runnable_load_avg true to
> + * the sum of the scaled loads of all tasks queued under it, which
> + * is important for the correct operation of the load balancer.
> + *
> + * This can make the sched_entity's load_avg jumpier but that
> + * correctly reflects what would happen without cgroups if each
> + * task's load is scaled across nesting - the load is being
> + * averaged at the task and each cfs_rq.
> */
> - if (load) {
> - long tg_load;
> + if (gcfs_rq->load.weight) {
> + long shares = calc_cfs_shares(gcfs_rq, gcfs_rq->tg);
>
> - /* Get tg's load and ensure tg_load > 0 */
> - tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
> -
> - /* Ensure tg_load >= load and updated with current load*/
> - tg_load -= gcfs_rq->tg_load_avg_contrib;
> - tg_load += load;
> -
> - /*
> - * We need to compute a correction term in the case that the
> - * task group is consuming more CPU than a task of equal
> - * weight. A task with a weight equals to tg->shares will have
> - * a load less or equal to scale_load_down(tg->shares).
> - * Similarly, the sched_entities that represent the task group
> - * at parent level, can't have a load higher than
> - * scale_load_down(tg->shares). And the Sum of sched_entities'
> - * load must be <= scale_load_down(tg->shares).
> - */
> - if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
> - /* scale gcfs_rq's load into tg's shares*/
> - load *= scale_load_down(gcfs_rq->tg->shares);
> - load /= tg_load;
> - }
> + load = min(gcfs_rq->runnable_load_avg *
> + shares / gcfs_rq->load.weight, shares);
> }
>
> delta = load - se->avg.load_avg;
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2017-04-25 20:20 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tAdeb-88w-27@gated-at.bofh.it> |
| In reply to | #1630301 |
Hello, On Tue, Apr 25, 2017 at 10:35:53AM +0200, Vincent Guittot wrote: > not sure to catch your example: > a task TA with a load_avg = 1 is the only task in a task group GB so > the cfs_rq load_avg = 1 too and the group_entity of this cfs_rq has > got a weight of 1024 (I use 10bits format for readability) which is > the total share of task group GB The group_entity (the sched_entity corresponding to the cfs_rq) should behave as if it's a task which has the weight of 1024. > Are you saying that the group_entity load_avg should be around 1024 and not 1 ? Yes. > I would say it depends of TA weight. I assume that TA weight is the > default value (1024) as you don't specify any value in your example Please consider the following configuration, where GA is a group entity, and TA and TB are tasks. ROOT - GA (weight 1024) - TA (weight 1) \ GB (weight 1 ) - TB (weight 1) Let's say both TA and TB are running full-tilt. Now let's take out GA and GB. ROOT - TA1 (weight 1024) \ TB1 (weight 1 ) GA should behave the same as TA1 and GB TB1. GA's load should match TA1's, and GA's load when seen from ROOT's cfs_rq has nothing to do with how much total absolute weight it has inside it. ROOT - GA2 (weight 1024) - TA2 (weight 1 ) \ GB2 (weight 1 ) - TB2 (weight 1024) If TA2 and TB2 are constantly running, GA2 and GB2's in ROOT's cfs_rq should match GA and GB's, respectively. > If TA directly runs at parent level, its sched_entity would have a > load_avg of 1 so why the group entity load_avg should be 1024 ? it Because then the hierarchical weight configuration doesn't mean anything. > will just temporally show the cfs_rq more loaded than it is really and > at the end the group entity load_avg will go back to 1 It's not temporary. The weight of a group is its shares, which is its load fraction of the configured weight of the group. Assuming UP, if you configure a group to the weight of 1024 and have any task running full-tilt in it, the group will converge to the load of 1024. The problem is that the propagation logic is currently doing something completely different and temporarily push down the load whenever it triggers. Thanks. -- tejun
[toc] | [prev] | [next] | [standalone]
| From | Vincent Guittot <vincent.guittot@linaro.org> |
|---|---|
| Date | 2017-04-26 19:00 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tAysi-4UM-7@gated-at.bofh.it> |
| In reply to | #1630860 |
Le Tuesday 25 Apr 2017 à 11:12:19 (-0700), Tejun Heo a écrit :
> Hello,
>
> On Tue, Apr 25, 2017 at 10:35:53AM +0200, Vincent Guittot wrote:
> > not sure to catch your example:
> > a task TA with a load_avg = 1 is the only task in a task group GB so
> > the cfs_rq load_avg = 1 too and the group_entity of this cfs_rq has
> > got a weight of 1024 (I use 10bits format for readability) which is
> > the total share of task group GB
>
> The group_entity (the sched_entity corresponding to the cfs_rq) should
> behave as if it's a task which has the weight of 1024.
>
> > Are you saying that the group_entity load_avg should be around 1024 and not 1 ?
>
> Yes.
>
> > I would say it depends of TA weight. I assume that TA weight is the
> > default value (1024) as you don't specify any value in your example
>
> Please consider the following configuration, where GA is a group
> entity, and TA and TB are tasks.
>
> ROOT - GA (weight 1024) - TA (weight 1)
> \ GB (weight 1 ) - TB (weight 1)
>
> Let's say both TA and TB are running full-tilt. Now let's take out GA
> and GB.
>
> ROOT - TA1 (weight 1024)
> \ TB1 (weight 1 )
>
> GA should behave the same as TA1 and GB TB1. GA's load should match
> TA1's, and GA's load when seen from ROOT's cfs_rq has nothing to do
> with how much total absolute weight it has inside it.
>
> ROOT - GA2 (weight 1024) - TA2 (weight 1 )
> \ GB2 (weight 1 ) - TB2 (weight 1024)
>
> If TA2 and TB2 are constantly running, GA2 and GB2's in ROOT's cfs_rq
> should match GA and GB's, respectively.
Yes I agree
>
> > If TA directly runs at parent level, its sched_entity would have a
> > load_avg of 1 so why the group entity load_avg should be 1024 ? it
>
> Because then the hierarchical weight configuration doesn't mean
> anything.
>
> > will just temporally show the cfs_rq more loaded than it is really and
> > at the end the group entity load_avg will go back to 1
>
> It's not temporary. The weight of a group is its shares, which is its
> load fraction of the configured weight of the group. Assuming UP, if
> you configure a group to the weight of 1024 and have any task running
> full-tilt in it, the group will converge to the load of 1024. The
> problem is that the propagation logic is currently doing something
> completely different and temporarily push down the load whenever it
> triggers.
Ok, I see your point and agree that there is an issue when propagating
load_avg of a task group which has tasks with lower weight than the share
but your proposal has got issue because it uses runnable_load_avg instead
of load_avg and this makes propagation of loadavg_avg incorrect, something
like below which keeps using load_avg solve the problem
+ if (gcfs_rq->load.weight) {
+ long shares = scale_load_down(calc_cfs_shares(gcfs_rq, gcfs_rq->tg));
+
+ load = min(gcfs_rq->avg.load_avg *
+ shares / scale_load_down(gcfs_rq->load.weight), shares);
I have run schbench with the change above on v4.11-rc8 and latency are ok
Thanks
Vincent
>
>
> Thanks.
>
> --
> tejun
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2017-04-27 00:50 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tADV0-jp-15@gated-at.bofh.it> |
| In reply to | #1631605 |
Hello,
On Wed, Apr 26, 2017 at 06:51:23PM +0200, Vincent Guittot wrote:
> > It's not temporary. The weight of a group is its shares, which is its
> > load fraction of the configured weight of the group. Assuming UP, if
> > you configure a group to the weight of 1024 and have any task running
> > full-tilt in it, the group will converge to the load of 1024. The
> > problem is that the propagation logic is currently doing something
> > completely different and temporarily push down the load whenever it
> > triggers.
>
> Ok, I see your point and agree that there is an issue when propagating
> load_avg of a task group which has tasks with lower weight than the share
> but your proposal has got issue because it uses runnable_load_avg instead
> of load_avg and this makes propagation of loadavg_avg incorrect, something
> like below which keeps using load_avg solve the problem
>
> + if (gcfs_rq->load.weight) {
> + long shares = scale_load_down(calc_cfs_shares(gcfs_rq, gcfs_rq->tg));
> +
> + load = min(gcfs_rq->avg.load_avg *
> + shares / scale_load_down(gcfs_rq->load.weight), shares);
>
> I have run schbench with the change above on v4.11-rc8 and latency are ok
Hmm... so, I'll test this but this wouldn't solve the problem of
root's runnable_load_avg being out of sync with the approximate sum of
all task loads, which is the cause of the latencies that I'm seeing.
Are you saying that with the above change, you're not seeing the
higher latency issue that you reported in the other reply?
Thanks.
--
tejun
[toc] | [prev] | [next] | [standalone]
| From | Vincent Guittot <vincent.guittot@linaro.org> |
|---|---|
| Date | 2017-04-27 09:10 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tALIS-5Aa-5@gated-at.bofh.it> |
| In reply to | #1631778 |
On 27 April 2017 at 00:40, Tejun Heo <tj@kernel.org> wrote:
> Hello,
>
> On Wed, Apr 26, 2017 at 06:51:23PM +0200, Vincent Guittot wrote:
>> > It's not temporary. The weight of a group is its shares, which is its
>> > load fraction of the configured weight of the group. Assuming UP, if
>> > you configure a group to the weight of 1024 and have any task running
>> > full-tilt in it, the group will converge to the load of 1024. The
>> > problem is that the propagation logic is currently doing something
>> > completely different and temporarily push down the load whenever it
>> > triggers.
>>
>> Ok, I see your point and agree that there is an issue when propagating
>> load_avg of a task group which has tasks with lower weight than the share
>> but your proposal has got issue because it uses runnable_load_avg instead
>> of load_avg and this makes propagation of loadavg_avg incorrect, something
>> like below which keeps using load_avg solve the problem
>>
>> + if (gcfs_rq->load.weight) {
>> + long shares = scale_load_down(calc_cfs_shares(gcfs_rq, gcfs_rq->tg));
>> +
>> + load = min(gcfs_rq->avg.load_avg *
>> + shares / scale_load_down(gcfs_rq->load.weight), shares);
>>
>> I have run schbench with the change above on v4.11-rc8 and latency are ok
>
> Hmm... so, I'll test this but this wouldn't solve the problem of
> root's runnable_load_avg being out of sync with the approximate sum of
> all task loads, which is the cause of the latencies that I'm seeing.
>
> Are you saying that with the above change, you're not seeing the
> higher latency issue that you reported in the other reply?
yes I don't have any latency regression like v4.11-rc8 with the above
change that uses load_avg but fix the propagation for of a task with a
lower weight than task group share.
>
> Thanks.
>
> --
> tejun
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2017-05-01 16:20 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tCklb-1LR-9@gated-at.bofh.it> |
| In reply to | #1631605 |
Hi,
sorry for being late to the party, trying to catch-up..
On Wed, Apr 26, 2017 at 06:51:23PM +0200, Vincent Guittot wrote:
> Ok, I see your point and agree that there is an issue when propagating
> load_avg of a task group which has tasks with lower weight than the share
> but your proposal has got issue because it uses runnable_load_avg instead
> of load_avg and this makes propagation of loadavg_avg incorrect, something
> like below which keeps using load_avg solve the problem
>
> + if (gcfs_rq->load.weight) {
> + long shares = scale_load_down(calc_cfs_shares(gcfs_rq, gcfs_rq->tg));
> +
> + load = min(gcfs_rq->avg.load_avg *
> + shares / scale_load_down(gcfs_rq->load.weight), shares);
>
So this here does:
( tg->load_avg = \Sum cfs_rq->load_avg )
load = cfs_rq->load.weight
tg_weight = tg->load_avg - cfs_rq->contrib + load
tg->shares * load
shares = -----------------
tg_weight
cfs_rq->load_avg
avg_shares = shares * ----------------
load
tg->shares * cfs_rq->load_avg
= -----------------------------
tg_weight
( se->load.weight = shares )
se->load_avg = min(shares, avg_shares);
So where shares (and se->load.weight) are an upper bound (due to using
cfs_rq->load.weight, see calc_cfs_shares), avg_shares is supposedly a
more accurate representation based on our PELT averages.
This looks OK; and I agree with Vincent that we should use
cfs_rq->avg.load_avg, not cfs_rq->runnable_load_avg, since tg->load_avg
is a sum of the former, not the latter.
Also, arguably calculating the above avg_shares directly (using the
second equation) might be more precise; but I doubt it makes much of a
difference, however since we do min(), we should at least clamp against
MIN_SHARES again.
Furthermore, it appears to me we want a different tg_weight value for
the avg_shares, something like:
tg_weight = tg->load_avg - cfs_rq->contrib + cfs_rq->avg.load_avg
To better match with the numerator's units, otherwise it will have a
tendency to push avg_shares down further than it needs to be.
(All assuming it actually works of course.. compile tested only)
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2634,7 +2634,9 @@ account_entity_dequeue(struct cfs_rq *cf
# ifdef CONFIG_SMP
static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
{
- long tg_weight, load, shares;
+ long tg_weight, tg_shares, load, shares;
+
+ tg_shares = READ_ONCE(tg->shares);
/*
* This really should be: cfs_rq->avg.load_avg, but instead we use
@@ -2665,12 +2667,7 @@ static long calc_cfs_shares(struct cfs_r
* case no task is runnable on a CPU MIN_SHARES=2 should be returned
* instead of 0.
*/
- if (shares < MIN_SHARES)
- shares = MIN_SHARES;
- if (shares > tg->shares)
- shares = tg->shares;
-
- return shares;
+ return clamp_t(long, shares, MIN_SHARES, tg_shares);
}
# else /* CONFIG_SMP */
static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
@@ -3075,37 +3072,69 @@ static inline void
update_tg_cfs_load(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
struct cfs_rq *gcfs_rq = group_cfs_rq(se);
- long delta, load = gcfs_rq->avg.load_avg;
+ long load = 0, delta;
/*
- * If the load of group cfs_rq is null, the load of the
- * sched_entity will also be null so we can skip the formula
+ * If there is load in our group cfs_rq (@gcfs_rq), then update its
+ * corresponding group se (@se) load value to reflect any change in
+ * weights.
+ *
+ * Also see effective_load(), where we do something similar.
+ *
+ * ( tg->load_avg = \Sum cfs_rq->load_avg )
+ *
+ * tg_weight = tg->load_avg - cfs_rq->contrib
+ *
+ *
+ * tg->shares * cfs_rq->weight
+ * shares = ---------------------------
+ * tg_weight + cfs_rq->weight
+ *
+ *
+ * tg->shares * cfs_rq->load_avg
+ * avg_shares = -----------------------------
+ * tg_weight + cfs_rq->load_avg
+ *
+ *
+ * ( se->load.weight = shares )
+ *
+ * se->load_avg = min(shares, avg_shares);
+ *
+ * Where @shares is an upper bound to @avg_shares, see the comments
+ * in calc_cfs_shares().
*/
- if (load) {
- long tg_load;
-
- /* Get tg's load and ensure tg_load > 0 */
- tg_load = atomic_long_read(&gcfs_rq->tg->load_avg) + 1;
-
- /* Ensure tg_load >= load and updated with current load*/
- tg_load -= gcfs_rq->tg_load_avg_contrib;
- tg_load += load;
+ if (gcfs_rq->load.weight) {
+ long tg_weight1, tg_weight2, tg_shares, shares, avg_shares;
+ struct task_group *tg = gcfs_rq->tg;
/*
- * We need to compute a correction term in the case that the
- * task group is consuming more CPU than a task of equal
- * weight. A task with a weight equals to tg->shares will have
- * a load less or equal to scale_load_down(tg->shares).
- * Similarly, the sched_entities that represent the task group
- * at parent level, can't have a load higher than
- * scale_load_down(tg->shares). And the Sum of sched_entities'
- * load must be <= scale_load_down(tg->shares).
+ * This open-codes calc_cfs_shares(), in order to ensure
+ * we use consistent values for @shares and @avg_shares,
+ * as well as make sure we clip the result properly.
*/
- if (tg_load > scale_load_down(gcfs_rq->tg->shares)) {
- /* scale gcfs_rq's load into tg's shares*/
- load *= scale_load_down(gcfs_rq->tg->shares);
- load /= tg_load;
- }
+
+ tg_shares = READ_ONCE(tg->shares);
+
+ load = scale_load_down(gcfs_rq->load.weight);
+
+ tg_weight1 = atomic_long_read(&tg->load_avg);
+ tg_weight2 = (tg_weight1 -= cfs_rq->tg_load_avg_contrib);
+ tg_weight1 += load;
+
+ shares = tg_shares * load;
+ if (tg_weight1)
+ shares /= tg_weight1;
+
+
+ load = READ_ONCE(gcfs_rq->avg.load_avg);
+
+ tg_weight2 += load;
+
+ avg_shares = tg_shares * load;
+ if (tg_weight2)
+ avg_shares /= tg_weight2;
+
+ load = clamp_t(long, min(shares, avg_shares), MIN_SHARES, tg_shares);
}
delta = load - se->avg.load_avg;
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2017-05-01 17:00 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tCkXT-1YA-11@gated-at.bofh.it> |
| In reply to | #1633683 |
On Mon, May 01, 2017 at 04:17:33PM +0200, Peter Zijlstra wrote: > So this here does: > > ( tg->load_avg = \Sum cfs_rq->load_avg ) > > load = cfs_rq->load.weight > > tg_weight = tg->load_avg - cfs_rq->contrib + load > > > tg->shares * load > shares = ----------------- > tg_weight > > > cfs_rq->load_avg > avg_shares = shares * ---------------- > load > > tg->shares * cfs_rq->load_avg > = ----------------------------- > tg_weight > > > ( se->load.weight = shares ) > > se->load_avg = min(shares, avg_shares); I wonder though; do we really need the min() ? Can't we simply use avg_shares all the time?
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2017-05-02 00:00 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tCrwn-626-39@gated-at.bofh.it> |
| In reply to | #1633683 |
Hello, Peter. On Mon, May 01, 2017 at 04:17:33PM +0200, Peter Zijlstra wrote: > So this here does: > > ( tg->load_avg = \Sum cfs_rq->load_avg ) > > load = cfs_rq->load.weight > > tg_weight = tg->load_avg - cfs_rq->contrib + load > > > tg->shares * load > shares = ----------------- > tg_weight > > > cfs_rq->load_avg > avg_shares = shares * ---------------- > load > > tg->shares * cfs_rq->load_avg > = ----------------------------- > tg_weight > > > ( se->load.weight = shares ) > > se->load_avg = min(shares, avg_shares); > > > So where shares (and se->load.weight) are an upper bound (due to using > cfs_rq->load.weight, see calc_cfs_shares), avg_shares is supposedly a > more accurate representation based on our PELT averages. > > This looks OK; and I agree with Vincent that we should use > cfs_rq->avg.load_avg, not cfs_rq->runnable_load_avg, since tg->load_avg > is a sum of the former, not the latter. With this, we end up using a different metric for picking the busiest queue depending on whether there are nested cfs_rq's or not. The root's runnable_load_avg ends up including blocked load avgs queued behind nested cfs_rq's because we lose the resolution across threads across nesting. > Also, arguably calculating the above avg_shares directly (using the > second equation) might be more precise; but I doubt it makes much of a > difference, however since we do min(), we should at least clamp against > MIN_SHARES again. > > Furthermore, it appears to me we want a different tg_weight value for > the avg_shares, something like: > > tg_weight = tg->load_avg - cfs_rq->contrib + cfs_rq->avg.load_avg > > To better match with the numerator's units, otherwise it will have a > tendency to push avg_shares down further than it needs to be. > > > (All assuming it actually works of course.. compile tested only) So, if changing gcfs_rq se->load_avg.avg to match the gcfs_rq's runnable_load_avg is icky, and I can see why that would be, we can simply introduce a separate channel of propagation so that runnable_load_avg gets propagated independently from se->load_avg propagation, so that for all every cfs_rq, its runnable_load_avg is the sum of all active load_avgs queued on itself and its descendents, which is the number we want for load balancing anyway. I'll try to spin a patch which does that. I still wonder what gcfs_rq se->load_avg.avg is good for tho? It's nice to keep the value in line but is it actually used anywhere? The parent cfs_rq's values are independently calculated and, AFAICS, the only time the value is used is to propagate into the parent's runnable_load_sum, which has to use a different value, as explained above. Thanks. -- tejun
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2017-05-02 10:20 +0200 |
| Subject | Re: [PATCH 1/2] sched/fair: Fix how load gets propagated from cfs_rq to its sched_entity |
| Message-ID | <tCBcm-421-43@gated-at.bofh.it> |
| In reply to | #1633981 |
On Mon, May 01, 2017 at 05:56:04PM -0400, Tejun Heo wrote:
> I still wonder what gcfs_rq se->load_avg.avg is good for tho? It's
> nice to keep the value in line but is it actually used anywhere?
Its used to manage its parent's cfs_rq sums boundary conditions. When we
enqueue the group se to the parent group, we do:
enqueue_entity()
enqueue_entity_load_avg()
// update runnable
// add se.avg to cfs_rq.avg if 'migrated'
Now obviously group se's never actually migrate between CPUs, but they
still pass through that code. I think the 'migrate' condition also
triggers for new entities for example, they 'migrate' into the system.
Similar for dequeue, that should trigger when groups entities
get destroyed, they 'migrate' out of the system.
But I get what you're saying. They're not overly useful as such.
> So, if changing gcfs_rq se->load_avg.avg to match the gcfs_rq's
> runnable_load_avg is icky, and I can see why that would be, we can
> simply introduce a separate channel of propagation ...
Can you have a play with something like the below? I suspect
'shares_runnable' might work for you here.
Its still 'icky', but not more so than calc_cfs_shares() was to begin
with. When many CPUs are involved the global sum (tg_shares) is still
dominated by avg_load and the division will have a downward bias, but
given the purpose that might not be too bad.
---
kernel/sched/fair.c | 62 +++++++++++++++++++++++++++++++++++++----------------
1 file changed, 44 insertions(+), 18 deletions(-)
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index a903276fcb62..7d1fb5f421bc 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2630,26 +2630,56 @@ static inline void account_numa_dequeue(struct rq *rq, struct task_struct *p)
cfs_rq->nr_running--;
}
+enum shares_type {
+ shares_runnable,
+ shares_avg,
+ shares_weight,
+};
+
#ifdef CONFIG_FAIR_GROUP_SCHED
# ifdef CONFIG_SMP
-static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
+static long
+calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg, enum shares_type)
{
- long tg_weight, load, shares;
+ long tg_weight, tg_shares, load, shares;
- /*
- * This really should be: cfs_rq->avg.load_avg, but instead we use
- * cfs_rq->load.weight, which is its upper bound. This helps ramp up
- * the shares for small weight interactive tasks.
- */
- load = scale_load_down(cfs_rq->load.weight);
+ tg_shares = READ_ONCE(tg->shares);
+
+ switch (shares_type) {
+ case shares_runnable:
+ /*
+ * Instead of the correct cfs_rq->avg.load_avg we use
+ * cfs_rq->runnable_load_avg, which does not include the
+ * blocked load.
+ */
+ load = cfs_rq->runnable_load_avg;
+ break;
+
+ case shares_avg:
+ load = cfs_rq->avg.load_avg;
+ break;
+
+ case shares_weight:
+ /*
+ * Instead of the correct cfs_rq->avg.load_avg we use
+ * cfs_rq->load.weight, which is its upper bound. This helps
+ * ramp up the shares for small weight interactive tasks.
+ */
+ load = scale_load_down(cfs_rq->load.weight);
+ break;
+ }
tg_weight = atomic_long_read(&tg->load_avg);
- /* Ensure tg_weight >= load */
+ /*
+ * This ensures the sum is up-to-date for this CPU, in case of the other
+ * two approximations it biases the sum towards their value and in case
+ * of (near) UP ensures the division ends up <= 1.
+ */
tg_weight -= cfs_rq->tg_load_avg_contrib;
tg_weight += load;
- shares = (tg->shares * load);
+ shares = (tg_shares * load);
if (tg_weight)
shares /= tg_weight;
@@ -2665,15 +2695,11 @@ static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
* case no task is runnable on a CPU MIN_SHARES=2 should be returned
* instead of 0.
*/
- if (shares < MIN_SHARES)
- shares = MIN_SHARES;
- if (shares > tg->shares)
- shares = tg->shares;
-
- return shares;
+ return clamp_t(long, shares, MIN_SHARES, tg_shares);
}
# else /* CONFIG_SMP */
-static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg)
+static inline long
+calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg, enum shares_type)
{
return tg->shares;
}
@@ -2715,7 +2741,7 @@ static void update_cfs_shares(struct sched_entity *se)
if (likely(se->load.weight == tg->shares))
return;
#endif
- shares = calc_cfs_shares(cfs_rq, tg);
+ shares = calc_cfs_shares(cfs_rq, tg, shares_weight);
reweight_entity(cfs_rq_of(se), se, shares);
}
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | linux.kernel
csiph-web