Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

sched/fair: Fix calc_cfs_shares() fixed point arithmetics width confusion

Commit:

fde7d22e01aa ("sched/fair: Fix overly small weight for interactive group entities")

did something non-obvious but also did it buggy yet latent.

The problem was exposed for real by a later commit in the v4.7 merge window:

2159197d6677 ("sched/core: Enable increased load resolution on 64-bit kernels")

... after which tg->load_avg and cfs_rq->load.weight had different
units (10 bit fixed point and 20 bit fixed point resp.).

Add a comment to explain the use of cfs_rq->load.weight over the
'natural' cfs_rq->avg.load_avg and add scale_load_down() to correct
for the difference in unit.

Since this is (now, as per a previous commit) the only user of
calc_tg_weight(), collapse it.

The effects of this bug should be randomly inconsistent SMP-balancing
of cgroups workloads.

Reported-by: Jirka Hladky <jhladky@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: 2159197d6677 ("sched/core: Enable increased load resolution on 64-bit kernels")
Fixes: fde7d22e01aa ("sched/fair: Fix overly small weight for interactive group entities")
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Peter Zijlstra and committed by
Ingo Molnar
ea1dc6fc 7dd49125

+13 -18
+13 -18
kernel/sched/fair.c
··· 2497 2497 2498 2498 #ifdef CONFIG_FAIR_GROUP_SCHED 2499 2499 # ifdef CONFIG_SMP 2500 - static inline long calc_tg_weight(struct task_group *tg, struct cfs_rq *cfs_rq) 2501 - { 2502 - long tg_weight; 2503 - 2504 - /* 2505 - * Use this CPU's real-time load instead of the last load contribution 2506 - * as the updating of the contribution is delayed, and we will use the 2507 - * the real-time load to calc the share. See update_tg_load_avg(). 2508 - */ 2509 - tg_weight = atomic_long_read(&tg->load_avg); 2510 - tg_weight -= cfs_rq->tg_load_avg_contrib; 2511 - tg_weight += cfs_rq->load.weight; 2512 - 2513 - return tg_weight; 2514 - } 2515 - 2516 2500 static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg) 2517 2501 { 2518 2502 long tg_weight, load, shares; 2519 2503 2520 - tg_weight = calc_tg_weight(tg, cfs_rq); 2521 - load = cfs_rq->load.weight; 2504 + /* 2505 + * This really should be: cfs_rq->avg.load_avg, but instead we use 2506 + * cfs_rq->load.weight, which is its upper bound. This helps ramp up 2507 + * the shares for small weight interactive tasks. 2508 + */ 2509 + load = scale_load_down(cfs_rq->load.weight); 2510 + 2511 + tg_weight = atomic_long_read(&tg->load_avg); 2512 + 2513 + /* Ensure tg_weight >= load */ 2514 + tg_weight -= cfs_rq->tg_load_avg_contrib; 2515 + tg_weight += load; 2522 2516 2523 2517 shares = (tg->shares * load); 2524 2518 if (tg_weight) ··· 2531 2537 return tg->shares; 2532 2538 } 2533 2539 # endif /* CONFIG_SMP */ 2540 + 2534 2541 static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, 2535 2542 unsigned long weight) 2536 2543 {