Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1191345 > unrolled thread

[PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page

Started bySpencer Baugh <sbaugh@catern.com>
First post2015-07-24 00:00 +0200
Last post2015-07-24 01:10 +0200
Articles 5 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page Spencer Baugh <sbaugh@catern.com> - 2015-07-24 00:00 +0200
    Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and  follow_hugetlb_page David Rientjes <rientjes@google.com> - 2015-07-24 00:10 +0200
      Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and  follow_hugetlb_page Jörn Engel <joern@purestorage.com> - 2015-07-24 00:40 +0200
        Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and  follow_hugetlb_page David Rientjes <rientjes@google.com> - 2015-07-24 01:00 +0200
          Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and  follow_hugetlb_page Jörn Engel <joern@purestorage.com> - 2015-07-24 01:10 +0200

#1191345 — [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page

FromSpencer Baugh <sbaugh@catern.com>
Date2015-07-24 00:00 +0200
Subject[PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page
Message-ID<pPwH0-2zU-15@gated-at.bofh.it>
From: Joern Engel <joern@logfs.org>

~150ms scheduler latency for both observed in the wild.

Signed-off-by: Joern Engel <joern@logfs.org>
Signed-off-by: Spencer Baugh <sbaugh@catern.com>
---
 mm/hugetlb.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index a8c3087..2eb6919 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1836,6 +1836,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
 			ret = alloc_fresh_gigantic_page(h, nodes_allowed);
 		else
 			ret = alloc_fresh_huge_page(h, nodes_allowed);
+		cond_resched();
 		spin_lock(&hugetlb_lock);
 		if (!ret)
 			goto out;
@@ -3521,6 +3522,7 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
 				spin_unlock(ptl);
 			ret = hugetlb_fault(mm, vma, vaddr,
 				(flags & FOLL_WRITE) ? FAULT_FLAG_WRITE : 0);
+			cond_resched();
 			if (!(ret & VM_FAULT_ERROR))
 				continue;
 
-- 
2.5.0.rc3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [next] | [standalone]


#1191362 — Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page

FromDavid Rientjes <rientjes@google.com>
Date2015-07-24 00:10 +0200
SubjectRe: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page
Message-ID<pPwQH-30s-21@gated-at.bofh.it>
In reply to#1191345
On Thu, 23 Jul 2015, Spencer Baugh wrote:

> From: Joern Engel <joern@logfs.org>
> 
> ~150ms scheduler latency for both observed in the wild.
> 
> Signed-off-by: Joern Engel <joern@logfs.org>
> Signed-off-by: Spencer Baugh <sbaugh@catern.com>
> ---
>  mm/hugetlb.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index a8c3087..2eb6919 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1836,6 +1836,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
>  			ret = alloc_fresh_gigantic_page(h, nodes_allowed);
>  		else
>  			ret = alloc_fresh_huge_page(h, nodes_allowed);
> +		cond_resched();
>  		spin_lock(&hugetlb_lock);
>  		if (!ret)
>  			goto out;

This is wrong, you'd want to do any cond_resched() before the page 
allocation to avoid racing with an update to h->nr_huge_pages or 
h->surplus_huge_pages while hugetlb_lock was dropped that would result in 
the page having been uselessly allocated.

> @@ -3521,6 +3522,7 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
>  				spin_unlock(ptl);
>  			ret = hugetlb_fault(mm, vma, vaddr,
>  				(flags & FOLL_WRITE) ? FAULT_FLAG_WRITE : 0);
> +			cond_resched();
>  			if (!(ret & VM_FAULT_ERROR))
>  				continue;
>  

This is almost certainly the wrong placement as well since it's inserted 
inside a conditional inside a while loop and there's no reason to 
hugetlb_fault(), schedule, and then check the return value.  You need to 
insert your cond_resched()'s in legitimate places.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1191372 — Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page

FromJörn Engel <joern@purestorage.com>
Date2015-07-24 00:40 +0200
SubjectRe: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page
Message-ID<pPxjH-3z4-5@gated-at.bofh.it>
In reply to#1191362
On Thu, Jul 23, 2015 at 03:08:58PM -0700, David Rientjes wrote:
> On Thu, 23 Jul 2015, Spencer Baugh wrote:
> > From: Joern Engel <joern@logfs.org>
> > 
> > ~150ms scheduler latency for both observed in the wild.
> > 
> > Signed-off-by: Joern Engel <joern@logfs.org>
> > Signed-off-by: Spencer Baugh <sbaugh@catern.com>
> > ---
> >  mm/hugetlb.c | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> > index a8c3087..2eb6919 100644
> > --- a/mm/hugetlb.c
> > +++ b/mm/hugetlb.c
> > @@ -1836,6 +1836,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
> >  			ret = alloc_fresh_gigantic_page(h, nodes_allowed);
> >  		else
> >  			ret = alloc_fresh_huge_page(h, nodes_allowed);
> > +		cond_resched();
> >  		spin_lock(&hugetlb_lock);
> >  		if (!ret)
> >  			goto out;
> 
> This is wrong, you'd want to do any cond_resched() before the page 
> allocation to avoid racing with an update to h->nr_huge_pages or 
> h->surplus_huge_pages while hugetlb_lock was dropped that would result in 
> the page having been uselessly allocated.

There are three options.  Either
	/* some allocation */
	cond_resched();
or
	cond_resched();
	/* some allocation */
or
	if (cond_resched()) {
		spin_lock(&hugetlb_lock);
		continue;
	}
	/* some allocation */

I think you want the second option instead of the first.  That way we
have a little less memory allocation for the time we are scheduled out.
Sure, we can do that.  It probably doesn't make a big difference either
way, but why not.

If you are asking for the third option, I would rather avoid that.  It
makes the code more complex and doesn't change the fact that we have a
race and better be able to handle the race.  The code size growth will
likely cost us more performance that we would ever gain.  nr_huge_pages
tends to get updated once per system boot.

> > @@ -3521,6 +3522,7 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
> >  				spin_unlock(ptl);
> >  			ret = hugetlb_fault(mm, vma, vaddr,
> >  				(flags & FOLL_WRITE) ? FAULT_FLAG_WRITE : 0);
> > +			cond_resched();
> >  			if (!(ret & VM_FAULT_ERROR))
> >  				continue;
> >  
> 
> This is almost certainly the wrong placement as well since it's inserted 
> inside a conditional inside a while loop and there's no reason to 
> hugetlb_fault(), schedule, and then check the return value.  You need to 
> insert your cond_resched()'s in legitimate places.

I assume you want the second option here as well.  Am I right?

Jörn

--
Sometimes it pays to stay in bed on Monday, rather than spending the rest
of the week debugging Monday's code.
-- Christopher Thompson
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1191386 — Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page

FromDavid Rientjes <rientjes@google.com>
Date2015-07-24 01:00 +0200
SubjectRe: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page
Message-ID<pPxD4-433-11@gated-at.bofh.it>
In reply to#1191372

[Multipart message — attachments visible in raw view] — view raw

On Thu, 23 Jul 2015, Jörn Engel wrote:

> > This is wrong, you'd want to do any cond_resched() before the page 
> > allocation to avoid racing with an update to h->nr_huge_pages or 
> > h->surplus_huge_pages while hugetlb_lock was dropped that would result in 
> > the page having been uselessly allocated.
> 
> There are three options.  Either
> 	/* some allocation */
> 	cond_resched();
> or
> 	cond_resched();
> 	/* some allocation */
> or
> 	if (cond_resched()) {
> 		spin_lock(&hugetlb_lock);
> 		continue;
> 	}
> 	/* some allocation */
> 
> I think you want the second option instead of the first.  That way we
> have a little less memory allocation for the time we are scheduled out.
> Sure, we can do that.  It probably doesn't make a big difference either
> way, but why not.
> 

The loop is dropping the lock simply to do the allocation and it needs to 
compare with the user-written number of hugepages to allocate.

What we don't want is to allocate, reschedule, and check if we really 
needed to allocate.  That's what your patch does because it races with 
persistent_huge_page().  It's probably the worst place to do it.

Rather, what you want to do is check if you need to allocate, reschedule 
if needed (and if so, recheck), and then allocate.

> If you are asking for the third option, I would rather avoid that.  It
> makes the code more complex and doesn't change the fact that we have a
> race and better be able to handle the race.  The code size growth will
> likely cost us more performance that we would ever gain.  nr_huge_pages
> tends to get updated once per system boot.
> 

Your third option is nonsensical, you didn't save the state of whether you 
locked the lock so you can't reliably unlock it, and you cannot hold a 
spinlock while allocating in this context.

[toc] | [prev] | [next] | [standalone]


#1191390 — Re: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page

FromJörn Engel <joern@purestorage.com>
Date2015-07-24 01:10 +0200
SubjectRe: [PATCH] hugetlb: cond_resched for set_max_huge_pages and follow_hugetlb_page
Message-ID<pPxMJ-4tL-3@gated-at.bofh.it>
In reply to#1191386
On Thu, Jul 23, 2015 at 03:54:43PM -0700, David Rientjes wrote:
> On Thu, 23 Jul 2015, Jörn Engel wrote:
> 
> > > This is wrong, you'd want to do any cond_resched() before the page 
> > > allocation to avoid racing with an update to h->nr_huge_pages or 
> > > h->surplus_huge_pages while hugetlb_lock was dropped that would result in 
> > > the page having been uselessly allocated.
> > 
> > There are three options.  Either
> > 	/* some allocation */
> > 	cond_resched();
> > or
> > 	cond_resched();
> > 	/* some allocation */
> > or
> > 	if (cond_resched()) {
> > 		spin_lock(&hugetlb_lock);
> > 		continue;
> > 	}
> > 	/* some allocation */
> > 
> > I think you want the second option instead of the first.  That way we
> > have a little less memory allocation for the time we are scheduled out.
> > Sure, we can do that.  It probably doesn't make a big difference either
> > way, but why not.
> > 
> 
> The loop is dropping the lock simply to do the allocation and it needs to 
> compare with the user-written number of hugepages to allocate.

And at this point the existing code is racy.  Page allocation might
block for minutes trying to free some memory.  A cond_resched doesn't
change that - it only increases the odds of hitting the race window.

> What we don't want is to allocate, reschedule, and check if we really 
> needed to allocate.  That's what your patch does because it races with 
> persistent_huge_page().  It's probably the worst place to do it.
> 
> Rather, what you want to do is check if you need to allocate, reschedule 
> if needed (and if so, recheck), and then allocate.
> 
> > If you are asking for the third option, I would rather avoid that.  It
> > makes the code more complex and doesn't change the fact that we have a
> > race and better be able to handle the race.  The code size growth will
> > likely cost us more performance that we would ever gain.  nr_huge_pages
> > tends to get updated once per system boot.
> 
> Your third option is nonsensical, you didn't save the state of whether you 
> locked the lock so you can't reliably unlock it, and you cannot hold a 
> spinlock while allocating in this context.

Are we looking at the same code?  Mine looks like this:
	while (count > persistent_huge_pages(h)) {
		/*
		 * If this allocation races such that we no longer need the
		 * page, free_huge_page will handle it by freeing the page
		 * and reducing the surplus.
		 */
		spin_unlock(&hugetlb_lock);
		if (hstate_is_gigantic(h))
			ret = alloc_fresh_gigantic_page(h, nodes_allowed);
		else
			ret = alloc_fresh_huge_page(h, nodes_allowed);
		spin_lock(&hugetlb_lock);
		if (!ret)
			goto out;

		/* Bail for signals. Probably ctrl-c from user */
		if (signal_pending(current))
			goto out;
	}

What state is there to save?  We just called spin_unlock, we did a
schedule and if we want to continue without doing page allocation we
better take the lock again.  Or do you want to go even more complex and
check for signals as well?

The case you are concerned about is rare.  It is so rare that it doesn't
matter from a performance point of view, only for correctness.  And if
we hit the rare case, the worst harm would be an unnecessary allocation
that we return back to the system.  How much complexity do you think it
is worth to avoid this allocation?  How much runtime will the bigger
text size cost you in the common cases?

What matters to me is the scheduler latency.  That is real and happens
reliably once per boot.

Jörn

--
Chance favors only the prepared mind.
-- Louis Pasteur
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web