|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCHv2 5/6] xen: use ticket locks for spin locks
At 15:19 +0100 on 10 Apr (1428679196), David Vrabel wrote:
> Replace the byte locks with ticket locks. Ticket locks are: a) fair;
> and b) peform better when contented since they spin without an atomic
> operation.
>
> The lock is split into two ticket values: head and tail. A locker
> acquires a ticket by (atomically) increasing tail and using the
> previous tail value. A CPU holds the lock if its ticket == head. The
> lock is released by increasing head.
>
> Architectures need only provide an xadd() implementation.
I like this. Thanks for measuring the IRQ latency too -- that's the
most nervous-making part of the overall change.
+1 to Andrew's comment about needing some more barriers on ARM. In
particular read barriers during the spin and full acquire/release on
lock/unlock.
Should there be a follow-up patch that removes all the arch-specific
raw_spinlock_t stuff? Or is it still in use somewhere else?
> +static int __spin_is_locked(spinlock_t *lock)
> +{
> + return lock->tickets.head != lock->tickets.tail;
> +}
Maybe atomic_read the lock and do the comparison on the local value?
Just from an abundance of caution - can't think of an obvious reason
why this race should matter.
> +
> int _spin_is_locked(spinlock_t *lock)
> {
> check_lock(&lock->debug);
> - return _raw_spin_is_locked(&lock->raw);
> + return __spin_is_locked(lock);
> }
>
> int _spin_trylock(spinlock_t *lock)
> {
> + spinlock_tickets_t old, new;
> +
> check_lock(&lock->debug);
> - if ( !_raw_spin_trylock(&lock->raw) )
> + old.head_tail = read_atomic(&lock->tickets.head_tail);
This is common enough that we might want a helper like:
static inline spinlock_tickets_t observe_lock (spinlock_tickets_t *l)
{
smp_rmb();
return (spinlock_tickets_t) { .head_tail =
read_atomic(&l->tickets.head_tail) };
}
(or some similar formulation that's actually valid C).
> @@ -239,7 +228,7 @@ void _spin_barrier(spinlock_t *lock)
> u64 loop = 0;
>
> check_barrier(&lock->debug);
> - do { smp_mb(); loop++;} while ( _raw_spin_is_locked(&lock->raw) );
> + do { smp_mb(); loop++;} while ( __spin_is_locked(lock) );
> if ((loop > 1) && lock->profile)
> {
> lock->profile->time_block += NOW() - block;
> @@ -247,14 +236,14 @@ void _spin_barrier(spinlock_t *lock)
> }
> #else
> check_barrier(&lock->debug);
> - do { smp_mb(); } while ( _raw_spin_is_locked(&lock->raw) );
> + do { smp_mb(); } while ( __spin_is_locked(lock) );
For a contended lock this is potentially a lot stronger than the old
barrier: this waits until the lock is held _and_ no other CPU is waiting
for it. I think what we need here is:
- sample := observe_lock()
- if sample.head == sample.tail, exit immediately
- else wait until observe_lock().head != sample.head
Cheers,
Tim.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |