Hello Everyone,
I recently came up with a spinlock algorithm that can adapt to
preemption, which you may be interested in.
downgrade a fair lock to an unfair lock automatically upon preemption,
and preserve the fairness otherwise.
and can be used as a complementary technique to host side optimizations
like co-scheduling and Pause-Loop Exiting.
In my experiments, it improves VM performance by 5:32X on average, when
running on a non paravirtual VMM, and by 7:91X when running on a VMM
that supports a paravirtual locking interface (using a pv preemptable
ticket spinlock), when executing a set of microbenchmarks as well as a
realistic e-commerce benchmark.
A detailed algorithm description can be found in my VEE 2013 paper,
Preemptable Ticket Spinlocks: Improving Consolidated Performance in the
Cloud
Jiannan Ouyang, John R. Lange
ouyang,jacklange@xxxxxxxxxxx <mailto:jacklange@xxxxxxxxxxx>
University of Pittsburgh
http://people.cs.pitt.edu/~ouyang/files/publication/preemptable_lock-ouyang-vee13.pdf
The patch is based on stock Linux kernel 3.5.0, and tested on kernel
3.4.41 as well.
http://www.cs.pitt.edu/~ouyang/files/preemptable_lock.tar.gz
Thanks
--Jiannan
I'm not familiar with patch over email, so I just paste it below, sorry
for the inconvenience.
======================
diff --git a/arch/x86/include/asm/spinlock.h
b/arch/x86/include/asm/spinlock.h
index b315a33..895d3b3 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -48,18 +48,35 @@
* in the high part, because a wide xadd increment of the low part
would carry
* up and contaminate the high part.
*/
+#define TIMEOUT_UNIT (1<<14)
static __always_inline void __ticket_spin_lock(arch_spinlock_t *lock)
{
register struct __raw_tickets inc = { .tail = 1 };
+ unsigned int timeout = 0;
+ __ticket_t current_head;
inc = xadd(&lock->tickets, inc);
-
+ if (likely(inc.head == inc.tail))
+ goto spin;
+
+ timeout = TIMEOUT_UNIT * (inc.tail - inc.head);
+ do {
+ current_head = ACCESS_ONCE(lock->tickets.head);
+ if (inc.tail <= current_head) {
+ goto spin;
+ } else if (inc.head != current_head) {
+ inc.head = current_head;
+ timeout = TIMEOUT_UNIT * (inc.tail - inc.head);