diff options
-rw-r--r-- | kernel/sched_fair.c | 73 |
1 files changed, 51 insertions, 22 deletions
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c index e4d4483fd617..a32df1524746 100644 --- a/kernel/sched_fair.c +++ b/kernel/sched_fair.c | |||
@@ -1319,6 +1319,41 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu) | |||
1319 | } | 1319 | } |
1320 | 1320 | ||
1321 | /* | 1321 | /* |
1322 | * Try and locate an idle CPU in the sched_domain. | ||
1323 | */ | ||
1324 | static int | ||
1325 | select_idle_sibling(struct task_struct *p, struct sched_domain *sd, int target) | ||
1326 | { | ||
1327 | int cpu = smp_processor_id(); | ||
1328 | int prev_cpu = task_cpu(p); | ||
1329 | int i; | ||
1330 | |||
1331 | /* | ||
1332 | * If this domain spans both cpu and prev_cpu (see the SD_WAKE_AFFINE | ||
1333 | * test in select_task_rq_fair) and the prev_cpu is idle then that's | ||
1334 | * always a better target than the current cpu. | ||
1335 | */ | ||
1336 | if (target == cpu) { | ||
1337 | if (!cpu_rq(prev_cpu)->cfs.nr_running) | ||
1338 | target = prev_cpu; | ||
1339 | } | ||
1340 | |||
1341 | /* | ||
1342 | * Otherwise, iterate the domain and find an elegible idle cpu. | ||
1343 | */ | ||
1344 | if (target == -1 || target == cpu) { | ||
1345 | for_each_cpu_and(i, sched_domain_span(sd), &p->cpus_allowed) { | ||
1346 | if (!cpu_rq(i)->cfs.nr_running) { | ||
1347 | target = i; | ||
1348 | break; | ||
1349 | } | ||
1350 | } | ||
1351 | } | ||
1352 | |||
1353 | return target; | ||
1354 | } | ||
1355 | |||
1356 | /* | ||
1322 | * sched_balance_self: balance the current task (running on cpu) in domains | 1357 | * sched_balance_self: balance the current task (running on cpu) in domains |
1323 | * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and | 1358 | * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and |
1324 | * SD_BALANCE_EXEC. | 1359 | * SD_BALANCE_EXEC. |
@@ -1373,36 +1408,30 @@ static int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flag | |||
1373 | } | 1408 | } |
1374 | 1409 | ||
1375 | if (want_affine && (tmp->flags & SD_WAKE_AFFINE)) { | 1410 | if (want_affine && (tmp->flags & SD_WAKE_AFFINE)) { |
1376 | int candidate = -1, i; | 1411 | int target = -1; |
1377 | 1412 | ||
1413 | /* | ||
1414 | * If both cpu and prev_cpu are part of this domain, | ||
1415 | * cpu is a valid SD_WAKE_AFFINE target. | ||
1416 | */ | ||
1378 | if (cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) | 1417 | if (cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) |
1379 | candidate = cpu; | 1418 | target = cpu; |
1380 | 1419 | ||
1381 | /* | 1420 | /* |
1382 | * Check for an idle shared cache. | 1421 | * If there's an idle sibling in this domain, make that |
1422 | * the wake_affine target instead of the current cpu. | ||
1423 | * | ||
1424 | * XXX: should we possibly do this outside of | ||
1425 | * WAKE_AFFINE, in case the shared cache domain is | ||
1426 | * smaller than the WAKE_AFFINE domain? | ||
1383 | */ | 1427 | */ |
1384 | if (tmp->flags & SD_PREFER_SIBLING) { | 1428 | if (tmp->flags & SD_PREFER_SIBLING) |
1385 | if (candidate == cpu) { | 1429 | target = select_idle_sibling(p, tmp, target); |
1386 | if (!cpu_rq(prev_cpu)->cfs.nr_running) | ||
1387 | candidate = prev_cpu; | ||
1388 | } | ||
1389 | |||
1390 | if (candidate == -1 || candidate == cpu) { | ||
1391 | for_each_cpu(i, sched_domain_span(tmp)) { | ||
1392 | if (!cpumask_test_cpu(i, &p->cpus_allowed)) | ||
1393 | continue; | ||
1394 | if (!cpu_rq(i)->cfs.nr_running) { | ||
1395 | candidate = i; | ||
1396 | break; | ||
1397 | } | ||
1398 | } | ||
1399 | } | ||
1400 | } | ||
1401 | 1430 | ||
1402 | if (candidate >= 0) { | 1431 | if (target >= 0) { |
1403 | affine_sd = tmp; | 1432 | affine_sd = tmp; |
1404 | want_affine = 0; | 1433 | want_affine = 0; |
1405 | cpu = candidate; | 1434 | cpu = target; |
1406 | } | 1435 | } |
1407 | } | 1436 | } |
1408 | 1437 | ||