aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Galbraith <efault@gmx.de>2009-09-08 05:12:28 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-08 07:15:34 -0400
commitb5d9d734a53e0204aab0089079cbde2a1285a38f (patch)
treef8c657d213514de7affaab50ed4cfd8b3a17d0f3
parenta8fae3ec5f118dc92517dcbed3ecf69ddb641d0f (diff)
sched: Ensure that a child can't gain time over it's parent after fork()
A fork/exec load is usually "pass the baton", so the child should never be placed behind the parent. With START_DEBIT we make room for the new task, but with child_runs_first, that room comes out of the _parent's_ hide. There's nothing to say that the parent wasn't ahead of min_vruntime at fork() time, which means that the "baton carrier", who is essentially the parent in drag, can gain time and increase scheduling latencies for waiters. With NEW_FAIR_SLEEPERS + START_DEBIT + child_runs_first enabled, we essentially pass the sleeper fairness off to the child, which is fine, but if we don't base placement on the parent's updated vruntime, we can end up compounding latency woes if the child itself then does fork/exec. The debit incurred at fork doesn't hurt the parent who is then going to sleep and maybe exit, but the child who acquires the error harms all comers. This improves latencies of make -j<n> kernel build workloads. Reported-by: Jens Axboe <jens.axboe@oracle.com> Signed-off-by: Mike Galbraith <efault@gmx.de> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--kernel/sched_fair.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index cc97ea498f24..e386e5dfcdae 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -728,11 +728,11 @@ place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
728 728
729 vruntime -= thresh; 729 vruntime -= thresh;
730 } 730 }
731
732 /* ensure we never gain time by being placed backwards. */
733 vruntime = max_vruntime(se->vruntime, vruntime);
734 } 731 }
735 732
733 /* ensure we never gain time by being placed backwards. */
734 vruntime = max_vruntime(se->vruntime, vruntime);
735
736 se->vruntime = vruntime; 736 se->vruntime = vruntime;
737} 737}
738 738
@@ -1756,6 +1756,8 @@ static void task_new_fair(struct rq *rq, struct task_struct *p)
1756 sched_info_queued(p); 1756 sched_info_queued(p);
1757 1757
1758 update_curr(cfs_rq); 1758 update_curr(cfs_rq);
1759 if (curr)
1760 se->vruntime = curr->vruntime;
1759 place_entity(cfs_rq, se, 1); 1761 place_entity(cfs_rq, se, 1);
1760 1762
1761 /* 'curr' will be NULL if the child belongs to a different group */ 1763 /* 'curr' will be NULL if the child belongs to a different group */