diff options
| -rw-r--r-- | include/linux/sched.h | 7 | ||||
| -rw-r--r-- | kernel/sched/fair.c | 63 | ||||
| -rw-r--r-- | mm/mempolicy.c | 29 |
3 files changed, 71 insertions, 28 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 5fb0cfb43ecf..5ab3b89fc33e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1589,6 +1589,8 @@ extern void task_numa_fault(int last_node, int node, int pages, int flags); | |||
| 1589 | extern pid_t task_numa_group_id(struct task_struct *p); | 1589 | extern pid_t task_numa_group_id(struct task_struct *p); |
| 1590 | extern void set_numabalancing_state(bool enabled); | 1590 | extern void set_numabalancing_state(bool enabled); |
| 1591 | extern void task_numa_free(struct task_struct *p); | 1591 | extern void task_numa_free(struct task_struct *p); |
| 1592 | extern bool should_numa_migrate_memory(struct task_struct *p, struct page *page, | ||
| 1593 | int src_nid, int dst_cpu); | ||
| 1592 | #else | 1594 | #else |
| 1593 | static inline void task_numa_fault(int last_node, int node, int pages, | 1595 | static inline void task_numa_fault(int last_node, int node, int pages, |
| 1594 | int flags) | 1596 | int flags) |
| @@ -1604,6 +1606,11 @@ static inline void set_numabalancing_state(bool enabled) | |||
| 1604 | static inline void task_numa_free(struct task_struct *p) | 1606 | static inline void task_numa_free(struct task_struct *p) |
| 1605 | { | 1607 | { |
| 1606 | } | 1608 | } |
| 1609 | static inline bool should_numa_migrate_memory(struct task_struct *p, | ||
| 1610 | struct page *page, int src_nid, int dst_cpu) | ||
| 1611 | { | ||
| 1612 | return true; | ||
| 1613 | } | ||
| 1607 | #endif | 1614 | #endif |
| 1608 | 1615 | ||
| 1609 | static inline struct pid *task_pid(struct task_struct *task) | 1616 | static inline struct pid *task_pid(struct task_struct *task) |
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 1ee921f1ec35..eeabb33f349e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
| @@ -954,6 +954,69 @@ static inline unsigned long group_weight(struct task_struct *p, int nid) | |||
| 954 | return 1000 * group_faults(p, nid) / p->numa_group->total_faults; | 954 | return 1000 * group_faults(p, nid) / p->numa_group->total_faults; |
| 955 | } | 955 | } |
| 956 | 956 | ||
| 957 | bool should_numa_migrate_memory(struct task_struct *p, struct page * page, | ||
| 958 | int src_nid, int dst_cpu) | ||
| 959 | { | ||
| 960 | struct numa_group *ng = p->numa_group; | ||
| 961 | int dst_nid = cpu_to_node(dst_cpu); | ||
| 962 | int last_cpupid, this_cpupid; | ||
| 963 | |||
| 964 | this_cpupid = cpu_pid_to_cpupid(dst_cpu, current->pid); | ||
| 965 | |||
| 966 | /* | ||
| 967 | * Multi-stage node selection is used in conjunction with a periodic | ||
| 968 | * migration fault to build a temporal task<->page relation. By using | ||
| 969 | * a two-stage filter we remove short/unlikely relations. | ||
| 970 | * | ||
| 971 | * Using P(p) ~ n_p / n_t as per frequentist probability, we can equate | ||
| 972 | * a task's usage of a particular page (n_p) per total usage of this | ||
| 973 | * page (n_t) (in a given time-span) to a probability. | ||
| 974 | * | ||
| 975 | * Our periodic faults will sample this probability and getting the | ||
| 976 | * same result twice in a row, given these samples are fully | ||
| 977 | * independent, is then given by P(n)^2, provided our sample period | ||
| 978 | * is sufficiently short compared to the usage pattern. | ||
| 979 | * | ||
| 980 | * This quadric squishes small probabilities, making it less likely we | ||
| 981 | * act on an unlikely task<->page relation. | ||
| 982 | */ | ||
| 983 | last_cpupid = page_cpupid_xchg_last(page, this_cpupid); | ||
| 984 | if (!cpupid_pid_unset(last_cpupid) && | ||
| 985 | cpupid_to_nid(last_cpupid) != dst_nid) | ||
| 986 | return false; | ||
| 987 | |||
| 988 | /* Always allow migrate on private faults */ | ||
| 989 | if (cpupid_match_pid(p, last_cpupid)) | ||
| 990 | return true; | ||
| 991 | |||
| 992 | /* A shared fault, but p->numa_group has not been set up yet. */ | ||
| 993 | if (!ng) | ||
| 994 | return true; | ||
| 995 | |||
| 996 | /* | ||
| 997 | * Do not migrate if the destination is not a node that | ||
| 998 | * is actively used by this numa group. | ||
| 999 | */ | ||
| 1000 | if (!node_isset(dst_nid, ng->active_nodes)) | ||
| 1001 | return false; | ||
| 1002 | |||
| 1003 | /* | ||
| 1004 | * Source is a node that is not actively used by this | ||
| 1005 | * numa group, while the destination is. Migrate. | ||
| 1006 | */ | ||
| 1007 | if (!node_isset(src_nid, ng->active_nodes)) | ||
| 1008 | return true; | ||
| 1009 | |||
| 1010 | /* | ||
| 1011 | * Both source and destination are nodes in active | ||
| 1012 | * use by this numa group. Maximize memory bandwidth | ||
| 1013 | * by migrating from more heavily used groups, to less | ||
| 1014 | * heavily used ones, spreading the load around. | ||
| 1015 | * Use a 1/4 hysteresis to avoid spurious page movement. | ||
| 1016 | */ | ||
| 1017 | return group_faults(p, dst_nid) < (group_faults(p, src_nid) * 3 / 4); | ||
| 1018 | } | ||
| 1019 | |||
| 957 | static unsigned long weighted_cpuload(const int cpu); | 1020 | static unsigned long weighted_cpuload(const int cpu); |
| 958 | static unsigned long source_load(int cpu, int type); | 1021 | static unsigned long source_load(int cpu, int type); |
| 959 | static unsigned long target_load(int cpu, int type); | 1022 | static unsigned long target_load(int cpu, int type); |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 68d5c7f7164e..784c11ef7719 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -2377,37 +2377,10 @@ int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long | |||
| 2377 | 2377 | ||
| 2378 | /* Migrate the page towards the node whose CPU is referencing it */ | 2378 | /* Migrate the page towards the node whose CPU is referencing it */ |
| 2379 | if (pol->flags & MPOL_F_MORON) { | 2379 | if (pol->flags & MPOL_F_MORON) { |
| 2380 | int last_cpupid; | ||
| 2381 | int this_cpupid; | ||
| 2382 | |||
| 2383 | polnid = thisnid; | 2380 | polnid = thisnid; |
| 2384 | this_cpupid = cpu_pid_to_cpupid(thiscpu, current->pid); | ||
| 2385 | 2381 | ||
| 2386 | /* | 2382 | if (!should_numa_migrate_memory(current, page, curnid, thiscpu)) |
| 2387 | * Multi-stage node selection is used in conjunction | ||
| 2388 | * with a periodic migration fault to build a temporal | ||
| 2389 | * task<->page relation. By using a two-stage filter we | ||
| 2390 | * remove short/unlikely relations. | ||
| 2391 | * | ||
| 2392 | * Using P(p) ~ n_p / n_t as per frequentist | ||
| 2393 | * probability, we can equate a task's usage of a | ||
| 2394 | * particular page (n_p) per total usage of this | ||
| 2395 | * page (n_t) (in a given time-span) to a probability. | ||
| 2396 | * | ||
| 2397 | * Our periodic faults will sample this probability and | ||
| 2398 | * getting the same result twice in a row, given these | ||
| 2399 | * samples are fully independent, is then given by | ||
| 2400 | * P(n)^2, provided our sample period is sufficiently | ||
| 2401 | * short compared to the usage pattern. | ||
| 2402 | * | ||
| 2403 | * This quadric squishes small probabilities, making | ||
| 2404 | * it less likely we act on an unlikely task<->page | ||
| 2405 | * relation. | ||
| 2406 | */ | ||
| 2407 | last_cpupid = page_cpupid_xchg_last(page, this_cpupid); | ||
| 2408 | if (!cpupid_pid_unset(last_cpupid) && cpupid_to_nid(last_cpupid) != thisnid) { | ||
| 2409 | goto out; | 2383 | goto out; |
| 2410 | } | ||
| 2411 | } | 2384 | } |
| 2412 | 2385 | ||
| 2413 | if (curnid != polnid) | 2386 | if (curnid != polnid) |
