Scalability in the Clouds! A Myth or Reality?
Sanidhya Kashyap, Changwoo Min, Taesoo Kim
Scalability in the Clouds! A Myth or Reality? Sanidhya Kashyap , - - PowerPoint PPT Presentation
Scalability in the Clouds! A Myth or Reality? Sanidhya Kashyap , Changwoo Min, Taesoo Kim Programmer's Paradise? A programmer day-to-day task: program compilation, like Linux kernel compilation. Relies on Buildbot to complete the job ASAP!
Sanidhya Kashyap, Changwoo Min, Taesoo Kim
– With respect to vertical scalability, a parallel job with no
– With respect to vertical scalability, a parallel job with no
2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 10 20 30 40 50
1 4 8 8 16 32 32 32 32 40
vCPUs
200 400 600 800 1000 1200 1400 20 40 60 80 100 120 140 160
#halt exits x 1000 #vCPUs
Guest 50 100 150 200 20 40 60 80 100 120 140 160
builds / hour
Guest
200 400 600 800 1000 1200 1400 20 40 60 80 100 120 140 160
#halt exits x 1000 #vCPUs
Guest 50 100 150 200 20 40 60 80 100 120 140 160
builds / hour
Guest
Test-and- Test-And-Set spinlock
Test-and- Test-And-Set spinlock 2.6.25 (April 2008) Ticket spinlock Fairness
3.15 (July 2014) qspinlock, variant
be merged)
Test-and- Test-And-Set spinlock 2.6.25 (April 2008) Ticket spinlock Fairness Shared cacheline contention
3.15 (July 2014) qspinlock, variant
be merged)
Test-and- Test-And-Set spinlock 2.6.25 (April 2008) Ticket spinlock Fairness Shared cacheline contention 3.11 ( 2013) Paravirtual Ticket spinlock
3.15 (July 2014) qspinlock, variant
be merged)
Test-and- Test-And-Set spinlock 2.6.25 (April 2008) Ticket spinlock Fairness Shared cacheline contention 3.11 ( 2013) Paravirtual Ticket spinlock 4.0 (May, 2015) OTicket
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
F&I(*addr) {
*addr++; return old; }
tail head
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); }
} void unlock() { head++; }
Hypervisor vCPU1 vCPU2
CPU1
Scheduled Preempted
head = 0 tail = 1 Scheduled Preempted
1 head = 0 tail = 2 Scheduled Preempted
1 2 head = 0 Scheduled Preempted
1 2 head = 1 Scheduled Preempted
2 1 head = 1 Scheduled Preempted
2 1 head = 1 Scheduled Preempted
3 tail = 4
1 2 head = 1 3 tail = 4 Scheduled Preempted
1 head = 1 3 tail = 4 Scheduled Preempted 2
3 tail = 4 Scheduled Preempted 2
3 tail = 4 Scheduled Preempted 2
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
#defj fjne SPIN_THRESHOLD (1 << 15) int head = 0; int tail = 0; int threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count);
+ slowpath_spin(tail);
}
} void unlock() {
+ wakeup_cpu(head + 1);
head++; }
– Fast path: spin till a certain
– Slow path: notify the
– Wake-up procedure to re-
– Most vCPUs trap to the hypervisor – Switching overhead between guest and host +
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
+#defj fjne EAGER_WAITERS 4 +#defj fjne TICKET_QUEUE 18 +#defj fjne SPIN_MAX_THRESHOLD 34 #defj fjne SPIN_THRESHOLD 15 int head = 0; int tail = 0; + u64 threshold = SPIN_THRESHOLD; void lock() { my_ticket = F&I(tail); + if(my_ticket - head < TICKET_QUEUE) { + threshold = SPIN_MAX_THRESHOLD + >> (dist – 1); + } for( ; ; ) { int count = threshold; do { if(my_ticket == head); goto out; } while(--count); slowpath_spin(tail); }
}
1000 100 10
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 t
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 t
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 t
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 t
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 1000 100 t+1 t+2 t+3 t
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 1000 100 t+1 t+2 t+3 t
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 1000 100 t+1 t+2 t+3 t
void unlock() { + for(count = 1; count <= EAGER_WAITERS; + ++count) { + wakeup_cpu(head + count);
}
head++; }
t+1 t+2 t+3 1000 100 t+1 t+2 t+3 t
50 100 150 200 20 40 60 80 100 120 140 160
builds / hour #vCPUs
Host Guest 200 400 600 800 1000 1200 1400 20 40 60 80 100 120 140 160
#halt exits x 1000 #vCPUs
Guest
50 100 150 200 20 40 60 80 100 120 140 160
builds / hour #vCPUs
Host Guest OTicket 200 400 600 800 1000 1200 1400 20 40 60 80 100 120 140 160
#halt exits x 1000 #vCPUs
Guest OTicket
20 40 60 80 100 120 140 160 20 40 60 80 100 120 140 160
OTicket
20 40 60 80 100 120 140 160 20 40 60 80 100 120 140 160
OTicket Opportunistic spinning
20 40 60 80 100 120 140 160 20 40 60 80 100 120 140 160
OTicket Opportunistic spinning Opportunistic wake-up
5 10 15 20 25 30 35 40 45 20 40 60 80 100 120 140 160
Guest
5 10 15 20 25 30 35 40 45 20 40 60 80 100 120 140 160
Guest Longer spinning
5 10 15 20 25 30 35 40 45 20 40 60 80 100 120 140 160
Guest OTicket Longer spinning
– Current ticket spinlock – Fast-queue spinlock
50 100 150 200 250 20 40 60 80 100 120 140 160
Guest OTicket
– Current ticket spinlock – Fast-queue spinlock
50 100 150 200 250 20 40 60 80 100 120 140 160
Guest OTicket Qspin
– Current ticket spinlock – Fast-queue spinlock Qspinlock has the same issue. Our design has been already acknowledged!
50 100 150 200 250 20 40 60 80 100 120 140 160
Guest OTicket Qspin
100 150 200 250 300 10 20 30 40 50 60 70 80
Ideal Host OTicket
Sanidhya Kashyap sanidhya@gatech.edu Changwoo Min, Taesoo Kim
https://github.com/sslab-gatech/vbench