All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Cooper <andrew.cooper3@citrix.com>
To: David Vrabel <david.vrabel@citrix.com>, xen-devel@lists.xenproject.org
Cc: Tim Deegan <tim@xen.org>, Keir Fraser <keir@xen.org>,
	Ian Campbell <ian.campbell@citrix.com>,
	Jan Beulich <jbeulich@suse.com>,
	Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Subject: Re: [PATCHv2 5/6] xen: use ticket locks for spin locks
Date: Fri, 10 Apr 2015 16:29:09 +0100	[thread overview]
Message-ID: <5527EC45.2030203@citrix.com> (raw)
In-Reply-To: <1428675597-28465-6-git-send-email-david.vrabel@citrix.com>

On 10/04/15 15:19, 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.
>
> Signed-off-by: David Vrabel <david.vrabel@citrix.com>

While I think this implementation is fine for x86, ARM almost certainly
requires some smp barriers.

~Andrew

> ---
>  xen/common/spinlock.c      |   80 +++++++++++++++++++++-----------------------
>  xen/include/xen/spinlock.h |   16 ++++++---
>  2 files changed, 50 insertions(+), 46 deletions(-)
>
> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
> index 0c4289c..99163c5 100644
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -138,14 +138,17 @@ void spin_debug_disable(void)
>  
>  void _spin_lock(spinlock_t *lock)
>  {
> +    spinlock_tickets_t tickets = { .tail = 1, };
>      LOCK_PROFILE_VAR;
>  
>      check_lock(&lock->debug);
> -    while ( unlikely(!_raw_spin_trylock(&lock->raw)) )
> +    tickets.head_tail = xadd(&lock->tickets, tickets.head_tail);
> +    if ( tickets.tail != read_atomic(&lock->tickets.head) )
>      {
>          LOCK_PROFILE_BLOCK;
> -        while ( likely(_raw_spin_is_locked(&lock->raw)) )
> +        do {
>              cpu_relax();
> +        } while ( tickets.tail != read_atomic(&lock->tickets.head) );
>      }
>      LOCK_PROFILE_GOT;
>      preempt_disable();
> @@ -153,40 +156,17 @@ void _spin_lock(spinlock_t *lock)
>  
>  void _spin_lock_irq(spinlock_t *lock)
>  {
> -    LOCK_PROFILE_VAR;
> -
>      ASSERT(local_irq_is_enabled());
>      local_irq_disable();
> -    check_lock(&lock->debug);
> -    while ( unlikely(!_raw_spin_trylock(&lock->raw)) )
> -    {
> -        LOCK_PROFILE_BLOCK;
> -        local_irq_enable();
> -        while ( likely(_raw_spin_is_locked(&lock->raw)) )
> -            cpu_relax();
> -        local_irq_disable();
> -    }
> -    LOCK_PROFILE_GOT;
> -    preempt_disable();
> +    _spin_lock(lock);
>  }
>  
>  unsigned long _spin_lock_irqsave(spinlock_t *lock)
>  {
>      unsigned long flags;
> -    LOCK_PROFILE_VAR;
>  
>      local_irq_save(flags);
> -    check_lock(&lock->debug);
> -    while ( unlikely(!_raw_spin_trylock(&lock->raw)) )
> -    {
> -        LOCK_PROFILE_BLOCK;
> -        local_irq_restore(flags);
> -        while ( likely(_raw_spin_is_locked(&lock->raw)) )
> -            cpu_relax();
> -        local_irq_disable();
> -    }
> -    LOCK_PROFILE_GOT;
> -    preempt_disable();
> +    _spin_lock(lock);
>      return flags;
>  }
>  
> @@ -194,35 +174,44 @@ void _spin_unlock(spinlock_t *lock)
>  {
>      preempt_enable();
>      LOCK_PROFILE_REL;
> -    _raw_spin_unlock(&lock->raw);
> +    lock->tickets.head++;
>  }
>  
>  void _spin_unlock_irq(spinlock_t *lock)
>  {
> -    preempt_enable();
> -    LOCK_PROFILE_REL;
> -    _raw_spin_unlock(&lock->raw);
> +    _spin_unlock(lock);
>      local_irq_enable();
>  }
>  
>  void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
>  {
> -    preempt_enable();
> -    LOCK_PROFILE_REL;
> -    _raw_spin_unlock(&lock->raw);
> +    _spin_unlock(lock);
>      local_irq_restore(flags);
>  }
>  
> +static int __spin_is_locked(spinlock_t *lock)
> +{
> +    return lock->tickets.head != lock->tickets.tail;
> +}
> +
>  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);
> +    if ( old.head != old.tail )
> +        return 0;
> +    new = old;
> +    new.tail++;
> +    if ( cmpxchg(&lock->tickets.head_tail, old.head_tail, new.head_tail)
> +         != old.head_tail )
>          return 0;
>  #ifdef LOCK_PROFILE
>      if (lock->profile)
> @@ -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) );
>  #endif
>      smp_mb();
>  }
>  
>  int _spin_trylock_recursive(spinlock_t *lock)
>  {
> -    int cpu = smp_processor_id();
> +    unsigned int cpu = smp_processor_id();
>  
>      /* Don't allow overflow of recurse_cpu field. */
>      BUILD_BUG_ON(NR_CPUS > 0xfffu);
> @@ -277,8 +266,17 @@ int _spin_trylock_recursive(spinlock_t *lock)
>  
>  void _spin_lock_recursive(spinlock_t *lock)
>  {
> -    while ( !spin_trylock_recursive(lock) )
> -        cpu_relax();
> +    unsigned int cpu = smp_processor_id();
> +
> +    if ( likely(lock->recurse_cpu != cpu) )
> +    {
> +        spin_lock(lock);
> +        lock->recurse_cpu = cpu;
> +    }
> +
> +    /* We support only fairly shallow recursion, else the counter overflows. */
> +    ASSERT(lock->recurse_cnt < 0xfu);
> +    lock->recurse_cnt++;
>  }
>  
>  void _spin_unlock_recursive(spinlock_t *lock)
> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
> index eda9b2e..bafbc74 100644
> --- a/xen/include/xen/spinlock.h
> +++ b/xen/include/xen/spinlock.h
> @@ -80,8 +80,7 @@ struct lock_profile_qhead {
>      static struct lock_profile *__lock_profile_##name                         \
>      __used_section(".lockprofile.data") =                                     \
>      &__lock_profile_data_##name
> -#define _SPIN_LOCK_UNLOCKED(x) { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0,          \
> -                                 _LOCK_DEBUG, x }
> +#define _SPIN_LOCK_UNLOCKED(x) { { 0 }, 0xfffu, 0, _LOCK_DEBUG, x }
>  #define SPIN_LOCK_UNLOCKED _SPIN_LOCK_UNLOCKED(NULL)
>  #define DEFINE_SPINLOCK(l)                                                    \
>      spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
> @@ -117,8 +116,7 @@ extern void spinlock_profile_reset(unsigned char key);
>  
>  struct lock_profile_qhead { };
>  
> -#define SPIN_LOCK_UNLOCKED                                                    \
> -    { _RAW_SPIN_LOCK_UNLOCKED, 0xfffu, 0, _LOCK_DEBUG }
> +#define SPIN_LOCK_UNLOCKED { { 0 }, 0xfffu, 0, _LOCK_DEBUG }
>  #define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
>  
>  #define spin_lock_init_prof(s, l) spin_lock_init(&((s)->l))
> @@ -127,8 +125,16 @@ struct lock_profile_qhead { };
>  
>  #endif
>  
> +typedef union {
> +    u32 head_tail;
> +    struct {
> +        u16 head;
> +        u16 tail;
> +    };
> +} spinlock_tickets_t;
> +
>  typedef struct spinlock {
> -    raw_spinlock_t raw;
> +    spinlock_tickets_t tickets;
>      u16 recurse_cpu:12;
>      u16 recurse_cnt:4;
>      struct lock_debug debug;

  reply	other threads:[~2015-04-10 15:30 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-10 14:19 [PATCHv2 0/6] Use ticket locks for spinlocks David Vrabel
2015-04-10 14:19 ` [PATCHv2 1/6] x86/hvm: don't include asm/spinlock.h David Vrabel
2015-04-10 15:24   ` Andrew Cooper
2015-04-13 13:13     ` David Vrabel
2015-04-13 13:15       ` Andrew Cooper
2015-04-16 11:09   ` Tim Deegan
2015-04-10 14:19 ` [PATCHv2 2/6] x86/mtrr: include asm/atomic.h David Vrabel
2015-04-10 15:25   ` Andrew Cooper
2015-04-16 11:10   ` Tim Deegan
2015-04-10 14:19 ` [PATCHv2 3/6] xen: generic xadd() for ticket locks David Vrabel
2015-04-14 13:17   ` Ian Campbell
2015-04-14 16:37     ` David Vrabel
2015-04-15  8:34       ` Ian Campbell
2015-04-16 11:13   ` Tim Deegan
2015-04-16 15:28   ` Jan Beulich
2015-04-17 12:32     ` Ian Campbell
2015-04-17 12:33       ` Ian Campbell
2015-04-17 12:34       ` David Vrabel
2015-04-17 13:09         ` Ian Campbell
2015-04-17 13:13           ` David Vrabel
2015-04-10 14:19 ` [PATCHv2 4/6] x86: provide xadd() David Vrabel
2015-04-16 11:25   ` Tim Deegan
2015-04-16 11:38     ` David Vrabel
2015-04-16 11:41       ` Tim Deegan
2015-04-16 11:49     ` Jan Beulich
2015-04-16 12:49       ` Tim Deegan
2015-04-16 12:55         ` Ian Campbell
2015-04-16 13:19           ` Jan Beulich
2015-04-16 14:07             ` Ian Campbell
2015-04-16 14:09               ` Ian Campbell
2015-04-16 12:00     ` Ian Campbell
2015-04-10 14:19 ` [PATCHv2 5/6] xen: use ticket locks for spin locks David Vrabel
2015-04-10 15:29   ` Andrew Cooper [this message]
2015-04-10 16:44   ` Boris Ostrovsky
2015-04-10 17:29     ` David Vrabel
2015-04-10 17:58       ` Boris Ostrovsky
2015-04-16 12:03   ` Tim Deegan
2015-04-16 12:46     ` David Vrabel
2015-04-16 12:50       ` Tim Deegan
2015-04-16 13:32     ` Jan Beulich
2015-04-21  9:59     ` David Vrabel
2015-04-10 14:19 ` [PATCHv2 6/6] x86, arm: remove asm/spinlock.h from all architectures David Vrabel
2015-04-16 12:51   ` Tim Deegan
2015-04-16 15:29   ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5527EC45.2030203@citrix.com \
    --to=andrew.cooper3@citrix.com \
    --cc=david.vrabel@citrix.com \
    --cc=ian.campbell@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=keir@xen.org \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=tim@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.