From: Stefan Liebler <stli@linux.vnet.ibm.com>
To: libc-alpha@sourceware.org
Cc: Stefan Liebler <stli@linux.vnet.ibm.com>
Subject: [PATCH 1/2] Optimize generic spinlock code and use C11 like atomic macros.
Date: Fri, 16 Dec 2016 16:32:00 -0000 [thread overview]
Message-ID: <1481905917-15654-1-git-send-email-stli@linux.vnet.ibm.com> (raw)
This patch optimizes the generic spinlock code.
The type pthread_spinlock_t is a typedef to volatile int on all archs.
Passing a volatile pointer to the atomic macros can lead to extra stores
and loads to stack if such a macro creates a temporary variable by using
__typeof (*(mem)). Thus the patch passes a int pointer to the atomic macros.
The atomic macros are replaced by the C11 like atomic macros and thus
the code is aligned to it.
I've added a glibc_likely hint to the first atomic exchange in
pthread_spin_lock in order to return immediately to caller if lock is free.
Without the hint, there is an additional jump if lock is free.
I've added the atomic_spin_nop macro within the loop of plain reads.
The plain reads are realized by dereferencing the volatile pointer
as the for-loop was optimized out with atomic_load_relaxed.
For pthread_spin_trylock, a machine-specific version can define
SPIN_TRYLOCK_USE_CMPXCHG_INSTEAD_OF_XCHG to 1 if an explicit test if
lock is free is optimal.
ChangeLog:
* nptl/pthread_spin_init.c (pthread_spin_init):
Use atomic_store_relaxed.
* nptl/pthread_spin_lock.c (pthread_spin_lock):
Use C11-like atomic macros and pass int pointers instead of
volatile int pointers.
* nptl/pthread_spin_trylock.c
(pthread_spin_trylock): Likewise. Use an explicit test if lock
is free, if new SPIN_TRYLOCK_USE_CMPXCHG_INSTEAD_OF_XCHG macro
is set to one.
(SPIN_TRYLOCK_USE_CMPXCHG_INSTEAD_OF_XCHG): New define.
* nptl/pthread_spin_unlock.c (pthread_spin_unlock):
Use atomic_store_release.
---
nptl/pthread_spin_init.c | 4 +++-
nptl/pthread_spin_lock.c | 54 +++++++++++++++++++++++++++++++++++----------
nptl/pthread_spin_trylock.c | 29 ++++++++++++++++++++++--
nptl/pthread_spin_unlock.c | 6 +++--
4 files changed, 76 insertions(+), 17 deletions(-)
diff --git a/nptl/pthread_spin_init.c b/nptl/pthread_spin_init.c
index 8ed4772..65d05b8 100644
--- a/nptl/pthread_spin_init.c
+++ b/nptl/pthread_spin_init.c
@@ -22,6 +22,8 @@
int
pthread_spin_init (pthread_spinlock_t *lock, int pshared)
{
- *lock = 0;
+ /* The atomic_store_relaxed is enough as we only initialize the spinlock here
+ and we are not in a critical region. */
+ atomic_store_relaxed (lock, 0);
return 0;
}
diff --git a/nptl/pthread_spin_lock.c b/nptl/pthread_spin_lock.c
index fb9bcc1..adbc9d7 100644
--- a/nptl/pthread_spin_lock.c
+++ b/nptl/pthread_spin_lock.c
@@ -21,7 +21,7 @@
/* A machine-specific version can define SPIN_LOCK_READS_BETWEEN_CMPXCHG
to the number of plain reads that it's optimal to spin on between uses
- of atomic_compare_and_exchange_val_acq. If spinning forever is optimal
+ of atomic_compare_exchange_weak_acquire. If spinning forever is optimal
then use -1. If no plain reads here would ever be optimal, use 0. */
#ifndef SPIN_LOCK_READS_BETWEEN_CMPXCHG
# warning machine-dependent file should define SPIN_LOCK_READS_BETWEEN_CMPXCHG
@@ -29,18 +29,27 @@
#endif
int
-pthread_spin_lock (pthread_spinlock_t *lock)
+pthread_spin_lock (pthread_spinlock_t *lock_volatile)
{
+ /* The type pthread_spinlock_t is a typedef to volatile int on all archs.
+ Passing a volatile pointer to the atomic macros can lead to extra stores
+ and loads to stack if such a macro creates a temporary variable by using
+ __typeof (*(mem)). */
+ int *lock = (int *) lock_volatile;
+
/* atomic_exchange usually takes less instructions than
atomic_compare_and_exchange. On the other hand,
atomic_compare_and_exchange potentially generates less bus traffic
when the lock is locked.
We assume that the first try mostly will be successful, and we use
atomic_exchange. For the subsequent tries we use
- atomic_compare_and_exchange. */
- if (atomic_exchange_acq (lock, 1) == 0)
+ atomic_compare_and_exchange.
+ We need acquire memory order here as we need to see if another thread has
+ locked / unlocked this spinlock. */
+ if (__glibc_likely (atomic_exchange_acquire (lock, 1) == 0))
return 0;
+ int val;
do
{
/* The lock is contended and we need to wait. Going straight back
@@ -50,20 +59,41 @@ pthread_spin_lock (pthread_spinlock_t *lock)
On the other hand, we do want to update memory state on the local core
once in a while to avoid spinning indefinitely until some event that
will happen to update local memory as a side-effect. */
- if (SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0)
+
+#if SPIN_LOCK_READS_BETWEEN_CMPXCHG >= 0
+ /* Use at most SPIN_LOCK_READS_BETWEEN_CMPXCHG plain reads between the
+ atomic compare and exchanges. */
+ int wait;
+ for (wait = 0; wait < SPIN_LOCK_READS_BETWEEN_CMPXCHG; wait ++)
{
- int wait = SPIN_LOCK_READS_BETWEEN_CMPXCHG;
+ atomic_spin_nop ();
- while (*lock != 0 && wait > 0)
- --wait;
+ /* Use a plain read every round. */
+ val = *lock_volatile;
+ if (val == 0)
+ break;
}
- else
+
+ /* Set expected value to zero for the next compare and exchange. */
+ val = 0;
+
+#else /* SPIN_LOCK_READS_BETWEEN_CMPXCHG < 0 */
+ /* Use plain reads until spinlock is free and then try a further atomic
+ compare and exchange the next time. */
+ do
{
- while (*lock != 0)
- ;
+ atomic_spin_nop ();
+
+ /* Use a plain read every round. */
+ val = *lock_volatile;
}
+ while (val != 0);
+
+#endif
+ /* We need acquire memory order here for the same reason as mentioned
+ for the first try to lock the spinlock. */
}
- while (atomic_compare_and_exchange_val_acq (lock, 1, 0) != 0);
+ while (!atomic_compare_exchange_weak_acquire (lock, &val, 1));
return 0;
}
diff --git a/nptl/pthread_spin_trylock.c b/nptl/pthread_spin_trylock.c
index 4e1a96c..8e9c76f 100644
--- a/nptl/pthread_spin_trylock.c
+++ b/nptl/pthread_spin_trylock.c
@@ -20,8 +20,33 @@
#include <atomic.h>
#include "pthreadP.h"
+/* A machine-specific version can define
+ SPIN_TRYLOCK_USE_CMPXCHG_INSTEAD_OF_XCHG to 1 if an explicit test if
+ lock is free is optimal. */
+#ifndef SPIN_TRYLOCK_USE_CMPXCHG_INSTEAD_OF_XCHG
+# define SPIN_TRYLOCK_USE_CMPXCHG_INSTEAD_OF_XCHG 0
+#endif
+
int
-pthread_spin_trylock (pthread_spinlock_t *lock)
+pthread_spin_trylock (pthread_spinlock_t *lock_volatile)
{
- return atomic_exchange_acq (lock, 1) ? EBUSY : 0;
+ /* See comment in pthread_spin_lock.c. */
+ int *lock = (int *) lock_volatile;
+
+ /* We need acquire memory order here as we need to see if another
+ thread has locked / unlocked this spinlock. */
+#if SPIN_TRYLOCK_USE_CMPXCHG_INSTEAD_OF_XCHG == 1
+ /* Load and test the spinlock and only try to lock the spinlock if it is
+ free. */
+ int val = atomic_load_relaxed (lock);
+ if (__glibc_likely (val == 0
+ && atomic_compare_exchange_weak_acquire (lock, &val, 1)))
+ return 0;
+#else
+ /* Set spinlock to locked and test if we have locked it. */
+ if (__glibc_likely (atomic_exchange_acquire (lock, 1) == 0))
+ return 0;
+#endif
+
+ return EBUSY;
}
diff --git a/nptl/pthread_spin_unlock.c b/nptl/pthread_spin_unlock.c
index d4b63ac..014f295 100644
--- a/nptl/pthread_spin_unlock.c
+++ b/nptl/pthread_spin_unlock.c
@@ -23,7 +23,9 @@
int
pthread_spin_unlock (pthread_spinlock_t *lock)
{
- atomic_full_barrier ();
- *lock = 0;
+ /* The atomic_store_release synchronizes-with the atomic_exchange_acquire
+ or atomic_compare_exchange_weak_acquire in pthread_spin_lock /
+ pthread_spin_trylock. */
+ atomic_store_release (lock, 0);
return 0;
}
--
2.3.0
next reply other threads:[~2016-12-16 16:32 UTC|newest]
Thread overview: 63+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-12-16 16:32 Stefan Liebler [this message]
2016-12-16 16:32 ` [PATCH 2/2] S390: Use generic spinlock code Stefan Liebler
2017-02-08 14:49 ` Stefan Liebler
2017-02-13 20:39 ` Torvald Riegel
2017-02-15 16:26 ` Stefan Liebler
2017-02-18 17:05 ` Torvald Riegel
2017-03-14 15:55 ` Stefan Liebler
2017-03-21 15:43 ` Stefan Liebler
2017-04-06 12:27 ` Torvald Riegel
2016-12-19 12:14 ` [PATCH 1/2] Optimize generic spinlock code and use C11 like atomic macros Szabolcs Nagy
2017-02-08 14:49 ` Stefan Liebler
2017-02-13 20:29 ` Torvald Riegel
2017-02-15 9:36 ` Stefan Liebler
2017-02-18 16:57 ` Torvald Riegel
2017-02-19 9:20 ` Florian Weimer
2017-02-20 13:11 ` Torvald Riegel
2017-02-26 7:55 ` Florian Weimer
2017-02-26 20:06 ` Torvald Riegel
2017-02-26 20:29 ` Florian Weimer
2017-02-26 20:35 ` Torvald Riegel
2017-02-27 17:57 ` Szabolcs Nagy
2017-02-28 7:15 ` Torvald Riegel
2017-03-14 15:55 ` Stefan Liebler
2017-02-20 12:15 ` Stefan Liebler
2017-02-20 13:51 ` Torvald Riegel
2017-03-14 15:55 ` Stefan Liebler
2017-03-21 15:43 ` Stefan Liebler
2017-03-22 12:56 ` Szabolcs Nagy
2017-03-23 16:16 ` Stefan Liebler
2017-03-23 17:52 ` Szabolcs Nagy
2017-04-06 12:04 ` Torvald Riegel
2017-03-27 13:08 ` Stefan Liebler
2017-04-04 10:29 ` [PING] " Stefan Liebler
2017-03-29 14:16 ` Stefan Liebler
2017-04-06 14:00 ` Torvald Riegel
2017-04-07 16:23 ` Stefan Liebler
2017-04-09 13:51 ` Torvald Riegel
2017-04-10 12:00 ` Stefan Liebler
2017-04-18 13:09 ` Stefan Liebler
2017-04-25 6:47 ` Stefan Liebler
2017-05-03 11:38 ` [PATCH 1/2] [PING] " Stefan Liebler
2017-05-10 13:00 ` Stefan Liebler
2017-05-17 13:09 ` Stefan Liebler
2017-05-24 6:37 ` Stefan Liebler
2017-05-30 7:18 ` Torvald Riegel
2017-05-31 8:29 ` Stefan Liebler
2017-05-31 16:48 ` Torvald Riegel
2017-06-01 13:40 ` Joseph Myers
2017-06-01 14:33 ` Torvald Riegel
2017-06-06 7:51 ` [PATCH 1/2] [COMMITTED] " Stefan Liebler
2017-04-10 8:17 ` [PATCH 1/2] " Andreas Schwab
2017-04-10 12:00 ` Stefan Liebler
2017-04-10 13:36 ` Andreas Schwab
2017-04-11 7:06 ` Stefan Liebler
2017-04-11 8:45 ` Andreas Schwab
2017-04-11 10:15 ` Stefan Liebler
2017-04-11 12:05 ` Andreas Schwab
2017-04-11 12:19 ` Stefan Liebler
2017-04-11 13:08 ` Zack Weinberg
2017-04-13 16:36 ` Torvald Riegel
2017-05-30 21:00 ` Tulio Magno Quites Machado Filho
2017-04-18 21:17 ` Joseph Myers
2017-04-19 8:27 ` Stefan Liebler
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=1481905917-15654-1-git-send-email-stli@linux.vnet.ibm.com \
--to=stli@linux.vnet.ibm.com \
--cc=libc-alpha@sourceware.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 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 read-only IMAP folder(s) and NNTP newsgroup(s).