diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2013-08-09 10:21:49 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2013-08-09 10:53:05 -0400 |
commit | 545ac13892ab391049a92108cf59a0d05de7e28c (patch) | |
tree | e993b90bcbedd44b77c895cf7fcee89ee5fe9d51 /arch/x86/xen | |
parent | c095ba7224d8edc71dcef0d655911399a8bd4a3f (diff) |
x86, spinlock: Replace pv spinlocks with pv ticketlocks
Rather than outright replacing the entire spinlock implementation in
order to paravirtualize it, keep the ticket lock implementation but add
a couple of pvops hooks on the slow patch (long spin on lock, unlocking
a contended lock).
Ticket locks have a number of nice properties, but they also have some
surprising behaviours in virtual environments. They enforce a strict
FIFO ordering on cpus trying to take a lock; however, if the hypervisor
scheduler does not schedule the cpus in the correct order, the system can
waste a huge amount of time spinning until the next cpu can take the lock.
(See Thomas Friebel's talk "Prevent Guests from Spinning Around"
http://www.xen.org/files/xensummitboston08/LHP.pdf for more details.)
To address this, we add two hooks:
- __ticket_spin_lock which is called after the cpu has been
spinning on the lock for a significant number of iterations but has
failed to take the lock (presumably because the cpu holding the lock
has been descheduled). The lock_spinning pvop is expected to block
the cpu until it has been kicked by the current lock holder.
- __ticket_spin_unlock, which on releasing a contended lock
(there are more cpus with tail tickets), it looks to see if the next
cpu is blocked and wakes it if so.
When compiled with CONFIG_PARAVIRT_SPINLOCKS disabled, a set of stub
functions causes all the extra code to go away.
Results:
=======
setup: 32 core machine with 32 vcpu KVM guest (HT off) with 8GB RAM
base = 3.11-rc
patched = base + pvspinlock V12
+-----------------+----------------+--------+
dbench (Throughput in MB/sec. Higher is better)
+-----------------+----------------+--------+
| base (stdev %)|patched(stdev%) | %gain |
+-----------------+----------------+--------+
| 15035.3 (0.3) |15150.0 (0.6) | 0.8 |
| 1470.0 (2.2) | 1713.7 (1.9) | 16.6 |
| 848.6 (4.3) | 967.8 (4.3) | 14.0 |
| 652.9 (3.5) | 685.3 (3.7) | 5.0 |
+-----------------+----------------+--------+
pvspinlock shows benefits for overcommit ratio > 1 for PLE enabled cases,
and undercommits results are flat
Signed-off-by: Jeremy Fitzhardinge <jeremy@goop.org>
Link: http://lkml.kernel.org/r/1376058122-8248-2-git-send-email-raghavendra.kt@linux.vnet.ibm.com
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Tested-by: Attilio Rao <attilio.rao@citrix.com>
[ Raghavendra: Changed SPIN_THRESHOLD, fixed redefinition of arch_spinlock_t]
Signed-off-by: Raghavendra K T <raghavendra.kt@linux.vnet.ibm.com>
Acked-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r-- | arch/x86/xen/spinlock.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c index cf3caee356b3..d50962936af4 100644 --- a/arch/x86/xen/spinlock.c +++ b/arch/x86/xen/spinlock.c | |||
@@ -139,6 +139,9 @@ struct xen_spinlock { | |||
139 | xen_spinners_t spinners; /* count of waiting cpus */ | 139 | xen_spinners_t spinners; /* count of waiting cpus */ |
140 | }; | 140 | }; |
141 | 141 | ||
142 | static DEFINE_PER_CPU(int, lock_kicker_irq) = -1; | ||
143 | |||
144 | #if 0 | ||
142 | static int xen_spin_is_locked(struct arch_spinlock *lock) | 145 | static int xen_spin_is_locked(struct arch_spinlock *lock) |
143 | { | 146 | { |
144 | struct xen_spinlock *xl = (struct xen_spinlock *)lock; | 147 | struct xen_spinlock *xl = (struct xen_spinlock *)lock; |
@@ -167,7 +170,6 @@ static int xen_spin_trylock(struct arch_spinlock *lock) | |||
167 | } | 170 | } |
168 | 171 | ||
169 | static DEFINE_PER_CPU(char *, irq_name); | 172 | static DEFINE_PER_CPU(char *, irq_name); |
170 | static DEFINE_PER_CPU(int, lock_kicker_irq) = -1; | ||
171 | static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners); | 173 | static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners); |
172 | 174 | ||
173 | /* | 175 | /* |
@@ -354,6 +356,7 @@ static void xen_spin_unlock(struct arch_spinlock *lock) | |||
354 | if (unlikely(xl->spinners)) | 356 | if (unlikely(xl->spinners)) |
355 | xen_spin_unlock_slow(xl); | 357 | xen_spin_unlock_slow(xl); |
356 | } | 358 | } |
359 | #endif | ||
357 | 360 | ||
358 | static irqreturn_t dummy_handler(int irq, void *dev_id) | 361 | static irqreturn_t dummy_handler(int irq, void *dev_id) |
359 | { | 362 | { |
@@ -418,13 +421,14 @@ void __init xen_init_spinlocks(void) | |||
418 | return; | 421 | return; |
419 | 422 | ||
420 | BUILD_BUG_ON(sizeof(struct xen_spinlock) > sizeof(arch_spinlock_t)); | 423 | BUILD_BUG_ON(sizeof(struct xen_spinlock) > sizeof(arch_spinlock_t)); |
421 | 424 | #if 0 | |
422 | pv_lock_ops.spin_is_locked = xen_spin_is_locked; | 425 | pv_lock_ops.spin_is_locked = xen_spin_is_locked; |
423 | pv_lock_ops.spin_is_contended = xen_spin_is_contended; | 426 | pv_lock_ops.spin_is_contended = xen_spin_is_contended; |
424 | pv_lock_ops.spin_lock = xen_spin_lock; | 427 | pv_lock_ops.spin_lock = xen_spin_lock; |
425 | pv_lock_ops.spin_lock_flags = xen_spin_lock_flags; | 428 | pv_lock_ops.spin_lock_flags = xen_spin_lock_flags; |
426 | pv_lock_ops.spin_trylock = xen_spin_trylock; | 429 | pv_lock_ops.spin_trylock = xen_spin_trylock; |
427 | pv_lock_ops.spin_unlock = xen_spin_unlock; | 430 | pv_lock_ops.spin_unlock = xen_spin_unlock; |
431 | #endif | ||
428 | } | 432 | } |
429 | 433 | ||
430 | #ifdef CONFIG_XEN_DEBUG_FS | 434 | #ifdef CONFIG_XEN_DEBUG_FS |