diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-06 18:45:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-06 18:45:40 -0500 |
commit | 067ab19923673e3d8c982d877bedb9d65c976c22 (patch) | |
tree | b11c20e4b5a6671355924b656f9348d4ece5523f /kernel | |
parent | 7597bc94d6f3bdccb086ac7f2ad91292fdaee2a4 (diff) | |
parent | 9fcd18c9e63e325dbd2b4c726623f760788d5aa8 (diff) |
Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
sched: re-tune balancing
sched: fix buddies for group scheduling
sched: backward looking buddy
sched: fix fair preempt check
sched: cleanup fair task selection
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched.c | 6 | ||||
-rw-r--r-- | kernel/sched_fair.c | 76 | ||||
-rw-r--r-- | kernel/sched_features.h | 1 |
3 files changed, 54 insertions, 29 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index e8819bc6f462..82cc839c9210 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -397,7 +397,7 @@ struct cfs_rq { | |||
397 | * 'curr' points to currently running entity on this cfs_rq. | 397 | * 'curr' points to currently running entity on this cfs_rq. |
398 | * It is set to NULL otherwise (i.e when none are currently running). | 398 | * It is set to NULL otherwise (i.e when none are currently running). |
399 | */ | 399 | */ |
400 | struct sched_entity *curr, *next; | 400 | struct sched_entity *curr, *next, *last; |
401 | 401 | ||
402 | unsigned long nr_spread_over; | 402 | unsigned long nr_spread_over; |
403 | 403 | ||
@@ -1805,7 +1805,9 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd) | |||
1805 | /* | 1805 | /* |
1806 | * Buddy candidates are cache hot: | 1806 | * Buddy candidates are cache hot: |
1807 | */ | 1807 | */ |
1808 | if (sched_feat(CACHE_HOT_BUDDY) && (&p->se == cfs_rq_of(&p->se)->next)) | 1808 | if (sched_feat(CACHE_HOT_BUDDY) && |
1809 | (&p->se == cfs_rq_of(&p->se)->next || | ||
1810 | &p->se == cfs_rq_of(&p->se)->last)) | ||
1809 | return 1; | 1811 | return 1; |
1810 | 1812 | ||
1811 | if (p->sched_class != &fair_sched_class) | 1813 | if (p->sched_class != &fair_sched_class) |
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index ce514afd78ff..51aa3e102acb 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c | |||
@@ -341,23 +341,20 @@ static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) | |||
341 | cfs_rq->rb_leftmost = next_node; | 341 | cfs_rq->rb_leftmost = next_node; |
342 | } | 342 | } |
343 | 343 | ||
344 | if (cfs_rq->next == se) | ||
345 | cfs_rq->next = NULL; | ||
346 | |||
347 | rb_erase(&se->run_node, &cfs_rq->tasks_timeline); | 344 | rb_erase(&se->run_node, &cfs_rq->tasks_timeline); |
348 | } | 345 | } |
349 | 346 | ||
350 | static inline struct rb_node *first_fair(struct cfs_rq *cfs_rq) | ||
351 | { | ||
352 | return cfs_rq->rb_leftmost; | ||
353 | } | ||
354 | |||
355 | static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq) | 347 | static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq) |
356 | { | 348 | { |
357 | return rb_entry(first_fair(cfs_rq), struct sched_entity, run_node); | 349 | struct rb_node *left = cfs_rq->rb_leftmost; |
350 | |||
351 | if (!left) | ||
352 | return NULL; | ||
353 | |||
354 | return rb_entry(left, struct sched_entity, run_node); | ||
358 | } | 355 | } |
359 | 356 | ||
360 | static inline struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) | 357 | static struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) |
361 | { | 358 | { |
362 | struct rb_node *last = rb_last(&cfs_rq->tasks_timeline); | 359 | struct rb_node *last = rb_last(&cfs_rq->tasks_timeline); |
363 | 360 | ||
@@ -741,6 +738,12 @@ dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int sleep) | |||
741 | #endif | 738 | #endif |
742 | } | 739 | } |
743 | 740 | ||
741 | if (cfs_rq->last == se) | ||
742 | cfs_rq->last = NULL; | ||
743 | |||
744 | if (cfs_rq->next == se) | ||
745 | cfs_rq->next = NULL; | ||
746 | |||
744 | if (se != cfs_rq->curr) | 747 | if (se != cfs_rq->curr) |
745 | __dequeue_entity(cfs_rq, se); | 748 | __dequeue_entity(cfs_rq, se); |
746 | account_entity_dequeue(cfs_rq, se); | 749 | account_entity_dequeue(cfs_rq, se); |
@@ -794,24 +797,15 @@ set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) | |||
794 | static int | 797 | static int |
795 | wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se); | 798 | wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se); |
796 | 799 | ||
797 | static struct sched_entity * | ||
798 | pick_next(struct cfs_rq *cfs_rq, struct sched_entity *se) | ||
799 | { | ||
800 | if (!cfs_rq->next || wakeup_preempt_entity(cfs_rq->next, se) == 1) | ||
801 | return se; | ||
802 | |||
803 | return cfs_rq->next; | ||
804 | } | ||
805 | |||
806 | static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq) | 800 | static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq) |
807 | { | 801 | { |
808 | struct sched_entity *se = NULL; | 802 | struct sched_entity *se = __pick_next_entity(cfs_rq); |
809 | 803 | ||
810 | if (first_fair(cfs_rq)) { | 804 | if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, se) < 1) |
811 | se = __pick_next_entity(cfs_rq); | 805 | return cfs_rq->next; |
812 | se = pick_next(cfs_rq, se); | 806 | |
813 | set_next_entity(cfs_rq, se); | 807 | if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, se) < 1) |
814 | } | 808 | return cfs_rq->last; |
815 | 809 | ||
816 | return se; | 810 | return se; |
817 | } | 811 | } |
@@ -1325,26 +1319,53 @@ wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se) | |||
1325 | return 0; | 1319 | return 0; |
1326 | } | 1320 | } |
1327 | 1321 | ||
1322 | static void set_last_buddy(struct sched_entity *se) | ||
1323 | { | ||
1324 | for_each_sched_entity(se) | ||
1325 | cfs_rq_of(se)->last = se; | ||
1326 | } | ||
1327 | |||
1328 | static void set_next_buddy(struct sched_entity *se) | ||
1329 | { | ||
1330 | for_each_sched_entity(se) | ||
1331 | cfs_rq_of(se)->next = se; | ||
1332 | } | ||
1333 | |||
1328 | /* | 1334 | /* |
1329 | * Preempt the current task with a newly woken task if needed: | 1335 | * Preempt the current task with a newly woken task if needed: |
1330 | */ | 1336 | */ |
1331 | static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync) | 1337 | static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int sync) |
1332 | { | 1338 | { |
1333 | struct task_struct *curr = rq->curr; | 1339 | struct task_struct *curr = rq->curr; |
1334 | struct cfs_rq *cfs_rq = task_cfs_rq(curr); | ||
1335 | struct sched_entity *se = &curr->se, *pse = &p->se; | 1340 | struct sched_entity *se = &curr->se, *pse = &p->se; |
1336 | 1341 | ||
1337 | if (unlikely(rt_prio(p->prio))) { | 1342 | if (unlikely(rt_prio(p->prio))) { |
1343 | struct cfs_rq *cfs_rq = task_cfs_rq(curr); | ||
1344 | |||
1338 | update_rq_clock(rq); | 1345 | update_rq_clock(rq); |
1339 | update_curr(cfs_rq); | 1346 | update_curr(cfs_rq); |
1340 | resched_task(curr); | 1347 | resched_task(curr); |
1341 | return; | 1348 | return; |
1342 | } | 1349 | } |
1343 | 1350 | ||
1351 | if (unlikely(p->sched_class != &fair_sched_class)) | ||
1352 | return; | ||
1353 | |||
1344 | if (unlikely(se == pse)) | 1354 | if (unlikely(se == pse)) |
1345 | return; | 1355 | return; |
1346 | 1356 | ||
1347 | cfs_rq_of(pse)->next = pse; | 1357 | /* |
1358 | * Only set the backward buddy when the current task is still on the | ||
1359 | * rq. This can happen when a wakeup gets interleaved with schedule on | ||
1360 | * the ->pre_schedule() or idle_balance() point, either of which can | ||
1361 | * drop the rq lock. | ||
1362 | * | ||
1363 | * Also, during early boot the idle thread is in the fair class, for | ||
1364 | * obvious reasons its a bad idea to schedule back to the idle thread. | ||
1365 | */ | ||
1366 | if (sched_feat(LAST_BUDDY) && likely(se->on_rq && curr != rq->idle)) | ||
1367 | set_last_buddy(se); | ||
1368 | set_next_buddy(pse); | ||
1348 | 1369 | ||
1349 | /* | 1370 | /* |
1350 | * We can come here with TIF_NEED_RESCHED already set from new task | 1371 | * We can come here with TIF_NEED_RESCHED already set from new task |
@@ -1396,6 +1417,7 @@ static struct task_struct *pick_next_task_fair(struct rq *rq) | |||
1396 | 1417 | ||
1397 | do { | 1418 | do { |
1398 | se = pick_next_entity(cfs_rq); | 1419 | se = pick_next_entity(cfs_rq); |
1420 | set_next_entity(cfs_rq, se); | ||
1399 | cfs_rq = group_cfs_rq(se); | 1421 | cfs_rq = group_cfs_rq(se); |
1400 | } while (cfs_rq); | 1422 | } while (cfs_rq); |
1401 | 1423 | ||
diff --git a/kernel/sched_features.h b/kernel/sched_features.h index fda016218296..da5d93b5d2c6 100644 --- a/kernel/sched_features.h +++ b/kernel/sched_features.h | |||
@@ -12,3 +12,4 @@ SCHED_FEAT(LB_BIAS, 1) | |||
12 | SCHED_FEAT(LB_WAKEUP_UPDATE, 1) | 12 | SCHED_FEAT(LB_WAKEUP_UPDATE, 1) |
13 | SCHED_FEAT(ASYM_EFF_LOAD, 1) | 13 | SCHED_FEAT(ASYM_EFF_LOAD, 1) |
14 | SCHED_FEAT(WAKEUP_OVERLAP, 0) | 14 | SCHED_FEAT(WAKEUP_OVERLAP, 0) |
15 | SCHED_FEAT(LAST_BUDDY, 1) | ||