sched/numa: Skip some page migrations after a shared fault

Shared faults can lead to lots of unnecessary page migrations,
slowing down the system, and causing private faults to hit the
per-pgdat migration ratelimit.

This patch adds sysctl numa_balancing_migrate_deferred, which specifies
how many shared page migrations to skip unconditionally, after each page
migration that is skipped because it is a shared fault.

This reduces the number of page migrations back and forth in
shared fault situations. It also gives a strong preference to
the tasks that are already running where most of the memory is,
and to moving the other tasks to near the memory.

Testing this with a much higher scan rate than the default
still seems to result in fewer page migrations than before.

Memory seems to be somewhat better consolidated than previously,
with multi-instance specjbb runs on a 4 node system.

Signed-off-by: Rik van Riel <[email protected]>
Signed-off-by: Mel Gorman <[email protected]>
Cc: Andrea Arcangeli <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: Srikar Dronamraju <[email protected]>
Signed-off-by: Peter Zijlstra <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
This commit is contained in:
Rik van Riel 2013-10-07 11:29:39 +01:00 • committed by Ingo Molnar
commit de1c9ce6f0
5 changed files with 75 additions and 3 deletions

View file

@ -2301,6 +2301,35 @@ static void sp_free(struct sp_node *n)
kmem_cache_free(sn_cache, n);
}
#ifdef CONFIG_NUMA_BALANCING
static bool numa_migrate_deferred(struct task_struct *p, int last_cpupid)
{
/* Never defer a private fault */
if (cpupid_match_pid(p, last_cpupid))
return false;
if (p->numa_migrate_deferred) {
p->numa_migrate_deferred--;
return true;
}
return false;
}
static inline void defer_numa_migrate(struct task_struct *p)
{
p->numa_migrate_deferred = sysctl_numa_balancing_migrate_deferred;
}
#else
static inline bool numa_migrate_deferred(struct task_struct *p, int last_cpupid)
{
return false;
}
static inline void defer_numa_migrate(struct task_struct *p)
{
}
#endif /* CONFIG_NUMA_BALANCING */
/**
* mpol_misplaced - check whether current page node is valid in policy
*
@ -2402,7 +2431,24 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long
* relation.
*/
last_cpupid = page_cpupid_xchg_last(page, this_cpupid);
if (!cpupid_pid_unset(last_cpupid) && cpupid_to_nid(last_cpupid) != thisnid)
if (!cpupid_pid_unset(last_cpupid) && cpupid_to_nid(last_cpupid) != thisnid) {
/* See sysctl_numa_balancing_migrate_deferred comment */
if (!cpupid_match_pid(current, last_cpupid))
defer_numa_migrate(current);
goto out;
}
/*
* The quadratic filter above reduces extraneous migration
* of shared pages somewhat. This code reduces it even more,
* reducing the overhead of page migrations of shared pages.
* This makes workloads with shared pages rely more on
* "move task near its memory", and less on "move memory
* towards its task", which is exactly what we want.
*/
if (numa_migrate_deferred(current, last_cpupid))
goto out;
}