From: Andrea Arcangeli <aarcange@redhat.com>
To: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: linux-mm@kvack.org, Andrew Morton <akpm@linux-foundation.org>,
KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>,
Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>,
Hillf Danton <dhillf@gmail.com>,
linux-kernel@vger.kernel.org
Subject: Re: [RFC][PATCH] memcg: avoid THP split in task migration
Date: Thu, 1 Mar 2012 03:33:14 +0100 [thread overview]
Message-ID: <20120301023314.GF28383@redhat.com> (raw)
In-Reply-To: <1330463552-18473-1-git-send-email-n-horiguchi@ah.jp.nec.com>
Hi Naoya,
On Tue, Feb 28, 2012 at 04:12:32PM -0500, Naoya Horiguchi 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.
Nice.
> diff --git linux-next-20120228.orig/mm/memcontrol.c linux-next-20120228/mm/memcontrol.c
> index c83aeb5..e97c041 100644
> --- linux-next-20120228.orig/mm/memcontrol.c
> +++ linux-next-20120228/mm/memcontrol.c
> @@ -5211,6 +5211,42 @@ 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.
> + */
> +static int is_target_huge_pmd_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;
> +
> + if (pmd_present(pmd))
> + page = pmd_page(pmd);
> + if (!page)
> + return 0;
It can't be present and null at the same time.
No need to check pmd_present if you already checked pmd_trans_huge. In
fact checking pmd_present is a bug. For a little time the pmd won't be
present if it's set as splitting. (that short clearing of pmd_present
during pmd splitting is to deal with a vendor CPU errata without
having to flush the smp TLB twice)
Following Kame's suggestion is correct, an unconditional pmd_page is
correct here:
page = pmd_page(pmd);
We might actually decide to change pmd_present to return true if
pmd_trans_splitting is set to avoid the risk of using an erratic
pmd_present on a pmd_trans_huge pmd, but it's not really necessary if
you never check pmd_present when a pmd is (or can be) a
pmd_trans_huge.
The safe check for pmd is only pmd_none, never pmd_present (as in
__pte_alloc/pte_alloc_map/...).
> + VM_BUG_ON(!PageHead(page));
> + get_page(page);
Other review mentioned we can do get_page only when it succeeds, but I
think we can drop the whole get_page and simplify it further see the
end.
> @@ -5219,7 +5255,13 @@ 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_huge_pmd_for_mc(vma, addr, *pmd, NULL))
> + mc.precharge += HPAGE_PMD_NR;
Your use of HPAGE_PMD_NR looks fine, that path will be eliminated at
build time if THP is off. This is the nice way to write code that is
already optimal for THP=off without making special cases or #ifdefs.
Other review suggests changing HPAGE_PMD_NR as BUILD_BUG, that sounds
good idea too, but in this (correct) usage of HPAGE_PMD_NR it wouldn't
make a difference because of the whole branch is correctly eliminated
at build time. In short changing it to BUILD_BUG will simply make sure
the whole pmd_trans_huge_lock == 1 branch is eliminated at build
time. It looks good change too but it's orthogonal so I'd leave it for
a separate patch.
> + spin_unlock(&walk->mm->page_table_lock);
Agree with other review, vma looks cleaner.
> + cond_resched();
> + return 0;
> + }
>
> pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
> for (; addr != end; pte++, addr += PAGE_SIZE)
> @@ -5378,16 +5420,38 @@ 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;
> +
> + if (pmd_trans_huge_lock(pmd, vma) == 1) {
> + if (!mc.precharge)
> + return 0;
Agree with Hillf.
> + type = is_target_huge_pmd_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;
> + }
Like you mentioned, a race with split_huge_page_refcount (and hence
mem_cgroup_split_huge_fixup) is not possible because of
pmd_trans_huge_lock succeeding.
However the mmap_sem checked by pmd_trans_huge_lock is there just
because we deal with pmds and so pagetables (and we aren't doing a
lockless lookup like gup_fast). But it's not true that a concurrent
split_huge_page would _not_ prevented by the mmap_sem. The swapout
path will still split hugepages under you even if you hold the
mmap_sem (even in write mode).
The mmap_sem (either read or write) only prevents a concurrent
collapsing/creation of hugepages (but that's irrelevant here). It
won't stop split_huge_page.
So - back to our issue - you're safe against split_huge_page not
running here thanks to the pmd_trans_huge_lock.
There's one tricky locking bit here, that is isolate_lru_page, that
takes the lru_lock.
So the lock order is the page_table_lock first and the lru_lock
second, and so there must not be another place that takes the lru_lock
first and the page_table_lock second. In general it's good idea to
exercise locking code with lockdep prove locking enabled just in case.
> + putback_lru_page(page);
> + }
> + put_page(page);
I wonder if you need a get_page at all in is_target_huge_pmd_for_mc if
you drop the above put_page instead. How can this page go away from
under us, if we've been holding the page_table_lock the whole time?
You can probably drop both get_page above and put_page above.
> + }
> + spin_unlock(&walk->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)
I read the other two great reviews done so far in parallel with the
code, and I ended up replying here to the code as I was reading it,
hope it wasn't too confusing.
Thanks!
Andrea
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2012-03-01 2:33 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-02-28 21:12 [RFC][PATCH] memcg: avoid THP split in task migration Naoya Horiguchi
2012-02-29 0:28 ` KAMEZAWA Hiroyuki
2012-02-29 9:50 ` Naoya Horiguchi
2012-02-29 14:40 ` Hillf Danton
2012-02-29 19:39 ` Naoya Horiguchi
2012-03-01 2:33 ` Andrea Arcangeli [this message]
2012-03-01 20:22 ` Naoya Horiguchi
2012-03-01 22:01 ` Naoya Horiguchi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20120301023314.GF28383@redhat.com \
--to=aarcange@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=dhillf@gmail.com \
--cc=kamezawa.hiroyu@jp.fujitsu.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=n-horiguchi@ah.jp.nec.com \
--cc=nishimura@mxp.nes.nec.co.jp \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).