Re: [PATCH v2 2/2] memcg: avoid THP split in task migration

From: Hillf Danton
Date: Fri Mar 02 2012 - 07:22:29 EST


On Fri, Mar 2, 2012 at 8:31 AM, Naoya Horiguchi
<n-horiguchi@xxxxxxxxxxxxx> wrote:
> Currently we can't do task migration among memory cgroups without THP split,
> which means processes heavily using THP experience large overhead in task
> migration. This patch introduce the code for moving charge of THP and makes
> THP more valuable.
>
> Changes from v1:
> - rename is_target_huge_pmd_for_mc() to is_target_thp_for_mc()
> - remove pmd_present() check (it's buggy when pmd_trans_huge(pmd) is true)
> - is_target_thp_for_mc() calls get_page() only when checks are passed
> - unlock page table lock if !mc.precharge
> - compare return value of is_target_thp_for_mc() explicitly to MC_TARGET_TYPE
> - clean up &walk->mm->page_table_lock to &vma->vm_mm->page_table_lock
> - add comment about why race with split_huge_page() does not happen
>
> Signed-off-by: Naoya Horiguchi <n-horiguchi@xxxxxxxxxxxxx>
> Cc: Hillf Danton <dhillf@xxxxxxxxx>
> ---
> Âmm/memcontrol.c | Â 87 +++++++++++++++++++++++++++++++++++++++++++++++++++----
> Â1 files changed, 81 insertions(+), 6 deletions(-)
>
> diff --git linux-next-20120228.orig/mm/memcontrol.c linux-next-20120228/mm/memcontrol.c
> index c83aeb5..d45b21c 100644
> --- linux-next-20120228.orig/mm/memcontrol.c
> +++ linux-next-20120228/mm/memcontrol.c
> @@ -5211,6 +5211,39 @@ static int is_target_pte_for_mc(struct vm_area_struct *vma,
> Â Â Â Âreturn ret;
> Â}
>
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +/*
> + * We don't consider swapping or file mapped pages because THP does not
> + * support them for now.
> + * Caller should make sure that pmd_trans_huge(pmd) is true.
> + */
> +static int is_target_thp_for_mc(struct vm_area_struct *vma,
> + Â Â Â Â Â Â Â unsigned long addr, pmd_t pmd, union mc_target *target)
> +{
> + Â Â Â struct page *page = NULL;
> + Â Â Â struct page_cgroup *pc;
> + Â Â Â int ret = 0;
> +

Need to check move_anon() ?

Other than that,
Acked-by: Hillf Danton <dhillf@xxxxxxxxx>

> + Â Â Â page = pmd_page(pmd);
> + Â Â Â VM_BUG_ON(!page || !PageHead(page));
> + Â Â Â pc = lookup_page_cgroup(page);
> + Â Â Â if (PageCgroupUsed(pc) && pc->mem_cgroup == mc.from) {
> + Â Â Â Â Â Â Â ret = MC_TARGET_PAGE;
> + Â Â Â Â Â Â Â if (target) {
> + Â Â Â Â Â Â Â Â Â Â Â get_page(page);
> + Â Â Â Â Â Â Â Â Â Â Â target->page = page;
> + Â Â Â Â Â Â Â }
> + Â Â Â }
> + Â Â Â return ret;
> +}
> +#else
> +static inline int is_target_thp_for_mc(struct vm_area_struct *vma,
> + Â Â Â Â Â Â Â unsigned long addr, pmd_t pmd, union mc_target *target)
> +{
> + Â Â Â return 0;
> +}
> +#endif
> +
> Âstatic int mem_cgroup_count_precharge_pte_range(pmd_t *pmd,
> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âunsigned long addr, unsigned long end,
> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âstruct mm_walk *walk)
> @@ -5219,7 +5252,14 @@ static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd,
> Â Â Â Âpte_t *pte;
> Â Â Â Âspinlock_t *ptl;
>
> - Â Â Â split_huge_page_pmd(walk->mm, pmd);
> + Â Â Â if (pmd_trans_huge_lock(pmd, vma) == 1) {
> + Â Â Â Â Â Â Â if (is_target_thp_for_mc(vma, addr, *pmd, NULL)
> + Â Â Â Â Â Â Â Â Â == MC_TARGET_PAGE)
> + Â Â Â Â Â Â Â Â Â Â Â mc.precharge += HPAGE_PMD_NR;
> + Â Â Â Â Â Â Â spin_unlock(&vma->vm_mm->page_table_lock);
> + Â Â Â Â Â Â Â cond_resched();
> + Â Â Â Â Â Â Â return 0;
> + Â Â Â }
>
> Â Â Â Âpte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
> Â Â Â Âfor (; addr != end; pte++, addr += PAGE_SIZE)
> @@ -5378,16 +5418,51 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
> Â Â Â Âstruct vm_area_struct *vma = walk->private;
> Â Â Â Âpte_t *pte;
> Â Â Â Âspinlock_t *ptl;
> + Â Â Â int type;
> + Â Â Â union mc_target target;
> + Â Â Â struct page *page;
> + Â Â Â struct page_cgroup *pc;
> +
> + Â Â Â /*
> + Â Â Â Â* We don't take compound_lock() here but no race with splitting thp
> + Â Â Â Â* happens because:
> + Â Â Â Â* Â- if pmd_trans_huge_lock() returns 1, the relevant thp is not
> + Â Â Â Â* Â Âunder splitting, which means there's no concurrent thp split,
> + Â Â Â Â* Â- if another thread runs into split_huge_page() just after we
> + Â Â Â Â* Â Âentered this if-block, the thread must wait for page table lock
> + Â Â Â Â* Â Âto be unlocked in __split_huge_page_splitting(), where the main
> + Â Â Â Â* Â Âpart of thp split is not executed yet.
> + Â Â Â Â*/
> + Â Â Â if (pmd_trans_huge_lock(pmd, vma) == 1) {
> + Â Â Â Â Â Â Â if (!mc.precharge) {
> + Â Â Â Â Â Â Â Â Â Â Â spin_unlock(&vma->vm_mm->page_table_lock);
> + Â Â Â Â Â Â Â Â Â Â Â cond_resched();
> + Â Â Â Â Â Â Â Â Â Â Â return 0;
> + Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â Â type = is_target_thp_for_mc(vma, addr, *pmd, &target);
> + Â Â Â Â Â Â Â if (type == MC_TARGET_PAGE) {
> + Â Â Â Â Â Â Â Â Â Â Â page = target.page;
> + Â Â Â Â Â Â Â Â Â Â Â if (!isolate_lru_page(page)) {
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pc = lookup_page_cgroup(page);
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â if (!mem_cgroup_move_account(page, HPAGE_PMD_NR,
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âpc, mc.from, mc.to,
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Âfalse)) {
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mc.precharge -= HPAGE_PMD_NR;
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mc.moved_charge += HPAGE_PMD_NR;
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â putback_lru_page(page);
> + Â Â Â Â Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â Â Â Â Â Â put_page(page);
> + Â Â Â Â Â Â Â }
> + Â Â Â Â Â Â Â spin_unlock(&vma->vm_mm->page_table_lock);
> + Â Â Â Â Â Â Â cond_resched();
> + Â Â Â Â Â Â Â return 0;
> + Â Â Â }
>
> - Â Â Â split_huge_page_pmd(walk->mm, pmd);
> Âretry:
> Â Â Â Âpte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
> Â Â Â Âfor (; addr != end; addr += PAGE_SIZE) {
> Â Â Â Â Â Â Â Âpte_t ptent = *(pte++);
> - Â Â Â Â Â Â Â union mc_target target;
> - Â Â Â Â Â Â Â int type;
> - Â Â Â Â Â Â Â struct page *page;
> - Â Â Â Â Â Â Â struct page_cgroup *pc;
> Â Â Â Â Â Â Â Âswp_entry_t ent;
>
> Â Â Â Â Â Â Â Âif (!mc.precharge)
> --
> 1.7.7.6
>
¢éì®&Þ~º&¶¬–+-±éÝ¥Šw®žË±Êâmébžìdz¹Þ)í…æèw*jg¬±¨¶‰šŽŠÝj/êäz¹ÞŠà2ŠÞ¨è­Ú&¢)ß«a¶Úþø®G«éh®æj:+v‰¨Šwè†Ù>Wš±êÞiÛaxPjØm¶Ÿÿà -»+ƒùdš_