diff options
Diffstat (limited to 'kernel/sched_fair.c')
| -rw-r--r-- | kernel/sched_fair.c | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index 37087a7fac22..f61837ad336d 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c | |||
| @@ -1345,6 +1345,37 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu) | |||
| 1345 | } | 1345 | } |
| 1346 | 1346 | ||
| 1347 | /* | 1347 | /* |
| 1348 | * Try and locate an idle CPU in the sched_domain. | ||
| 1349 | */ | ||
| 1350 | static int | ||
| 1351 | select_idle_sibling(struct task_struct *p, struct sched_domain *sd, int target) | ||
| 1352 | { | ||
| 1353 | int cpu = smp_processor_id(); | ||
| 1354 | int prev_cpu = task_cpu(p); | ||
| 1355 | int i; | ||
| 1356 | |||
| 1357 | /* | ||
| 1358 | * If this domain spans both cpu and prev_cpu (see the SD_WAKE_AFFINE | ||
| 1359 | * test in select_task_rq_fair) and the prev_cpu is idle then that's | ||
| 1360 | * always a better target than the current cpu. | ||
| 1361 | */ | ||
| 1362 | if (target == cpu && !cpu_rq(prev_cpu)->cfs.nr_running) | ||
| 1363 | return prev_cpu; | ||
| 1364 | |||
| 1365 | /* | ||
| 1366 | * Otherwise, iterate the domain and find an elegible idle cpu. | ||
| 1367 | */ | ||
| 1368 | for_each_cpu_and(i, sched_domain_span(sd), &p->cpus_allowed) { | ||
| 1369 | if (!cpu_rq(i)->cfs.nr_running) { | ||
| 1370 | target = i; | ||
| 1371 | break; | ||
| 1372 | } | ||
| 1373 | } | ||
| 1374 | |||
| 1375 | return target; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | /* | ||
| 1348 | * sched_balance_self: balance the current task (running on cpu) in domains | 1379 | * sched_balance_self: balance the current task (running on cpu) in domains |
| 1349 | * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and | 1380 | * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and |
| 1350 | * SD_BALANCE_EXEC. | 1381 | * SD_BALANCE_EXEC. |
| @@ -1398,11 +1429,35 @@ static int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flag | |||
| 1398 | want_sd = 0; | 1429 | want_sd = 0; |
| 1399 | } | 1430 | } |
| 1400 | 1431 | ||
| 1401 | if (want_affine && (tmp->flags & SD_WAKE_AFFINE) && | 1432 | /* |
| 1402 | cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) { | 1433 | * While iterating the domains looking for a spanning |
| 1434 | * WAKE_AFFINE domain, adjust the affine target to any idle cpu | ||
| 1435 | * in cache sharing domains along the way. | ||
| 1436 | */ | ||
| 1437 | if (want_affine) { | ||
| 1438 | int target = -1; | ||
| 1403 | 1439 | ||
| 1404 | affine_sd = tmp; | 1440 | /* |
| 1405 | want_affine = 0; | 1441 | * If both cpu and prev_cpu are part of this domain, |
| 1442 | * cpu is a valid SD_WAKE_AFFINE target. | ||
| 1443 | */ | ||
| 1444 | if (cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) | ||
| 1445 | target = cpu; | ||
| 1446 | |||
| 1447 | /* | ||
| 1448 | * If there's an idle sibling in this domain, make that | ||
| 1449 | * the wake_affine target instead of the current cpu. | ||
| 1450 | */ | ||
| 1451 | if (tmp->flags & SD_PREFER_SIBLING) | ||
| 1452 | target = select_idle_sibling(p, tmp, target); | ||
| 1453 | |||
| 1454 | if (target >= 0) { | ||
| 1455 | if (tmp->flags & SD_WAKE_AFFINE) { | ||
| 1456 | affine_sd = tmp; | ||
| 1457 | want_affine = 0; | ||
| 1458 | } | ||
| 1459 | cpu = target; | ||
| 1460 | } | ||
| 1406 | } | 1461 | } |
| 1407 | 1462 | ||
| 1408 | if (!want_sd && !want_affine) | 1463 | if (!want_sd && !want_affine) |
| @@ -1679,7 +1734,7 @@ static struct task_struct *pick_next_task_fair(struct rq *rq) | |||
| 1679 | struct cfs_rq *cfs_rq = &rq->cfs; | 1734 | struct cfs_rq *cfs_rq = &rq->cfs; |
| 1680 | struct sched_entity *se; | 1735 | struct sched_entity *se; |
| 1681 | 1736 | ||
| 1682 | if (unlikely(!cfs_rq->nr_running)) | 1737 | if (!cfs_rq->nr_running) |
| 1683 | return NULL; | 1738 | return NULL; |
| 1684 | 1739 | ||
| 1685 | do { | 1740 | do { |
