All of lore.kernel.org
 help / color / mirror / Atom feed
From: Waiman Long <waiman.long@hp.com>
To: Jason Low <jason.low2@hp.com>
Cc: mingo@redhat.com, peterz@infradead.org,
	paulmck@linux.vnet.ibm.com, torvalds@linux-foundation.org,
	tglx@linutronix.de, linux-kernel@vger.kernel.org,
	riel@redhat.com, akpm@linux-foundation.org, davidlohr@hp.com,
	hpa@zytor.com, aswin@hp.com, scott.norton@hp.com
Subject: Re: [RFC 2/3] mutex: Modify the way optimistic spinners are queued
Date: Wed, 15 Jan 2014 10:10:51 -0500	[thread overview]
Message-ID: <52D6A4FB.7060305@hp.com> (raw)
In-Reply-To: <1389745990-7069-3-git-send-email-jason.low2@hp.com>

On 01/14/2014 07:33 PM, Jason Low wrote:
> This patch is needed for patch 3, but should also be beneficial in general.
>
> The mutex->spin_mlock was introduced in order to ensure that only 1 thread
> loops on lock->owner field at a time to reduce cache line contention. When
> lock->owner is NULL and the lock->count is still not 1, the spinner(s) will
> continually release and obtain the lock->spin_mlock. This can generate
> quite a bit of overhead/contention, and also might just delay the spinner
> from getting the lock.
>
> This patch modifies the way optimistic spinners are queued by queuing before
> entering the optimistic spinning loop as oppose to acquiring before every
> call to mutex_spin_on_owner(). So in situations where the spinner requires
> extra spins before obtaining the lock, then there will only be 1 spinner
> trying to get the lock and it will avoid the overhead from unnecessarily
> unlocking and locking the spin_mlock.
>
> Signed-off-by: Jason Low<jason.low2@hp.com>
> ---
>   kernel/locking/mutex.c |   13 ++++++++-----
>   1 files changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
> index 85c6be1..b500cc7 100644
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -419,6 +419,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>   	struct mutex_waiter waiter;
>   	unsigned long flags;
>   	int ret;
> +	struct mspin_node node;
>
>   	preempt_disable();
>   	mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
> @@ -449,9 +450,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>   	if (!mutex_can_spin_on_owner(lock))
>   		goto slowpath;
>
> +	mspin_lock(MLOCK(lock),&node);
>   	for (;;) {
>   		struct task_struct *owner;
> -		struct mspin_node  node;
>
>   		if (use_ww_ctx&&  ww_ctx->acquired>  0) {
>   			struct ww_mutex *ww;
> @@ -465,15 +466,16 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>   			 * As such, when deadlock detection needs to be
>   			 * performed the optimistic spinning cannot be done.
>   			 */
> -			if (ACCESS_ONCE(ww->ctx))
> +			if (ACCESS_ONCE(ww->ctx)) {
> +				mspin_unlock(MLOCK(lock),&node);
>   				goto slowpath;
> +			}
>   		}
>
>   		/*
>   		 * If there's an owner, wait for it to either
>   		 * release the lock or go to sleep.
>   		 */
> -		mspin_lock(MLOCK(lock),&node);
>   		owner = ACCESS_ONCE(lock->owner);
>   		if (owner&&  !mutex_spin_on_owner(lock, owner)) {
>   			mspin_unlock(MLOCK(lock),&node);
> @@ -495,7 +497,6 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>   			preempt_enable();
>   			return 0;
>   		}
> -		mspin_unlock(MLOCK(lock),&node);
>
>   		/*
>   		 * When there's no owner, we might have preempted between the
> @@ -503,8 +504,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
>   		 * we're an RT task that will live-lock because we won't let
>   		 * the owner complete.
>   		 */
> -		if (!owner&&  (need_resched() || rt_task(task)))
> +		if (!owner&&  (need_resched() || rt_task(task))) {
> +			mspin_unlock(MLOCK(lock),&node);
>   			goto slowpath;
> +		}
>
>   		/*
>   		 * The cpu_relax() call is a compiler barrier which forces

Maybe you can consider restructure the code as follows to reduce the 
number of mspin_unlock() call sites:
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index 4dd6e4c..0a78a0c 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -416,6 +416,7 @@ __mutex_lock_common(struct mutex *lock, long state, 
unsigned
         struct mutex_waiter waiter;
         unsigned long flags;
         int ret;
+       struct mspin_node  node;

         preempt_disable();
         mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
@@ -446,9 +447,9 @@ __mutex_lock_common(struct mutex *lock, long state, 
unsigned
         if (!mutex_can_spin_on_owner(lock))
                 goto slowpath;

+       mspin_lock(MLOCK(lock), &node);
         for (;;) {
                 struct task_struct *owner;
-               struct mspin_node  node;

                 if (use_ww_ctx && ww_ctx->acquired > 0) {
                         struct ww_mutex *ww;
@@ -463,19 +464,16 @@ __mutex_lock_common(struct mutex *lock, long 
state, unsign
                          * performed the optimistic spinning cannot be 
done.
                          */
                         if (ACCESS_ONCE(ww->ctx))
-                               goto slowpath;
+                               break;
                 }

                 /*
                  * If there's an owner, wait for it to either
                  * release the lock or go to sleep.
                  */
