* [REJECT femalloc] xtlifo: reduce spinnning with futex
@ 2014-08-04 21:26 Eric Wong
0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2014-08-04 21:26 UTC (permalink / raw)
To: mm
I'm probably going to drop the LIFO stack of arenas entirely and use
thread-local arenas, but for the sake of documentation, I attempted to
use a futex to reduce spinning on arena contention.
diff --git a/xtlifo.h b/xtlifo.h
index 4d6d219..ccb8dc2 100644
--- a/xtlifo.h
+++ b/xtlifo.h
@@ -11,9 +11,27 @@
* (n.b. ck is 2-clause BSD)
*/
+#include <assert.h>
+#include <unistd.h>
+#include <errno.h>
#include <ck_stack.h>
#include <ck_spinlock.h>
#include <urcu/uatomic.h>
+#include <urcu/compiler.h>
+#include <linux/futex.h>
+#include <sys/syscall.h>
+
+static inline int futex_wait(int *addr, int val) {
+ int rc = syscall(SYS_futex, addr, FUTEX_WAIT_PRIVATE, val, 0, 0, 0);
+ if (caa_unlikely(rc != 0))
+ assert(errno == EINTR);
+ return rc;
+}
+
+static inline void futex_wake(int *addr) {
+ int rc = syscall(SYS_futex, addr, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0);
+ assert(rc >= 0);
+}
/* push, pop */
struct xtlifo {
@@ -23,7 +41,12 @@ struct xtlifo {
struct ck_stack_entry *head;
ck_spinlock_t lock;
};
+ struct {
+ int padding; /* FIXME: this is broken on 32-bit */
+ int ftx;
+ } f;
};
+ int contended;
};
#ifdef CK_F_STACK_POP_MPMC
@@ -40,10 +63,12 @@ static inline void xtlifo_init(struct xtlifo *lifo) {
lifo->head = 0;
ck_spinlock_init(&lifo->lock);
}
+ lifo->contended = 0;
}
static inline struct ck_stack_entry *xtlifo_trypop(struct xtlifo *lifo) {
struct ck_stack_entry *e;
+
if (LFLIFO) {
if (ck_stack_trypop_mpmc(&lifo->stack, &e))
return e;
@@ -59,6 +84,33 @@ static inline struct ck_stack_entry *xtlifo_trypop(struct xtlifo *lifo) {
}
}
+/*
+ * n.b. due to the ABA problem, we may get spurious wakeups.
+ * This is probably unavoidable. Of course, too many wakeups is
+ * preferable to missing wakeups and deadlocking.
+ */
+static void xtlifo_wait_for_push(struct xtlifo *lifo) {
+ /* this reaches into the ck_stack generation counter */
+ int val = uatomic_read(&lifo->f.ftx);
+
+ /* check the pointer did not just get set */
+ if (val)
+ return;
+
+ /* declare we are busy so the pusher can wake us up */
+ cmm_smp_mb__before_uatomic_inc();
+ uatomic_inc(&lifo->contended);
+ cmm_smp_mb__after_uatomic_inc();
+
+ /* wait for the stack head to change */
+ futex_wait(&lifo->f.ftx, val);
+
+ /* prevent unnecessary syscalls from the pusher */
+ cmm_smp_mb__before_uatomic_dec();
+ uatomic_dec(&lifo->contended);
+ cmm_smp_mb__after_uatomic_dec();
+}
+
static inline struct ck_stack_entry *xtlifo_pop(struct xtlifo *lifo) {
struct ck_stack_entry *e;
@@ -67,7 +119,7 @@ static inline struct ck_stack_entry *xtlifo_pop(struct xtlifo *lifo) {
e = ck_stack_pop_mpmc(&lifo->stack);
if (e)
return e;
- caa_cpu_relax();
+ xtlifo_wait_for_push(lifo);
}
}
else {
@@ -82,8 +134,16 @@ static inline struct ck_stack_entry *xtlifo_pop(struct xtlifo *lifo) {
}
static inline void xtlifo_push(struct xtlifo *lifo, struct ck_stack_entry *e) {
- if (LFLIFO)
+ if (LFLIFO) {
ck_stack_push_mpmc(&lifo->stack, e);
+
+ /*
+ * Try to only make a syscall if we have waiters.
+ * Syscall avoidance is best-effort.
+ */
+ if (uatomic_read(&lifo->contended));
+ futex_wake(&lifo->f.ftx);
+ }
else {
ck_spinlock_lock(&lifo->lock);
ck_stack_push_spnc(&lifo->stack, e);
--
EW
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2014-08-04 21:26 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-04 21:26 [REJECT femalloc] xtlifo: reduce spinnning with futex Eric Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox