From: Waiman Long <Waiman.Long@hp.com>
To: Ingo Molnar <mingo@elte.hu>, Andrew Morton <akpm@linux-foundation.org>
Cc: Waiman Long <Waiman.Long@hp.com>,
linux-kernel@vger.kernel.org, Rik van Riel <riel@redhat.com>,
Peter Hurley <peter@hurleysoftware.com>,
Davidlohr Bueso <davidlohr.bueso@hp.com>,
Alex Shi <alex.shi@intel.com>,
Tim Chen <tim.c.chen@linux.intel.com>,
Linus Torvalds <torvalds@linux-foundation.org>,
Peter Zijlstra <a.p.zijlstra@chello.nl>,
Andrea Arcangeli <aarcange@redhat.com>,
Matthew R Wilcox <matthew.r.wilcox@intel.com>,
Dave Hansen <dave.hansen@intel.com>,
Michel Lespinasse <walken@google.com>,
Andi Kleen <andi@firstfloor.org>,
"Chandramouleeswaran, Aswin" <aswin@hp.com>,
"Norton, Scott J" <scott.norton@hp.com>
Subject: [PATCH] rwsem: reduce spinlock contention in wakeup code path
Date: Fri, 27 Sep 2013 15:00:24 -0400 [thread overview]
Message-ID: <1380308424-31011-1-git-send-email-Waiman.Long@hp.com> (raw)
With the 3.12-rc2 kernel, there is sizable spinlock contention on
the rwsem wakeup code path when running AIM7's high_systime workload
on a 8-socket 80-core DL980 (HT off) as reported by perf:
7.64% reaim [kernel.kallsyms] [k] _raw_spin_lock_irqsave
|--41.77%-- rwsem_wake
1.61% reaim [kernel.kallsyms] [k] _raw_spin_lock_irq
|--92.37%-- rwsem_down_write_failed
That was 4.7% of recorded CPU cycles.
On a large NUMA machine, it is entirely possible that a fairly large
number of threads are queuing up in the ticket spinlock queue to do
the wakeup operation. In fact, only one will be needed. This patch
tries to reduce spinlock contention by doing just that.
A new wakeup field is added to the rwsem structure. This field is
set on entry to rwsem_wake() and __rwsem_do_wake() to mark that a
thread is pending to do the wakeup call. It is cleared on exit from
those functions.
By checking if the wakeup flag is set, a thread can exit rwsem_wake()
immediately if another thread is pending to do the wakeup instead of
waiting to get the spinlock and find out that nothing need to be done.
The setting of the wakeup flag may not be visible on all processors in
some architectures. However, this won't affect program correctness. The
clearing of the wakeup flag before spin_unlock will ensure that it is
visible to all processors.
With this patch, the performance improvement on jobs per minute (JPM)
of the high_systime workload (at 1500 users) was as follows:
HT JPM w/o patch JPM with patch % Change
-- ------------- -------------- --------
off 128466 150000 +16.8%
on 121606 146778 +20.7%
The new perf profile (HT off) was as follows:
2.96% reaim [kernel.kallsyms] [k] _raw_spin_lock_irqsave
|--0.94%-- rwsem_wake
1.00% reaim [kernel.kallsyms] [k] _raw_spin_lock_irq
|--88.70%-- rwsem_down_write_failed
Signed-off-by: Waiman Long <Waiman.Long@hp.com>
---
include/linux/rwsem.h | 2 ++
lib/rwsem.c | 19 +++++++++++++++++++
2 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 0616ffe..e25792e 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -25,6 +25,7 @@ struct rw_semaphore;
struct rw_semaphore {
long count;
raw_spinlock_t wait_lock;
+ int wakeup; /* Waking-up in progress flag */
struct list_head wait_list;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
@@ -58,6 +59,7 @@ static inline int rwsem_is_locked(struct rw_semaphore *sem)
#define __RWSEM_INITIALIZER(name) \
{ RWSEM_UNLOCKED_VALUE, \
__RAW_SPIN_LOCK_UNLOCKED(name.wait_lock), \
+ 0, \
LIST_HEAD_INIT((name).wait_list) \
__RWSEM_DEP_MAP_INIT(name) }
diff --git a/lib/rwsem.c b/lib/rwsem.c
index 19c5fa9..39290a5 100644
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -25,6 +25,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name,
lockdep_init_map(&sem->dep_map, name, key, 0);
#endif
sem->count = RWSEM_UNLOCKED_VALUE;
+ sem->wakeup = 0;
raw_spin_lock_init(&sem->wait_lock);
INIT_LIST_HEAD(&sem->wait_list);
}
@@ -66,6 +67,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type)
struct list_head *next;
long oldcount, woken, loop, adjustment;
+ sem->wakeup = 1; /* Waking up in progress */
waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list);
if (waiter->type == RWSEM_WAITING_FOR_WRITE) {
if (wake_type == RWSEM_WAKE_ANY)
@@ -137,6 +139,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, enum rwsem_wake_type wake_type)
next->prev = &sem->wait_list;
out:
+ sem->wakeup = 0;
return sem;
}
@@ -256,11 +259,27 @@ struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem)
{
unsigned long flags;
+ if (sem->wakeup)
+ return sem; /* Waking up in progress already */
+ /*
+ * Optimistically set the wakeup flag to indicate that the current
+ * flag is going to wakeup the sleeping waiters so that the
+ * following threads don't need to wait for doing the wakeup.
+ * It is perfectly fine if another thread resets the flag. It just
+ * leads to another thread waiting to call __rwsem_do_wake().
+ */
+ sem->wakeup = 1;
raw_spin_lock_irqsave(&sem->wait_lock, flags);
/* do nothing if list empty */
if (!list_empty(&sem->wait_list))
sem = __rwsem_do_wake(sem, RWSEM_WAKE_ANY);
+ else
+ sem->wakeup = 0; /* Make sure wakeup flag is reset */
+ /*
+ * The spin_unlock() call will force the nulled wakeup flag to
+ * be visible to all the processors.
+ */
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
--
1.7.1
next reply other threads:[~2013-09-27 19:01 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-27 19:00 Waiman Long [this message]
2013-09-27 19:28 ` Linus Torvalds
2013-09-27 19:39 ` Davidlohr Bueso
2013-09-27 21:49 ` Tim Chen
2013-09-28 6:45 ` Ingo Molnar
2013-09-28 7:41 ` Ingo Molnar
2013-09-28 18:55 ` Linus Torvalds
2013-09-28 19:13 ` Andi Kleen
2013-09-28 19:22 ` Linus Torvalds
2013-09-28 19:21 ` Ingo Molnar
2013-09-28 19:33 ` Linus Torvalds
2013-09-28 19:39 ` Ingo Molnar
2013-09-30 10:44 ` Peter Zijlstra
2013-09-30 16:13 ` Linus Torvalds
2013-09-30 16:41 ` Peter Zijlstra
2013-10-01 7:28 ` Ingo Molnar
2013-10-01 8:09 ` Peter Zijlstra
2013-10-01 8:25 ` Ingo Molnar
2013-09-30 15:58 ` Waiman Long
2013-10-01 7:33 ` Ingo Molnar
2013-10-01 20:03 ` Waiman Long
2013-09-28 19:37 ` [PATCH] anon_vmas: Convert the rwsem to an rwlock_t Ingo Molnar
2013-09-28 19:43 ` Linus Torvalds
2013-09-28 19:46 ` Ingo Molnar
2013-09-28 19:52 ` [PATCH, v2] " Ingo Molnar
2013-09-30 11:00 ` Peter Zijlstra
2013-09-30 11:44 ` Peter Zijlstra
2013-09-30 17:03 ` Andrew Morton
2013-09-30 17:25 ` Linus Torvalds
2013-09-30 17:10 ` Tim Chen
2013-09-30 18:14 ` Peter Zijlstra
2013-09-30 19:23 ` Tim Chen
2013-09-30 19:35 ` Waiman Long
2013-09-30 19:47 ` Tim Chen
2013-09-30 22:03 ` Tim Chen
2013-10-01 2:41 ` Waiman Long
2013-09-30 8:52 ` [PATCH] " Andrea Arcangeli
2013-09-30 14:40 ` Jerome Glisse
2013-09-30 16:26 ` Linus Torvalds
2013-09-30 19:16 ` Andrea Arcangeli
2013-09-30 18:21 ` Andi Kleen
2013-09-30 19:04 ` Jerome Glisse
2013-09-29 23:06 ` [PATCH] rwsem: reduce spinlock contention in wakeup code path Davidlohr Bueso
2013-09-29 23:26 ` Linus Torvalds
2013-09-30 0:40 ` Davidlohr Bueso
2013-09-30 0:51 ` Linus Torvalds
2013-09-30 6:57 ` Ingo Molnar
2013-09-30 1:11 ` Michel Lespinasse
2013-09-30 7:05 ` Ingo Molnar
2013-09-30 16:03 ` Waiman Long
2013-09-30 10:46 ` Peter Zijlstra
2013-10-01 7:48 ` Ingo Molnar
2013-10-01 8:10 ` Peter Zijlstra
2013-09-27 19:32 ` Peter Hurley
2013-09-28 0:46 ` Waiman Long
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=1380308424-31011-1-git-send-email-Waiman.Long@hp.com \
--to=waiman.long@hp.com \
--cc=a.p.zijlstra@chello.nl \
--cc=aarcange@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=alex.shi@intel.com \
--cc=andi@firstfloor.org \
--cc=aswin@hp.com \
--cc=dave.hansen@intel.com \
--cc=davidlohr.bueso@hp.com \
--cc=linux-kernel@vger.kernel.org \
--cc=matthew.r.wilcox@intel.com \
--cc=mingo@elte.hu \
--cc=peter@hurleysoftware.com \
--cc=riel@redhat.com \
--cc=scott.norton@hp.com \
--cc=tim.c.chen@linux.intel.com \
--cc=torvalds@linux-foundation.org \
--cc=walken@google.com \
/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
all inboxes | Powered by JetHome®