-               mspin_lock(MLOCK(lock), &node);
                 owner = ACCESS_ONCE(lock->owner);
-               if (owner && !mutex_spin_on_owner(lock, owner)) {
-                       mspin_unlock(MLOCK(lock), &node);
-                       goto slowpath;
-               }
+               if (owner && !mutex_spin_on_owner(lock, owner))
+                       break;

                 if ((atomic_read(&lock->count) == 1) &&
                     (atomic_cmpxchg(&lock->count, 1, 0) == 1)) {
@@ -492,7 +490,6 @@ __mutex_lock_common(struct mutex *lock, long state, 
unsigned
                         preempt_enable();
                         return 0;
                 }
-               mspin_unlock(MLOCK(lock), &node);

                 /*
                  * When there's no owner, we might have preempted 
between the
@@ -501,7 +498,7 @@ __mutex_lock_common(struct mutex *lock, long state, 
unsigned
                  * the owner complete.
                  */
                 if (!owner && (need_resched() || rt_task(task)))
-                       goto slowpath;
+                       break;

                 /*
                  * The cpu_relax() call is a compiler barrier which forces
@@ -511,6 +508,7 @@ __mutex_lock_common(struct mutex *lock, long state, 
unsigned
                  */
                 arch_mutex_cpu_relax();
         }
+       mspin_unlock(MLOCK(lock), &node);
  slowpath:
  #endif
         spin_lock_mutex(&lock->wait_lock, flags);



  reply	other threads:[~2014-01-15 15:11 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-01-15  0:33 [RFC 0/3] mutex: Reduce spinning contention when there is no lock owner Jason Low
2014-01-15  0:33 ` [RFC 1/3] mutex: In mutex_can_spin_on_owner(), return false if task need_resched() Jason Low
2014-01-15  7:44   ` Peter Zijlstra
2014-01-15  7:48     ` Peter Zijlstra
2014-01-15 20:37       ` Paul E. McKenney
2014-01-15  0:33 ` [RFC 2/3] mutex: Modify the way optimistic spinners are queued Jason Low
2014-01-15 15:10   ` Waiman Long [this message]
2014-01-15 19:23     ` Jason Low
2014-01-15  0:33 ` [RFC 3/3] mutex: When there is no owner, stop spinning after too many tries Jason Low
2014-01-15  1:00   ` Andrew Morton
2014-01-15  7:04     ` Jason Low
2014-01-15  1:06   ` Davidlohr Bueso
2014-01-15  7:34     ` Jason Low
2014-01-15 15:19   ` Waiman Long
2014-01-16  2:45   ` Jason Low
2014-01-16  3:14     ` Linus Torvalds
2014-01-16  6:46       ` Jason Low
2014-01-16 12:05         ` Peter Zijlstra
2014-01-16 20:48           ` Jason Low

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=52D6A4FB.7060305@hp.com \
    --to=waiman.long@hp.com \
    --cc=akpm@linux-foundation.org \
    --cc=aswin@hp.com \
    --cc=davidlohr@hp.com \
    --cc=hpa@zytor.com \
    --cc=jason.low2@hp.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=paulmck@linux.vnet.ibm.com \
    --cc=peterz@infradead.org \
    --cc=riel@redhat.com \
    --cc=scott.norton@hp.com \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.