|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 3/8] qspinlock, x86: Add x86 specific optimization for 2 contending tasks
You don't happen to have a proper state diagram for this thing do you?
I suppose I'm going to have to make one; this is all getting a bit
unwieldy, and those xchg() + fixup things are hard to read.
On Wed, Feb 26, 2014 at 10:14:23AM -0500, Waiman Long wrote:
> +static inline int queue_spin_trylock_quick(struct qspinlock *lock, int qsval)
> +{
> + union arch_qspinlock *qlock = (union arch_qspinlock *)lock;
> + u16 old;
> +
> + /*
> + * Fall into the quick spinning code path only if no one is waiting
> + * or the lock is available.
> + */
> + if (unlikely((qsval != _QSPINLOCK_LOCKED) &&
> + (qsval != _QSPINLOCK_WAITING)))
> + return 0;
> +
> + old = xchg(&qlock->lock_wait, _QSPINLOCK_WAITING|_QSPINLOCK_LOCKED);
> +
> + if (old == 0) {
> + /*
> + * Got the lock, can clear the waiting bit now
> + */
> + smp_u8_store_release(&qlock->wait, 0);
So we just did an atomic op, and now you're trying to optimize this
write. Why do you need a whole byte for that?
Surely a cmpxchg loop with the right atomic op can't be _that_ much
slower? Its far more readable and likely avoids that steal fail below as
well.
> + return 1;
> + } else if (old == _QSPINLOCK_LOCKED) {
> +try_again:
> + /*
> + * Wait until the lock byte is cleared to get the lock
> + */
> + do {
> + cpu_relax();
> + } while (ACCESS_ONCE(qlock->lock));
> + /*
> + * Set the lock bit & clear the waiting bit
> + */
> + if (cmpxchg(&qlock->lock_wait, _QSPINLOCK_WAITING,
> + _QSPINLOCK_LOCKED) == _QSPINLOCK_WAITING)
> + return 1;
> + /*
> + * Someone has steal the lock, so wait again
> + */
> + goto try_again;
That's just a fail.. steals should not ever be allowed. It's a fair lock
after all.
> + } else if (old == _QSPINLOCK_WAITING) {
> + /*
> + * Another task is already waiting while it steals the lock.
> + * A bit of unfairness here won't change the big picture.
> + * So just take the lock and return.
> + */
> + return 1;
> + }
> + /*
> + * Nothing need to be done if the old value is
> + * (_QSPINLOCK_WAITING | _QSPINLOCK_LOCKED).
> + */
> + return 0;
> +}
> @@ -296,6 +478,9 @@ void queue_spin_lock_slowpath(struct qspinlock *lock, int
> qsval)
> return;
> }
>
> +#ifdef queue_code_xchg
> + prev_qcode = queue_code_xchg(lock, my_qcode);
> +#else
> /*
> * Exchange current copy of the queue node code
> */
> @@ -329,6 +514,7 @@ void queue_spin_lock_slowpath(struct qspinlock *lock, int
> qsval)
> } else
> prev_qcode &= ~_QSPINLOCK_LOCKED; /* Clear the lock bit */
> my_qcode &= ~_QSPINLOCK_LOCKED;
> +#endif /* queue_code_xchg */
>
> if (prev_qcode) {
> /*
That's just horrible.. please just make the entire #else branch another
version of that same queue_code_xchg() function.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |