Skip to contentSkip to conversation

kvm: Improving directed yield in PLE handler

RFC PATCH Superseded Raghavendra K T 9 participants 50 messages Jul 9, 2012 – Jul 12, 2012

Subsystems (5)
x86 KVM s390 KVM x86 +1 more subsystems

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

cover kvm: Improving directed yield in PLE handler

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Problem is, for large vcpu guests, we have more probability of yielding to a bad vcpu. We are not able to prevent directed yield to same guy who has done PL exit recently, who perhaps spins again and wastes CPU.

Fix that by keeping track of who has done PL exit. So The Algorithm in series give chance to a VCPU which has:

(a) Not done PLE exit at all (probably he is preempted lock-holder)

(b) VCPU skipped in last iteration because it did PL exit, and probably has become eligible now (next eligible lock holder)

Future enhancemnets:
(1) Currently we have a boolean to decide on eligibility of vcpu. It would be nice if I get feedback on guest (>32 vcpu) whether we can improve better with integer counter. (with counter = say f(log n )).

(2) We have not considered system load during iteration of vcpu. With that information we can limit the scan and also decide whether schedule() is better. [ I am able to use #kicked vcpus to decide on this But may be there are better ideas like information from global loadavg.]

(3) We can exploit this further with PV patches since it also knows about next eligible lock-holder.

Summary: There is a huge improvement for moderate / no overcommit scenario
for kvm based guest on PLE machine (which is difficult ;) ).

Result:
Base : kernel 3.5.0-rc5 with Rik's Ple handler fix

Machine : Intel(R) Xeon(R) CPU X7560 @ 2.27GHz, 4 numa node, 256GB RAM,
32 core machine

Host: enterprise linux gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
with test kernels

Guest: fedora 16 with 32 vcpus 8GB memory.

Benchmarks:
1) kernbench: kernbench-0.5 (kernbench -f -H -M -o 2*vcpu) Very first run in kernbench is omitted.

2) sysbench: 0.4.12
sysbench --test=oltp --db-driver=pgsql prepare
sysbench --num-threads=2*vcpu --max-requests=100000 --test=oltp --oltp-table-size=500000 --db-driver=pgsql --oltp-read-only run Note that driver for this pgsql.

3) ebizzy: release 0.3
cmd: ebizzy -S 120

1) kernbench (time in sec lesser is better)

+-----------+-----------+-----------+------------+-----------+
   base_rik    stdev       patched      stdev       %improve
+-----------+-----------+-----------+------------+-----------+
1x  49.2300     1.0171	    38.3792     1.3659	   28.27261%
2x  91.9358     1.7768	    85.8842     1.6654      7.04623%
+-----------+-----------+-----------+------------+-----------+

2) sysbench (time in sec lesser is better)

+-----------+-----------+-----------+------------+-----------+
   base_rik    stdev       patched      stdev       %improve
+-----------+-----------+-----------+------------+-----------+
1x  12.1623     0.0942	    12.1674     0.3126	  -0.04192%
2x  14.3069     0.8520	    14.1879     0.6811	   0.83874%
+-----------+-----------+-----------+------------+-----------+

Note that 1x scenario differs in only third decimal place and degradation/improvemnet for sysbench will not be seen even with higher confidence interval.

3) ebizzy (records/sec more is better)

+-----------+-----------+-----------+------------+-----------+
   base_rik    stdev       patched      stdev       %improve
+-----------+-----------+-----------+------------+-----------+
1x  1129.2500  28.6793    2316.6250    53.0066     105.14722%
2x  1892.3750  75.1112    2386.5000   168.8033      26.11137%
+-----------+-----------+-----------+------------+-----------+

kernbench 1x: 4 fast runs = 12 runs avg
kernbench 2x: 4 fast runs = 12 runs avg

sysbench 1x: 8runs avg
sysbench 2x: 8runs avg

ebizzy 1x: 8runs avg
ebizzy 2x: 8runs avg

Thanks Vatsa and Srikar for brainstorming discussions regarding optimizations.

Raghavendra K T (2):
kvm vcpu: Note down pause loop exit
kvm PLE handler: Choose better candidate for directed yield

 arch/s390/include/asm/kvm_host.h |    5 +++++
 arch/x86/include/asm/kvm_host.h  |    9 ++++++++-
 arch/x86/kvm/svm.c               |    1 +
 arch/x86/kvm/vmx.c               |    1 +
 arch/x86/kvm/x86.c               |   18 +++++++++++++++++-
 virt/kvm/kvm_main.c              |    3 +++
 6 files changed, 35 insertions(+), 2 deletions(-)
#1 lore raw

RFC PATCH 1/2 kvm vcpu: Note down pause loop exit

Noting pause loop exited vcpu helps in filtering right candidate to yield. Yielding to same vcpu may result in more wastage of cpu.

From: Raghavendra K T <[email protected]>

---
 arch/x86/include/asm/kvm_host.h |    7 +++++++
 arch/x86/kvm/svm.c              |    1 +
 arch/x86/kvm/vmx.c              |    1 +
 arch/x86/kvm/x86.c              |    4 +++-
 4 files changed, 12 insertions(+), 1 deletions(-)
arch/x86/include/asm/kvm_host.h +7 -0
index db7c1f2..857ca68 100644
@@ -484,6 +484,13 @@ struct kvm_vcpu_arch {
 		u64 length;
 		u64 status;
 	} osvw;
+
+	/* Pause loop exit optimization */
+	struct {
+		bool pause_loop_exited;
+		bool dy_eligible;
+	} plo;
+
 };
 
 struct kvm_lpage_info {
arch/x86/kvm/svm.c +1 -0
index f75af40..a492f5d 100644
@@ -3264,6 +3264,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
 
 static int pause_interception(struct vcpu_svm *svm)
 {
+	svm->vcpu.arch.plo.pause_loop_exited = true;
 	kvm_vcpu_on_spin(&(svm->vcpu));
 	return 1;
 }
arch/x86/kvm/vmx.c +1 -0
index 32eb588..600fb3c 100644
@@ -4945,6 +4945,7 @@ out:
 static int handle_pause(struct kvm_vcpu *vcpu)
 {
 	skip_emulated_instruction(vcpu);
+	vcpu->arch.plo.pause_loop_exited = true;
 	kvm_vcpu_on_spin(vcpu);
 
 	return 1;
arch/x86/kvm/x86.c +3 -1
index be6d549..07dbd14 100644
@@ -5331,7 +5331,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 	if (req_immediate_exit)
 		smp_send_reschedule(vcpu->cpu);
-
+	vcpu->arch.plo.pause_loop_exited = false;
 	kvm_guest_enter();
 
 	if (unlikely(vcpu->arch.switch_db_regs)) {
@@ -6168,6 +6168,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 	BUG_ON(vcpu->kvm == NULL);
 	kvm = vcpu->kvm;
 
+	vcpu->arch.plo.pause_loop_exited = false;
+	vcpu->arch.plo.dy_eligible = true;
 	vcpu->arch.emulate_ctxt.ops = &emulate_ops;
 	if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_bsp(vcpu))
 		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
#2 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

Quoted 7 lines · Raghavendra K T

Noting pause loop exited vcpu helps in filtering right candidate to yield. Yielding to same vcpu may result in more wastage of cpu.

From: Raghavendra K T<[email protected]>
---

Oops. Sorry some how sign-off and from interchanged.. interchanged

#3 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

In reply to Raghavendra K T

arch/x86/include/asm/kvm_host.h struct kvm_vcpu_arch { · line 492

Quoted 10 lines · Raghavendra K T
arch/x86/include/asm/kvm_host.h +6 -0
@@ -484,6 +484,13 @@ struct kvm_vcpu_arch {
  		u64 length;
  		u64 status;
  	} osvw;
+
+	/* Pause loop exit optimization */
+	struct {
+		bool pause_loop_exited;
+		bool dy_eligible;
+	} plo;

I know kvm_vcpu_arch is traditionally not a well documented structure, but it would be really nice if each variable inside this sub-structure could get some documentation.

Also, do we really want to introduce another acronym here?

Or would we be better off simply calling this struct .ple, since that is a name people are already familiar with.

Signature · 1 line
All rights reversed
#4 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

Quoted 16 lines · Rik van Riel

arch/x86/include/asm/kvm_host.h struct kvm_vcpu_arch { · line 492

Quoted 10 lines · Raghavendra K T
arch/x86/include/asm/kvm_host.h +6 -0
@@ -484,6 +484,13 @@ struct kvm_vcpu_arch {
 u64 length;
 u64 status;
 } osvw;
+
+ /* Pause loop exit optimization */
+ struct {
+ bool pause_loop_exited;
+ bool dy_eligible;
+ } plo;

I know kvm_vcpu_arch is traditionally not a well documented structure, but it would be really nice if each variable inside this sub-structure could get some documentation.

Sure. Will document it.

Quoted 5 lines

Also, do we really want to introduce another acronym here?

Or would we be better off simply calling this struct .ple, since that is a name people are already familiar with.

Yes. it makes sense to have .ple.

#5 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

In reply to Raghavendra K T
Quoted 24 lines · Raghavendra K T

Noting pause loop exited vcpu helps in filtering right candidate to yield. Yielding to same vcpu may result in more wastage of cpu.

struct kvm_lpage_info {

arch/x86/kvm/svm.c +1 -0
index f75af40..a492f5d 100644
@@ -3264,6 +3264,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
 
 static int pause_interception(struct vcpu_svm *svm)
 {
+	svm->vcpu.arch.plo.pause_loop_exited = true;
 	kvm_vcpu_on_spin(&(svm->vcpu));
 	return 1;
 }
arch/x86/kvm/vmx.c +0 -0
index 32eb588..600fb3c 100644

arch/x86/kvm/vmx.c out: · line 4950

Quoted 6 lines
arch/x86/kvm/vmx.c +1 -0
@@ -4945,6 +4945,7 @@ out:
 static int handle_pause(struct kvm_vcpu *vcpu)
 {
 	skip_emulated_instruction(vcpu);
+	vcpu->arch.plo.pause_loop_exited = true;
 	kvm_vcpu_on_spin(vcpu);
 

This code is duplicated. Should we move it to kvm_vcpu_on_spin?

That means the .plo structure needs to be in common code, but that's not too bad perhaps.

arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5334

Quoted 9 lines

index be6d549..07dbd14 100644

arch/x86/kvm/x86.c +1 -1
@@ -5331,7 +5331,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 	if (req_immediate_exit)
 		smp_send_reschedule(vcpu->cpu);
-
+	vcpu->arch.plo.pause_loop_exited = false;

This adds some tiny overhead to vcpu entry. You could remove it by using the vcpu->requests mechanism to clear the flag, since vcpu->requests is already checked on every entry.

Quoted 2 lines
arch/x86/kvm/x86.c +0 -0
 	kvm_guest_enter();
 
Signature · 1 line
error compiling committee.c: too many arguments to function
#6 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

Quoted 34 lines · Avi Kivity
Quoted 24 lines · Raghavendra K T

Noting pause loop exited vcpu helps in filtering right candidate to yield. Yielding to same vcpu may result in more wastage of cpu.

  struct kvm_lpage_info {
arch/x86/kvm/svm.c +1 -0
index f75af40..a492f5d 100644
@@ -3264,6 +3264,7 @@ static int interrupt_window_interception(struct vcpu_svm *svm)
 
  static int pause_interception(struct vcpu_svm *svm)
  {
+	svm->vcpu.arch.plo.pause_loop_exited = true;
  	kvm_vcpu_on_spin(&(svm->vcpu));
  	return 1;
  }
arch/x86/kvm/vmx.c +0 -0
index 32eb588..600fb3c 100644

arch/x86/kvm/vmx.c out: · line 4950

Quoted 6 lines
arch/x86/kvm/vmx.c +1 -0
@@ -4945,6 +4945,7 @@ out:
  static int handle_pause(struct kvm_vcpu *vcpu)
  {
  	skip_emulated_instruction(vcpu);
+	vcpu->arch.plo.pause_loop_exited = true;
  	kvm_vcpu_on_spin(vcpu);
 

This code is duplicated. Should we move it to kvm_vcpu_on_spin?

Quoted 3 lines

That means the .plo structure needs to be in common code, but that's not too bad perhaps.

Since PLE is very much tied to x86, and proposed changes are very much specific to PLE handler, I thought it is better to make arch specific.

So do you think it is good to move inside vcpu_on_spin and make ple structure belong to common code?

Quoted 5 lines
Quoted 5 lines

index be6d549..07dbd14 100644

arch/x86/kvm/x86.c +0 -0
@@ -5331,7 +5331,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
Quoted 8 lines

arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5334

Quoted 4 lines
arch/x86/kvm/x86.c +1 -1
  	if (req_immediate_exit)
  		smp_send_reschedule(vcpu->cpu);
-
+	vcpu->arch.plo.pause_loop_exited = false;

This adds some tiny overhead to vcpu entry. You could remove it by using the vcpu->requests mechanism to clear the flag, since vcpu->requests is already checked on every entry.

So IIUC, let's have request bit for indicating PLE,

pause_interception() /handle_pause()
{
make_request(PLE_REQUEST)
vcpu_on_spin()

}

check_eligibility()
{
!test_request(PLE_REQUEST) || ( test_request(PLE_REQUEST) &&
dy_eligible())
.
.
}

vcpu_run()
{

check_request(PLE_REQUEST)
.
.
}

Is this is the expected flow you had in mind?

[ But my only concern was not resetting for cases where we do not do guest_enter(). will test how that goes].

Quoted 3 lines
Quoted 3 lines
arch/x86/kvm/x86.c +0 -0
  	kvm_guest_enter();
 
#7 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

Quoted 41 lines · Raghavendra K T
Quoted 36 lines · Avi Kivity
Quoted 26 lines · Raghavendra K T

Noting pause loop exited vcpu helps in filtering right candidate to yield.
Yielding to same vcpu may result in more wastage of cpu.

  struct kvm_lpage_info {
arch/x86/kvm/svm.c +1 -0
index f75af40..a492f5d 100644
@@ -3264,6 +3264,7 @@ static int interrupt_window_interception(struct
 vcpu_svm *svm)
 
  static int pause_interception(struct vcpu_svm *svm)
  {
+    svm->vcpu.arch.plo.pause_loop_exited = true;
      kvm_vcpu_on_spin(&(svm->vcpu));
      return 1;
  }
arch/x86/kvm/vmx.c +0 -0
index 32eb588..600fb3c 100644

arch/x86/kvm/vmx.c out: · line 4950

Quoted 6 lines
arch/x86/kvm/vmx.c +1 -0
@@ -4945,6 +4945,7 @@ out:
  static int handle_pause(struct kvm_vcpu *vcpu)
  {
      skip_emulated_instruction(vcpu);
+    vcpu->arch.plo.pause_loop_exited = true;
      kvm_vcpu_on_spin(vcpu);
 

This code is duplicated. Should we move it to kvm_vcpu_on_spin?

Quoted 3 lines

That means the .plo structure needs to be in common code, but that's not too bad perhaps.

Quoted 5 lines

Since PLE is very much tied to x86, and proposed changes are very much specific to PLE handler, I thought it is better to make arch specific.

So do you think it is good to move inside vcpu_on_spin and make ple structure belong to common code?

See the discussion with Christian. PLE is tied to x86, but cpu_relax() and facilities to trap it are not.

Quoted 25 lines
Quoted 4 lines

This adds some tiny overhead to vcpu entry. You could remove it by using the vcpu->requests mechanism to clear the flag, since vcpu->requests is already checked on every entry.

So IIUC, let's have request bit for indicating PLE,

pause_interception() /handle_pause()
{
make_request(PLE_REQUEST)
vcpu_on_spin()

}

check_eligibility()
{
!test_request(PLE_REQUEST) || ( test_request(PLE_REQUEST) &&
dy_eligible())
.
.
}

vcpu_run()
{

Quoted 6 lines

check_request(PLE_REQUEST)
.
.
}

Is this is the expected flow you had in mind?

Yes, something like that.

Quoted 3 lines

[ But my only concern was not resetting for cases where we do not do guest_enter(). will test how that goes].

Hm, suppose we're the next-in-line for a ticket lock and exit due to PLE. The lock holder completes and unlocks, which really assigns the lock to us. So now we are the lock owner, yet we are marked as don't yield-to-us in the PLE code.

Signature · 1 line
error compiling committee.c: too many arguments to function
#8 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

Quoted 42 lines · Avi Kivity
Quoted 41 lines · Raghavendra K T
Quoted 39 lines · Avi Kivity
Quoted 26 lines · Raghavendra K T

Noting pause loop exited vcpu helps in filtering right candidate to yield.
Yielding to same vcpu may result in more wastage of cpu.

   struct kvm_lpage_info {
arch/x86/kvm/svm.c +1 -0
index f75af40..a492f5d 100644
@@ -3264,6 +3264,7 @@ static int interrupt_window_interception(struct
 vcpu_svm *svm)
 
   static int pause_interception(struct vcpu_svm *svm)
   {
+    svm->vcpu.arch.plo.pause_loop_exited = true;
       kvm_vcpu_on_spin(&(svm->vcpu));
       return 1;
   }
arch/x86/kvm/vmx.c +0 -0
index 32eb588..600fb3c 100644

arch/x86/kvm/vmx.c out: · line 4950

Quoted 6 lines
arch/x86/kvm/vmx.c +1 -0
@@ -4945,6 +4945,7 @@ out:
   static int handle_pause(struct kvm_vcpu *vcpu)
   {
       skip_emulated_instruction(vcpu);
+    vcpu->arch.plo.pause_loop_exited = true;
       kvm_vcpu_on_spin(vcpu);
 

This code is duplicated. Should we move it to kvm_vcpu_on_spin?

That means the .plo structure needs to be in common code, but that's not too bad perhaps.

Quoted 8 lines
Quoted 5 lines

Since PLE is very much tied to x86, and proposed changes are very much specific to PLE handler, I thought it is better to make arch specific.

So do you think it is good to move inside vcpu_on_spin and make ple structure belong to common code?

See the discussion with Christian. PLE is tied to x86, but cpu_relax() and facilities to trap it are not.

Yep.

Quoted 26 lines
Quoted 26 lines
Quoted 5 lines

This adds some tiny overhead to vcpu entry. You could remove it by using the vcpu->requests mechanism to clear the flag, since vcpu->requests is already checked on every entry.

So IIUC, let's have request bit for indicating PLE,

pause_interception() /handle_pause()
{
make_request(PLE_REQUEST)
vcpu_on_spin()

}

check_eligibility()
{
!test_request(PLE_REQUEST) || ( test_request(PLE_REQUEST)&&
dy_eligible())
.
.
}

vcpu_run()
{

Quoted 8 lines
Quoted 6 lines

check_request(PLE_REQUEST)
.
.
}

Is this is the expected flow you had in mind?

Yes, something like that.

ok..

Quoted 9 lines
Quoted 4 lines

[ But my only concern was not resetting for cases where we do not do guest_enter(). will test how that goes].

Hm, suppose we're the next-in-line for a ticket lock and exit due to PLE. The lock holder completes and unlocks, which really assigns the lock to us. So now we are the lock owner, yet we are marked as don't yield-to-us in the PLE code.

Yes.. off-topic but that is solved by kicked flag in PV spinlocks.

#9 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

----- Original Message -----

Quoted 11 lines
Quoted 8 lines

Hm, suppose we're the next-in-line for a ticket lock and exit due to
PLE. The lock holder completes and unlocks, which really assigns the
lock to us. So now we are the lock owner, yet we are marked as don't
yield-to-us in the PLE code.

Yes.. off-topic but that is solved by kicked flag in PV spinlocks.

Yeah, this is a different, but related, topic. pvticketlocks not only help yield spinning vcpus, but also allow the use of ticketlocks for the guaranteed fairness. If we want that fairness we'll always need some pv-ness, even if it's a mostly PLE solution. I see that as a reasonable reason to take the pvticketlock series, assuming it performs at least as well as PLE. The following options have all been brought up at some point by various people, and all have their own pluses and minuses;

PLE-only best-effort:
+ hardware-only, algorithm improvements can be made independent of guest OSes
- has limited info about spinning vcpus, making it hard to improve the algorithm (improved with an auto-adjusting ple_window?)
- perf enhancement/degradation is workload/ple_window dependant
- impossible? to guarantee FIFO order

pvticketlocks:
- have to maintain pv code, both hosts and guests
+ perf is only workload dependant (should disable ple to avoid interference?)
+ guarantees FIFO order
+ can fall-back on PLE-only if the guest doesn't support it

hybrid:
+ takes advantage of the hw support
- still requires host and guest pv code
- will likely make perf dependant on ple_window again
+ guarantees FIFO order

???: did I miss any?

I think more benchmarking of PLE vs. pvticketlocks is needed, which I'm working on. If we see that it performs just as well or better, then IMHO, we should consider committing Raghu's latest version of the pvticketlock series, perhaps with and additional patch that auto-disables PLE when pvticketlocks are enabled.

Drew

#10 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

In reply to Raghavendra K T
Quoted 23 lines · Raghavendra K T
Quoted 4 lines · Avi Kivity

This adds some tiny overhead to vcpu entry. You could remove it by using the vcpu->requests mechanism to clear the flag, since vcpu->requests is already checked on every entry.

So IIUC, let's have request bit for indicating PLE,

pause_interception() /handle_pause()
{
make_request(PLE_REQUEST)
vcpu_on_spin()

}

check_eligibility()
{
!test_request(PLE_REQUEST) || ( test_request(PLE_REQUEST) &&
dy_eligible())
.
.
}

Quoted 5 lines

vcpu_run()
{

check_request(PLE_REQUEST)

I know check_request will clear PLE_REQUEST, but you just need a clear_request here, right?

#11 lore raw

Re: [PATCH RFC 1/2] kvm vcpu: Note down pause loop exit

Quoted 24 lines · Nikunj A Dadhania
Quoted 23 lines · Raghavendra K T
Quoted 4 lines · Avi Kivity

This adds some tiny overhead to vcpu entry. You could remove it by using the vcpu->requests mechanism to clear the flag, since vcpu->requests is already checked on every entry.

So IIUC, let's have request bit for indicating PLE,

pause_interception() /handle_pause()

{
   make_request(PLE_REQUEST)
   vcpu_on_spin()

}

check_eligibility()

   {
   !test_request(PLE_REQUEST) || ( test_request(PLE_REQUEST)&&

dy_eligible())
.
.
}

Quoted 8 lines
Quoted 5 lines

vcpu_run()
{

check_request(PLE_REQUEST)

I know check_request will clear PLE_REQUEST, but you just need a clear_request here, right?

Yes. tried to use check_request for clearing. But I ended up in different implementation. (latest thread)

#12 lore raw

RFC PATCH 2/2 kvm PLE handler: Choose better candidate for directed yield

In reply to Raghavendra K T

From: Raghavendra K T <[email protected]>

Currently PLE handler can repeatedly do a directed yield to same vcpu that has recently done PL exit. This can degrade the performance Try to yield to most eligible guy instead, by alternate yielding.

Precisely, give chance to a VCPU which has:
(a) Not done PLE exit at all (probably he is preempted lock-holder)
(b) VCPU skipped in last iteration because it did PL exit, and probably has become eligible now (next eligible lock holder)

---
 arch/s390/include/asm/kvm_host.h |    5 +++++
 arch/x86/include/asm/kvm_host.h  |    2 +-
 arch/x86/kvm/x86.c               |   14 ++++++++++++++
 virt/kvm/kvm_main.c              |    3 +++
 4 files changed, 23 insertions(+), 1 deletions(-)
arch/s390/include/asm/kvm_host.h +5 -0
index dd17537..884f2c4 100644
@@ -256,5 +256,10 @@ struct kvm_arch{
 	struct gmap *gmap;
 };
 
+static inline bool kvm_arch_vcpu_check_and_update_eligible(struct kvm_vcpu *v)
+{
+	return true;
+}
+
 extern int sie64a(struct kvm_s390_sie_block *, u64 *);
 #endif
arch/x86/include/asm/kvm_host.h +1 -1
index 857ca68..ce01db3 100644
@@ -962,7 +962,7 @@ extern bool kvm_find_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn);
 void kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err);
 
 int kvm_is_in_guest(void);
-
+bool kvm_arch_vcpu_check_and_update_eligible(struct kvm_vcpu *vcpu);
 void kvm_pmu_init(struct kvm_vcpu *vcpu);
 void kvm_pmu_destroy(struct kvm_vcpu *vcpu);
 void kvm_pmu_reset(struct kvm_vcpu *vcpu);
arch/x86/kvm/x86.c +14 -0
index 07dbd14..24ceae8 100644
@@ -6623,6 +6623,20 @@ bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu)
 			kvm_x86_ops->interrupt_allowed(vcpu);
 }
 
+bool kvm_arch_vcpu_check_and_update_eligible(struct kvm_vcpu *vcpu)
+{
+	bool eligible;
+
+	eligible = !vcpu->arch.plo.pause_loop_exited ||
+			(vcpu->arch.plo.pause_loop_exited &&
+			 vcpu->arch.plo.dy_eligible);
+
+	if (vcpu->arch.plo.pause_loop_exited)
+		vcpu->arch.plo.dy_eligible = !vcpu->arch.plo.dy_eligible;
+
+	return eligible;
+}
+
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_exit);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_inj_virq);
 EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_page_fault);
virt/kvm/kvm_main.c +3 -0
index 7e14068..519321a 100644
@@ -1595,6 +1595,9 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
 				continue;
 			if (waitqueue_active(&vcpu->wq))
 				continue;
+			if (!kvm_arch_vcpu_check_and_update_eligible(vcpu)) {
+				continue;
+			}
 			if (kvm_vcpu_yield_to(vcpu)) {
 				kvm->last_boosted_vcpu = i;
 				yielded = 1;
#13 lore raw

Re: [PATCH RFC 2/2] kvm PLE handler: Choose better candidate for directed yield

arch/x86/kvm/x86.c bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu) · line 6638

Quoted 13 lines · Raghavendra K T
arch/x86/kvm/x86.c +13 -0
+bool kvm_arch_vcpu_check_and_update_eligible(struct kvm_vcpu *vcpu)
+{
+	bool eligible;
+
+	eligible = !vcpu->arch.plo.pause_loop_exited ||
+			(vcpu->arch.plo.pause_loop_exited&&
+			 vcpu->arch.plo.dy_eligible);
+
+	if (vcpu->arch.plo.pause_loop_exited)
+		vcpu->arch.plo.dy_eligible = !vcpu->arch.plo.dy_eligible;
+
+	return eligible;
+}

This is a nice simple mechanism to skip CPUs that were eligible last time and had pause loop exits recently.

However, it could stand some documentation. Please add a good comment explaining how and why the algorithm works, when arch.plo.pause_loop_exited is cleared, etc...

It would be good to make this heuristic understandable to people who look at the code for the first time.

Signature · 1 line
All rights reversed
#14 lore raw

Re: [PATCH RFC 2/2] kvm PLE handler: Choose better candidate for directed yield

Quoted 19 lines · Rik van Riel

arch/x86/kvm/x86.c bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu) · line 6638

Quoted 13 lines · Raghavendra K T
arch/x86/kvm/x86.c +13 -0
+bool kvm_arch_vcpu_check_and_update_eligible(struct kvm_vcpu *vcpu)
+{
+ bool eligible;
+
+ eligible = !vcpu->arch.plo.pause_loop_exited ||
+ (vcpu->arch.plo.pause_loop_exited&&
+ vcpu->arch.plo.dy_eligible);
+
+ if (vcpu->arch.plo.pause_loop_exited)
+ vcpu->arch.plo.dy_eligible = !vcpu->arch.plo.dy_eligible;
+
+ return eligible;
+}

This is a nice simple mechanism to skip CPUs that were eligible last time and had pause loop exits recently.

Quoted 7 lines

However, it could stand some documentation. Please add a good comment explaining how and why the algorithm works, when arch.plo.pause_loop_exited is cleared, etc...

It would be good to make this heuristic understandable to people who look at the code for the first time.

Thanks for the review. will do more documentation.

#15 lore raw
In reply to Raghavendra K T
Quoted 10 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Problem is, for large vcpu guests, we have more probability of yielding to a bad vcpu. We are not able to prevent directed yield to same guy who has done PL exit recently, who perhaps spins again and wastes CPU.

Fix that by keeping track of who has done PL exit. So The Algorithm in series give chance to a VCPU which has:

We could do the same for s390. The appropriate exit would be diag44 (yield to hypervisor).

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though. So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Thanks

Christian

#16 lore raw
Quoted 13 lines · Christian Borntraeger
Quoted 10 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Problem is, for large vcpu guests, we have more probability of yielding to a bad vcpu. We are not able to prevent directed yield to same guy who has done PL exit recently, who perhaps spins again and wastes CPU.

Fix that by keeping track of who has done PL exit. So The Algorithm in series give chance to a VCPU which has:

Quoted 8 lines

We could do the same for s390. The appropriate exit would be diag44 (yield to hypervisor).

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though. So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Thanks for the review. Nice to know that, patch has potential to help s390 also.

#17 lore raw
In reply to Christian Borntraeger
Quoted 9 lines · Christian Borntraeger
Quoted 8 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Problem is, for large vcpu guests, we have more probability of yielding to a bad vcpu. We are not able to prevent directed yield to same guy who has done PL exit recently, who perhaps spins again and wastes CPU.

Quoted 7 lines
Quoted 2 lines

Fix that by keeping track of who has done PL exit. So The Algorithm in series give chance to a VCPU which has:

We could do the same for s390. The appropriate exit would be diag44 (yield to hypervisor).

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

Quoted 4 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Signature · 1 line
error compiling committee.c: too many arguments to function
#18 lore raw

On 11/07/12 11:06, Avi Kivity wrote:
[...]

Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful
- if lock holder is not running and we looped for a while do a directed yield to that cpu.

Quoted 10 lines
Quoted 5 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Ignoring the name, yes the data structure itself seems based on the algorithm and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

So this would probably improve guests that uses cpu_relax, for example stop_machine_run. I have no measurements, though.

Christian

#19 lore raw
Quoted 6 lines · Christian Borntraeger

On 11/07/12 11:06, Avi Kivity wrote:
[...]

Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

Quoted 7 lines

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

We could make it available via shared memory, updated using preempt notifiers. Of course piling on more pv makes this less attractive.

Quoted 9 lines

- if lock holder is not running and we looped for a while do a directed yield to that cpu.

Quoted 6 lines
Quoted 5 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Quoted 6 lines
Quoted 4 lines

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Ignoring the name,

What name would you suggest?

Quoted 4 lines

yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit, and the way it implements cpu_relax() by adjusting hw thread priority, I'm guessing it doesn't intercept those either, but I'm copying the ppc people in case I'm wrong. So it's s390 and x86.

Quoted 2 lines

So this would probably improve guests that uses cpu_relax, for example stop_machine_run. I have no measurements, though.

smp_call_function() too (though that can be converted to directed yield too). It seems worthwhile.

Signature · 1 line
error compiling committee.c: too many arguments to function
#20 lore raw
Quoted 36 lines · Avi Kivity
Quoted 6 lines · Christian Borntraeger

On 11/07/12 11:06, Avi Kivity wrote:
[...]

Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

Quoted 7 lines

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

We could make it available via shared memory, updated using preempt notifiers. Of course piling on more pv makes this less attractive.

Quoted 9 lines

- if lock holder is not running and we looped for a while do a directed yield to that cpu.

Quoted 6 lines
Quoted 5 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Quoted 6 lines
Quoted 4 lines

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Ignoring the name,

What name would you suggest?

Quoted 7 lines
Quoted 4 lines

yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit,

What dislike of overcommit?

Quoted 1 line

and the way it implements cpu_relax() by adjusting hw thread priority,

Yeah, I don't think we can intercept relaxing. It's basically a nop-like instruction that gives hardware hints on its current priorities. That said, we can always add PV code.

Alex

#21 lore raw
Quoted 10 lines · Alexander Graf
Quoted 8 lines
Quoted 5 lines

yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit,

What dislike of overcommit?

I understood ppc virtualization is more of the partitioning sort. Perhaps I misunderstood it. But the reliance on device assignment, the restrictions on scheduling, etc. all point to it.

Quoted 4 lines
Quoted 2 lines

and the way it implements cpu_relax() by adjusting hw thread priority,

Yeah, I don't think we can intercept relaxing.

... and the lack of ability to intercept cpu_relax() ...

Quoted 1 line

It's basically a nop-like instruction that gives hardware hints on its current priorities.

That's what x88 PAUSE does. But we can intercept it (and not just any execution - we can restrict intercept to tight loops executed more than a specific number of times).

Quoted 1 line

That said, we can always add PV code.

Sure, but that's defeated by advancements like self-tuning PLE exits. It's hard to get this right.

Signature · 1 line
error compiling committee.c: too many arguments to function
#22 lore raw
Quoted 7 lines · Avi Kivity
Quoted 6 lines · Alexander Graf
Quoted 6 lines
Quoted 5 lines

yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit,

What dislike of overcommit?

I understood ppc virtualization is more of the partitioning sort. Perhaps I misunderstood it. But the reliance on device assignment, the restrictions on scheduling, etc. all point to it.

Well, you need to distinguish the different PPC targets here. In the embedded world, partitioning is obviously the biggest use case, though overcommit is possible. For big servers however, we usually do want overcommit and we do support it within the constraints hardware gives us.

It's really no different from x86 when it comes to the use case wideness :).

Quoted 6 lines
Quoted 5 lines
Quoted 3 lines

and the way it implements cpu_relax() by adjusting hw thread priority,

Yeah, I don't think we can intercept relaxing.

Quoted 7 lines

... and the lack of ability to intercept cpu_relax() ...

Quoted 1 line

It's basically a nop-like instruction that gives hardware hints on its current priorities.

That's what x88 PAUSE does. But we can intercept it (and not just any execution - we can restrict intercept to tight loops executed more than a specific number of times).

Yeah, it's pretty hard to fetch that information from PPC, since unlike x86 we split the hint from the loop. But I'll let Ben speak to that, he certainly knows way better how the hardware works.

Quoted 5 lines
Quoted 2 lines

That said, we can always add PV code.

Sure, but that's defeated by advancements like self-tuning PLE exits. It's hard to get this right.

Well, eventually everything we do in PV is going to be moot as soon as hardware catches up. In most cases from what I've seen it's only useful as an interim solution. But for that time it's good to have :).

Alex

#23 lore raw
Quoted 15 lines · Alexander Graf
Quoted 12 lines · Avi Kivity
Quoted 10 lines · Alexander Graf
Quoted 8 lines
Quoted 5 lines

yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit,

What dislike of overcommit?

Quoted 7 lines
Quoted 3 lines

I understood ppc virtualization is more of the partitioning sort. Perhaps I misunderstood it. But the reliance on device assignment, the restrictions on scheduling, etc. all point to it.

Well, you need to distinguish the different PPC targets here. In the embedded world, partitioning is obviously the biggest use case, though overcommit is possible. For big servers however, we usually do want overcommit and we do support it within the constraints hardware gives us.

It's really no different from x86 when it comes to the use case wideness :).

Okay, thanks for the correction.

Quoted 9 lines
Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

and the way it implements cpu_relax() by adjusting hw thread priority,

Yeah, I don't think we can intercept relaxing.

... and the lack of ability to intercept cpu_relax() ...

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

It's basically a nop-like instruction that gives hardware hints on its current priorities.

That's what x88 PAUSE does. But we can intercept it (and not just any execution - we can restrict intercept to tight loops executed more than a specific number of times).

Yeah, it's pretty hard to fetch that information from PPC, since unlike x86 we split the hint from the loop. But I'll let Ben speak to that, he certainly knows way better how the hardware works.

On x86 it's split from the loop as well (inside cpu_relax() like ppc). But the hardware detects the loop and lets us know about it.

Quoted 8 lines
Quoted 6 lines
Quoted 3 lines

That said, we can always add PV code.

Sure, but that's defeated by advancements like self-tuning PLE exits. It's hard to get this right.

Well, eventually everything we do in PV is going to be moot as soon as hardware catches up. In most cases from what I've seen it's only useful as an interim solution. But for that time it's good to have :).

Depends on how interim it is. If better hardware is coming, I'd rather not add more pv-ness.

Signature · 1 line
error compiling committee.c: too many arguments to function
#24 lore raw
In reply to Avi Kivity
Quoted 7 lines · Avi Kivity
Quoted 6 lines · Alexander Graf
Quoted 6 lines
Quoted 5 lines

yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit,

What dislike of overcommit?

I understood ppc virtualization is more of the partitioning sort. Perhaps I misunderstood it. But the reliance on device assignment, the restrictions on scheduling, etc. all point to it.

It historically was but that has changed quite a bit. Essentially the user can configure partitions to be more of the "all virtualized" kind or on the contrary more fixed partitions. The hypervisor does shared processors and we have paravirt APIs to cede our time slice to the lock holder.

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

and the way it implements cpu_relax() by adjusting hw thread priority,

Yeah, I don't think we can intercept relaxing.

... and the lack of ability to intercept cpu_relax() ...

Quoted 1 line

It's basically a nop-like instruction that gives hardware hints on its current priorities.

Quoted 9 lines

That's what x88 PAUSE does. But we can intercept it (and not just any execution - we can restrict intercept to tight loops executed more than a specific number of times).

Quoted 1 line

That said, we can always add PV code.

Sure, but that's defeated by advancements like self-tuning PLE exits. It's hard to get this right.

Cheers,
Ben.

#25 lore raw
In reply to Avi Kivity
Quoted 27 lines · Avi Kivity
Quoted 6 lines · Christian Borntraeger

On 11/07/12 11:06, Avi Kivity wrote:
[...]

Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

Quoted 7 lines

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

We could make it available via shared memory, updated using preempt notifiers. Of course piling on more pv makes this less attractive.

Quoted 9 lines

- if lock holder is not running and we looped for a while do a directed yield to that cpu.

Quoted 6 lines
Quoted 5 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Quoted 8 lines
Quoted 6 lines
Quoted 4 lines

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Ignoring the name,

What name would you suggest?

maybe vcpu_no_progress instead of pause_loop_exited

Quoted 12 lines
Quoted 5 lines

yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work. If we move that to common code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit, and the way it implements cpu_relax() by adjusting hw thread priority, I'm guessing it doesn't intercept those either, but I'm copying the ppc people in case I'm wrong. So it's s390 and x86.

Quoted 5 lines
Quoted 2 lines

So this would probably improve guests that uses cpu_relax, for example stop_machine_run. I have no measurements, though.

smp_call_function() too (though that can be converted to directed yield too). It seems worthwhile.

Indeed. For those places where is is possible I would like to see an architecture primitive for directed yield. That could be useful for other places as well (e.g. maybe lib/spinlock_debug.c, which has no yielding at all)

Christian

#26 lore raw
Quoted 33 lines · Christian Borntraeger
Quoted 32 lines · Avi Kivity
Quoted 6 lines · Christian Borntraeger

On 11/07/12 11:06, Avi Kivity wrote:
[...]

Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

Quoted 7 lines

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

We could make it available via shared memory, updated using preempt notifiers. Of course piling on more pv makes this less attractive.

Quoted 14 lines

- if lock holder is not running and we looped for a while do a directed yield to that cpu.

Quoted 10 lines
Quoted 5 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Ignoring the name,

What name would you suggest?

maybe vcpu_no_progress instead of pause_loop_exited

Ah, I thouht you objected to the CONFIG var. Maybe call it cpu_relax_intercepted since that's the linuxy name for the instruction.

Signature · 1 line
error compiling committee.c: too many arguments to function
#27 lore raw
Quoted 34 lines · Avi Kivity
Quoted 33 lines · Christian Borntraeger
Quoted 32 lines · Avi Kivity
Quoted 6 lines · Christian Borntraeger

On 11/07/12 11:06, Avi Kivity wrote:
[...]

Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

Quoted 7 lines

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

We could make it available via shared memory, updated using preempt notifiers. Of course piling on more pv makes this less attractive.

Quoted 14 lines

- if lock holder is not running and we looped for a while do a directed yield to that cpu.

Quoted 10 lines
Quoted 5 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Quoted 9 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line

Ignoring the name,

What name would you suggest?

maybe vcpu_no_progress instead of pause_loop_exited

Ah, I thouht you objected to the CONFIG var. Maybe call it cpu_relax_intercepted since that's the linuxy name for the instruction.

Ok, just to be on same page. 'll have :
1. cpu_relax_intercepted instead of pause_loop_exited.

2. CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT which is unconditionally selected for x86 and s390

3. make request mechanism to clear cpu_relax_intercepted.

('ll do same thing for s390 also but have not seen s390 code using request mechanism, so not sure if it ok.. otherwise we have to clear unconditionally for s390 before guest enter and for x86 we have to move make_request back to vmx/svm). will post V3 with these changes.

#28 lore raw
Quoted 10 lines · Raghavendra K T
Quoted 3 lines

Ah, I thouht you objected to the CONFIG var. Maybe call it cpu_relax_intercepted since that's the linuxy name for the instruction.

Ok, just to be on same page. 'll have :
1. cpu_relax_intercepted instead of pause_loop_exited.

2. CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT which is unconditionally selected for x86 and s390

Quoted 7 lines

3. make request mechanism to clear cpu_relax_intercepted.

('ll do same thing for s390 also but have not seen s390 code using request mechanism, so not sure if it ok.. otherwise we have to clear unconditionally for s390 before guest enter and for x86 we have to move make_request back to vmx/svm).
will post V3 with these changes.

You can leave the s390 changes to the s390 people; just make sure the generic code is ready.

Signature · 1 line
error compiling committee.c: too many arguments to function
#29 lore raw
Quoted 13 lines · Avi Kivity
Quoted 12 lines · Raghavendra K T
Quoted 3 lines

Ah, I thouht you objected to the CONFIG var. Maybe call it cpu_relax_intercepted since that's the linuxy name for the instruction.

Ok, just to be on same page. 'll have :
1. cpu_relax_intercepted instead of pause_loop_exited.

2. CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT which is unconditionally selected for x86 and s390

3. make request mechanism to clear cpu_relax_intercepted.

Quoted 9 lines
Quoted 5 lines

('ll do same thing for s390 also but have not seen s390 code using request mechanism, so not sure if it ok.. otherwise we have to clear unconditionally for s390 before guest enter and for x86 we have to move make_request back to vmx/svm).
will post V3 with these changes.

You can leave the s390 changes to the s390 people; just make sure the generic code is ready.

Yep,
Checked the following logic with make_request and it works fine,

vcpu_spin()
{
ple_exited = true;
.
.
make_request(KVM_REQ_CLEAR_PLE, vcpu);
}

vcpu_enter_guest()
{
if(check_request(KVM_REQ_CLEAR_PLE))

    ple_exited = false;

.
.
}

But there is following approach that is working perfectly fine. vcpu_spin()
{
ple_exited = true;
.
.

ple_exited = false;
}

I hope to go with second approach. let me know if you find any loop hole.

#30 lore raw
In reply to Avi Kivity
Quoted 5 lines

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit, and the way it implements cpu_relax() by adjusting hw thread priority, I'm guessing it doesn't intercept those either, but I'm copying the ppc people in case I'm wrong. So it's s390 and x86.

No but our spinlocks call __spin_yield() (or __rw_yield) which does some paravirt tricks already.

We check if the holder is currently running, and if not, we call the H_CONFER hypercall which can be used to "give" our time slice to the holder.

Our implementation of H_CONFER in KVM is currently a nop though.

Cheers,
Ben.

#31 lore raw
Quoted 6 lines · Benjamin Herrenschmidt
Quoted 5 lines

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit, and the way it implements cpu_relax() by adjusting hw thread priority, I'm guessing it doesn't intercept those either, but I'm copying the ppc people in case I'm wrong. So it's s390 and x86.

Quoted 8 lines

No but our spinlocks call __spin_yield() (or __rw_yield) which does some paravirt tricks already.

We check if the holder is currently running, and if not, we call the H_CONFER hypercall which can be used to "give" our time slice to the holder.

Our implementation of H_CONFER in KVM is currently a nop though.

Okay, so you can join the party. See yield_to() and kvm_vcpu_on_spin().

Signature · 1 line
error compiling committee.c: too many arguments to function
#32 lore raw
Quoted 10 lines · Avi Kivity
Quoted 9 lines · Benjamin Herrenschmidt
Quoted 5 lines

ARM doesn't have an instruction for cpu_relax(), so it can't intercept it. Given ppc's dislike of overcommit, and the way it implements cpu_relax() by adjusting hw thread priority, I'm guessing it doesn't intercept those either, but I'm copying the ppc people in case I'm wrong. So it's s390 and x86.

No but our spinlocks call __spin_yield() (or __rw_yield) which does some paravirt tricks already.

Quoted 7 lines
Quoted 5 lines

We check if the holder is currently running, and if not, we call the H_CONFER hypercall which can be used to "give" our time slice to the holder.

Our implementation of H_CONFER in KVM is currently a nop though.

Okay, so you can join the party. See yield_to() and kvm_vcpu_on_spin().

Thanks ! I'll have a look eventually :-)

Cheers,
Ben.

#33 lore raw
In reply to Avi Kivity
Quoted 7 lines · Avi Kivity
Quoted 3 lines

So this would probably improve guests that uses cpu_relax, for example stop_machine_run. I have no measurements, though.

smp_call_function() too (though that can be converted to directed yield too). It seems worthwhile.

With

https://lkml.org/lkml/2012/6/26/266 in tip:x86/mm

which now uses smp_call_function_many in native_flush_tlb_others. It will help that too.

Nikunj

#34 lore raw
In reply to Christian Borntraeger
Quoted 6 lines · Christian Borntraeger

On 11/07/12 11:06, Avi Kivity wrote:
[...]

Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

Quoted 7 lines

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

Unfortunately we do not have information on lock-holder.

Quoted 9 lines

- if lock holder is not running and we looped for a while do a directed yield to that cpu.

Quoted 6 lines
Quoted 5 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax. I have to double check with others, if these cases are critical, but for now, it seems that your dummy implementation for s390 is just fine. After all it is a no-op until we implement something.

Quoted 7 lines
Quoted 4 lines

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Ignoring the name, yes the data structure itself seems based on the algorithm and not on arch specific things. That should work.

Ok. can you please elaborate, on the flow.

If we move that to common

Quoted 8 lines

code then s390 will use that scheme automatically for the cases were we call kvm_vcpu_on_spin(). All others archs as well.

So this would probably improve guests that uses cpu_relax, for example stop_machine_run. I have no measurements, though.

Christian

#35 lore raw
Quoted 12 lines · Raghavendra K T
Quoted 11 lines
Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

Quoted 1 line

Unfortunately we do not have information on lock-holder.

That would be an independent patch and requires guest changes.

#36 lore raw
Quoted 13 lines · Christian Borntraeger
Quoted 12 lines · Raghavendra K T
Quoted 11 lines
Quoted 3 lines
Quoted 1 line

Almost all s390 kernels use diag9c (directed yield to a given guest cpu) for spinlocks, though.

Perhaps x86 should copy this.

See arch/s390/lib/spinlock.c
The basic idea is using several heuristics:
- loop for a given amount of loops
- check if the lock holder is currently scheduled by the hypervisor (smp_vcpu_scheduled, which uses the sigp sense running instruction) Dont know if such thing is available for x86. It must be a lot cheaper than a guest exit to be useful

Quoted 4 lines
Quoted 1 line

Unfortunately we do not have information on lock-holder.

That would be an independent patch and requires guest changes.

Yes, AFAI think, there are two options:
(1) extend lock and use spare bit in ticketlock indicate lock is held
(2) use percpu list entry.

#37 lore raw
In reply to Raghavendra K T
Quoted 2 lines · Raghavendra K T
Quoted 1 line · Christian Borntraeger

On 11/07/12 11:06, Avi Kivity wrote:

[...]

Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
Quoted 7 lines

So there is no win here, but there are other cases were diag44 is used, e.g. cpu_relax.
I have to double check with others, if these cases are critical, but for now, it seems
that your dummy implementation for s390 is just fine. After all it is a no-op until
we implement something.

Does the data structure make sense for you? If so we can move it to common code (and manage it in kvm_vcpu_on_spin()). We can guard it with CONFIG_KVM_HAVE_CPU_RELAX_INTERCEPT or something, so other archs don't have to pay anything.

Quoted 6 lines
Quoted 3 lines

Ignoring the name, yes the data structure itself seems based on the algorithm
and not on arch specific things. That should work.

Ok. can you please elaborate, on the flow.

Ok got it.. Will check how the code can be common to both x86 and s390.

#38 lore raw
In reply to Raghavendra K T
Quoted 3 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Hi, Raghu.

Quoted 25 lines

Problem is, for large vcpu guests, we have more probability of yielding to a bad vcpu. We are not able to prevent directed yield to same guy who has done PL exit recently, who perhaps spins again and wastes CPU.

Fix that by keeping track of who has done PL exit. So The Algorithm in series give chance to a VCPU which has:

(a) Not done PLE exit at all (probably he is preempted lock-holder)

(b) VCPU skipped in last iteration because it did PL exit, and probably has become eligible now (next eligible lock holder)

Future enhancemnets:
(1) Currently we have a boolean to decide on eligibility of vcpu. It would be nice if I get feedback on guest (>32 vcpu) whether we can improve better with integer counter. (with counter = say f(log n )).

(2) We have not considered system load during iteration of vcpu. With that information we can limit the scan and also decide whether schedule() is better. [ I am able to use #kicked vcpus to decide on this But may be there are better ideas like information from global loadavg.]

(3) We can exploit this further with PV patches since it also knows about next eligible lock-holder.

Quoted 8 lines

Summary: There is a huge improvement for moderate / no overcommit scenario
for kvm based guest on PLE machine (which is difficult ;) ).

Result:
Base : kernel 3.5.0-rc5 with Rik's Ple handler fix

Machine : Intel(R) Xeon(R) CPU X7560 @ 2.27GHz, 4 numa node, 256GB RAM,
32 core machine

Is this with HT enabled, therefore 64 CPU threads?

Quoted 4 lines

Host: enterprise linux gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
with test kernels

Guest: fedora 16 with 32 vcpus 8GB memory.

Can you briefly explain the 1x and 2x configs? This of course is highly dependent whether or not HT is enabled...

FWIW, I started testing what I would call "0.5x", where I have one 40 vcpu guest running on a host with 40 cores and 80 CPU threads total (HT enabled, no extra load on the system). For ebizzy, the results are quite erratic from run to run, so I am inclined to discard it as a workload, but maybe I should try "1x" and "2x" cpu over-commit as well.

Quoted 1 line

From initial observations, at least for the ebizzy workload, the

percentage of exits that result in a yield_to() are very low, around 1%, before these patches. So, I am concerned that at least for this test, reducing that number even more has diminishing returns. I am however still concerned about the scalability problem with yield_to(), which shows like this for me (perf):

Quoted 7 lines
63.56%     282095         qemu-kvm  [kernel.kallsyms]        [k] _raw_spin_lock                  
5.42%      24420         qemu-kvm  [kvm]                    [k] kvm_vcpu_yield_to               
5.33%      26481         qemu-kvm  [kernel.kallsyms]        [k] get_pid_task                    
4.35%      20049         qemu-kvm  [kernel.kallsyms]        [k] yield_to                        
2.74%      15652         qemu-kvm  [kvm]                    [k] kvm_apic_present                
1.70%       8657         qemu-kvm  [kvm]                    [k] kvm_vcpu_on_spin                
1.45%       7889         qemu-kvm  [kvm]                    [k] vcpu_enter_guest                

For the cpu threads in the host that are actually active (in this case 1/2 of them), ~50% of their time is in kernel and ~43% in guest. This is for a no-IO workload, so that's just incredible to see so much cpu wasted. I feel that 2 important areas to tackle are a more scalable yield_to() and reducing the number of pause exits itself (hopefully by just tuning ple_window for the latter).

Honestly, I not confident addressing this problem will improve the ebizzy score. That workload is so erratic for me, that I do not trust the results at all. I have however seen consistent improvements in disabling PLE for a http guest workload and a very high IOPS guest workload, both with much time spent in host in the double runqueue lock for yield_to(), so that's why I still gravitate toward that issue.

-Andrew Theurer

#39 lore raw
Quoted 6 lines · Andrew Theurer
Quoted 3 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Hi, Raghu.

Hi Andrew,
Thank you for your analysis and inputs

Quoted 29 lines
Quoted 29 lines

Problem is, for large vcpu guests, we have more probability of yielding to a bad vcpu. We are not able to prevent directed yield to same guy who has done PL exit recently, who perhaps spins again and wastes CPU.

Fix that by keeping track of who has done PL exit. So The Algorithm in series give chance to a VCPU which has:

(a) Not done PLE exit at all (probably he is preempted lock-holder)

(b) VCPU skipped in last iteration because it did PL exit, and probably has become eligible now (next eligible lock holder)

Future enhancemnets:
(1) Currently we have a boolean to decide on eligibility of vcpu. It would be nice if I get feedback on guest (>32 vcpu) whether we can improve better with integer counter. (with counter = say f(log n )).

(2) We have not considered system load during iteration of vcpu. With that information we can limit the scan and also decide whether schedule() is better. [ I am able to use #kicked vcpus to decide on this But may be there are better ideas like information from global loadavg.]

(3) We can exploit this further with PV patches since it also knows about next eligible lock-holder.

Summary: There is a huge improvement for moderate / no overcommit scenario
for kvm based guest on PLE machine (which is difficult ;) ).

Quoted 7 lines
Quoted 5 lines

Result:
Base : kernel 3.5.0-rc5 with Rik's Ple handler fix

Machine : Intel(R) Xeon(R) CPU X7560 @ 2.27GHz, 4 numa node, 256GB RAM,
32 core machine

Is this with HT enabled, therefore 64 CPU threads?

No. HT disabled with 32 online CPUs

Quoted 8 lines
Quoted 5 lines

Host: enterprise linux gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)
with test kernels

Guest: fedora 16 with 32 vcpus 8GB memory.

Can you briefly explain the 1x and 2x configs? This of course is highly dependent whether or not HT is enabled...

1x config: kernbench/ebizzy/sysbench running on 1 guest (32 vcpu)
all the benchmarks have 2*#vcpu = 64 threads

2x config: kernbench/ebizzy/sysbench running on 2 guests each with 32 vcpu)
all the benchmarks have 2*#vcpu = 64 threads

Quoted 5 lines

FWIW, I started testing what I would call "0.5x", where I have one 40 vcpu guest running on a host with 40 cores and 80 CPU threads total (HT enabled, no extra load on the system). For ebizzy, the results are quite erratic from run to run, so I am inclined to discard it as a

I will be posting full run detail (individual run) in reply to this mail since it is big. I have posted stdev also with the result.. it has not shown too much deviation.

Quoted 5 lines

workload, but maybe I should try "1x" and "2x" cpu over-commit as well.

Quoted 1 line

From initial observations, at least for the ebizzy workload, the

percentage of exits that result in a yield_to() are very low, around 1%, before these patches.

Hmm Ok..
IMO for a under-committed workload, probably low percentage of yield_to was expected, but not sure whether 1% is too less though. But importantly, number of successful yield_to can never measure benefit.

With this patch what I am trying to address is to ensure successful yield_to result in benefit.

So, I am concerned that at least for this test,

Quoted 2 lines

reducing that number even more has diminishing returns. I am however still concerned about the scalability problem with yield_to(),

So did you mean you are expected to see more yield_to overheads with large guests? As already mentioned in future enhancements, one thing I will be trying in future would be,

a. have counter instead of boolean for skipping yield_to
b. just scan probably f(log(n)) vcpu to yield and then schedule()/ return depending on system load.

so we will be reducing overall vcpu iteration in PLE handler from O(n * n) to O(n log n)

which

Quoted 10 lines

shows like this for me (perf):

Quoted 7 lines
63.56%     282095         qemu-kvm  [kernel.kallsyms]        [k] _raw_spin_lock
5.42%      24420         qemu-kvm  [kvm]                    [k] kvm_vcpu_yield_to
5.33%      26481         qemu-kvm  [kernel.kallsyms]        [k] get_pid_task
4.35%      20049         qemu-kvm  [kernel.kallsyms]        [k] yield_to
2.74%      15652         qemu-kvm  [kvm]                    [k] kvm_apic_present
1.70%       8657         qemu-kvm  [kvm]                    [k] kvm_vcpu_on_spin
1.45%       7889         qemu-kvm  [kvm]                    [k] vcpu_enter_guest
Quoted 6 lines

For the cpu threads in the host that are actually active (in this case 1/2 of them), ~50% of their time is in kernel and ~43% in guest.This is for a no-IO workload, so that's just incredible to see so much cpu wasted. I feel that 2 important areas to tackle are a more scalable yield_to() and reducing the number of pause exits itself (hopefully by just tuning ple_window for the latter).

I think this is a concern and as you stated I agree that tuning ple_window helps here.

Quoted 7 lines

Honestly, I not confident addressing this problem will improve the ebizzy score. That workload is so erratic for me, that I do not trust the results at all. I have however seen consistent improvements in disabling PLE for a http guest workload and a very high IOPS guest workload, both with much time spent in host in the double runqueue lock for yield_to(), so that's why I still gravitate toward that issue.

The problem starts (in PLE disabled) when we have workload just > 1x.We start burning so much of cpu.

IIRC, in 2x overcommit, kernel compilation that takes 10hr on non-PLE, used to take just 1hr after pv patches (and should be same with PLE enabled)

If we leave PLE disabled case, I do not expect any degradation even in 0.5 x scenario, though you say results are erratic.

Could you please let me know, When PLE was enabled, before and after the patch did you see any degradation for 0.5x?

Quoted 3 lines

-Andrew Theurer

#40 lore raw

Re: [PATCH RFC 0/2] kvm: Improving directed yield in PLE handler : detailed result

In reply to Andrew Theurer
Quoted 5 lines · Andrew Theurer
Quoted 3 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

[...]

Quoted 7 lines

Honestly, I not confident addressing this problem will improve the ebizzy score. That workload is so erratic for me, that I do not trust the results at all. I have however seen consistent improvements in disabling PLE for a http guest workload and a very high IOPS guest workload, both with much time spent in host in the double runqueue lock for yield_to(), so that's why I still gravitate toward that issue.

Deatiled result
Base + Rik patch

ebizzy
=========

overcommit 1 x
1160 records/s
real 60.00 s
user 6.28 s
sys 1078.69 s
1130 records/s
real 60.00 s
user 5.15 s
sys 1080.51 s
1073 records/s
real 60.00 s
user 5.02 s
sys 1030.21 s
1151 records/s
real 60.00 s
user 5.51 s
sys 1097.63 s
1145 records/s
real 60.00 s
user 5.21 s
sys 1093.56 s
1149 records/s
real 60.00 s
user 5.32 s
sys 1097.30 s
1111 records/s
real 60.00 s
user 5.16 s
sys 1061.77 s
1115 records/s
real 60.00 s
user 5.16 s
sys 1066.99 s

overcommit 2 x
1818 records/s
real 60.00 s
user 11.67 s
sys 843.84 s
1809 records/s
real 60.00 s
user 11.77 s
sys 845.68 s
1865 records/s
real 60.00 s
user 11.94 s
sys 866.69 s
1822 records/s
real 60.00 s
user 12.81 s
sys 843.05 s
1928 records/s
real 60.00 s
user 14.02 s
sys 887.86 s
1915 records/s
real 60.00 s
user 11.55 s
sys 888.68 s
1997 records/s
real 60.00 s
user 11.34 s
sys 923.54 s
1985 records/s
real 60.00 s
user 11.41 s
sys 923.44 s

kernbench
===============
overcommit 1 x
Elapsed Time 49.2367 (33.6921) User Time 243.313 (343.965) System Time 385.21 (125.151) Percent CPU 1243.33 (79.5257) Context Switches 58450.7 (31603.6) Sleeps 73987 (41782.5)
--
Elapsed Time 47.8367 (37.2156) User Time 244.79 (349.112) System Time 338.553 (141.732) Percent CPU 1181 (81.074) Context Switches 56194.3 (36421.6) Sleeps 74355.3 (40263.5)
--
Elapsed Time 49.6067 (34.7325) User Time 250.117 (354.008) System Time 341.277 (57.5594) Percent CPU 1197 (46.3573) Context Switches 55520.3 (27748.1) Sleeps 72673 (38997.4)
--
Elapsed Time 50.24 (36.6571) User Time 247.873 (352.427) System Time 349.11 (79.4226) Percent CPU 1193.67 (50.362) Context Switches 55153.3 (27926.2) Sleeps 73128 (39532.4)

overcommit 2 x
Elapsed Time 91.9233 (96.6304) User Time 278.347 (371.217) System Time 222.447 (181.378) Percent CPU 521.667 (46.1988) Context Switches 49597 (35766.4) Sleeps 77939.7 (36840.1)
--
Elapsed Time 89.48 (92.7224) User Time 275.223 (364.737) System Time 202.473 (172.233) Percent CPU 497.333 (53.0031) Context Switches 44117 (30001) Sleeps 77196 (35746.2)
--
Elapsed Time 93.6133 (95.7924) User Time 294.767 (379.39) System Time 235.487 (207.567) Percent CPU 529.667 (58.2866) Context Switches 50588 (36669.4) Sleeps 79323.7 (38285.8)
--
Elapsed Time 92.7267 (100.928) User Time 286.537 (384.253) System Time 232.983 (192.233) Percent CPU 552 (76.961) Context Switches 51071 (35090) Sleeps 79059 (36466.4)

sysbench
==============
overcommit 1 x
total time: 12.1229s
total number of events: 100041
total time taken by event execution: 772.8819
--
total time: 12.0775s
total number of events: 100013
total time taken by event execution: 769.5969
--
total time: 12.1671s
total number of events: 100011
total time taken by event execution: 775.5967
--
total time: 12.2695s
total number of events: 100003
total time taken by event execution: 782.3780
--
total time: 12.1526s
total number of events: 100014
total time taken by event execution: 773.9802
--
total time: 12.3350s
total number of events: 100069
total time taken by event execution: 786.2091
--
total time: 12.1019s
total number of events: 100013
total time taken by event execution: 771.5163
--
total time: 12.0716s
total number of events: 100010
total time taken by event execution: 769.8809

overcommit 2 x
total time: 13.6532s
total number of events: 100011
total time taken by event execution: 870.0869
--
total time: 15.8572s
total number of events: 100010
total time taken by event execution: 910.6689
--
total time: 13.6100s
total number of events: 100008
total time taken by event execution: 867.1782
--
total time: 15.4295s
total number of events: 100008
total time taken by event execution: 917.8441
--
total time: 13.8994s
total number of events: 100004
total time taken by event execution: 885.6729
--
total time: 14.2006s
total number of events: 100005
total time taken by event execution: 887.0262
--
total time: 13.8869s
total number of events: 100011
total time taken by event execution: 885.3583
--
total time: 13.9183s
total number of events: 100007
total time taken by event execution: 880.4344

With Rik + PLE handler optimization patch
===========================================
ebizzy
==========
overcommit 1 x
2249 records/s
real 60.00 s
user 9.87 s
sys 1529.54 s
2316 records/s
real 60.00 s
user 10.51 s
sys 1550.33 s
2353 records/s
real 60.00 s
user 10.82 s
sys 1565.10 s
2365 records/s
real 60.00 s
user 10.88 s
sys 1569.00 s
2282 records/s
real 60.00 s
user 10.77 s
sys 1540.03 s
2292 records/s
real 60.00 s
user 10.60 s
sys 1553.76 s
2272 records/s
real 60.00 s
user 10.44 s
sys 1510.90 s
2404 records/s
real 60.00 s
user 10.96 s
sys 1563.49 s

overcommit 2 x
2454 records/s
real 60.00 s
user 14.66 s
sys 880.17 s
2192 records/s
real 60.00 s
user 15.56 s
sys 881.12 s
2329 records/s
real 60.00 s
user 17.56 s
sys 933.03 s
2281 records/s
real 60.00 s
user 16.22 s
sys 925.34 s
2286 records/s
real 60.00 s
user 16.93 s
sys 902.04 s
2289 records/s
real 60.00 s
user 15.53 s
sys 909.78 s
2586 records/s
real 60.00 s
user 15.38 s
sys 857.22 s
2675 records/s
real 60.00 s
user 15.93 s
sys 842.40 s

kernbench
=============
overcommit 1 x
Elapsed Time 36.6633 (33.6422) User Time 248.303 (359.64) System Time 123.003 (67.1702) Percent CPU 864 (242.52) Context Switches 44936.3 (28799.8) Sleeps 76076.7 (41142.1)
--
Elapsed Time 37.9167 (37.3285) User Time 247.517 (358.659) System Time 118.883 (86.7824) Percent CPU 807.333 (245.133) Context Switches 44219.3 (29480.9) Sleeps 77137.3 (42685.4)
--
Elapsed Time 39.65 (39.0432) User Time 248.07 (357.765) System Time 100.76 (58.7603) Percent CPU 748.333 (199.803) Context Switches 42332.3 (27183.7) Sleeps 75248.7 (41084.4)
--
Elapsed Time 39.2867 (39.8316) User Time 245.903 (356.194) System Time 101.783 (60.4971) Percent CPU 762.667 (186.827) Context Switches 42289.3 (24882.1) Sleeps 74964.7 (38139.1)

overcommit 2 x
Elapsed Time 85.6567 (92.092) User Time 274.607 (370.598) System Time 172.12 (134.705) Percent CPU 496.667 (34.2977) Context Switches 45715.7 (29180.4) Sleeps 76054 (34844.5)
--
Elapsed Time 86.8667 (92.72) User Time 278.767 (365.877) System Time 193.277 (142.811) Percent CPU 538.667 (36.5558) Context Switches 48035.3 (32107.3) Sleeps 78004.7 (37835.6)
--
Elapsed Time 87.38 (91.6723) User Time 269.133 (374.608) System Time 165.283 (122.423) Percent CPU 465.667 (119.068) Context Switches 45107.3 (29571.6) Sleeps 76942.7 (33102.4)
--
Elapsed Time 83.6333 (96.6314) User Time 267.97 (374.691) System Time 156.843 (123.183) Percent CPU 503 (28.5832) Context Switches 44406.7 (30002.8) Sleeps 78975.7 (40787.4)

sysbench
=================
overcommit 1 x
total time: 11.7338s
total number of events: 100021
total time taken by event execution: 747.8628
--
total time: 11.9323s
total number of events: 100006
total time taken by event execution: 760.7567
--
total time: 12.0282s
total number of events: 100068
total time taken by event execution: 766.2259
--
total time: 12.0065s
total number of events: 100010
total time taken by event execution: 765.0691
--
total time: 12.2033s
total number of events: 100016
total time taken by event execution: 777.9971
--
total time: 12.2472s
total number of events: 100041
total time taken by event execution: 780.9914
--
total time: 12.4853s
total number of events: 100015
total time taken by event execution: 795.9082
--
total time: 12.7028s
total number of events: 100015
total time taken by event execution: 810.4563

overcommit 2 x
total time: 13.7335s
total number of events: 100005
total time taken by event execution: 872.0665
--
total time: 14.0005s
total number of events: 100010
total time taken by event execution: 892.4587
--
total time: 13.8066s
total number of events: 100008
total time taken by event execution: 880.2714
--
total time: 14.6350s
total number of events: 100006
total time taken by event execution: 875.3052
--
total time: 13.8536s
total number of events: 100007
total time taken by event execution: 877.8040
--
total time: 15.7213s
total number of events: 100007
total time taken by event execution: 896.5455
--
total time: 13.9135s
total number of events: 100007
total time taken by event execution: 882.0964
--
total time: 13.8390s
total number of events: 100009
total time taken by event execution: 881.8267

#41 lore raw
In reply to Andrew Theurer
Quoted 7 lines · Andrew Theurer
Quoted 3 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Hi, Raghu.

[...]

Quoted 4 lines

Can you briefly explain the 1x and 2x configs? This of course is highly dependent whether or not HT is enabled...

Sorry if I had not made very clear in earlier threads. Have you applied
Rik's following patch for base. without this you could see some inconsistent results perhaps.

https://lkml.org/lkml/2012/6/19/401

#42 lore raw
Quoted 14 lines · Raghavendra K T
Quoted 7 lines · Andrew Theurer
Quoted 3 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Hi, Raghu.

[...]

Quoted 4 lines

Can you briefly explain the 1x and 2x configs? This of course is highly dependent whether or not HT is enabled...

Quoted 5 lines

Sorry if I had not made very clear in earlier threads. Have you applied Rik's following patch for base. without this you could see some inconsistent results perhaps.

https://lkml.org/lkml/2012/6/19/401

Yes, I do have that applied with your patch and in my baseline.

-Andrew Theurer

#43 lore raw
In reply to Andrew Theurer
Quoted 7 lines · Andrew Theurer

For the cpu threads in the host that are actually active (in this case 1/2 of them), ~50% of their time is in kernel and ~43% in guest. This is for a no-IO workload, so that's just incredible to see so much cpu wasted. I feel that 2 important areas to tackle are a more scalable yield_to() and reducing the number of pause exits itself (hopefully by just tuning ple_window for the latter).

One thing we can do is autotune ple_window. If a ple exit fails to wake anybody (because all vcpus are either running, sleeping, or in ple exits) then we deduce we are not overcommitted and we can increase the ple window. There's the question of how to decrease it again though.

Signature · 1 line
error compiling committee.c: too many arguments to function
#44 lore raw
Quoted 9 lines · Avi Kivity
Quoted 7 lines · Andrew Theurer

For the cpu threads in the host that are actually active (in this case 1/2 of them), ~50% of their time is in kernel and ~43% in guest. This is for a no-IO workload, so that's just incredible to see so much cpu wasted. I feel that 2 important areas to tackle are a more scalable yield_to() and reducing the number of pause exits itself (hopefully by just tuning ple_window for the latter).

Quoted 5 lines

One thing we can do is autotune ple_window. If a ple exit fails to wake anybody (because all vcpus are either running, sleeping, or in ple exits) then we deduce we are not overcommitted and we can increase the ple window. There's the question of how to decrease it again though.

I see some problem here, If I interpret situation correctly. What
happens if we have two guests with one VM having no over-commit and other with high over-commit. (except when we have gang scheduling).

Rather we should have something tied to VM rather than rigid PLE window.

#45 lore raw
Quoted 16 lines · Raghavendra K T
Quoted 9 lines · Avi Kivity
Quoted 7 lines · Andrew Theurer

For the cpu threads in the host that are actually active (in this case 1/2 of them), ~50% of their time is in kernel and ~43% in guest. This is for a no-IO workload, so that's just incredible to see so much cpu wasted. I feel that 2 important areas to tackle are a more scalable yield_to() and reducing the number of pause exits itself (hopefully by just tuning ple_window for the latter).

Quoted 5 lines

One thing we can do is autotune ple_window. If a ple exit fails to wake anybody (because all vcpus are either running, sleeping, or in ple exits) then we deduce we are not overcommitted and we can increase the ple window. There's the question of how to decrease it again though.

Quoted 4 lines

I see some problem here, If I interpret situation correctly. What happens if we have two guests with one VM having no over-commit and other with high over-commit. (except when we have gang scheduling).

Sorry, I meant less load and high load inside the guest.

Quoted 2 lines

Rather we should have something tied to VM rather than rigid PLE window.

#46 lore raw
Quoted 17 lines · Raghavendra K T
Quoted 16 lines · Raghavendra K T
Quoted 14 lines · Avi Kivity
Quoted 7 lines · Andrew Theurer

For the cpu threads in the host that are actually active (in this case 1/2 of them), ~50% of their time is in kernel and ~43% in guest. This is for a no-IO workload, so that's just incredible to see so much cpu wasted. I feel that 2 important areas to tackle are a more scalable yield_to() and reducing the number of pause exits itself (hopefully by just tuning ple_window for the latter).

One thing we can do is autotune ple_window. If a ple exit fails to wake anybody (because all vcpus are either running, sleeping, or in ple exits) then we deduce we are not overcommitted and we can increase the ple window. There's the question of how to decrease it again though.

Quoted 8 lines
Quoted 4 lines

I see some problem here, If I interpret situation correctly. What happens if we have two guests with one VM having no over-commit and other with high over-commit. (except when we have gang scheduling).

Sorry, I meant less load and high load inside the guest.

Quoted 2 lines

Rather we should have something tied to VM rather than rigid PLE window.

The problem occurs even with no overcommit at all. One vcpu is in a legitimately long pause loop. All those exits accomplish nothing, since all vcpus are scheduled. Better to let it spin in guest mode.

Signature · 1 line
error compiling committee.c: too many arguments to function
#47 lore raw
Quoted 22 lines · Avi Kivity
Quoted 21 lines · Raghavendra K T
Quoted 20 lines · Raghavendra K T
Quoted 9 lines · Avi Kivity
Quoted 7 lines · Andrew Theurer

For the cpu threads in the host that are actually active (in this case 1/2 of them), ~50% of their time is in kernel and ~43% in guest. This is for a no-IO workload, so that's just incredible to see so much cpu wasted. I feel that 2 important areas to tackle are a more scalable yield_to() and reducing the number of pause exits itself (hopefully by just tuning ple_window for the latter).

Quoted 5 lines

One thing we can do is autotune ple_window. If a ple exit fails to wake anybody (because all vcpus are either running, sleeping, or in ple exits) then we deduce we are not overcommitted and we can increase the ple window. There's the question of how to decrease it again though.

I see some problem here, If I interpret situation correctly. What happens if we have two guests with one VM having no over-commit and other with high over-commit. (except when we have gang scheduling).

Quoted 9 lines
Quoted 4 lines

Sorry, I meant less load and high load inside the guest.

Quoted 2 lines

Rather we should have something tied to VM rather than rigid PLE window.

The problem occurs even with no overcommit at all. One vcpu is in a legitimately long pause loop. All those exits accomplish nothing, since all vcpus are scheduled. Better to let it spin in guest mode.

I agree. One idea is we can have a scan_window to limit the scan of all n vcpus each time we enter vcpu_spin, to say 2*log n initially;

then algorithm would be like;

if (yield fails)
increase ple_window , increase scan_window

if (yield succeeds)
decrease ple_window , decrease scan_window

and we have to set limit on what is max and min scan window and max and min ple_window.

#48 lore raw
Quoted 8 lines · Raghavendra K T
Quoted 5 lines

The problem occurs even with no overcommit at all. One vcpu is in a legitimately long pause loop. All those exits accomplish nothing, since all vcpus are scheduled. Better to let it spin in guest mode.

I agree. One idea is we can have a scan_window to limit the scan of all n vcpus each time we enter vcpu_spin, to say 2*log n initially;

Not sure I agree. The subset that we scan is in no way special, there's no reason to suppose it would be effective.

We can make the loop exit time scale with the number of vcpus to account for the greater effort needed to wake a vcpu.

Signature · 1 line
error compiling committee.c: too many arguments to function
#49 lore raw
In reply to Raghavendra K T
Quoted 11 lines · Raghavendra K T

Currently Pause Looop Exit (PLE) handler is doing directed yield to a random VCPU on PL exit. Though we already have filtering while choosing the candidate to yield_to, we can do better.

Problem is, for large vcpu guests, we have more probability of yielding to a bad vcpu. We are not able to prevent directed yield to same guy who has done PL exit recently, who perhaps spins again and wastes CPU.

Fix that by keeping track of who has done PL exit. So The Algorithm in series give chance to a VCPU which has:

Quoted 6 lines

(a) Not done PLE exit at all (probably he is preempted lock-holder)

(b) VCPU skipped in last iteration because it did PL exit, and probably has become eligible now (next eligible lock holder)

Future enhancemnets:

Your patch series looks good to me. Simple changes with a significant result.

However, the simple heuristic could use some comments :)

Signature · 1 line
All rights reversed