Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1465926 > unrolled thread
| Started by | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| First post | 2016-08-19 04:40 +0200 |
| Last post | 2016-08-19 09:00 +0200 |
| Articles | 5 — 2 participants |
Back to article view | Back to linux.kernel
[RFC PATCH-tip v4 00/10] locking/rwsem: Enable reader optimistic spinning Waiman Long <Waiman.Long@hpe.com> - 2016-08-19 04:40 +0200
[RFC PATCH-tip v4 06/10] locking/rwsem: Move common rwsem macros to asm-generic/rwsem_types.h Waiman Long <Waiman.Long@hpe.com> - 2016-08-19 04:40 +0200
[RFC PATCH-tip v4 10/10] locking/rwsem: Add a boot parameter to reader spinning threshold Waiman Long <Waiman.Long@hpe.com> - 2016-08-19 09:00 +0200
Re: [RFC PATCH-tip v4 10/10] locking/rwsem: Add a boot parameter to reader spinning threshold Davidlohr Bueso <dave@stgolabs.net> - 2016-08-24 06:10 +0200
[RFC PATCH-tip v4 08/10] locking/rwsem: Enable spinning readers Waiman Long <Waiman.Long@hpe.com> - 2016-08-19 09:00 +0200
| From | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| Date | 2016-08-19 04:40 +0200 |
| Subject | [RFC PATCH-tip v4 00/10] locking/rwsem: Enable reader optimistic spinning |
| Message-ID | <s7Gka-6XF-49@gated-at.bofh.it> |
v3->v4:
- Rebased to the latest tip tree due to changes to rwsem-xadd.c.
- Update the OSQ patch to fix race condition.
v2->v3:
- Used smp_acquire__after_ctrl_dep() to provide acquire barrier.
- Added the following new patches:
1) make rwsem_spin_on_owner() return a tristate value.
2) reactivate reader spinning when there is a large number of
favorable writer-on-writer spinnings.
3) move all the rwsem macros in arch-specific rwsem.h files
into a common asm-generic/rwsem_types.h file.
4) add a boot parameter to specify the reader spinning threshold.
- Updated some of the patches as suggested by PeterZ and adjusted
some of the reader spinning parameters.
v1->v2:
- Fixed a 0day build error.
- Added a new patch 1 to make osq_lock() a proper acquire memory
barrier.
- Replaced the explicit enabling of reader spinning by an autotuning
mechanism that disable reader spinning for those rwsems that may
not benefit from reader spinning.
- Remove the last xfs patch as it is no longer necessary.
This patchset enables more aggressive optimistic spinning on
both readers and writers waiting on a writer or reader owned
lock. Spinning on writer is done by looking at the on_cpu flag of the
lock owner. Spinning on readers, on the other hand, is count-based as
there is no easy way to figure out if all the readers are running. The
spinner will stop spinning once the count goes to 0. Because of that,
spinning on readers may hurt performance in some cases.
An autotuning mechanism is used to determine if a rwsem can benefit
from reader optimistic spinning. It will maintain reader spinning as
long as no less than 80% of the spins are successful.
Patch 1 updates the osq_lock() function to make it a proper acquire
memory barrier.
Patch 2 reduces the length of the blocking window after a read locking
attempt where writer lock stealing is disabled because of the active
read lock. It can improve rwsem performance for contended lock. It is
independent of the rest of the patchset.
Patch 3 modifies rwsem_spin_on_owner() to return a tri-state value
that can be used in later patch.
Patch 4 puts in place the autotuning mechanism to check if reader
optimistic spinning should be used or not.
Patch 5 moves down the rwsem_down_read_failed() function for later
patches.
Patch 6 moves the macro definitions in various arch-specific rwsem.h
header files into a commont asm-generic/rwsem_types.h file.
Patch 7 changes RWSEM_WAITING_BIAS to simpify reader trylock code.
Patch 8 enables readers to do optimistic spinning.
Patch 9 allows reactivation of reader spinning when a lot of
writer-on-writer spins are successful.
Patch 10 adds a new boot parameter to change the reader spinning
threshold which can be system specific.
Waiman Long (10):
locking/osq: Make lock/unlock proper acquire/release barrier
locking/rwsem: Stop active read lock ASAP
locking/rwsem: Make rwsem_spin_on_owner() return a tri-state value
locking/rwsem: Enable count-based spinning on reader
locking/rwsem: move down rwsem_down_read_failed function
locking/rwsem: Move common rwsem macros to asm-generic/rwsem_types.h
locking/rwsem: Change RWSEM_WAITING_BIAS for better disambiguation
locking/rwsem: Enable spinning readers
locking/rwsem: Enable reactivation of reader spinning
locking/rwsem: Add a boot parameter to reader spinning threshold
Documentation/kernel-parameters.txt | 3 +
arch/alpha/include/asm/rwsem.h | 11 +-
arch/ia64/include/asm/rwsem.h | 9 +-
arch/s390/include/asm/rwsem.h | 9 +-
arch/x86/include/asm/rwsem.h | 22 +---
include/asm-generic/rwsem.h | 20 +--
include/asm-generic/rwsem_types.h | 28 ++++
include/linux/rwsem.h | 23 +++-
kernel/locking/osq_lock.c | 24 ++-
kernel/locking/rwsem-xadd.c | 296 ++++++++++++++++++++++++++---------
10 files changed, 308 insertions(+), 137 deletions(-)
create mode 100644 include/asm-generic/rwsem_types.h
[toc] | [next] | [standalone]
| From | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| Date | 2016-08-19 04:40 +0200 |
| Subject | [RFC PATCH-tip v4 06/10] locking/rwsem: Move common rwsem macros to asm-generic/rwsem_types.h |
| Message-ID | <s7HSW-892-31@gated-at.bofh.it> |
| In reply to | #1465926 |
Almost all the macro definitions in the various architecture specific
rwsem.h header files are essentially the same. This patch moves all
of them into a common header asm-generic/rwsem_types.h to eliminate
the duplication.
Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Waiman Long <Waiman.Long@hpe.com>
---
arch/alpha/include/asm/rwsem.h | 8 +-------
arch/ia64/include/asm/rwsem.h | 7 ++-----
arch/s390/include/asm/rwsem.h | 7 +------
arch/x86/include/asm/rwsem.h | 19 +------------------
include/asm-generic/rwsem.h | 16 +---------------
include/asm-generic/rwsem_types.h | 26 ++++++++++++++++++++++++++
6 files changed, 32 insertions(+), 51 deletions(-)
create mode 100644 include/asm-generic/rwsem_types.h
diff --git a/arch/alpha/include/asm/rwsem.h b/arch/alpha/include/asm/rwsem.h
index 77873d0..f99e39a 100644
--- a/arch/alpha/include/asm/rwsem.h
+++ b/arch/alpha/include/asm/rwsem.h
@@ -13,13 +13,7 @@
#ifdef __KERNEL__
#include <linux/compiler.h>
-
-#define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
-#define RWSEM_ACTIVE_BIAS 0x0000000000000001L
-#define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
-#define RWSEM_WAITING_BIAS (-0x0000000100000000L)
-#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+#include <asm-generic/rwsem_types.h>
static inline void __down_read(struct rw_semaphore *sem)
{
diff --git a/arch/ia64/include/asm/rwsem.h b/arch/ia64/include/asm/rwsem.h
index 8fa98dd..21a9066 100644
--- a/arch/ia64/include/asm/rwsem.h
+++ b/arch/ia64/include/asm/rwsem.h
@@ -26,13 +26,10 @@
#endif
#include <asm/intrinsics.h>
+#include <asm-generic/rwsem_types.h>
+#undef RWSEM_UNLOCKED_VALUE
#define RWSEM_UNLOCKED_VALUE __IA64_UL_CONST(0x0000000000000000)
-#define RWSEM_ACTIVE_BIAS (1L)
-#define RWSEM_ACTIVE_MASK (0xffffffffL)
-#define RWSEM_WAITING_BIAS (-0x100000000L)
-#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
/*
* lock for reading
diff --git a/arch/s390/include/asm/rwsem.h b/arch/s390/include/asm/rwsem.h
index 597e7e9..13dedc8 100644
--- a/arch/s390/include/asm/rwsem.h
+++ b/arch/s390/include/asm/rwsem.h
@@ -39,12 +39,7 @@
#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
#endif
-#define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
-#define RWSEM_ACTIVE_BIAS 0x0000000000000001L
-#define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
-#define RWSEM_WAITING_BIAS (-0x0000000100000000L)
-#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+#include <asm-generic/rwsem_types.h>
/*
* lock for reading
diff --git a/arch/x86/include/asm/rwsem.h b/arch/x86/include/asm/rwsem.h
index 8dbc762..da84726 100644
--- a/arch/x86/include/asm/rwsem.h
+++ b/arch/x86/include/asm/rwsem.h
@@ -38,24 +38,7 @@
#ifdef __KERNEL__
#include <asm/asm.h>
-
-/*
- * The bias values and the counter type limits the number of
- * potential readers/writers to 32767 for 32 bits and 2147483647
- * for 64 bits.
- */
-
-#ifdef CONFIG_X86_64
-# define RWSEM_ACTIVE_MASK 0xffffffffL
-#else
-# define RWSEM_ACTIVE_MASK 0x0000ffffL
-#endif
-
-#define RWSEM_UNLOCKED_VALUE 0x00000000L
-#define RWSEM_ACTIVE_BIAS 0x00000001L
-#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
-#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+#include <asm-generic/rwsem_types.h>
/*
* lock for reading
diff --git a/include/asm-generic/rwsem.h b/include/asm-generic/rwsem.h
index 5be122e..3cb8d98 100644
--- a/include/asm-generic/rwsem.h
+++ b/include/asm-generic/rwsem.h
@@ -12,21 +12,7 @@
* Adapted largely from include/asm-i386/rwsem.h
* by Paul Mackerras <paulus@samba.org>.
*/
-
-/*
- * the semaphore definition
- */
-#ifdef CONFIG_64BIT
-# define RWSEM_ACTIVE_MASK 0xffffffffL
-#else
-# define RWSEM_ACTIVE_MASK 0x0000ffffL
-#endif
-
-#define RWSEM_UNLOCKED_VALUE 0x00000000L
-#define RWSEM_ACTIVE_BIAS 0x00000001L
-#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
-#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
-#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+#include <asm-generic/rwsem_types.h>
/*
* lock for reading
diff --git a/include/asm-generic/rwsem_types.h b/include/asm-generic/rwsem_types.h
new file mode 100644
index 0000000..093ef6a
--- /dev/null
+++ b/include/asm-generic/rwsem_types.h
@@ -0,0 +1,26 @@
+#ifndef _ASM_GENERIC_RWSEM_TYPES_H
+#define _ASM_GENERIC_RWSEM_TYPES_H
+
+#ifdef __KERNEL__
+
+/*
+ * the semaphore definition
+ *
+ * The bias values and the counter type limits the number of
+ * potential readers/writers to 32767 for 32 bits and 2147483647
+ * for 64 bits.
+ */
+#ifdef CONFIG_64BIT
+# define RWSEM_ACTIVE_MASK 0xffffffffL
+#else
+# define RWSEM_ACTIVE_MASK 0x0000ffffL
+#endif
+
+#define RWSEM_UNLOCKED_VALUE 0x00000000L
+#define RWSEM_ACTIVE_BIAS 0x00000001L
+#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
+#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_GENERIC_RWSEM_TYPES_H */
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| Date | 2016-08-19 09:00 +0200 |
| Subject | [RFC PATCH-tip v4 10/10] locking/rwsem: Add a boot parameter to reader spinning threshold |
| Message-ID | <s7LWx-2b5-11@gated-at.bofh.it> |
| In reply to | #1465926 |
The default reader spining threshold is current set to 4096. However,
the right reader spinning threshold may vary from one system to
another and among the different architectures. This patch adds a new
kernel boot parameter to modify the threshold value. This enables
better tailoring to the needs of different systems as well as for
testing purposes.
Signed-off-by: Waiman Long <Waiman.Long@hpe.com>
---
Documentation/kernel-parameters.txt | 3 +++
kernel/locking/rwsem-xadd.c | 14 +++++++++++++-
2 files changed, 16 insertions(+), 1 deletions(-)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 46c030a..90892ac 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3690,6 +3690,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
rw [KNL] Mount root device read-write on boot
+ rwsem_rspin_threshold=
+ [KNL] Set rw semaphore reader spinning threshold
+
S [KNL] Run init in single mode
s390_iommu= [HW,S390]
diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
index 9978159..7bb6255 100644
--- a/kernel/locking/rwsem-xadd.c
+++ b/kernel/locking/rwsem-xadd.c
@@ -272,6 +272,18 @@ static inline bool rwsem_try_write_lock(long count, struct rw_semaphore *sem)
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
/*
+ * Reader spinning threshold
+ */
+static int __read_mostly rspin_threshold = RWSEM_RSPIN_THRESHOLD;
+
+static int __init set_rspin_threshold(char *str)
+{
+ get_option(&str, &rspin_threshold);
+ return 0;
+}
+early_param("rwsem_rspin_threshold", set_rspin_threshold);
+
+/*
* Try to acquire write lock before the writer has been put on wait queue.
*/
static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem)
@@ -394,7 +406,7 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem,
if (!osq_lock(&sem->osq))
goto done;
- rspin_cnt = sem->rspin_enabled ? RWSEM_RSPIN_THRESHOLD : 0;
+ rspin_cnt = sem->rspin_enabled ? rspin_threshold : 0;
/*
* Optimistically spin on the owner field and attempt to acquire the
--
1.7.1
[toc] | [prev] | [next] | [standalone]
| From | Davidlohr Bueso <dave@stgolabs.net> |
|---|---|
| Date | 2016-08-24 06:10 +0200 |
| Subject | Re: [RFC PATCH-tip v4 10/10] locking/rwsem: Add a boot parameter to reader spinning threshold |
| Message-ID | <s9xFM-5og-3@gated-at.bofh.it> |
| In reply to | #1466067 |
On Thu, 18 Aug 2016, Waiman Long wrote: >The default reader spining threshold is current set to 4096. However, >the right reader spinning threshold may vary from one system to >another and among the different architectures. This patch adds a new >kernel boot parameter to modify the threshold value. This enables >better tailoring to the needs of different systems as well as for >testing purposes. It also means that those systems could very easily be incorrectly tailored. (and worse case scenario: reboot, is obviously a terrible way to get rid of any issues). I very much disagree with exposing this sort of core stuff, it should work well for everyone out of the box, not relying on users to properly configure this. Thanks, Davidlohr
[toc] | [prev] | [next] | [standalone]
| From | Waiman Long <Waiman.Long@hpe.com> |
|---|---|
| Date | 2016-08-19 09:00 +0200 |
| Subject | [RFC PATCH-tip v4 08/10] locking/rwsem: Enable spinning readers |
| Message-ID | <s7LWy-2b5-17@gated-at.bofh.it> |
| In reply to | #1465926 |
This patch enables readers to optimistically spin when the
rspin_threshold is non-zero. That threshold value should only
be set when the lock owners of the rwsem are unlikely to go to
sleep. Otherwise enabling reader spinning may make the performance
worse in some cases.
On a 4-socket Haswell machine running on a 4.7-rc1 tip-based kernel,
the fio test with multithreaded randrw and randwrite tests on the
same file on a XFS partition on top of a NVDIMM with DAX were run,
the aggregated bandwidths before and after the reader optimistic
spinning patchset were as follows:
Test BW before patch BW after patch % change
---- --------------- -------------- --------
randrw 1352 MB/s 2164 MB/s +60%
randwrite 1710 MB/s 2550 MB/s +49%
Signed-off-by: Waiman Long <Waiman.Long@hpe.com>
---
kernel/locking/rwsem-xadd.c | 48 ++++++++++++++++++++++++++++++++++++------
1 files changed, 41 insertions(+), 7 deletions(-)
diff --git a/kernel/locking/rwsem-xadd.c b/kernel/locking/rwsem-xadd.c
index 8b118b3..d850214 100644
--- a/kernel/locking/rwsem-xadd.c
+++ b/kernel/locking/rwsem-xadd.c
@@ -83,6 +83,12 @@
* (2) WAITING_BIAS - ACTIVE_WRITE_BIAS < count < 0
*/
+static inline bool count_has_writer(long count)
+{
+ return (count < RWSEM_WAITING_BIAS) || ((count < 0) &&
+ (count > RWSEM_WAITING_BIAS - RWSEM_ACTIVE_WRITE_BIAS));
+}
+
/*
* Initialize an rwsem:
*/
@@ -286,6 +292,25 @@ static inline bool rwsem_try_write_lock_unqueued(struct rw_semaphore *sem)
}
}
+/*
+ * Try to acquire read lock before the reader is put on wait queue
+ */
+static inline bool rwsem_try_read_lock_unqueued(struct rw_semaphore *sem)
+{
+ long count = atomic_long_read(&sem->count);
+
+ if (count_has_writer(count))
+ return false;
+ count = atomic_long_add_return_acquire(RWSEM_ACTIVE_READ_BIAS,
+ &sem->count);
+ if (!count_has_writer(count))
+ return true;
+
+ /* Back out the change */
+ atomic_long_add(-RWSEM_ACTIVE_READ_BIAS, &sem->count);
+ return false;
+}
+
static inline bool rwsem_can_spin_on_owner(struct rw_semaphore *sem)
{
struct task_struct *owner;
@@ -352,7 +377,8 @@ out:
return rwsem_owner_is_reader(READ_ONCE(sem->owner)) ? 0 : 1;
}
-static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
+static bool rwsem_optimistic_spin(struct rw_semaphore *sem,
+ enum rwsem_waiter_type type)
{
bool taken = false;
int owner_state; /* Lock owner state */
@@ -380,10 +406,11 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
/*
* Try to acquire the lock
*/
- if (rwsem_try_write_lock_unqueued(sem)) {
- taken = true;
+ taken = (type == RWSEM_WAITING_FOR_WRITE)
+ ? rwsem_try_write_lock_unqueued(sem)
+ : rwsem_try_read_lock_unqueued(sem);
+ if (taken)
break;
- }
/*
* We only decremnt the rspin_cnt when the lock is owned
@@ -418,7 +445,8 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
* Check the success or failure of writer spinning on reader so as
* to adjust the rspin_enabled count accordingly.
*/
- if (rwsem_owner_is_reader(sem->owner)) {
+ if ((type == RWSEM_WAITING_FOR_WRITE) &&
+ rwsem_owner_is_reader(sem->owner)) {
/*
* Update rspin_enabled for reader spinning.
*
@@ -458,7 +486,8 @@ static inline bool reader_spinning_enabled(struct rw_semaphore *sem)
return sem->rspin_enabled;
}
#else
-static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
+static bool rwsem_optimistic_spin(struct rw_semaphore *sem,
+ enum rwsem_waiter_type type)
{
return false;
}
@@ -492,6 +521,11 @@ struct rw_semaphore __sched *rwsem_down_read_failed(struct rw_semaphore *sem)
*/
atomic_long_add(-RWSEM_ACTIVE_READ_BIAS, &sem->count);
+ /* do optimistic spinning and steal lock if possible */
+ if (reader_spinning_enabled(sem) &&
+ rwsem_optimistic_spin(sem, RWSEM_WAITING_FOR_READ))
+ return sem;
+
waiter.task = tsk;
waiter.type = RWSEM_WAITING_FOR_READ;
@@ -548,7 +582,7 @@ __rwsem_down_write_failed_common(struct rw_semaphore *sem, int state)
count = atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, &sem->count);
/* do optimistic spinning and steal lock if possible */
- if (rwsem_optimistic_spin(sem))
+ if (rwsem_optimistic_spin(sem, RWSEM_WAITING_FOR_WRITE))
return sem;
/*
--
1.7.1
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web