From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-2.0 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00 shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: mm@80x24.org Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 90EF61FB36; Mon, 4 Aug 2014 21:26:44 +0000 (UTC) Date: Mon, 4 Aug 2014 21:26:44 +0000 From: Eric Wong To: mm@80x24.org Subject: [REJECT femalloc] xtlifo: reduce spinnning with futex Message-ID: <20140804212644.GA23906@dcvr.yhbt.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline List-Id: 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 +#include +#include #include #include #include +#include +#include +#include + +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