asm-generic: ticket-lock: Optimize arch_spin_value_unlocked
Subsystems (2)
PATCH v3 1/1 asm-generic: ticket-lock: Optimize arch_spin_value_unlocked
From: Guo Ren <[email protected]>
The arch_spin_value_unlocked of ticket-lock would cause the compiler to generate inefficient asm code in riscv architecture because of unnecessary memory access to the contended value.
Before the patch:
------
void lockref_get(struct lockref *lockref)
{
78: fd010113 add sp,sp,-48 7c: 02813023 sd s0,32(sp) 80: 02113423 sd ra,40(sp) 84: 03010413 add s0,sp,48
0000000000000088 <.LBB296>:
CMPXCHG_LOOP(
88: 00053783 ld a5,0(a0)
------
After the patch:
------
void lockref_get(struct lockref *lockref)
{
CMPXCHG_LOOP( 78: 00053783 ld a5,0(a0)
------
After the patch, the lockref_get could get in a fast path instead of the function's prologue. This is because ticket lock complex logic would limit compiler optimization for the spinlock fast path, and qspinlock won't.
The caller of arch_spin_value_unlocked() could benefit from this change. Currently, the only caller is lockref.
---
Changelog
V3:
- Add Acked-by tags
- Optimize commit log
V2:
- Fixup commit log with Waiman advice.
- Add Waiman comment in the commit msg.
--- include/asm-generic/spinlock.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
include/asm-generic/spinlock.h +9 -7
@@ -68,11 +68,18 @@ static __always_inline void arch_spin_unlock(arch_spinlock_t *lock)smp_store_release (ptr, (u16 )val +1 ); } +static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock) +{ +u32 val = lock.counter; + +return ((val >>16 ) == (val &0xffff )); +} + static __always_inline int arch_spin_is_locked(arch_spinlock_t *lock) { -u32 val =atomic_read (lock); +arch_spinlock_t val =READ_ONCE (*lock); -return ((val >>16 ) != (val &0xffff )); +return !arch_spin_value_unlocked (val); } static __always_inline int arch_spin_is_contended(arch_spinlock_t *lock)
@@ -82,11 +89,6 @@ static __always_inline int arch_spin_is_contended(arch_spinlock_t *lock) return (s16)((val >> 16) - (val & 0xffff)) > 1; } -static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock) -{ -return !arch_spin_is_locked (&lock); -} -#include <asm/qrwlock.h> #endif /* __ASM_GENERIC_SPINLOCK_H */
Signature · 1 line
2.36.1
[tip: locking/core] asm-generic: ticket-lock: Optimize arch_spin_value_unlocked()
The following commit has been merged into the locking/core branch of tip:
The following commit has been merged into the locking/core branch of tip:
Commit-ID: c6f4a90022524d06f6d9de323b1757031dcf0c26 Gitweb: https://git.kernel.org/tip/c6f4a90022524d06f6d9de323b1757031dcf0c26 Author: Guo Ren <[email protected]> AuthorDate: Fri, 08 Sep 2023 11:43:39 -04:00 Committer: Ingo Molnar <[email protected]> CommitterDate: Thu, 21 Sep 2023 10:17:00 +02:00
asm-generic: ticket-lock: Optimize arch_spin_value_unlocked()
The arch_spin_value_unlocked() of ticket-lock would cause the compiler to generate inefficient asm code in riscv architecture because of unnecessary memory access to the contended value.
Before the patch:
void lockref_get(struct lockref *lockref)
{
78: fd010113 add sp,sp,-48
7c: 02813023 sd s0,32(sp)
80: 02113423 sd ra,40(sp)
84: 03010413 add s0,sp,48
0000000000000088 <.LBB296>:
CMPXCHG_LOOP(
88: 00053783 ld a5,0(a0)After the patch:
void lockref_get(struct lockref *lockref)
{
CMPXCHG_LOOP(
78: 00053783 ld a5,0(a0)After the patch, the lockref_get() could get in a fast path instead of the function's prologue. This is because ticket lock complex logic would limit compiler optimization for the spinlock fast path, and qspinlock won't.
The caller of arch_spin_value_unlocked() could benefit from this change. Currently, the only caller is lockref.
--- include/asm-generic/spinlock.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-)
include/asm-generic/spinlock.h +9 -7
@@ -68,11 +68,18 @@ static __always_inline void arch_spin_unlock(arch_spinlock_t *lock)smp_store_release (ptr, (u16 )val +1 ); } +static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock) +{ +u32 val = lock.counter; + +return ((val >>16 ) == (val &0xffff )); +} + static __always_inline int arch_spin_is_locked(arch_spinlock_t *lock) { -u32 val =atomic_read (lock); +arch_spinlock_t val =READ_ONCE (*lock); -return ((val >>16 ) != (val &0xffff )); +return !arch_spin_value_unlocked (val); } static __always_inline int arch_spin_is_contended(arch_spinlock_t *lock)
@@ -82,11 +89,6 @@ static __always_inline int arch_spin_is_contended(arch_spinlock_t *lock) return (s16)((val >> 16) - (val & 0xffff)) > 1; } -static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock) -{ -return !arch_spin_is_locked (&lock); -} -#include <asm/qrwlock.h> #endif /* __ASM_GENERIC_SPINLOCK_H */