diff options
author | Mike Galbraith <efault@gmx.de> | 2009-10-23 17:09:22 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-10-23 17:48:28 -0400 |
commit | f685ceacab07d3f6c236f04803e2f2f0dbcc5afb (patch) | |
tree | f5fbbb177ccb784ffa6d6224b7b8f0cb8a096bb9 /kernel | |
parent | 92f6a5e37a2e2d3342dafb2b39c2f8bc340bbf84 (diff) |
sched: Strengthen buddies and mitigate buddy induced latencies
This patch restores the effectiveness of LAST_BUDDY in preventing
pgsql+oltp from collapsing due to wakeup preemption. It also
switches LAST_BUDDY to exclusively do what it does best, namely
mitigate the effects of aggressive wakeup preemption, which
improves vmark throughput markedly, and restores mysql+oltp
scalability.
Since buddies are about scalability, enable them beginning at the
point where we begin expanding sched_latency, namely
sched_nr_latency. Previously, buddies were cleared aggressively,
which seriously reduced their effectiveness. Not clearing
aggressively however, produces a small drop in mysql+oltp
throughput immediately after peak, indicating that LAST_BUDDY is
actually doing some harm. This is right at the point where X on the
desktop in competition with another load wants low latency service.
Ergo, do not enable until we need to scale.
To mitigate latency induced by buddies, or by a task just missing
wakeup preemption, check latency at tick time.
Last hunk prevents buddies from stymieing BALANCE_NEWIDLE via
CACHE_HOT_BUDDY.
Supporting performance tests:
tip = v2.6.32-rc5-1497-ga525b32
tipx = NO_GENTLE_FAIR_SLEEPERS NEXT_BUDDY granularity knobs = 31 knobs + 31 buddies
tip+x = NO_GENTLE_FAIR_SLEEPERS granularity knobs = 31 knobs
(Three run averages except where noted.)
vmark:
------
tip 108466 messages per second
tip+ 125307 messages per second
tip+x 125335 messages per second
tipx 117781 messages per second
2.6.31.3 122729 messages per second
mysql+oltp:
-----------
clients 1 2 4 8 16 32 64 128 256
..........................................................................................
tip 9949.89 18690.20 34801.24 34460.04 32682.88 30765.97 28305.27 25059.64 19548.08
tip+ 10013.90 18526.84 34900.38 34420.14 33069.83 32083.40 30578.30 28010.71 25605.47
tipx 9698.71 18002.70 34477.56 33420.01 32634.30 31657.27 29932.67 26827.52 21487.18
2.6.31.3 8243.11 18784.20 34404.83 33148.38 31900.32 31161.90 29663.81 25995.94 18058.86
pgsql+oltp:
-----------
clients 1 2 4 8 16 32 64 128 256
..........................................................................................
tip 13686.37 26609.25 51934.28 51347.81 49479.51 45312.65 36691.91 26851.57 24145.35
tip+ (1x) 13907.85 27135.87 52951.98 52514.04 51742.52 50705.43 49947.97 48374.19 46227.94
tip+x 13906.78 27065.81 52951.19 52542.59 52176.11 51815.94 50838.90 49439.46 46891.00
tipx 13742.46 26769.81 52351.99 51891.73 51320.79 50938.98 50248.65 48908.70 46553.84
2.6.31.3 13815.35 26906.46 52683.34 52061.31 51937.10 51376.80 50474.28 49394.47 47003.25
Signed-off-by: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched.c | 2 | ||||
-rw-r--r-- | kernel/sched_fair.c | 73 |
2 files changed, 48 insertions, 27 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 789001da0a94..cae6700bedb3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -2008,7 +2008,7 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd) | |||
2008 | /* | 2008 | /* |
2009 | * Buddy candidates are cache hot: | 2009 | * Buddy candidates are cache hot: |
2010 | */ | 2010 | */ |
2011 | if (sched_feat(CACHE_HOT_BUDDY) && | 2011 | if (sched_feat(CACHE_HOT_BUDDY) && this_rq()->nr_running && |
2012 | (&p->se == cfs_rq_of(&p->se)->next || | 2012 | (&p->se == cfs_rq_of(&p->se)->next || |
2013 | &p->se == cfs_rq_of(&p->se)->last)) | 2013 | &p->se == cfs_rq_of(&p->se)->last)) |
2014 | return 1; | 2014 | return 1; |
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index c32c3e643daa..37087a7fac22 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c | |||
@@ -822,6 +822,26 @@ check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) | |||
822 | * re-elected due to buddy favours. | 822 | * re-elected due to buddy favours. |
823 | */ | 823 | */ |
824 | clear_buddies(cfs_rq, curr); | 824 | clear_buddies(cfs_rq, curr); |
825 | return; | ||
826 | } | ||
827 | |||
828 | /* | ||
829 | * Ensure that a task that missed wakeup preemption by a | ||
830 | * narrow margin doesn't have to wait for a full slice. | ||
831 | * This also mitigates buddy induced latencies under load. | ||
832 | */ | ||
833 | if (!sched_feat(WAKEUP_PREEMPT)) | ||
834 | return; | ||
835 | |||
836 | if (delta_exec < sysctl_sched_min_granularity) | ||
837 | return; | ||
838 | |||
839 | if (cfs_rq->nr_running > 1) { | ||
840 | struct sched_entity *se = __pick_next_entity(cfs_rq); | ||
841 | s64 delta = curr->vruntime - se->vruntime; | ||
842 | |||
843 | if (delta > ideal_runtime) | ||
844 | resched_task(rq_of(cfs_rq)->curr); | ||
825 | } | 845 | } |
826 | } | 846 | } |
827 | 847 | ||
@@ -861,21 +881,18 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se); | |||
861 | static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq) | 881 | static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq) |
862 | { | 882 | { |
863 | struct sched_entity *se = __pick_next_entity(cfs_rq); | 883 | struct sched_entity *se = __pick_next_entity(cfs_rq); |
864 | struct sched_entity *buddy; | 884 | struct sched_entity *left = se; |
865 | 885 | ||
866 | if (cfs_rq->next) { | 886 | if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) |
867 | buddy = cfs_rq->next; | 887 | se = cfs_rq->next; |
868 | cfs_rq->next = NULL; | ||
869 | if (wakeup_preempt_entity(buddy, se) < 1) | ||
870 | return buddy; | ||
871 | } | ||
872 | 888 | ||
873 | if (cfs_rq->last) { | 889 | /* |
874 | buddy = cfs_rq->last; | 890 | * Prefer last buddy, try to return the CPU to a preempted task. |
875 | cfs_rq->last = NULL; | 891 | */ |
876 | if (wakeup_preempt_entity(buddy, se) < 1) | 892 | if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1) |
877 | return buddy; | 893 | se = cfs_rq->last; |
878 | } | 894 | |
895 | clear_buddies(cfs_rq, se); | ||
879 | 896 | ||
880 | return se; | 897 | return se; |
881 | } | 898 | } |
@@ -1577,6 +1594,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ | |||
1577 | struct sched_entity *se = &curr->se, *pse = &p->se; | 1594 | struct sched_entity *se = &curr->se, *pse = &p->se; |
1578 | struct cfs_rq *cfs_rq = task_cfs_rq(curr); | 1595 | struct cfs_rq *cfs_rq = task_cfs_rq(curr); |
1579 | int sync = wake_flags & WF_SYNC; | 1596 | int sync = wake_flags & WF_SYNC; |
1597 | int scale = cfs_rq->nr_running >= sched_nr_latency; | ||
1580 | 1598 | ||
1581 | update_curr(cfs_rq); | 1599 | update_curr(cfs_rq); |
1582 | 1600 | ||
@@ -1591,18 +1609,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ | |||
1591 | if (unlikely(se == pse)) | 1609 | if (unlikely(se == pse)) |
1592 | return; | 1610 | return; |
1593 | 1611 | ||
1594 | /* | 1612 | if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK)) |
1595 | * Only set the backward buddy when the current task is still on the | ||
1596 | * rq. This can happen when a wakeup gets interleaved with schedule on | ||
1597 | * the ->pre_schedule() or idle_balance() point, either of which can | ||
1598 | * drop the rq lock. | ||
1599 | * | ||
1600 | * Also, during early boot the idle thread is in the fair class, for | ||
1601 | * obvious reasons its a bad idea to schedule back to the idle thread. | ||
1602 | */ | ||
1603 | if (sched_feat(LAST_BUDDY) && likely(se->on_rq && curr != rq->idle)) | ||
1604 | set_last_buddy(se); | ||
1605 | if (sched_feat(NEXT_BUDDY) && !(wake_flags & WF_FORK)) | ||
1606 | set_next_buddy(pse); | 1613 | set_next_buddy(pse); |
1607 | 1614 | ||
1608 | /* | 1615 | /* |
@@ -1648,8 +1655,22 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_ | |||
1648 | 1655 | ||
1649 | BUG_ON(!pse); | 1656 | BUG_ON(!pse); |
1650 | 1657 | ||
1651 | if (wakeup_preempt_entity(se, pse) == 1) | 1658 | if (wakeup_preempt_entity(se, pse) == 1) { |
1652 | resched_task(curr); | 1659 | resched_task(curr); |
1660 | /* | ||
1661 | * Only set the backward buddy when the current task is still | ||
1662 | * on the rq. This can happen when a wakeup gets interleaved | ||
1663 | * with schedule on the ->pre_schedule() or idle_balance() | ||
1664 | * point, either of which can * drop the rq lock. | ||
1665 | * | ||
1666 | * Also, during early boot the idle thread is in the fair class, | ||
1667 | * for obvious reasons its a bad idea to schedule back to it. | ||
1668 | */ | ||
1669 | if (unlikely(!se->on_rq || curr == rq->idle)) | ||
1670 | return; | ||
1671 | if (sched_feat(LAST_BUDDY) && scale && entity_is_task(se)) | ||
1672 | set_last_buddy(se); | ||
1673 | } | ||
1653 | } | 1674 | } |
1654 | 1675 | ||
1655 | static struct task_struct *pick_next_task_fair(struct rq *rq) | 1676 | static struct task_struct *pick_next_task_fair(struct rq *rq) |