Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[PATCH RFC 2/2] kvm: Be courteous to other VMs in overcommitted scenario in PLE handler

83 views
Skip to first unread message

Raghavendra K T

unread,
Sep 21, 2012, 8:10:01 AM9/21/12
to
From: Raghavendra K T <raghave...@linux.vnet.ibm.com>

When PLE handler fails to find a better candidate to yield_to, it
goes back and does spin again. This is acceptable when we do not
have overcommit.
But in overcommitted scenarios (especially when we have large
number of small guests), it is better to yield.

Reviewed-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com>
Signed-off-by: Raghavendra K T <raghave...@linux.vnet.ibm.com>
---
virt/kvm/kvm_main.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 8323685..713b677 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1660,6 +1660,10 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
}
}
}
+ /* In overcommitted cases, yield instead of spinning */
+ if (!yielded && rq_nr_running() > 1)
+ schedule();
+
kvm_vcpu_set_in_spin_loop(me, false);

/* Ensure vcpu is not eligible during next spinloop */

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majo...@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Raghavendra K T

unread,
Sep 21, 2012, 8:10:02 AM9/21/12
to
From: Raghavendra K T <raghave...@linux.vnet.ibm.com>

When total number of VCPUs of system is less than or equal to physical CPUs,
PLE exits become costly since each VCPU can have dedicated PCPU, and
trying to find a target VCPU to yield_to just burns time in PLE handler.

This patch reduces overhead, by simply doing a return in such scenarios by
checking the length of current cpu runqueue.

Reviewed-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com>
Signed-off-by: Raghavendra K T <raghave...@linux.vnet.ibm.com>
---
include/linux/sched.h | 1 +
kernel/sched/core.c | 6 ++++++
virt/kvm/kvm_main.c | 3 +++
3 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index b8c8664..3645458 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -138,6 +138,7 @@ extern int nr_threads;
DECLARE_PER_CPU(unsigned long, process_counts);
extern int nr_processes(void);
extern unsigned long nr_running(void);
+extern unsigned long rq_nr_running(void);
extern unsigned long nr_uninterruptible(void);
extern unsigned long nr_iowait(void);
extern unsigned long nr_iowait_cpu(int cpu);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index fbf1fd0..2170b81 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4820,6 +4820,12 @@ void __sched yield(void)
}
EXPORT_SYMBOL(yield);

+unsigned long rq_nr_running(void)
+{
+ return this_rq()->nr_running;
+}
+EXPORT_SYMBOL(rq_nr_running);
+
/**
* yield_to - yield the current processor to another thread in
* your thread group, or accelerate that thread toward the
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 28f00bc..8323685 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1629,6 +1629,9 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
int pass;
int i;

+ if (unlikely(rq_nr_running() == 1))
+ return;
+
kvm_vcpu_set_in_spin_loop(me, true);
/*
* We boost the priority of a VCPU that is runnable but not

Raghavendra K T

unread,
Sep 21, 2012, 8:10:02 AM9/21/12
to
In some special scenarios like #vcpu <= #pcpu, PLE handler may
prove very costly, because there is no need to iterate over vcpus
and do unsuccessful yield_to burning CPU.

An idea to solve this is:
1) As Avi had proposed we can modify hardware ple_window
dynamically to avoid frequent PL-exit. (IMHO, it is difficult to
decide when we have mixed type of VMs).

Another idea, proposed in the first patch, is to identify
non-overcommit case and just return from the PLE handler.

There are are many ways to identify non-overcommit scenario.
1) Using loadavg etc (get_avenrun/calc_global_load
/this_cpu_load)

2) Explicitly check nr_running()/num_online_cpus()

3) Check source vcpu runqueue length.

Not sure how can we make use of (1) effectively/how to use it.
(2) has significant overhead since it iterates all cpus.
so this patch uses third method. (I feel it is uglier to export
runqueue length, but expecting suggestion on this).

In second patch, when we have large number of small guests, it is
possible that a spinning vcpu fails to yield_to any vcpu of same
VM and go back and spin. This is also not effective when we are
over-committed. Instead, we do a schedule() so that we give chance
to other VMs to run.

Raghavendra K T(2):
Handle undercommitted guest case in PLE handler
Be courteous to other VMs in overcommitted scenario in PLE handler

Results:
base = 3.6.0-rc5 + ple handler optimization patches from kvm tree.
patched = base + patch1 + patch2
machine: x240 with 16 core with HT enabled (32 cpu thread).
32 vcpu guest with 8GB RAM.

+-----------+-----------+-----------+------------+-----------+
ebizzy (record/sec higher is better)
+-----------+-----------+-----------+------------+-----------+
base stddev patched stdev %improve
+-----------+-----------+-----------+------------+-----------+
11293.3750 624.4378 18209.6250 371.7061 61.24166
3641.8750 468.9400 3725.5000 253.7823 2.29621
+-----------+-----------+-----------+------------+-----------+

+-----------+-----------+-----------+------------+-----------+
kernbench (time in sec lower is better)
+-----------+-----------+-----------+------------+-----------+
base stddev patched stdev %improve
+-----------+-----------+-----------+------------+-----------+
30.6020 1.3018 30.8287 1.1517 -0.74080
64.0825 2.3764 63.4721 5.0191 0.95252
95.8638 8.7030 94.5988 8.3832 1.31958
+-----------+-----------+-----------+------------+-----------+

Note:
on mx3850x5 machine with 32 cores HT disabled I got around
ebizzy 209%
kernbench 6%
improvement for 1x scenario.

Thanks Srikar for his active partipation in discussing ideas and
reviewing the patch.

Please let me know your suggestions and comments.
---
include/linux/sched.h | 1 +
kernel/sched/core.c | 6 ++++++
virt/kvm/kvm_main.c | 7 +++++++
3 files changed, 14 insertions(+), 0 deletions(-)

Rik van Riel

unread,
Sep 21, 2012, 9:10:02 AM9/21/12
to
On 09/21/2012 08:00 AM, Raghavendra K T wrote:
> From: Raghavendra K T <raghave...@linux.vnet.ibm.com>
>
> When total number of VCPUs of system is less than or equal to physical CPUs,
> PLE exits become costly since each VCPU can have dedicated PCPU, and
> trying to find a target VCPU to yield_to just burns time in PLE handler.
>
> This patch reduces overhead, by simply doing a return in such scenarios by
> checking the length of current cpu runqueue.

I am not convinced this is the way to go.

The VCPU that is holding the lock, and is not releasing it,
probably got scheduled out. That implies that VCPU is on a
runqueue with at least one other task.

> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1629,6 +1629,9 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
> int pass;
> int i;
>
> + if (unlikely(rq_nr_running() == 1))
> + return;
> +
> kvm_vcpu_set_in_spin_loop(me, true);
> /*
> * We boost the priority of a VCPU that is runnable but not
>


--
All rights reversed

Chegu Vinod

unread,
Sep 21, 2012, 9:20:01 AM9/21/12
to
On 9/21/2012 4:59 AM, Raghavendra K T wrote:
> In some special scenarios like #vcpu <= #pcpu, PLE handler may
> prove very costly,

Yes.
> because there is no need to iterate over vcpus
> and do unsuccessful yield_to burning CPU.
>
> An idea to solve this is:
> 1) As Avi had proposed we can modify hardware ple_window
> dynamically to avoid frequent PL-exit.

Yes. We had to do this to get around some scaling issues for large
(>20way) guests (with no overcommitment)

As part of some experimentation we even tried "switching off" PLE too :(



> (IMHO, it is difficult to
> decide when we have mixed type of VMs).

Agree.

Not sure if the following alternatives have also been looked at :

- Could the behavior associated with the "ple_window" be modified to
be a function of some [new] per-guest attribute (which can be conveyed
to the host as part of the guest launch sequence). The user can choose
to set this [new] attribute for a given guest. This would help avoid the
frequent exits due to PLE (as Avi had mentioned earlier) ?

- Can the PLE feature ( in VT) be "enhanced" to be made a per guest
attribute ?


IMHO, the approach of not taking a frequent exit is better than taking
an exit and returning back from the handler etc.

Thanks
Vinod
> .

Rik van Riel

unread,
Sep 21, 2012, 9:30:02 AM9/21/12
to
On 09/21/2012 08:00 AM, Raghavendra K T wrote:
> From: Raghavendra K T <raghave...@linux.vnet.ibm.com>
>
> When PLE handler fails to find a better candidate to yield_to, it
> goes back and does spin again. This is acceptable when we do not
> have overcommit.
> But in overcommitted scenarios (especially when we have large
> number of small guests), it is better to yield.
>
> Reviewed-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com>
> Signed-off-by: Raghavendra K T <raghave...@linux.vnet.ibm.com>

Acked-by: Rik van Riel <ri...@redhat.com>

--
All rights reversed

Takuya Yoshikawa

unread,
Sep 21, 2012, 9:50:01 AM9/21/12
to
On Fri, 21 Sep 2012 17:30:20 +0530
Raghavendra K T <raghave...@linux.vnet.ibm.com> wrote:

> From: Raghavendra K T <raghave...@linux.vnet.ibm.com>
>
> When PLE handler fails to find a better candidate to yield_to, it
> goes back and does spin again. This is acceptable when we do not
> have overcommit.
> But in overcommitted scenarios (especially when we have large
> number of small guests), it is better to yield.
>
> Reviewed-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com>
> Signed-off-by: Raghavendra K T <raghave...@linux.vnet.ibm.com>
> ---
> virt/kvm/kvm_main.c | 4 ++++
> 1 files changed, 4 insertions(+), 0 deletions(-)
>
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 8323685..713b677 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1660,6 +1660,10 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
> }
> }
> }
> + /* In overcommitted cases, yield instead of spinning */
> + if (!yielded && rq_nr_running() > 1)
> + schedule();

How about doing cond_resched() instead?

I'm not sure whether checking more sched stuff in KVM code is a
good thing.

Takuya

Rik van Riel

unread,
Sep 21, 2012, 10:00:02 AM9/21/12
to
On 09/21/2012 09:46 AM, Takuya Yoshikawa wrote:
> On Fri, 21 Sep 2012 17:30:20 +0530
> Raghavendra K T <raghave...@linux.vnet.ibm.com> wrote:
>
>> From: Raghavendra K T <raghave...@linux.vnet.ibm.com>
>>
>> When PLE handler fails to find a better candidate to yield_to, it
>> goes back and does spin again. This is acceptable when we do not
>> have overcommit.
>> But in overcommitted scenarios (especially when we have large
>> number of small guests), it is better to yield.
>>
>> Reviewed-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com>
>> Signed-off-by: Raghavendra K T <raghave...@linux.vnet.ibm.com>
>> ---
>> virt/kvm/kvm_main.c | 4 ++++
>> 1 files changed, 4 insertions(+), 0 deletions(-)
>>
>> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
>> index 8323685..713b677 100644
>> --- a/virt/kvm/kvm_main.c
>> +++ b/virt/kvm/kvm_main.c
>> @@ -1660,6 +1660,10 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
>> }
>> }
>> }
>> + /* In overcommitted cases, yield instead of spinning */
>> + if (!yielded && rq_nr_running() > 1)
>> + schedule();
>
> How about doing cond_resched() instead?

Actually, an actual call to yield() may be better.

That will set scheduler hints to make the scheduler pick
another task for one round, while preserving this task's
top position in the runqueue.

--
All rights reversed

Raghavendra K T

unread,
Sep 21, 2012, 1:30:02 PM9/21/12
to
On 09/21/2012 06:32 PM, Rik van Riel wrote:
> On 09/21/2012 08:00 AM, Raghavendra K T wrote:
>> From: Raghavendra K T <raghave...@linux.vnet.ibm.com>
>>
>> When total number of VCPUs of system is less than or equal to physical
>> CPUs,
>> PLE exits become costly since each VCPU can have dedicated PCPU, and
>> trying to find a target VCPU to yield_to just burns time in PLE handler.
>>
>> This patch reduces overhead, by simply doing a return in such
>> scenarios by
>> checking the length of current cpu runqueue.
>
> I am not convinced this is the way to go.
>
> The VCPU that is holding the lock, and is not releasing it,
> probably got scheduled out. That implies that VCPU is on a
> runqueue with at least one other task.

I see your point here, we have two cases:

case 1)

rq1 : vcpu1->wait(lockA) (spinning)
rq2 : vcpu2->holding(lockA) (running)

Here Ideally vcpu1 should not enter PLE handler, since it would surely
get the lock within ple_window cycle. (assuming ple_window is tuned for
that workload perfectly).

May be this explains why we are not seeing benefit with kernbench.

On the other side, Since we cannot have a perfect ple_window tuned for
all type of workloads, for those workloads, which may need more than
4096 cycles, we gain. thinking is it that we are seeing in benefited
cases?

case 2)
rq1 : vcpu1->wait(lockA) (spinning)
rq2 : vcpu3 (running) , vcpu2->holding(lockA) [scheduled out]

I agree that checking rq1 length is not proper in this case, and as you
rightly pointed out, we are in trouble here.
nr_running()/num_online_cpus() would give more accurate picture here,
but it seemed costly. May be load balancer save us a bit here in not
running to such sort of cases. ( I agree load balancer is far too
complex).

Raghavendra K T

unread,
Sep 21, 2012, 1:50:02 PM9/21/12
to
I am not a scheduler expert, but I am also inclined towards
Rik's suggestion here since we set skip buddy here. Takuya?

Raghavendra K T

unread,
Sep 21, 2012, 1:50:04 PM9/21/12
to
On 09/21/2012 06:48 PM, Chegu Vinod wrote:
> On 9/21/2012 4:59 AM, Raghavendra K T wrote:
>> In some special scenarios like #vcpu <= #pcpu, PLE handler may
>> prove very costly,
>
> Yes.
>> because there is no need to iterate over vcpus
>> and do unsuccessful yield_to burning CPU.
>>
>> An idea to solve this is:
>> 1) As Avi had proposed we can modify hardware ple_window
>> dynamically to avoid frequent PL-exit.
>
> Yes. We had to do this to get around some scaling issues for large
> (>20way) guests (with no overcommitment)

Do you mean you already have some solution tested for this?

>
> As part of some experimentation we even tried "switching off" PLE too :(
>

Honestly,
Your this experiment and Andrew Theurer's observations were the
motivation for this patch.

>
>
>> (IMHO, it is difficult to
>> decide when we have mixed type of VMs).
>
> Agree.
>
> Not sure if the following alternatives have also been looked at :
>
> - Could the behavior associated with the "ple_window" be modified to be
> a function of some [new] per-guest attribute (which can be conveyed to
> the host as part of the guest launch sequence). The user can choose to
> set this [new] attribute for a given guest. This would help avoid the
> frequent exits due to PLE (as Avi had mentioned earlier) ?

Ccing Drew also. We had a good discussion on this idea last time.
(sorry that I forgot to include in patch series)

May be a good idea when we know the load in advance..

>
> - Can the PLE feature ( in VT) be "enhanced" to be made a per guest
> attribute ?
>
>
> IMHO, the approach of not taking a frequent exit is better than taking
> an exit and returning back from the handler etc.

I entirely agree on this point. (though have not tried above
approaches). Hope to see more expert opinions pouring in.

Dor Laor

unread,
Sep 24, 2012, 4:50:02 AM9/24/12
to
In order to help PLE and pvticketlock converge I thought that a small
test code should be developed to test this in a predictable,
deterministic way.

The idea is to have a guest kernel module that spawn a new thread each
time you write to a /sys/.... entry.

Each such a thread spins over a spin lock. The specific spin lock is
also chosen by the /sys/ interface. Let's say we have an array of spin
locks *10 times the amount of vcpus.

All the threads are running a
while (1) {

spin_lock(my_lock);
sum += execute_dummy_cpu_computation(time);
spin_unlock(my_lock);

if (sys_tells_thread_to_die()) break;
}

print_result(sum);

Instead of calling the kernel's spin_lock functions, clone them and make
the ticket lock order deterministic and known (like a linear walk of all
the threads trying to catch that lock).

This way you can easy calculate:
1. the score of a single vcpu running a single thread
2. the score of sum of all thread scores when #thread==#vcpu all
taking the same spin lock. The overall sum should be close as
possible to #1.
3. Like #2 but #threads > #vcpus and other versions of #total vcpus
(belonging to all VMs) > #pcpus.
4. Create #thread == #vcpus but let each thread have it's own spin
lock
5. Like 4 + 2

Hopefully this way will allows you to judge and evaluate the exact
overhead of scheduling VMs and threads since you have the ideal result
in hand and you know what the threads are doing.

My 2 cents, Dor
> To unsubscribe from this list: send the line "unsubscribe kvm" in

Peter Zijlstra

unread,
Sep 24, 2012, 7:40:02 AM9/24/12
to
On Fri, 2012-09-21 at 17:30 +0530, Raghavendra K T wrote:
> +unsigned long rq_nr_running(void)
> +{
> + return this_rq()->nr_running;
> +}
> +EXPORT_SYMBOL(rq_nr_running);

Uhm,.. no, that's a horrible thing to export.

Peter Zijlstra

unread,
Sep 24, 2012, 7:40:02 AM9/24/12
to
On Fri, 2012-09-21 at 17:29 +0530, Raghavendra K T wrote:
> In some special scenarios like #vcpu <= #pcpu, PLE handler may
> prove very costly, because there is no need to iterate over vcpus
> and do unsuccessful yield_to burning CPU.

What's the costly thing? The vm-exit, the yield (which should be a nop
if its the only task there) or something else entirely?

Raghavendra K T

unread,
Sep 24, 2012, 7:50:01 AM9/24/12
to
On 09/24/2012 05:03 PM, Peter Zijlstra wrote:
> On Fri, 2012-09-21 at 17:30 +0530, Raghavendra K T wrote:
>> +unsigned long rq_nr_running(void)
>> +{
>> + return this_rq()->nr_running;
>> +}
>> +EXPORT_SYMBOL(rq_nr_running);
>
> Uhm,.. no, that's a horrible thing to export.
>

True.. I had the same fear :). Other options I thought were something
like nr_running()/num_online_cpus, this_cpu_load(), etc..

Could you please let me know, if we can rely some good metric to say,
system is not overcommitted/overcommitted?

Raghavendra K T

unread,
Sep 24, 2012, 8:00:02 AM9/24/12
to
On 09/24/2012 05:04 PM, Peter Zijlstra wrote:
> On Fri, 2012-09-21 at 17:29 +0530, Raghavendra K T wrote:
>> In some special scenarios like #vcpu<= #pcpu, PLE handler may
>> prove very costly, because there is no need to iterate over vcpus
>> and do unsuccessful yield_to burning CPU.
>
> What's the costly thing? The vm-exit, the yield (which should be a nop
> if its the only task there) or something else entirely?
>
Both vmexit and yield_to() actually,

because unsuccessful yield_to() overall is costly in PLE handler.

This is because when we have large guests, say 32/16 vcpus, and one
vcpu is holding lock, rest of the vcpus waiting for the lock, when they
do PL-exit, each of the vcpu try to iterate over rest of vcpu list in
the VM and try to do directed yield (unsuccessful). (O(n^2) tries).

this results is fairly high amount of cpu burning and double run queue
lock contention.

(if they were spinning probably lock progress would have been faster).
As Avi/Chegu Vinod had felt it is better to avoid vmexit itself, which
seems little complex to achieve currently.

Raghavendra K T

unread,
Sep 24, 2012, 8:10:02 AM9/24/12
to
On 09/24/2012 02:12 PM, Dor Laor wrote:
> In order to help PLE and pvticketlock converge I thought that a small
> test code should be developed to test this in a predictable,
> deterministic way.
>
> The idea is to have a guest kernel module that spawn a new thread each
> time you write to a /sys/.... entry.
>
> Each such a thread spins over a spin lock. The specific spin lock is
> also chosen by the /sys/ interface. Let's say we have an array of spin
> locks *10 times the amount of vcpus.
>
> All the threads are running a
> while (1) {
>
> spin_lock(my_lock);
> sum += execute_dummy_cpu_computation(time);
> spin_unlock(my_lock);
>
> if (sys_tells_thread_to_die()) break;
> }
>
> print_result(sum);
>
> Instead of calling the kernel's spin_lock functions, clone them and make
> the ticket lock order deterministic and known (like a linear walk of all
> the threads trying to catch that lock).

By Cloning you mean hierarchy of the locks?
Also I believe time should be passed via sysfs / hardcoded for each
type of lock we are mimicking

>
> This way you can easy calculate:
> 1. the score of a single vcpu running a single thread
> 2. the score of sum of all thread scores when #thread==#vcpu all
> taking the same spin lock. The overall sum should be close as
> possible to #1.
> 3. Like #2 but #threads > #vcpus and other versions of #total vcpus
> (belonging to all VMs) > #pcpus.
> 4. Create #thread == #vcpus but let each thread have it's own spin
> lock
> 5. Like 4 + 2
>
> Hopefully this way will allows you to judge and evaluate the exact
> overhead of scheduling VMs and threads since you have the ideal result
> in hand and you know what the threads are doing.
>
> My 2 cents, Dor
>

Thank you,
I think this is an excellent idea. ( Though I am trying to put all the
pieces together you mentioned). So overall we should be able to measure
the performance of pvspinlock/PLE improvements with a deterministic
load in guest.

Only thing I am missing is,
How to generate different combinations of the lock.

Okay, let me see if I can come with a solid model for this.

Peter Zijlstra

unread,
Sep 24, 2012, 8:40:02 AM9/24/12
to
On Mon, 2012-09-24 at 17:22 +0530, Raghavendra K T wrote:
> On 09/24/2012 05:04 PM, Peter Zijlstra wrote:
> > On Fri, 2012-09-21 at 17:29 +0530, Raghavendra K T wrote:
> >> In some special scenarios like #vcpu<= #pcpu, PLE handler may
> >> prove very costly, because there is no need to iterate over vcpus
> >> and do unsuccessful yield_to burning CPU.
> >
> > What's the costly thing? The vm-exit, the yield (which should be a nop
> > if its the only task there) or something else entirely?
> >
> Both vmexit and yield_to() actually,
>
> because unsuccessful yield_to() overall is costly in PLE handler.
>
> This is because when we have large guests, say 32/16 vcpus, and one
> vcpu is holding lock, rest of the vcpus waiting for the lock, when they
> do PL-exit, each of the vcpu try to iterate over rest of vcpu list in
> the VM and try to do directed yield (unsuccessful). (O(n^2) tries).
>
> this results is fairly high amount of cpu burning and double run queue
> lock contention.
>
> (if they were spinning probably lock progress would have been faster).
> As Avi/Chegu Vinod had felt it is better to avoid vmexit itself, which
> seems little complex to achieve currently.

OK, so the vmexit stays and we need to improve yield_to.

How about something like the below, that would allow breaking out of the
for-each-vcpu loop and simply going back into the vm, right?

---
kernel/sched/core.c | 25 +++++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index b38f00e..5d5b355 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4272,7 +4272,10 @@ EXPORT_SYMBOL(yield);
* It's the caller's job to ensure that the target task struct
* can't go away on us before we can do any checks.
*
- * Returns true if we indeed boosted the target task.
+ * Returns:
+ * true (>0) if we indeed boosted the target task.
+ * false (0) if we failed to boost the target.
+ * -ESRCH if there's no task to yield to.
*/
bool __sched yield_to(struct task_struct *p, bool preempt)
{
@@ -4284,6 +4287,15 @@ bool __sched yield_to(struct task_struct *p, bool preempt)
local_irq_save(flags);
rq = this_rq();

+ /*
+ * If we're the only runnable task on the rq, there's absolutely no
+ * point in yielding.
+ */
+ if (rq->nr_running == 1) {
+ yielded = -ESRCH;
+ goto out_irq;
+ }
+
again:
p_rq = task_rq(p);
double_rq_lock(rq, p_rq);
@@ -4293,13 +4305,13 @@ bool __sched yield_to(struct task_struct *p, bool preempt)
}

if (!curr->sched_class->yield_to_task)
- goto out;
+ goto out_unlock;

if (curr->sched_class != p->sched_class)
- goto out;
+ goto out_unlock;

if (task_running(p_rq, p) || p->state)
- goto out;
+ goto out_unlock;

yielded = curr->sched_class->yield_to_task(rq, p, preempt);
if (yielded) {
@@ -4312,11 +4324,12 @@ bool __sched yield_to(struct task_struct *p, bool preempt)
resched_task(p_rq->curr);
}

-out:
+out_unlock:
double_rq_unlock(rq, p_rq);
+out_irq:
local_irq_restore(flags);

- if (yielded)
+ if (yielded > 0)
schedule();

return yielded;

Raghavendra K T

unread,
Sep 24, 2012, 9:40:02 AM9/24/12
to
Yes, I think this is a nice idea. Any future users of yield_to
also would benefit from this. we will have to iterate only till first
attempt to yield_to.

I 'll run the test with this patch.

However Rik had a genuine concern in the cases where runqueue is not
equally distributed and lockholder might actually be on a different run
queue but not running.

Do you think instead of using rq->nr_running, we could get a global
sense of load using avenrun (something like avenrun/num_onlinecpus)

Takuya Yoshikawa

unread,
Sep 24, 2012, 9:50:02 AM9/24/12
to
On Fri, 21 Sep 2012 23:15:40 +0530
Raghavendra K T <raghave...@linux.vnet.ibm.com> wrote:

> >> How about doing cond_resched() instead?
> >
> > Actually, an actual call to yield() may be better.
> >
> > That will set scheduler hints to make the scheduler pick
> > another task for one round, while preserving this task's
> > top position in the runqueue.
>
> I am not a scheduler expert, but I am also inclined towards
> Rik's suggestion here since we set skip buddy here. Takuya?
>

Yes, I think it's better.
But I hope that experts in Cc will suggest the best way.

Thanks,
Takuya

Peter Zijlstra

unread,
Sep 24, 2012, 10:00:01 AM9/24/12
to
On Mon, 2012-09-24 at 18:59 +0530, Raghavendra K T wrote:
> However Rik had a genuine concern in the cases where runqueue is not
> equally distributed and lockholder might actually be on a different run
> queue but not running.

Load should eventually get distributed equally -- that's what the
load-balancer is for -- so this is a temporary situation.

We already try and favour the non running vcpu in this case, that's what
yield_to_task_fair() is about. If its still not eligible to run, tough
luck.

> Do you think instead of using rq->nr_running, we could get a global
> sense of load using avenrun (something like avenrun/num_onlinecpus)

To what purpose? Also, global stuff is expensive, so you should try and
stay away from it as hard as you possibly can.

Raghavendra K T

unread,
Sep 24, 2012, 10:30:02 AM9/24/12
to
On 09/24/2012 07:24 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 18:59 +0530, Raghavendra K T wrote:
>> However Rik had a genuine concern in the cases where runqueue is not
>> equally distributed and lockholder might actually be on a different run
>> queue but not running.
>
> Load should eventually get distributed equally -- that's what the
> load-balancer is for -- so this is a temporary situation.
>
> We already try and favour the non running vcpu in this case, that's what
> yield_to_task_fair() is about. If its still not eligible to run, tough
> luck.

Yes, I agree.

>
>> Do you think instead of using rq->nr_running, we could get a global
>> sense of load using avenrun (something like avenrun/num_onlinecpus)
>
> To what purpose? Also, global stuff is expensive, so you should try and
> stay away from it as hard as you possibly can.

Yes, that concern only had made me to fall back to rq->nr_running.

Will come back with the result soon.

Avi Kivity

unread,
Sep 24, 2012, 11:30:02 AM9/24/12
to
On 09/21/2012 03:00 PM, Raghavendra K T wrote:
> From: Raghavendra K T <raghave...@linux.vnet.ibm.com>
>
> When PLE handler fails to find a better candidate to yield_to, it
> goes back and does spin again. This is acceptable when we do not
> have overcommit.
> But in overcommitted scenarios (especially when we have large
> number of small guests), it is better to yield.
>
> Reviewed-by: Srikar Dronamraju <sri...@linux.vnet.ibm.com>
> Signed-off-by: Raghavendra K T <raghave...@linux.vnet.ibm.com>
> ---
> virt/kvm/kvm_main.c | 4 ++++
> 1 files changed, 4 insertions(+), 0 deletions(-)
>
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 8323685..713b677 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -1660,6 +1660,10 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
> }
> }
> }
> + /* In overcommitted cases, yield instead of spinning */
> + if (!yielded && rq_nr_running() > 1)
> + schedule();
> +

I think this is a no-op these (CFS) days. To get schedule() to do
anything, you need to wake up a task, or let time pass, or block.
Otherwise it will see that nothing has changed and as far as it's
concerned you're still the best task to be running (otherwise it
wouldn't have picked you in the first place).


--
error compiling committee.c: too many arguments to function

Peter Zijlstra

unread,
Sep 24, 2012, 11:40:01 AM9/24/12
to
On Mon, 2012-09-24 at 17:26 +0200, Avi Kivity wrote:
> I think this is a no-op these (CFS) days. To get schedule() to do
> anything, you need to wake up a task, or let time pass, or block.
> Otherwise it will see that nothing has changed and as far as it's
> concerned you're still the best task to be running (otherwise it
> wouldn't have picked you in the first place).

Time could have passed enough before calling this that there's now a
different/more eligible task around to schedule.

Esp. for a !PREEMPT kernel this is could be significant.

Avi Kivity

unread,
Sep 24, 2012, 11:50:02 AM9/24/12
to
On 09/24/2012 05:34 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 17:26 +0200, Avi Kivity wrote:
>> I think this is a no-op these (CFS) days. To get schedule() to do
>> anything, you need to wake up a task, or let time pass, or block.
>> Otherwise it will see that nothing has changed and as far as it's
>> concerned you're still the best task to be running (otherwise it
>> wouldn't have picked you in the first place).
>
> Time could have passed enough before calling this that there's now a
> different/more eligible task around to schedule.

Wouldn't this correspond to the scheduler interrupt firing and causing a
reschedule? I thought the timer was programmed for exactly the point in
time that CFS considers the right time for a switch. But I'm basing
this on my mental model of CFS, not CFS itself.

> Esp. for a !PREEMPT kernel this is could be significant.


--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 24, 2012, 11:50:02 AM9/24/12
to
Maybe we need to increase the ple window regardless. 4096 cycles is 2
microseconds or less (call it t_spin). The overhead from
kvm_vcpu_on_spin() and the associated task switches is at least a few
microseconds, increasing as contention is added (call it t_tield). The
time for a natural context switch is several milliseconds (call it
t_slice). There is also the time the lock holder owns the lock,
assuming no contention (t_hold).

If t_yield > t_spin, then in the undercommitted case it dominates
t_spin. If t_hold > t_spin we lose badly.

If t_spin > t_yield, then the undercommitted case doesn't suffer as much
as most of the spinning happens in the guest instead of the host, so it
can pick up the unlock timely. We don't lose too much in the
overcommitted case provided the values aren't too far apart (say a
factor of 3).

Obviously t_spin must be significantly smaller than t_slice, otherwise
it accomplishes nothing.

Regarding t_hold: if it is small, then a larger t_spin helps avoid false
exits. If it is large, then we're not very sensitive to t_spin. It
doesn't matter if it takes us 2 usec or 20 usec to yield, if we end up
yielding for several milliseconds.

So I think it's worth trying again with ple_window of 20000-40000.

>
> case 2)
> rq1 : vcpu1->wait(lockA) (spinning)
> rq2 : vcpu3 (running) , vcpu2->holding(lockA) [scheduled out]
>
> I agree that checking rq1 length is not proper in this case, and as you
> rightly pointed out, we are in trouble here.
> nr_running()/num_online_cpus() would give more accurate picture here,
> but it seemed costly. May be load balancer save us a bit here in not
> running to such sort of cases. ( I agree load balancer is far too
> complex).

In theory preempt notifier can tell us whether a vcpu is preempted or
not (except for exits to userspace), so we can keep track of whether
it's we're overcommitted in kvm itself. It also avoids false positives
from other guests and/or processes being overcommitted while our vm is fine.


--
error compiling committee.c: too many arguments to function

Peter Zijlstra

unread,
Sep 24, 2012, 12:00:02 PM9/24/12
to
On Mon, 2012-09-24 at 17:43 +0200, Avi Kivity wrote:
> Wouldn't this correspond to the scheduler interrupt firing and causing a
> reschedule? I thought the timer was programmed for exactly the point in
> time that CFS considers the right time for a switch. But I'm basing
> this on my mental model of CFS, not CFS itself.

No, we tried this for hrtimer kernels for a while, but programming
hrtimers the whole time (every actual task-switch) turns out to be far
too expensive. So we're back to HZ ticks and 'polling' the preemption
state.

Even if we remove all the hrtimer infrastructure overhead (can do with a
few hacks) setting the hardware requires going out to the LAPIC, which
is stupid slow.

Some hardware actually has fast/reliable/usable timers, sadly none of it
is popular.

Avi Kivity

unread,
Sep 24, 2012, 12:00:02 PM9/24/12
to
On 09/24/2012 05:52 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 17:43 +0200, Avi Kivity wrote:
>> Wouldn't this correspond to the scheduler interrupt firing and causing a
>> reschedule? I thought the timer was programmed for exactly the point in
>> time that CFS considers the right time for a switch. But I'm basing
>> this on my mental model of CFS, not CFS itself.
>
> No, we tried this for hrtimer kernels for a while, but programming
> hrtimers the whole time (every actual task-switch) turns out to be far
> too expensive. So we're back to HZ ticks and 'polling' the preemption
> state.

Ok, so I wasn't completely off base.

With HZ=1000, we can only be faster than the poll by a millisecond than
the interrupt-driven schedule(), and we need to be a lot faster.

> Even if we remove all the hrtimer infrastructure overhead (can do with a
> few hacks) setting the hardware requires going out to the LAPIC, which
> is stupid slow.
>
> Some hardware actually has fast/reliable/usable timers, sadly none of it
> is popular.

There is the TSC deadline timer mode of newer Intels. Programming the
timer is a simple wrmsr, and it will fire immediately if it already
expired. Unfortunately on AMDs it is not available, and on virtual
hardware it will be slow (~1-2 usec).

--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 24, 2012, 12:00:03 PM9/24/12
to
On 09/24/2012 03:54 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 18:59 +0530, Raghavendra K T wrote:
>> However Rik had a genuine concern in the cases where runqueue is not
>> equally distributed and lockholder might actually be on a different run
>> queue but not running.
>
> Load should eventually get distributed equally -- that's what the
> load-balancer is for -- so this is a temporary situation.

What's the expected latency? This is the whole problem. Eventually the
scheduler would pick the lock holder as well, the problem is that it's
in the millisecond scale while lock hold times are in the microsecond
scale, leading to a 1000x slowdown.

If we want to yield, we really want to boost someone.

> We already try and favour the non running vcpu in this case, that's what
> yield_to_task_fair() is about. If its still not eligible to run, tough
> luck.

Crazy idea: instead of yielding, just run that other vcpu in the thread
that would otherwise spin. I can see about a million objections to this
already though.

>> Do you think instead of using rq->nr_running, we could get a global
>> sense of load using avenrun (something like avenrun/num_onlinecpus)
>
> To what purpose? Also, global stuff is expensive, so you should try and
> stay away from it as hard as you possibly can.

Spinning is also expensive. How about we do the global stuff every N
times, to amortize the cost (and reduce contention)?

--
error compiling committee.c: too many arguments to function

Peter Zijlstra

unread,
Sep 24, 2012, 12:10:04 PM9/24/12
to
On Mon, 2012-09-24 at 17:58 +0200, Avi Kivity wrote:
> There is the TSC deadline timer mode of newer Intels. Programming the
> timer is a simple wrmsr, and it will fire immediately if it already
> expired. Unfortunately on AMDs it is not available, and on virtual
> hardware it will be slow (~1-2 usec).

Its also still a LAPIC write -- disguised as an MSR though :/

Also, who gives a hoot about virtual crap ;-)

Avi Kivity

unread,
Sep 24, 2012, 12:10:03 PM9/24/12
to
On 09/24/2012 05:41 PM, Avi Kivity wrote:
>
>>
>> case 2)
>> rq1 : vcpu1->wait(lockA) (spinning)
>> rq2 : vcpu3 (running) , vcpu2->holding(lockA) [scheduled out]
>>
>> I agree that checking rq1 length is not proper in this case, and as you
>> rightly pointed out, we are in trouble here.
>> nr_running()/num_online_cpus() would give more accurate picture here,
>> but it seemed costly. May be load balancer save us a bit here in not
>> running to such sort of cases. ( I agree load balancer is far too
>> complex).
>
> In theory preempt notifier can tell us whether a vcpu is preempted or
> not (except for exits to userspace), so we can keep track of whether
> it's we're overcommitted in kvm itself. It also avoids false positives
> from other guests and/or processes being overcommitted while our vm is fine.

It also allows us to cheaply skip running vcpus.

We would probably need a ->sched_exit() preempt notifier to make this
work. Peter, I know how much you love those, would it be acceptable?
We'd still need yield_to() but the pressure on it might be reduced.

Peter Zijlstra

unread,
Sep 24, 2012, 12:10:04 PM9/24/12
to
On Mon, 2012-09-24 at 17:51 +0200, Avi Kivity wrote:
> On 09/24/2012 03:54 PM, Peter Zijlstra wrote:
> > On Mon, 2012-09-24 at 18:59 +0530, Raghavendra K T wrote:
> >> However Rik had a genuine concern in the cases where runqueue is not
> >> equally distributed and lockholder might actually be on a different run
> >> queue but not running.
> >
> > Load should eventually get distributed equally -- that's what the
> > load-balancer is for -- so this is a temporary situation.
>
> What's the expected latency? This is the whole problem. Eventually the
> scheduler would pick the lock holder as well, the problem is that it's
> in the millisecond scale while lock hold times are in the microsecond
> scale, leading to a 1000x slowdown.

Yeah I know.. Heisenberg's uncertainty applied to SMP computing becomes
something like accurate or fast, never both.

> If we want to yield, we really want to boost someone.

Now if only you knew which someone ;-) This non-modified guest nonsense
is such a snake pit.. but you know how I feel about all that.

> > We already try and favour the non running vcpu in this case, that's what
> > yield_to_task_fair() is about. If its still not eligible to run, tough
> > luck.
>
> Crazy idea: instead of yielding, just run that other vcpu in the thread
> that would otherwise spin. I can see about a million objections to this
> already though.

Yah.. you want me to list a few? :-) It would require synchronization
with the other cpu to pull its task -- one really wants to avoid it also
running it.

Do this at a high enough frequency and you're dead too.

Anyway, you can do this inside the KVM stuff, simply flip the vcpu state
associated with a vcpu thread and use the preemption notifiers to sort
things against the scheduler or somesuch.

> >> Do you think instead of using rq->nr_running, we could get a global
> >> sense of load using avenrun (something like avenrun/num_onlinecpus)
> >
> > To what purpose? Also, global stuff is expensive, so you should try and
> > stay away from it as hard as you possibly can.
>
> Spinning is also expensive. How about we do the global stuff every N
> times, to amortize the cost (and reduce contention)?

Nah, spinning isn't expensive, its a waste of time, similar end result
for someone who wants to do useful work though, but not the same cause.

Pick N and I'll come up with a scenario for which its wrong ;-)

Anyway, its an ugly problem and one I really want to contain inside the
insanity that created it (virt), lets not taint the rest of the kernel
more than we need to.

Avi Kivity

unread,
Sep 24, 2012, 12:20:02 PM9/24/12
to
On 09/24/2012 06:05 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 17:58 +0200, Avi Kivity wrote:
>> There is the TSC deadline timer mode of newer Intels. Programming the
>> timer is a simple wrmsr, and it will fire immediately if it already
>> expired. Unfortunately on AMDs it is not available, and on virtual
>> hardware it will be slow (~1-2 usec).
>
> Its also still a LAPIC write -- disguised as an MSR though :/

It's probably a whole lot faster though.

> Also, who gives a hoot about virtual crap ;-)

I only mentioned it to see if your virtual crap detector is still
working. Looks like it's still in top condition, low latency and 100%
hit rate.

--
error compiling committee.c: too many arguments to function

Peter Zijlstra

unread,
Sep 24, 2012, 12:20:02 PM9/24/12
to
On Mon, 2012-09-24 at 18:06 +0200, Avi Kivity wrote:
>
> We would probably need a ->sched_exit() preempt notifier to make this
> work. Peter, I know how much you love those, would it be acceptable?

Where exactly do you want this? TASK_DEAD? or another exit?

Peter Zijlstra

unread,
Sep 24, 2012, 12:20:02 PM9/24/12
to
On Mon, 2012-09-24 at 18:10 +0200, Avi Kivity wrote:
> > Its also still a LAPIC write -- disguised as an MSR though :/
>
> It's probably a whole lot faster though.

I've been told its not, I haven't tried it.

Avi Kivity

unread,
Sep 24, 2012, 12:30:01 PM9/24/12
to
On 09/24/2012 06:14 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 18:06 +0200, Avi Kivity wrote:
>>
>> We would probably need a ->sched_exit() preempt notifier to make this
>> work. Peter, I know how much you love those, would it be acceptable?
>
> Where exactly do you want this? TASK_DEAD? or another exit?

TASK_DEAD of the task that registered the preempt notifier.

The idea is that I want to hold on to the notifier even when exiting to
userspace. Since userspace is under no obligation to call kvm again, I
need a chance to unregister the notifier and otherwise clean up.

Eh, looking at the code, we'll have a ->sched_out() after the state is
set to TASK_DEAD. So all we need to do is examine the state. We'll
need to examine the state anyway to see if we were preempted or blocking.

--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 24, 2012, 12:30:01 PM9/24/12
to
On 09/24/2012 06:03 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 17:51 +0200, Avi Kivity wrote:
>> On 09/24/2012 03:54 PM, Peter Zijlstra wrote:
>> > On Mon, 2012-09-24 at 18:59 +0530, Raghavendra K T wrote:
>> >> However Rik had a genuine concern in the cases where runqueue is not
>> >> equally distributed and lockholder might actually be on a different run
>> >> queue but not running.
>> >
>> > Load should eventually get distributed equally -- that's what the
>> > load-balancer is for -- so this is a temporary situation.
>>
>> What's the expected latency? This is the whole problem. Eventually the
>> scheduler would pick the lock holder as well, the problem is that it's
>> in the millisecond scale while lock hold times are in the microsecond
>> scale, leading to a 1000x slowdown.
>
> Yeah I know.. Heisenberg's uncertainty applied to SMP computing becomes
> something like accurate or fast, never both.
>
>> If we want to yield, we really want to boost someone.
>
> Now if only you knew which someone ;-) This non-modified guest nonsense
> is such a snake pit.. but you know how I feel about all that.

Actually if I knew that in addition to boosting someone, I also unboost
myself enough to be preempted, it wouldn't matter. While boosting the
lock holder is good, the main point is not spinning and doing useful
work instead. We can detect spinners and avoid boosting them.

That's the motivation for the "donate vruntime" approach I wanted earlier.

>
>> > We already try and favour the non running vcpu in this case, that's what
>> > yield_to_task_fair() is about. If its still not eligible to run, tough
>> > luck.
>>
>> Crazy idea: instead of yielding, just run that other vcpu in the thread
>> that would otherwise spin. I can see about a million objections to this
>> already though.
>
> Yah.. you want me to list a few? :-) It would require synchronization
> with the other cpu to pull its task -- one really wants to avoid it also
> running it.

Yeah, it's quite a horrible idea.

>
> Do this at a high enough frequency and you're dead too.
>
> Anyway, you can do this inside the KVM stuff, simply flip the vcpu state
> associated with a vcpu thread and use the preemption notifiers to sort
> things against the scheduler or somesuch.

That's what I thought when I wrote this, but I can't, I might be
preempted in random kvm code. So my state includes the host stack and
registers. Maybe we can special-case when we interrupt guest mode.

>
>> >> Do you think instead of using rq->nr_running, we could get a global
>> >> sense of load using avenrun (something like avenrun/num_onlinecpus)
>> >
>> > To what purpose? Also, global stuff is expensive, so you should try and
>> > stay away from it as hard as you possibly can.
>>
>> Spinning is also expensive. How about we do the global stuff every N
>> times, to amortize the cost (and reduce contention)?
>
> Nah, spinning isn't expensive, its a waste of time, similar end result
> for someone who wants to do useful work though, but not the same cause.
>
> Pick N and I'll come up with a scenario for which its wrong ;-)

Sure. But if it's rare enough, then that's okay for us.

> Anyway, its an ugly problem and one I really want to contain inside the
> insanity that created it (virt), lets not taint the rest of the kernel
> more than we need to.

Agreed. Though given that postgres and others use userspace spinlocks,
maybe it's not just virt.

--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 24, 2012, 12:30:02 PM9/24/12
to
On 09/24/2012 06:13 PM, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 18:10 +0200, Avi Kivity wrote:
>> > Its also still a LAPIC write -- disguised as an MSR though :/
>>
>> It's probably a whole lot faster though.
>
> I've been told its not, I haven't tried it.

I'll see if I can find a machine with it (don't see it on my Westmere,
it's probably on one of the Bridges. Or maybe the other Peter knows.


--
error compiling committee.c: too many arguments to function

Raghavendra K T

unread,
Sep 25, 2012, 3:40:01 AM9/25/12
to
Agree that spinning is not costly and I have tried increasing
ple_window earlier. I 'll give one more shot.

I was thinking, unnessary spinning of vcpus (spinning when lockholder
is preempted), add up to degradation significantly, especially in
ticketlock scenario is more problemtic. no?

Avi Kivity

unread,
Sep 25, 2012, 4:20:01 AM9/25/12
to
It will. The tradeoff is between false-positive costs (undercommit) and
true positive costs (overcommit). I think undercommit should perform
well no matter what.

If we utilize preempt notifiers to track overcommit dynamically, then we
can vary the spin time dynamically. Keep it long initially, as we get
more preempted vcpus make it shorter.

--
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

Raghavendra K T

unread,
Sep 25, 2012, 4:20:02 AM9/25/12
to
On 09/24/2012 09:36 PM, Avi Kivity wrote:
> On 09/24/2012 05:41 PM, Avi Kivity wrote:
>>
>>>
>>> case 2)
>>> rq1 : vcpu1->wait(lockA) (spinning)
>>> rq2 : vcpu3 (running) , vcpu2->holding(lockA) [scheduled out]
>>>
>>> I agree that checking rq1 length is not proper in this case, and as you
>>> rightly pointed out, we are in trouble here.
>>> nr_running()/num_online_cpus() would give more accurate picture here,
>>> but it seemed costly. May be load balancer save us a bit here in not
>>> running to such sort of cases. ( I agree load balancer is far too
>>> complex).
>>
>> In theory preempt notifier can tell us whether a vcpu is preempted or
>> not (except for exits to userspace), so we can keep track of whether
>> it's we're overcommitted in kvm itself. It also avoids false positives
>> from other guests and/or processes being overcommitted while our vm is fine.
>
> It also allows us to cheaply skip running vcpus.

Hi Avi,

Could you please elaborate on how preempt notifiers can be used
here to keep track of overcommit or skip running vcpus?

Are we planning set some flag in sched_out() handler etc?

Avi Kivity

unread,
Sep 25, 2012, 5:00:02 AM9/25/12
to
On 09/25/2012 10:09 AM, Raghavendra K T wrote:
> On 09/24/2012 09:36 PM, Avi Kivity wrote:
>> On 09/24/2012 05:41 PM, Avi Kivity wrote:
>>>
>>>>
>>>> case 2)
>>>> rq1 : vcpu1->wait(lockA) (spinning)
>>>> rq2 : vcpu3 (running) , vcpu2->holding(lockA) [scheduled out]
>>>>
>>>> I agree that checking rq1 length is not proper in this case, and as
>>>> you
>>>> rightly pointed out, we are in trouble here.
>>>> nr_running()/num_online_cpus() would give more accurate picture here,
>>>> but it seemed costly. May be load balancer save us a bit here in not
>>>> running to such sort of cases. ( I agree load balancer is far too
>>>> complex).
>>>
>>> In theory preempt notifier can tell us whether a vcpu is preempted or
>>> not (except for exits to userspace), so we can keep track of whether
>>> it's we're overcommitted in kvm itself. It also avoids false positives
>>> from other guests and/or processes being overcommitted while our vm
>>> is fine.
>>
>> It also allows us to cheaply skip running vcpus.
>
> Hi Avi,
>
> Could you please elaborate on how preempt notifiers can be used
> here to keep track of overcommit or skip running vcpus?
>
> Are we planning set some flag in sched_out() handler etc?
>

Keep a bitmap kvm->preempted_vcpus.

In sched_out, test whether we're TASK_RUNNING, and if so, set a vcpu
flag and our bit in kvm->preempted_vcpus. On sched_in, if the flag is
set, clear our bit in kvm->preempted_vcpus. We can also keep a counter
of preempted vcpus.

We can use the bitmap and the counter to quickly see if spinning is
worthwhile (if the counter is zero, better to spin). If not, we can use
the bitmap to select target vcpus quickly.

The only problem is that in order to keep this accurate we need to keep
the preempt notifiers active during exits to userspace. But we can
prototype this without this change, and add it later if it works.

--
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

Avi Kivity

unread,
Sep 25, 2012, 6:20:02 AM9/25/12
to
On 09/24/2012 06:21 PM, Avi Kivity wrote:
> On 09/24/2012 06:13 PM, Peter Zijlstra wrote:
> > On Mon, 2012-09-24 at 18:10 +0200, Avi Kivity wrote:
> >> > Its also still a LAPIC write -- disguised as an MSR though :/
> >>
> >> It's probably a whole lot faster though.
> >
> > I've been told its not, I haven't tried it.
>
> I'll see if I can find a machine with it (don't see it on my Westmere,
> it's probably on one of the Bridges. Or maybe the other Peter knows.
>
>

Before measuring TSC_DEADLINE, I measured writing to TMICT, it costs 32
cycles. This is on a Sandy Bridge.

--
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.

Raghavendra K T

unread,
Sep 25, 2012, 9:50:02 AM9/25/12
to
On 09/24/2012 07:46 PM, Raghavendra K T wrote:
> On 09/24/2012 07:24 PM, Peter Zijlstra wrote:
>> On Mon, 2012-09-24 at 18:59 +0530, Raghavendra K T wrote:
>>> However Rik had a genuine concern in the cases where runqueue is not
>>> equally distributed and lockholder might actually be on a different run
>>> queue but not running.
>>
>> Load should eventually get distributed equally -- that's what the
>> load-balancer is for -- so this is a temporary situation.
>>
>> We already try and favour the non running vcpu in this case, that's what
>> yield_to_task_fair() is about. If its still not eligible to run, tough
>> luck.
>
> Yes, I agree.
>
>>
>>> Do you think instead of using rq->nr_running, we could get a global
>>> sense of load using avenrun (something like avenrun/num_onlinecpus)
>>
>> To what purpose? Also, global stuff is expensive, so you should try and
>> stay away from it as hard as you possibly can.
>
> Yes, that concern only had made me to fall back to rq->nr_running.
>
> Will come back with the result soon.

Got the result with the patches:
So here is the result,

Tried this on a 32 core ple box with HT disabled. 32 guest vcpus with
1x and 2x overcommits

Base = 3.6.0-rc5 + ple handler optimization patches
A = Base + checking rq_running in vcpu_on_spin() patch
B = Base + checking rq->nr_running in sched/core
C = Base - PLE

---+-----------+-----------+-----------+-----------+
| Ebizzy result (rec/sec higher is better) |
---+-----------+-----------+-----------+-----------+
| Base | A | B | C |
---+-----------+-----------+-----------+-----------+
1x | 2374.1250 | 7273.7500 | 5690.8750 | 7364.3750|
2x | 2536.2500 | 2458.5000 | 2426.3750 | 48.5000|
---+-----------+-----------+-----------+-----------+

% improvements w.r.t BASE
---+------------+------------+------------+
| A | B | C |
---+------------+------------+------------+
1x | 206.37603 | 139.70410 | 210.19323 |
2x | -3.06555 | -4.33218 | -98.08773 |
---+------------+------------+------------+

we are getting the benefit of almost PLE disabled case with this
approach. With patch B, we have dropped a bit in gain.
(because we still would iterate vcpus until we decide to do a directed
yield).

Raghavendra K T

unread,
Sep 25, 2012, 10:00:01 AM9/25/12
to
Avi, Thanks for the idea.. I want to try this some time soon.

So ideally it means if we are under-committed the counter/ bitmap
effective value is zero.

Takuya Yoshikawa

unread,
Sep 25, 2012, 10:30:02 AM9/25/12
to
On Tue, 25 Sep 2012 10:12:49 +0200
Avi Kivity <a...@redhat.com> wrote:

> It will. The tradeoff is between false-positive costs (undercommit) and
> true positive costs (overcommit). I think undercommit should perform
> well no matter what.
>
> If we utilize preempt notifiers to track overcommit dynamically, then we
> can vary the spin time dynamically. Keep it long initially, as we get
> more preempted vcpus make it shorter.

What will happen if we pin each vcpu thread to some core?
I don't want to see so many vcpu threads moving around without
being pinned at all.

In that case, we don't want to make KVM do any work of searching
a vcpu thread to yield to.

Thanks,
Takuya

Dor Laor

unread,
Sep 25, 2012, 11:10:03 AM9/25/12
to
On 09/24/2012 02:02 PM, Raghavendra K T wrote:
> On 09/24/2012 02:12 PM, Dor Laor wrote:
>> In order to help PLE and pvticketlock converge I thought that a small
>> test code should be developed to test this in a predictable,
>> deterministic way.
>>
>> The idea is to have a guest kernel module that spawn a new thread each
>> time you write to a /sys/.... entry.
>>
>> Each such a thread spins over a spin lock. The specific spin lock is
>> also chosen by the /sys/ interface. Let's say we have an array of spin
>> locks *10 times the amount of vcpus.
>>
>> All the threads are running a
>> while (1) {
>>
>> spin_lock(my_lock);
>> sum += execute_dummy_cpu_computation(time);
>> spin_unlock(my_lock);
>>
>> if (sys_tells_thread_to_die()) break;
>> }
>>
>> print_result(sum);
>>
>> Instead of calling the kernel's spin_lock functions, clone them and make
>> the ticket lock order deterministic and known (like a linear walk of all
>> the threads trying to catch that lock).
>
> By Cloning you mean hierarchy of the locks?

No, I meant to clone the implementation of the current spin lock code in
order to set any order you may like for the ticket selection.
(even for a non pvticket lock version)

For instance, let's say you have N threads trying to grab the lock, you
can always make the ticket go linearly from 1->2...->N.
Not sure it's a good idea, just a recommendation.

> Also I believe time should be passed via sysfs / hardcoded for each
> type of lock we are mimicking

Yap

>
>>
>> This way you can easy calculate:
>> 1. the score of a single vcpu running a single thread
>> 2. the score of sum of all thread scores when #thread==#vcpu all
>> taking the same spin lock. The overall sum should be close as
>> possible to #1.
>> 3. Like #2 but #threads > #vcpus and other versions of #total vcpus
>> (belonging to all VMs) > #pcpus.
>> 4. Create #thread == #vcpus but let each thread have it's own spin
>> lock
>> 5. Like 4 + 2
>>
>> Hopefully this way will allows you to judge and evaluate the exact
>> overhead of scheduling VMs and threads since you have the ideal result
>> in hand and you know what the threads are doing.
>>
>> My 2 cents, Dor
>>
>
> Thank you,
> I think this is an excellent idea. ( Though I am trying to put all the
> pieces together you mentioned). So overall we should be able to measure
> the performance of pvspinlock/PLE improvements with a deterministic
> load in guest.
>
> Only thing I am missing is,
> How to generate different combinations of the lock.
>
> Okay, let me see if I can come with a solid model for this.
>

Do you mean the various options for PLE/pvticket/other? I haven't
thought of it and assumed its static but it can also be controlled
through the temporary /sys interface.

Thanks for following up!
Dor

Konrad Rzeszutek Wilk

unread,
Sep 26, 2012, 8:40:02 AM9/26/12
to
Wouldn't that defeat the purpose of trying the test the different
implementations that try to fix the lock-holder preemption problem?
You want something that you can shoe-in for all work-loads - also
for this test system.
>
> For instance, let's say you have N threads trying to grab the lock,
> you can always make the ticket go linearly from 1->2...->N.
> Not sure it's a good idea, just a recommendation.

So round-robin. Could you make NCPUS threads, pin them to CPUs, and set
them to be SCHED_RR? Or NCPUS*2 to overcommit.

Andrew Jones

unread,
Sep 26, 2012, 9:00:02 AM9/26/12
to
On Mon, Sep 24, 2012 at 02:36:05PM +0200, Peter Zijlstra wrote:
> On Mon, 2012-09-24 at 17:22 +0530, Raghavendra K T wrote:
> > On 09/24/2012 05:04 PM, Peter Zijlstra wrote:
> > > On Fri, 2012-09-21 at 17:29 +0530, Raghavendra K T wrote:
> > >> In some special scenarios like #vcpu<= #pcpu, PLE handler may
> > >> prove very costly, because there is no need to iterate over vcpus
> > >> and do unsuccessful yield_to burning CPU.
> > >
> > > What's the costly thing? The vm-exit, the yield (which should be a nop
> > > if its the only task there) or something else entirely?
> > >
> > Both vmexit and yield_to() actually,
> >
> > because unsuccessful yield_to() overall is costly in PLE handler.
> >
> > This is because when we have large guests, say 32/16 vcpus, and one
> > vcpu is holding lock, rest of the vcpus waiting for the lock, when they
> > do PL-exit, each of the vcpu try to iterate over rest of vcpu list in
> > the VM and try to do directed yield (unsuccessful). (O(n^2) tries).
> >
> > this results is fairly high amount of cpu burning and double run queue
> > lock contention.
> >
> > (if they were spinning probably lock progress would have been faster).
> > As Avi/Chegu Vinod had felt it is better to avoid vmexit itself, which
> > seems little complex to achieve currently.
>
> OK, so the vmexit stays and we need to improve yield_to.

Can't we do this check sooner as well, as it only requires per-cpu data?
If we do it way back in kvm_vcpu_on_spin, then we avoid get_pid_task()
and a bunch of read barriers from kvm_for_each_vcpu. Also, moving the test
into kvm code would allow us to do other kvm things as a result of the
check in order to avoid some vmexits. It looks like we should be able to
avoid some without much complexity by just making a per-vm ple_window
variable, and then, when we hit the nr_running == 1 condition, also doing
vmcs_write32(PLE_WINDOW, (kvm->ple_window += PLE_WINDOW_BUMP))
Reset the window to the default value when we successfully yield (and
maybe we should limit the number of bumps).

Drew

>
> How about something like the below, that would allow breaking out of the
> for-each-vcpu loop and simply going back into the vm, right?
>
> ---
> kernel/sched/core.c | 25 +++++++++++++++++++------
> 1 file changed, 19 insertions(+), 6 deletions(-)
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index b38f00e..5d5b355 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -4272,7 +4272,10 @@ EXPORT_SYMBOL(yield);
> * It's the caller's job to ensure that the target task struct
> * can't go away on us before we can do any checks.
> *
> - * Returns true if we indeed boosted the target task.
> + * Returns:
> + * true (>0) if we indeed boosted the target task.
> + * false (0) if we failed to boost the target.
> + * -ESRCH if there's no task to yield to.
> */
> bool __sched yield_to(struct task_struct *p, bool preempt)
> {
> @@ -4284,6 +4287,15 @@ bool __sched yield_to(struct task_struct *p, bool preempt)
> local_irq_save(flags);
> rq = this_rq();
>
> + /*
> + * If we're the only runnable task on the rq, there's absolutely no
> + * point in yielding.
> + */
> + if (rq->nr_running == 1) {
> + yielded = -ESRCH;
> + goto out_irq;
> + }
> +
> again:
> p_rq = task_rq(p);
> double_rq_lock(rq, p_rq);
> @@ -4293,13 +4305,13 @@ bool __sched yield_to(struct task_struct *p, bool preempt)
> }
>
> if (!curr->sched_class->yield_to_task)
> - goto out;
> + goto out_unlock;
>
> if (curr->sched_class != p->sched_class)
> - goto out;
> + goto out_unlock;
>
> if (task_running(p_rq, p) || p->state)
> - goto out;
> + goto out_unlock;
>
> yielded = curr->sched_class->yield_to_task(rq, p, preempt);
> if (yielded) {
> @@ -4312,11 +4324,12 @@ bool __sched yield_to(struct task_struct *p, bool preempt)
> resched_task(p_rq->curr);
> }
>
> -out:
> +out_unlock:
> double_rq_unlock(rq, p_rq);
> +out_irq:
> local_irq_restore(flags);
>
> - if (yielded)
> + if (yielded > 0)
> schedule();
>
> return yielded;

Andrew Jones

unread,
Sep 26, 2012, 9:30:02 AM9/26/12
to
On Mon, Sep 24, 2012 at 06:20:12PM +0200, Avi Kivity wrote:
> On 09/24/2012 06:03 PM, Peter Zijlstra wrote:
> > On Mon, 2012-09-24 at 17:51 +0200, Avi Kivity wrote:
> >> On 09/24/2012 03:54 PM, Peter Zijlstra wrote:
> >> > On Mon, 2012-09-24 at 18:59 +0530, Raghavendra K T wrote:
> >> >> However Rik had a genuine concern in the cases where runqueue is not
> >> >> equally distributed and lockholder might actually be on a different run
> >> >> queue but not running.
> >> >
> >> > Load should eventually get distributed equally -- that's what the
> >> > load-balancer is for -- so this is a temporary situation.
> >>
> >> What's the expected latency? This is the whole problem. Eventually the
> >> scheduler would pick the lock holder as well, the problem is that it's
> >> in the millisecond scale while lock hold times are in the microsecond
> >> scale, leading to a 1000x slowdown.
> >
> > Yeah I know.. Heisenberg's uncertainty applied to SMP computing becomes
> > something like accurate or fast, never both.
> >
> >> If we want to yield, we really want to boost someone.
> >
> > Now if only you knew which someone ;-) This non-modified guest nonsense
> > is such a snake pit.. but you know how I feel about all that.
>
> Actually if I knew that in addition to boosting someone, I also unboost
> myself enough to be preempted, it wouldn't matter. While boosting the
> lock holder is good, the main point is not spinning and doing useful
> work instead. We can detect spinners and avoid boosting them.
>
> That's the motivation for the "donate vruntime" approach I wanted earlier.

I'll probably get shot for the suggestion, but doesn't this problem merit
another scheduler class? We want FIFO order for a special class of tasks,
"spinners". Wouldn't a clean solution be to promote a task's scheduler
class to the spinner class when we PLE (or come from some special syscall
for userspace spinlocks?)? That class would be higher priority than the
fair class and would schedule in FIFO order, but it would only run its
tasks for short periods before switching. Also, after each task is run
its scheduler class would get reset down to its original class (fair).
At least at first thought this looks to me to be cleaner than the next
and skip hinting, plus it helps guarantee that the lock holder gets
scheduled before the tasks waiting on that lock.

Drew

Peter Zijlstra

unread,
Sep 26, 2012, 9:30:02 AM9/26/12
to
On Wed, 2012-09-26 at 15:20 +0200, Andrew Jones wrote:
> Wouldn't a clean solution be to promote a task's scheduler
> class to the spinner class when we PLE (or come from some special
> syscall
> for userspace spinlocks?)?

Userspace spinlocks are typically employed to avoid syscalls..

> That class would be higher priority than the
> fair class and would schedule in FIFO order, but it would only run its
> tasks for short periods before switching.

Since lock hold times aren't limited, esp. for things like userspace
'spin' locks, you've got a very good denial of service / opportunity for
abuse right there.

Andrew Jones

unread,
Sep 26, 2012, 9:50:02 AM9/26/12
to
On Wed, Sep 26, 2012 at 03:26:11PM +0200, Peter Zijlstra wrote:
> On Wed, 2012-09-26 at 15:20 +0200, Andrew Jones wrote:
> > Wouldn't a clean solution be to promote a task's scheduler
> > class to the spinner class when we PLE (or come from some special
> > syscall
> > for userspace spinlocks?)?
>
> Userspace spinlocks are typically employed to avoid syscalls..

I'm guessing there could be a slow path - spin N times and then give
up and yield.

>
> > That class would be higher priority than the
> > fair class and would schedule in FIFO order, but it would only run its
> > tasks for short periods before switching.
>
> Since lock hold times aren't limited, esp. for things like userspace
> 'spin' locks, you've got a very good denial of service / opportunity for
> abuse right there.

Maybe add some throttling to avoid overuse/maliciousness?

>
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in

Peter Zijlstra

unread,
Sep 26, 2012, 9:50:03 AM9/26/12
to
On Wed, 2012-09-26 at 15:39 +0200, Andrew Jones wrote:
> On Wed, Sep 26, 2012 at 03:26:11PM +0200, Peter Zijlstra wrote:
> > On Wed, 2012-09-26 at 15:20 +0200, Andrew Jones wrote:
> > > Wouldn't a clean solution be to promote a task's scheduler
> > > class to the spinner class when we PLE (or come from some special
> > > syscall
> > > for userspace spinlocks?)?
> >
> > Userspace spinlocks are typically employed to avoid syscalls..
>
> I'm guessing there could be a slow path - spin N times and then give
> up and yield.

Much better they should do a blocking futex call or so, once you do the
syscall you're in kernel space anyway and have paid the transition cost.

> >
> > > That class would be higher priority than the
> > > fair class and would schedule in FIFO order, but it would only run its
> > > tasks for short periods before switching.
> >
> > Since lock hold times aren't limited, esp. for things like userspace
> > 'spin' locks, you've got a very good denial of service / opportunity for
> > abuse right there.
>
> Maybe add some throttling to avoid overuse/maliciousness?

At which point you're pretty much back to where you started.

A much better approach is using things like priority inheritance, which
can be extended to cover the fair class just fine..

Also note that user-space spinning is inherently prone to live-locks
when combined with the static priority RT scheduling classes.

In general its a very bad idea..

Gleb Natapov

unread,
Sep 27, 2012, 3:50:03 AM9/27/12
to
Can user return notifier can be used instead? Set bit in
kvm->preempted_vcpus on return to userspace.

--
Gleb.

Avi Kivity

unread,
Sep 27, 2012, 4:40:01 AM9/27/12
to
This gives us a good case for tracking preemption on a per-vm basis. As
long as we aren't preempted, we can keep the PLE window high, and also
return immediately from the handler without looking for candidates.


--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 27, 2012, 4:50:01 AM9/27/12
to
On 09/25/2012 04:21 PM, Takuya Yoshikawa wrote:
> On Tue, 25 Sep 2012 10:12:49 +0200
> Avi Kivity <a...@redhat.com> wrote:
>
>> It will. The tradeoff is between false-positive costs (undercommit) and
>> true positive costs (overcommit). I think undercommit should perform
>> well no matter what.
>>
>> If we utilize preempt notifiers to track overcommit dynamically, then we
>> can vary the spin time dynamically. Keep it long initially, as we get
>> more preempted vcpus make it shorter.
>
> What will happen if we pin each vcpu thread to some core?
> I don't want to see so many vcpu threads moving around without
> being pinned at all.

If you do that you've removed a lot of flexibility from the scheduler,
so overcommit becomes even less likely to work well (a trivial example
is pinning two vcpus from the same vm to the same core -- it's so
obviously bad no one considers doing it).

> In that case, we don't want to make KVM do any work of searching
> a vcpu thread to yield to.

Why not? If a vcpu thread on another core has been preempted, and is
the lock holder, and we can boost it, then we've fixed our problem.
Even if the spinning thread keeps spinning because it is the only task
eligible to run on its core.

--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 27, 2012, 5:00:02 AM9/27/12
to
On 09/25/2012 04:43 PM, Jiannan Ouyang wrote:
> I've actually implemented this preempted_bitmap idea.

Interesting, please share the code if you can.

> However, I'm doing this to expose this information to the guest, so the
> guest is able to know if the lock holder is preempted or not before
> spining. Right now, I'm doing experiment to show that this idea works.
>
> I'm wondering what do you guys think of the relationship between the
> pv_ticketlock approach and PLE handler approach. Are we going to adopt
> PLE instead of the pv ticketlock, and why?

Right now we're searching for the best solution. The tradeoffs are more
or less:

PLE:
- works for unmodified / non-Linux guests
- works for all types of spins (e.g. smp_call_function*())
- utilizes an existing hardware interface (PAUSE instruction) so likely
more robust compared to a software interface

PV:
- has more information, so it can perform better

Given these tradeoffs, if we can get PLE to work for moderate amounts of
overcommit then I'll prefer it (even if it slightly underperforms PV).
If we are unable to make it work well, then we'll have to add PV.

--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 27, 2012, 5:00:02 AM9/27/12
to
User return notifier is per-cpu, not per-task. There is a new task_work
(<linux/task_work.h>) that does what you want. With these
technicalities out of the way, I think it's the wrong idea. If a vcpu
thread is in userspace, that doesn't mean it's preempted, there's no
point in boosting it if it's already running.

btw, we can have secondary effects. A vcpu can be waiting for a lock in
the host kernel, or for a host page fault. There's no point in boosting
anything for that. Or a vcpu in userspace can be waiting for a lock
that is held by another thread, which has been preempted. This is (like
I think Peter already said) a priority inheritance problem. However
with fine-grained locking in userspace, we can make it go away. The
guest kernel is unlikely to access one device simultaneously from two
threads (and if it does, we just need to improve the threading in the
device model).

--
error compiling committee.c: too many arguments to function

Gleb Natapov

unread,
Sep 27, 2012, 5:20:02 AM9/27/12
to
Ah, so you want to set bit in kvm->preempted_vcpus if task is _not_
TASK_RUNNING in sched_out (you wrote opposite in your email)? If a task
is in userspace it is definitely not preempted.

> btw, we can have secondary effects. A vcpu can be waiting for a lock in
> the host kernel, or for a host page fault. There's no point in boosting
> anything for that. Or a vcpu in userspace can be waiting for a lock
> that is held by another thread, which has been preempted.
Do you mean userspace spinlock? Because otherwise task that's waits on
a kernel lock will sleep in the kernel.

> This is (like
> I think Peter already said) a priority inheritance problem. However
> with fine-grained locking in userspace, we can make it go away. The
> guest kernel is unlikely to access one device simultaneously from two
> threads (and if it does, we just need to improve the threading in the
> device model).
>
> --
> error compiling committee.c: too many arguments to function

--
Gleb.

Avi Kivity

unread,
Sep 27, 2012, 5:40:02 AM9/27/12
to
On 09/27/2012 11:11 AM, Gleb Natapov wrote:
>>
>> User return notifier is per-cpu, not per-task. There is a new task_work
>> (<linux/task_work.h>) that does what you want. With these
>> technicalities out of the way, I think it's the wrong idea. If a vcpu
>> thread is in userspace, that doesn't mean it's preempted, there's no
>> point in boosting it if it's already running.
>>
> Ah, so you want to set bit in kvm->preempted_vcpus if task is _not_
> TASK_RUNNING in sched_out (you wrote opposite in your email)? If a task
> is in userspace it is definitely not preempted.

No, as I originally wrote. If it's TASK_RUNNING when it saw sched_out,
then it is preempted (i.e. runnable), not sleeping on some waitqueue,
voluntarily (HLT) or involuntarily (page fault).

>
>> btw, we can have secondary effects. A vcpu can be waiting for a lock in
>> the host kernel, or for a host page fault. There's no point in boosting
>> anything for that. Or a vcpu in userspace can be waiting for a lock
>> that is held by another thread, which has been preempted.
> Do you mean userspace spinlock? Because otherwise task that's waits on
> a kernel lock will sleep in the kernel.

I meant a kernel mutex.

vcpu 0: take guest spinlock
vcpu 0: vmexit
vcpu 0: spin_lock(some_lock)
vcpu 1: take same guest spinlock
vcpu 1: PLE vmexit
vcpu 1: wtf?

Waiting on a host kernel spinlock is not too bad because we expect to be
out shortly. Waiting on a host kernel mutex can be a lot worse.

--
error compiling committee.c: too many arguments to function
--

Raghavendra K T

unread,
Sep 27, 2012, 6:00:02 AM9/27/12
to
No, I am not there yet.

So In summary, we are suffering with inconsistent benchmark result,
while measuring the benefit of our improvement in PLE/pvlock etc..

So good point from your suggestion is,
- Giving predictability to workload that runs in guest, so that we have
pi-pi comparison of improvement.

- we can easily tune the workload via sysfs, and we can have script to
automate them.

What is complicated is:
- How can we simulate a workload close to what we measure with
benchmarks?
- How can we mimic lock holding time/ lock hierarchy close to the way
it is seen with real workloads (for e.g. highly contended zone lru lock
with similar amount of lockholding times).
- How close it would be to when we forget about other types of spinning
(for e.g, flush_tlb).

So I feel it is not as trivial as it looks like.

Avi Kivity

unread,
Sep 27, 2012, 6:10:02 AM9/27/12
to
On 09/27/2012 11:58 AM, Gleb Natapov wrote:
>
>> >
>> >> btw, we can have secondary effects. A vcpu can be waiting for a lock in
>> >> the host kernel, or for a host page fault. There's no point in boosting
>> >> anything for that. Or a vcpu in userspace can be waiting for a lock
>> >> that is held by another thread, which has been preempted.
>> > Do you mean userspace spinlock? Because otherwise task that's waits on
>> > a kernel lock will sleep in the kernel.
>>
>> I meant a kernel mutex.
>>
>> vcpu 0: take guest spinlock
>> vcpu 0: vmexit
>> vcpu 0: spin_lock(some_lock)
>> vcpu 1: take same guest spinlock
>> vcpu 1: PLE vmexit
>> vcpu 1: wtf?
>>
>> Waiting on a host kernel spinlock is not too bad because we expect to be
>> out shortly. Waiting on a host kernel mutex can be a lot worse.
>>
> We can't do much about it without PV spinlock since there is not
> information about what vcpu holds which guest spinlock, no?

It doesn't help. If the lock holder is waiting for another lock in the
host kernel, boosting it doesn't help even if we know who it is. We
need to boost the real lock holder, but we have no idea who it is (and
even if we did, we often can't do anything about it).

Gleb Natapov

unread,
Sep 27, 2012, 6:10:02 AM9/27/12
to
On Thu, Sep 27, 2012 at 11:33:56AM +0200, Avi Kivity wrote:
> On 09/27/2012 11:11 AM, Gleb Natapov wrote:
> >>
> >> User return notifier is per-cpu, not per-task. There is a new task_work
> >> (<linux/task_work.h>) that does what you want. With these
> >> technicalities out of the way, I think it's the wrong idea. If a vcpu
> >> thread is in userspace, that doesn't mean it's preempted, there's no
> >> point in boosting it if it's already running.
> >>
> > Ah, so you want to set bit in kvm->preempted_vcpus if task is _not_
> > TASK_RUNNING in sched_out (you wrote opposite in your email)? If a task
> > is in userspace it is definitely not preempted.
>
> No, as I originally wrote. If it's TASK_RUNNING when it saw sched_out,
> then it is preempted (i.e. runnable), not sleeping on some waitqueue,
> voluntarily (HLT) or involuntarily (page fault).
>
Of course, I got it all backwards. Need more coffee.

> >
> >> btw, we can have secondary effects. A vcpu can be waiting for a lock in
> >> the host kernel, or for a host page fault. There's no point in boosting
> >> anything for that. Or a vcpu in userspace can be waiting for a lock
> >> that is held by another thread, which has been preempted.
> > Do you mean userspace spinlock? Because otherwise task that's waits on
> > a kernel lock will sleep in the kernel.
>
> I meant a kernel mutex.
>
> vcpu 0: take guest spinlock
> vcpu 0: vmexit
> vcpu 0: spin_lock(some_lock)
> vcpu 1: take same guest spinlock
> vcpu 1: PLE vmexit
> vcpu 1: wtf?
>
> Waiting on a host kernel spinlock is not too bad because we expect to be
> out shortly. Waiting on a host kernel mutex can be a lot worse.
>
We can't do much about it without PV spinlock since there is not
information about what vcpu holds which guest spinlock, no?

--
Gleb.

Gleb Natapov

unread,
Sep 27, 2012, 6:10:02 AM9/27/12
to
On Thu, Sep 27, 2012 at 12:04:58PM +0200, Avi Kivity wrote:
> On 09/27/2012 11:58 AM, Gleb Natapov wrote:
> >
> >> >
> >> >> btw, we can have secondary effects. A vcpu can be waiting for a lock in
> >> >> the host kernel, or for a host page fault. There's no point in boosting
> >> >> anything for that. Or a vcpu in userspace can be waiting for a lock
> >> >> that is held by another thread, which has been preempted.
> >> > Do you mean userspace spinlock? Because otherwise task that's waits on
> >> > a kernel lock will sleep in the kernel.
> >>
> >> I meant a kernel mutex.
> >>
> >> vcpu 0: take guest spinlock
> >> vcpu 0: vmexit
> >> vcpu 0: spin_lock(some_lock)
> >> vcpu 1: take same guest spinlock
> >> vcpu 1: PLE vmexit
> >> vcpu 1: wtf?
> >>
> >> Waiting on a host kernel spinlock is not too bad because we expect to be
> >> out shortly. Waiting on a host kernel mutex can be a lot worse.
> >>
> > We can't do much about it without PV spinlock since there is not
> > information about what vcpu holds which guest spinlock, no?
>
> It doesn't help. If the lock holder is waiting for another lock in the
> host kernel, boosting it doesn't help even if we know who it is. We
> need to boost the real lock holder, but we have no idea who it is (and
> even if we did, we often can't do anything about it).
>
Without PV lock we will boost random preempted vcpu instead of going to
sleep in the situation you described.

--
Gleb.

Avi Kivity

unread,
Sep 27, 2012, 6:20:01 AM9/27/12
to
True. In theory boosting a random vcpu shouldn't have any negative
effects though. Right now the problem is that the boosting itself is
expensive.


--
error compiling committee.c: too many arguments to function

Raghavendra K T

unread,
Sep 27, 2012, 6:20:01 AM9/27/12
to
Hmm true. I think it is indeed difficult to shoe-in all workloads.

Andrew Jones

unread,
Sep 27, 2012, 6:30:02 AM9/27/12
to
Are you measuring the combined throughput of all running guests, or
just looking at the results of the benchmarks in a single test guest?

I've done some benchmarking as well and my stddevs look pretty good for
kcbench, ebizzy, dbench, and sysbench-memory. I do 5 runs for each
overcommit level (1.0 - 3.0, stepped by .25 or .5), and 2 runs of that
full sequence of tests (one with the overcommit levels in scrambled
order). The relative stddevs for each of the sets of 5 runs look pretty
good, and the data for the 2 runs match nicely as well.

To try and get consistent results I do the following
- interleave the memory of all guests across all numa nodes on the
machine
- echo 0 > /proc/sys/kernel/randomize_va_space on both host and test
guest
- echo 3 > /proc/sys/vm/drop_caches on both host and test guest before
each run
- use a ramdisk for the benchmark output files on all running guests
- no periodically running services installed on the test guest
- HT is turned off as you do, although I'd like to try running again
with it turned back on

Although, I still need to run again measuring the combined throughput
of all running vms (including the ones launched just to generate busy
vcpus). Maybe my results won't be as consistent then...

Drew

>
> So good point from your suggestion is,
> - Giving predictability to workload that runs in guest, so that we have
> pi-pi comparison of improvement.
>
> - we can easily tune the workload via sysfs, and we can have script to
> automate them.
>
> What is complicated is:
> - How can we simulate a workload close to what we measure with
> benchmarks?
> - How can we mimic lock holding time/ lock hierarchy close to the way
> it is seen with real workloads (for e.g. highly contended zone lru lock
> with similar amount of lockholding times).
> - How close it would be to when we forget about other types of spinning
> (for e.g, flush_tlb).
>
> So I feel it is not as trivial as it looks like.
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in

Raghavendra K T

unread,
Sep 27, 2012, 6:30:02 AM9/27/12
to
We indeed checked early in original undercommit patch and it has given
result closer to PLE disabled case. But Agree with Peter that it is ugly
to export nr_running info to ple handler.

Looking at the result and comparing result of A and C,
> Base = 3.6.0-rc5 + ple handler optimization patches
> A = Base + checking rq_running in vcpu_on_spin() patch
> B = Base + checking rq->nr_running in sched/core
> C = Base - PLE
>
> % improvements w.r.t BASE
> ---+------------+------------+------------+
> | A | B | C |
> ---+------------+------------+------------+
> 1x | 206.37603 | 139.70410 | 210.19323 |

I have a feeling that vmexit has not caused significant overhead
compared to iterating over vcpus in PLE handler.. Does it not sound so?

But
> vmcs_write32(PLE_WINDOW, (kvm->ple_window += PLE_WINDOW_BUMP))

is worth trying. I will have to see it eventually.

Dor Laor

unread,
Sep 27, 2012, 6:40:02 AM9/27/12
to
You can spin for a similar instruction count that you're interested

> - How close it would be to when we forget about other types of spinning
> (for e.g, flush_tlb).
>
> So I feel it is not as trivial as it looks like.


Indeed this is mainly a tool that can serve to optimize few synthetic
workloads.
I still believe that it worth to go through this exercise since a 100%
predictable and controlled case can help us purely asses the state of
PLE and pvticket code. Otherwise we're dealing w/ too many parameters
and assumptions at once.

Dor

Avi Kivity

unread,
Sep 27, 2012, 6:50:02 AM9/27/12
to
Another way to test is to execute

perf stat -e 'kvm_exit exit_reason==40' sleep 10

to see how many PAUSEs were intercepted in a given time (except I just
invented the filter syntax). The fewer we get, the more useful work the
system does. This ignores kvm_vcpu_on_spin overhead though, so it's
just a rough measure.

--
error compiling committee.c: too many arguments to function

Raghavendra K T

unread,
Sep 27, 2012, 7:30:01 AM9/27/12
to
1) So do you think, deferring preemption patch ( Vatsa was mentioning
long back) is also another thing worth trying, so we reduce the chance
of LHP.

IIRC, with defer preemption :
we will have hook in spinlock/unlock path to measure depth of lock held,
and shared with host scheduler (may be via MSRs now).
Host scheduler 'prefers' not to preempt lock holding vcpu. (or rather
give say one chance.

2) looking at the result (comparing A & C) , I do feel we have
significant in iterating over vcpus (when compared to even vmexit)
so We still would need undercommit fix sugested by PeterZ (improving by
140%). ?

So looking back at threads/ discussions so far, I am trying to
summarize, the discussions so far. I feel, at least here are the few
potential candidates to go in:

1) Avoiding double runqueue lock overhead (Andrew Theurer/ PeterZ)
2) Dynamically changing PLE window (Avi/Andrew/Chegu)
3) preempt_notify handler to identify preempted VCPUs (Avi)
4) Avoiding iterating over VCPUs in undercommit scenario. (Raghu/PeterZ)
5) Avoiding unnecessary spinning in overcommit scenario (Raghu/Rik)
6) Pv spinlock
7) Jiannan's proposed improvements
8) Defer preemption patches

Did we miss anything (or added extra?)

So here are my action items:
- I plan to repost this series with what PeterZ, Rik suggested with
performance analysis.
- I ll go back and explore on (3) and (6) ..

Please Let me know..

Raghavendra K T

unread,
Sep 27, 2012, 7:40:02 AM9/27/12
to
I was not doing this.

> - echo 3 > /proc/sys/vm/drop_caches on both host and test guest before
> each run

was doing already as you know

> - use a ramdisk for the benchmark output files on all running guests

Yes.. this is also helpful

> - no periodically running services installed on the test guest
> - HT is turned off as you do, although I'd like to try running again
> with it turned back on
> Although, I still need to run again measuring the combined throughput
> of all running vms (including the ones launched just to generate busy
> vcpus). Maybe my results won't be as consistent then...

May be. I take average from all the VMs..

Raghavendra K T

unread,
Sep 27, 2012, 7:40:03 AM9/27/12
to
On 09/27/2012 02:20 PM, Avi Kivity wrote:
> On 09/25/2012 04:43 PM, Jiannan Ouyang wrote:
>> I've actually implemented this preempted_bitmap idea.
>
> Interesting, please share the code if you can.
>
>> However, I'm doing this to expose this information to the guest, so the
>> guest is able to know if the lock holder is preempted or not before
>> spining. Right now, I'm doing experiment to show that this idea works.
>>
>> I'm wondering what do you guys think of the relationship between the
>> pv_ticketlock approach and PLE handler approach. Are we going to adopt
>> PLE instead of the pv ticketlock, and why?
>
> Right now we're searching for the best solution. The tradeoffs are more
> or less:
>
> PLE:
> - works for unmodified / non-Linux guests
> - works for all types of spins (e.g. smp_call_function*())
> - utilizes an existing hardware interface (PAUSE instruction) so likely
> more robust compared to a software interface
>
> PV:
> - has more information, so it can perform better

Should we also consider that we always have an edge here for non-PLE
machine?

>
> Given these tradeoffs, if we can get PLE to work for moderate amounts of
> overcommit then I'll prefer it (even if it slightly underperforms PV).
> If we are unable to make it work well, then we'll have to add PV.
>
Avi,
Thanks for this summary.. It is of great help to proceed in right
direction..

Avi Kivity

unread,
Sep 27, 2012, 8:10:02 AM9/27/12
to
On 09/27/2012 01:26 PM, Raghavendra K T wrote:
> On 09/27/2012 02:20 PM, Avi Kivity wrote:
>> On 09/25/2012 04:43 PM, Jiannan Ouyang wrote:
>>> I've actually implemented this preempted_bitmap idea.
>>
>> Interesting, please share the code if you can.
>>
>>> However, I'm doing this to expose this information to the guest, so the
>>> guest is able to know if the lock holder is preempted or not before
>>> spining. Right now, I'm doing experiment to show that this idea works.
>>>
>>> I'm wondering what do you guys think of the relationship between the
>>> pv_ticketlock approach and PLE handler approach. Are we going to adopt
>>> PLE instead of the pv ticketlock, and why?
>>
>> Right now we're searching for the best solution. The tradeoffs are more
>> or less:
>>
>> PLE:
>> - works for unmodified / non-Linux guests
>> - works for all types of spins (e.g. smp_call_function*())
>> - utilizes an existing hardware interface (PAUSE instruction) so likely
>> more robust compared to a software interface
>>
>> PV:
>> - has more information, so it can perform better
>
> Should we also consider that we always have an edge here for non-PLE
> machine?

True. The deployment share for these is decreasing rapidly though. I
hate optimizing for obsolete hardware.


--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 27, 2012, 8:10:02 AM9/27/12
to
On 09/27/2012 01:23 PM, Raghavendra K T wrote:
>>
>> This gives us a good case for tracking preemption on a per-vm basis. As
>> long as we aren't preempted, we can keep the PLE window high, and also
>> return immediately from the handler without looking for candidates.
>
> 1) So do you think, deferring preemption patch ( Vatsa was mentioning
> long back) is also another thing worth trying, so we reduce the chance
> of LHP.

Yes, we have to keep it in mind. It will be useful for fine grained
locks, not so much so coarse locks or IPIs.

I would still of course prefer a PLE solution, but if we can't get it to
work we can consider preemption deferral.

>
> IIRC, with defer preemption :
> we will have hook in spinlock/unlock path to measure depth of lock held,
> and shared with host scheduler (may be via MSRs now).
> Host scheduler 'prefers' not to preempt lock holding vcpu. (or rather
> give say one chance.

A downside is that we have to do that even when undercommitted.

Also there may be a lot of false positives (deferred preemptions even
when there is no contention).

>
> 2) looking at the result (comparing A & C) , I do feel we have
> significant in iterating over vcpus (when compared to even vmexit)
> so We still would need undercommit fix sugested by PeterZ (improving by
> 140%). ?

Looking only at the current runqueue? My worry is that it misses a lot
of cases. Maybe try the current runqueue first and then others.

Or were you referring to something else?

>
> So looking back at threads/ discussions so far, I am trying to
> summarize, the discussions so far. I feel, at least here are the few
> potential candidates to go in:
>
> 1) Avoiding double runqueue lock overhead (Andrew Theurer/ PeterZ)
> 2) Dynamically changing PLE window (Avi/Andrew/Chegu)
> 3) preempt_notify handler to identify preempted VCPUs (Avi)
> 4) Avoiding iterating over VCPUs in undercommit scenario. (Raghu/PeterZ)
> 5) Avoiding unnecessary spinning in overcommit scenario (Raghu/Rik)
> 6) Pv spinlock
> 7) Jiannan's proposed improvements
> 8) Defer preemption patches
>
> Did we miss anything (or added extra?)
>
> So here are my action items:
> - I plan to repost this series with what PeterZ, Rik suggested with
> performance analysis.
> - I ll go back and explore on (3) and (6) ..
>
> Please Let me know..

Undoubtedly we'll think of more stuff. But this looks like a good start.


--
error compiling committee.c: too many arguments to function

Andrew Theurer

unread,
Sep 27, 2012, 8:30:02 AM9/27/12
to
9) lazy gang-like scheduling with PLE to cover the non-gang-like
exceptions (/me runs and hides from scheduler folks)

-Andrew Theurer

H. Peter Anvin

unread,
Sep 28, 2012, 1:50:01 AM9/28/12
to
On 09/27/2012 10:38 PM, Raghavendra K T wrote:
> +
> +bool kvm_overcommitted()
> +{

This better not be C...

-hpa


--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.

Raghavendra K T

unread,
Sep 28, 2012, 1:50:01 AM9/28/12
to
On 09/27/2012 05:33 PM, Avi Kivity wrote:
> On 09/27/2012 01:23 PM, Raghavendra K T wrote:
>>>
>>> This gives us a good case for tracking preemption on a per-vm basis. As
>>> long as we aren't preempted, we can keep the PLE window high, and also
>>> return immediately from the handler without looking for candidates.
>>
>> 1) So do you think, deferring preemption patch ( Vatsa was mentioning
>> long back) is also another thing worth trying, so we reduce the chance
>> of LHP.
>
> Yes, we have to keep it in mind. It will be useful for fine grained
> locks, not so much so coarse locks or IPIs.
>

Agree.

> I would still of course prefer a PLE solution, but if we can't get it to
> work we can consider preemption deferral.
>

Okay.

>>
>> IIRC, with defer preemption :
>> we will have hook in spinlock/unlock path to measure depth of lock held,
>> and shared with host scheduler (may be via MSRs now).
>> Host scheduler 'prefers' not to preempt lock holding vcpu. (or rather
>> give say one chance.
>
> A downside is that we have to do that even when undercommitted.
>
> Also there may be a lot of false positives (deferred preemptions even
> when there is no contention).

Yes. That is a worry.

>
>>
>> 2) looking at the result (comparing A & C) , I do feel we have
>> significant in iterating over vcpus (when compared to even vmexit)
>> so We still would need undercommit fix sugested by PeterZ (improving by
>> 140%). ?
>
> Looking only at the current runqueue? My worry is that it misses a lot
> of cases. Maybe try the current runqueue first and then others.
>
> Or were you referring to something else?

No. I was referring to the same thing.

However. I had tried following also (which works well to check
undercommited scenario). But thinking to use only for yielding in case
of overcommit (yield in overcommit suggested by Rik) and keep
undercommit patch as suggested by PeterZ

[ patch is not in proper diff I suppose ].

Will test them.

Peter, Can I post your patch with your from/sob.. in V2?
Please let me know..

---
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 28f00bc..9ed3759 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -1620,6 +1620,21 @@ bool kvm_vcpu_eligible_for_directed_yield(struct
kvm_vcpu *vcpu)
return eligible;
}
#endif
+
+bool kvm_overcommitted()
+{
+ unsigned long load;
+
+ load = avenrun[0] + FIXED_1/200;
+ load = load >> FSHIFT;
+ load = (load << 7) / num_online_cpus();
+
+ if (load > 128)
+ return true;
+
+ return false;
+}
+
void kvm_vcpu_on_spin(struct kvm_vcpu *me)
{
struct kvm *kvm = me->kvm;
@@ -1629,6 +1644,9 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
int pass;
int i;

+ if (!kvm_overcommitted())
+ return;
+
kvm_vcpu_set_in_spin_loop(me, true);
/*
* We boost the priority of a VCPU that is runnable but not

Raghavendra K T

unread,
Sep 28, 2012, 2:10:02 AM9/28/12
to
On 09/28/2012 11:15 AM, H. Peter Anvin wrote:
> On 09/27/2012 10:38 PM, Raghavendra K T wrote:
>> +
>> +bool kvm_overcommitted()
>> +{
>
> This better not be C...

I think you meant I should have had like kvm_overcommitted(void) and
(different function name perhaps)

or is it the body of function?

Raghavendra K T

unread,
Sep 28, 2012, 2:30:01 AM9/28/12
to
On 09/28/2012 02:37 AM, Jiannan Ouyang wrote:
> FYI. The preempted_bitmap patch.
>
> I delete some unrelated code in the generated patch file and seems
> broken the patch file format... I hope anyone could teach me some
> solutions.
> However, it's pretty straight forward, four things: declaration,
> initialization, set and clear. I think you guys can figure it out easily!
>
> As Avi sugguested, you could check task state TASK_RUNNING in sched_out.
>
> Signed-off-by: Jiannan Ouyang <ouy...@cs.pitt.edu
> <mailto:ouy...@cs.pitt.edu>>
>
> diff --git a/arch/x86/include/asm/
>
> paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
> index 8613cbb..4fcb648 100644
> --- a/arch/x86/include/asm/paravirt_types.h
> +++ b/arch/x86/include/asm/paravirt_types.h
> @@ -73,6 +73,16 @@ struct pv_info {
> const char *name;
> };

I suppose we need this in common place since s390 also should have this,
if we are using this information in vcpu_on_spin()..

>
> +struct pv_sched_info {
> + unsigned long sched_bitmap;

Thinking, whether we need something similar to cpumask here?
Only thing is we are representing guest (v)cpumask.

> +} __attribute__((__packed__));
> +
> struct pv_init_ops {
> /*
> * Patch may replace one of the defined code sequences with
> diff --git a/arch/x86/kernel/paravirt-spinlocks.c
> b/arch/x86/kernel/paravirt-spinlocks.c
> index 676b8c7..2242d22 100644
> --- a/arch/x86/kernel/paravirt-spinlocks.c
> +++ b/arch/x86/kernel/paravirt-spinlocks.c
>
> +struct pv_sched_info pv_sched_info = {
> + .sched_bitmap = (unsigned long)-1,
> +};
> diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
> index 44ee712..3eb277e 100644
> --- a/virt/kvm/kvm_main.c
> +++ b/virt/kvm/kvm_main.c
> @@ -494,6 +494,11 @@ static struct kvm *kvm_create_vm(unsigned long
> type)
> mutex_init(&kvm->slots_lock);
> atomic_set(&kvm->users_count, 1);
>
> +#ifdef CONFIG_PARAVIRT_SPINLOCKS
> + kvm->pv_sched_info.sched_bitmap = (unsigned long)-1;
> +#endif
> +
> r = kvm_init_mmu_notifier(kvm);
> if (r)
> goto out_err;
> @@ -2697,7 +2702,13 @@ struct kvm_vcpu
> *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
> static void kvm_sched_in(struct preempt_notifier *pn, int cpu)
> {
> struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
>
> + set_bit(vcpu->vcpu_id, &vcpu->kvm->pv_sched_info.sched_bitmap);
> kvm_arch_vcpu_load(vcpu, cpu);
> }
>
> @@ -2705,7 +2716,13 @@ static void kvm_sched_out(struct
> preempt_notifier *pn,
> struct task_struct *next)
> {
> struct kvm_vcpu *vcpu = preempt_notifier_to_vcpu(pn);
>
> + clear_bit(vcpu->vcpu_id,
> &vcpu->kvm->pv_sched_info.sched_bitmap);
> kvm_arch_vcpu_put(vcpu);

Peter Zijlstra

unread,
Sep 28, 2012, 4:40:03 AM9/28/12
to
On Fri, 2012-09-28 at 11:08 +0530, Raghavendra K T wrote:
>
> Peter, Can I post your patch with your from/sob.. in V2?
> Please let me know..

Yeah I guess ;-)

Andrew Theurer

unread,
Sep 28, 2012, 7:50:02 AM9/28/12
to
On Fri, 2012-09-28 at 11:08 +0530, Raghavendra K T wrote:
> On 09/27/2012 05:33 PM, Avi Kivity wrote:
> > On 09/27/2012 01:23 PM, Raghavendra K T wrote:
> >>>
> >>> This gives us a good case for tracking preemption on a per-vm basis. As
> >>> long as we aren't preempted, we can keep the PLE window high, and also
> >>> return immediately from the handler without looking for candidates.
> >>
> >> 1) So do you think, deferring preemption patch ( Vatsa was mentioning
> >> long back) is also another thing worth trying, so we reduce the chance
> >> of LHP.
> >
> > Yes, we have to keep it in mind. It will be useful for fine grained
> > locks, not so much so coarse locks or IPIs.
> >
>
> Agree.
>
> > I would still of course prefer a PLE solution, but if we can't get it to
> > work we can consider preemption deferral.
> >
>
> Okay.
>
> >>
> >> IIRC, with defer preemption :
> >> we will have hook in spinlock/unlock path to measure depth of lock held,
> >> and shared with host scheduler (may be via MSRs now).
> >> Host scheduler 'prefers' not to preempt lock holding vcpu. (or rather
> >> give say one chance.
> >
> > A downside is that we have to do that even when undercommitted.

Hopefully vcpu preemption is very rare when undercommitted, so it should
not happen much at all.
> >
> > Also there may be a lot of false positives (deferred preemptions even
> > when there is no contention).

It will be interesting to see how this behaves with a very high lock
activity in a guest. Once the scheduler defers preemption, is it for a
fixed amount of time, or does it know to cut the deferral short as soon
as the lock depth is reduced [by x]?

Peter Zijlstra

unread,
Sep 28, 2012, 10:20:01 AM9/28/12
to
On Fri, 2012-09-28 at 06:40 -0500, Andrew Theurer wrote:
> It will be interesting to see how this behaves with a very high lock
> activity in a guest. Once the scheduler defers preemption, is it for
> a
> fixed amount of time, or does it know to cut the deferral short as
> soon
> as the lock depth is reduced [by x]?

Since the locks live in a guest/userspace, we don't even know they're
held at all, let alone when state changes.

Also, afaik PLE simply exits the guest whenever you do a busy-wait,
there's no guarantee its due to a lock at all, we could be waiting for a
'virtual' hardware resource or whatnot.

Raghavendra K T

unread,
Sep 28, 2012, 10:20:01 AM9/28/12
to
On 09/28/2012 05:10 PM, Andrew Theurer wrote:
> On Fri, 2012-09-28 at 11:08 +0530, Raghavendra K T wrote:
>> On 09/27/2012 05:33 PM, Avi Kivity wrote:
>>> On 09/27/2012 01:23 PM, Raghavendra K T wrote:
>>>>>
[...]
>>>
>>> Also there may be a lot of false positives (deferred preemptions even
>>> when there is no contention).
>
> It will be interesting to see how this behaves with a very high lock
> activity in a guest. Once the scheduler defers preemption, is it for a
> fixed amount of time, or does it know to cut the deferral short as soon
> as the lock depth is reduced [by x]?

Design/protocol that Vatsa, had in mind was something like this:

- scheduler does not give a vcpu holding lock forever, it may give one
chance that would give only few ticks. In addition to giving chance,
scheduler also sets some indication that he has been given chance.

- vcpu once he release (all) the lock(s), if it had given chance,
it should clear that (ACK), and relinquish the cpu.

Konrad Rzeszutek Wilk

unread,
Sep 28, 2012, 2:00:02 PM9/28/12
to
> >> PLE:
> >> - works for unmodified / non-Linux guests
> >> - works for all types of spins (e.g. smp_call_function*())
> >> - utilizes an existing hardware interface (PAUSE instruction) so likely
> >> more robust compared to a software interface
> >>
> >> PV:
> >> - has more information, so it can perform better
> >
> > Should we also consider that we always have an edge here for non-PLE
> > machine?
>
> True. The deployment share for these is decreasing rapidly though. I
> hate optimizing for obsolete hardware.

Keep in mind that the patchset that Jeremy provided also cleans (remove)
parts of the pv spinlock code. It removes the various spin_lock,
spin_unlock, etc that touch paravirt code. Instead the pv code is only
in the slowpath. And if you don't compile with CONFIG_PARAVIRT_SPINLOCK
the end code is the same as it is now.

On a different subject- I am curious whether the Haswell new locking
instructions (the transactional ones?) can be put in usage for the slow
case?

Avi Kivity

unread,
Sep 30, 2012, 4:20:02 AM9/30/12
to
On 09/28/2012 08:18 PM, Konrad Rzeszutek Wilk wrote:
>> >> PLE:
>> >> - works for unmodified / non-Linux guests
>> >> - works for all types of spins (e.g. smp_call_function*())
>> >> - utilizes an existing hardware interface (PAUSE instruction) so likely
>> >> more robust compared to a software interface
>> >>
>> >> PV:
>> >> - has more information, so it can perform better
>> >
>> > Should we also consider that we always have an edge here for non-PLE
>> > machine?
>>
>> True. The deployment share for these is decreasing rapidly though. I
>> hate optimizing for obsolete hardware.
>
> Keep in mind that the patchset that Jeremy provided also cleans (remove)
> parts of the pv spinlock code. It removes the various spin_lock,
> spin_unlock, etc that touch paravirt code. Instead the pv code is only
> in the slowpath. And if you don't compile with CONFIG_PARAVIRT_SPINLOCK
> the end code is the same as it is now.

We still need to maintain information about the lock holder if pv is
enabled at all, even if it is never used.

> On a different subject- I am curious whether the Haswell new locking
> instructions (the transactional ones?) can be put in usage for the slow
> case?

Transactions are blown on any context switch, so no.

--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 30, 2012, 4:20:02 AM9/30/12
to
On 09/28/2012 08:16 AM, Raghavendra K T wrote:
>
>>
>> +struct pv_sched_info {
>> + unsigned long sched_bitmap;
>
> Thinking, whether we need something similar to cpumask here?
> Only thing is we are representing guest (v)cpumask.
>

DECLARE_BITMAP(sched_bitmap, KVM_MAX_VCPUS)

cpumask is for host masks, this is a guest mask.

--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Sep 30, 2012, 4:30:02 AM9/30/12
to
On 09/28/2012 01:40 PM, Andrew Theurer wrote:
>>
>> >>
>> >> IIRC, with defer preemption :
>> >> we will have hook in spinlock/unlock path to measure depth of lock held,
>> >> and shared with host scheduler (may be via MSRs now).
>> >> Host scheduler 'prefers' not to preempt lock holding vcpu. (or rather
>> >> give say one chance.
>> >
>> > A downside is that we have to do that even when undercommitted.
>
> Hopefully vcpu preemption is very rare when undercommitted, so it should
> not happen much at all.

As soon as you're preempted, you're effectively overcommitted (even if
the system as a whole is undercommitted). What I meant was that you
need to communicate your lock state to the host, and with fine-grained
locking this can happen a lot. It may be as simple as an
increment/decrement instruction though.



--
error compiling committee.c: too many arguments to function

Gleb Natapov

unread,
Sep 30, 2012, 7:10:02 AM9/30/12
to
On Sun, Sep 30, 2012 at 10:18:17AM +0200, Avi Kivity wrote:
> On 09/28/2012 08:16 AM, Raghavendra K T wrote:
> >
> >>
> >> +struct pv_sched_info {
> >> + unsigned long sched_bitmap;
> >
> > Thinking, whether we need something similar to cpumask here?
> > Only thing is we are representing guest (v)cpumask.
> >
>
> DECLARE_BITMAP(sched_bitmap, KVM_MAX_VCPUS)
>
vcpu_id can be greater than KVM_MAX_VCPUS.

> cpumask is for host masks, this is a guest mask.
>
> --
> error compiling committee.c: too many arguments to function

--
Gleb.

Avi Kivity

unread,
Sep 30, 2012, 7:20:02 AM9/30/12
to
On 09/30/2012 01:07 PM, Gleb Natapov wrote:
> On Sun, Sep 30, 2012 at 10:18:17AM +0200, Avi Kivity wrote:
>> On 09/28/2012 08:16 AM, Raghavendra K T wrote:
>> >
>> >>
>> >> +struct pv_sched_info {
>> >> + unsigned long sched_bitmap;
>> >
>> > Thinking, whether we need something similar to cpumask here?
>> > Only thing is we are representing guest (v)cpumask.
>> >
>>
>> DECLARE_BITMAP(sched_bitmap, KVM_MAX_VCPUS)
>>
> vcpu_id can be greater than KVM_MAX_VCPUS.

Use the index into the vcpu table as the bitmap index then. In fact
it's better because then the lookup to get the vcpu pointer is trivial.


--
error compiling committee.c: too many arguments to function
--

Raghavendra K T

unread,
Oct 3, 2012, 8:30:02 AM10/3/12
to
* Avi Kivity <a...@redhat.com> [2012-09-24 17:41:19]:

> On 09/21/2012 08:24 PM, Raghavendra K T wrote:
> > On 09/21/2012 06:32 PM, Rik van Riel wrote:
> >> On 09/21/2012 08:00 AM, Raghavendra K T wrote:
> >>> From: Raghavendra K T <raghave...@linux.vnet.ibm.com>
> >>>
> >>> When total number of VCPUs of system is less than or equal to physical
> >>> CPUs,
> >>> PLE exits become costly since each VCPU can have dedicated PCPU, and
> >>> trying to find a target VCPU to yield_to just burns time in PLE handler.
> >>>
> >>> This patch reduces overhead, by simply doing a return in such
> >>> scenarios by
> >>> checking the length of current cpu runqueue.
> >>
> >> I am not convinced this is the way to go.
> >>
> >> The VCPU that is holding the lock, and is not releasing it,
> >> probably got scheduled out. That implies that VCPU is on a
> >> runqueue with at least one other task.
> >
> > I see your point here, we have two cases:
> >
> > case 1)
> >
> > rq1 : vcpu1->wait(lockA) (spinning)
> > rq2 : vcpu2->holding(lockA) (running)
> >
> > Here Ideally vcpu1 should not enter PLE handler, since it would surely
> > get the lock within ple_window cycle. (assuming ple_window is tuned for
> > that workload perfectly).
> >
> > May be this explains why we are not seeing benefit with kernbench.
> >
> > On the other side, Since we cannot have a perfect ple_window tuned for
> > all type of workloads, for those workloads, which may need more than
> > 4096 cycles, we gain. thinking is it that we are seeing in benefited
> > cases?
>
> Maybe we need to increase the ple window regardless. 4096 cycles is 2
> microseconds or less (call it t_spin). The overhead from
> kvm_vcpu_on_spin() and the associated task switches is at least a few
> microseconds, increasing as contention is added (call it t_tield). The
> time for a natural context switch is several milliseconds (call it
> t_slice). There is also the time the lock holder owns the lock,
> assuming no contention (t_hold).
>
> If t_yield > t_spin, then in the undercommitted case it dominates
> t_spin. If t_hold > t_spin we lose badly.
>
> If t_spin > t_yield, then the undercommitted case doesn't suffer as much
> as most of the spinning happens in the guest instead of the host, so it
> can pick up the unlock timely. We don't lose too much in the
> overcommitted case provided the values aren't too far apart (say a
> factor of 3).
>
> Obviously t_spin must be significantly smaller than t_slice, otherwise
> it accomplishes nothing.
>
> Regarding t_hold: if it is small, then a larger t_spin helps avoid false
> exits. If it is large, then we're not very sensitive to t_spin. It
> doesn't matter if it takes us 2 usec or 20 usec to yield, if we end up
> yielding for several milliseconds.
>
> So I think it's worth trying again with ple_window of 20000-40000.
>

Hi Avi,

I ran different benchmarks increasing ple_window, and results does not
seem to be encouraging for increasing ple_window.

Results:
16 core PLE machine with 16 vcpu guest.

base kernel = 3.6-rc5 + ple handler optimization patch
base_pleopt_8k = base kernel + ple window = 8k
base_pleopt_16k = base kernel + ple window = 16k
base_pleopt_32k = base kernel + ple window = 32k


Percentage improvements of benchmarks w.r.t base_pleopt with ple_window = 4096

base_pleopt_8k base_pleopt_16k base_pleopt_32k
-----------------------------------------------------------------
kernbench_1x -5.54915 -15.94529 -44.31562
kernbench_2x -7.89399 -17.75039 -37.73498
-----------------------------------------------------------------
sysbench_1x 0.45955 -0.98778 0.05252
sysbench_2x 1.44071 -0.81625 1.35620
sysbench_3x 0.45549 1.51795 -0.41573
-----------------------------------------------------------------

hackbench_1x -3.80272 -13.91456 -40.79059
hackbench_2x -4.78999 -7.61382 -7.24475
-----------------------------------------------------------------
ebizzy_1x -2.54626 -16.86050 -38.46109
ebizzy_2x -8.75526 -19.29116 -48.33314
-----------------------------------------------------------------

I also got perf top output to analyse the difference. Difference comes
because of flushtlb (and also spinlock).

Ebizzy run for 4k ple_window
- 87.20% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
- 100.00% _raw_spin_unlock_irqrestore
+ 52.89% release_pages
+ 47.10% pagevec_lru_move_fn
- 5.71% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
+ 86.03% default_send_IPI_mask_allbutself_phys
+ 13.96% default_send_IPI_mask_sequence_phys
- 3.10% [kernel] [k] smp_call_function_many
smp_call_function_many


Ebizzy run for 32k ple_window

- 91.40% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
- 100.00% _raw_spin_unlock_irqrestore
+ 53.13% release_pages
+ 46.86% pagevec_lru_move_fn
- 4.38% [kernel] [k] smp_call_function_many
smp_call_function_many
- 2.51% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
+ 90.76% default_send_IPI_mask_allbutself_phys
+ 9.24% default_send_IPI_mask_sequence_phys


Below is the detailed result:
patch = base_pleopt_8k
+-----------+-----------+-----------+------------+-----------+
kernbench
+-----------+-----------+-----------+------------+-----------+
base stddev patch stdev %improve
+-----------+-----------+-----------+------------+-----------+
41.0027 0.7990 43.2780 0.5180 -5.54915
89.2983 1.2406 96.3475 1.8891 -7.89399
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
sysbench
+-----------+-----------+-----------+------------+-----------+
9.9010 0.0558 9.8555 0.1246 0.45955
19.7611 0.4290 19.4764 0.0835 1.44071
29.1775 0.9903 29.0446 0.8641 0.45549
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
hackbench
+-----------+-----------+-----------+------------+-----------+
77.1580 1.9787 80.0921 2.9696 -3.80272
239.2490 1.5660 250.7090 2.6074 -4.78999
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
ebizzy
+-----------+-----------+-----------+------------+-----------+
4256.2500 186.8053 4147.8750 206.1840 -2.54626
2197.2500 93.1048 2004.8750 85.7995 -8.75526
+-----------+-----------+-----------+------------+-----------+

patch = base_pleopt_16k
+-----------+-----------+-----------+------------+-----------+
kernbench
+-----------+-----------+-----------+------------+-----------+
base stddev patch stdev %improve
+-----------+-----------+-----------+------------+-----------+
41.0027 0.7990 47.5407 0.5739 -15.94529
89.2983 1.2406 105.1491 1.2244 -17.75039
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
sysbench
+-----------+-----------+-----------+------------+-----------+
9.9010 0.0558 9.9988 0.1106 -0.98778
19.7611 0.4290 19.9224 0.9016 -0.81625
29.1775 0.9903 28.7346 0.2788 1.51795
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
hackbench
+-----------+-----------+-----------+------------+-----------+
77.1580 1.9787 87.8942 2.2132 -13.91456
239.2490 1.5660 257.4650 5.3674 -7.61382
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
ebizzy
+-----------+-----------+-----------+------------+-----------+
4256.2500 186.8053 3538.6250 101.1165 -16.86050
2197.2500 93.1048 1773.3750 91.8414 -19.29116
+-----------+-----------+-----------+------------+-----------+

patch = base_pleopt_32k
+-----------+-----------+-----------+------------+-----------+
kernbench
+-----------+-----------+-----------+------------+-----------+
base stddev patch stdev %improve
+-----------+-----------+-----------+------------+-----------+
41.0027 0.7990 59.1733 0.8102 -44.31562
89.2983 1.2406 122.9950 1.5534 -37.73498
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
sysbench
+-----------+-----------+-----------+------------+-----------+
9.9010 0.0558 9.8958 0.0593 0.05252
19.7611 0.4290 19.4931 0.1767 1.35620
29.1775 0.9903 29.2988 1.0420 -0.41573
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
hackbench
+-----------+-----------+-----------+------------+-----------+
77.1580 1.9787 108.6312 13.1500 -40.79059
239.2490 1.5660 256.5820 2.2722 -7.24475
+-----------+-----------+-----------+------------+-----------+
+-----------+-----------+-----------+------------+-----------+
ebizzy
+-----------+-----------+-----------+------------+-----------+
4256.2500 186.8053 2619.2500 80.8150 -38.46109
2197.2500 93.1048 1135.2500 22.2887 -48.33314
+-----------+-----------+-----------+------------+-----------+

Raghavendra K T

unread,
Oct 3, 2012, 10:30:02 AM10/3/12
to
* Avi Kivity <a...@redhat.com> [2012-09-30 13:13:09]:

> On 09/30/2012 01:07 PM, Gleb Natapov wrote:
> > On Sun, Sep 30, 2012 at 10:18:17AM +0200, Avi Kivity wrote:
> >> On 09/28/2012 08:16 AM, Raghavendra K T wrote:
> >> >
> >> >>
> >> >> +struct pv_sched_info {
> >> >> + unsigned long sched_bitmap;
> >> >
> >> > Thinking, whether we need something similar to cpumask here?
> >> > Only thing is we are representing guest (v)cpumask.
> >> >
> >>
> >> DECLARE_BITMAP(sched_bitmap, KVM_MAX_VCPUS)
> >>
> > vcpu_id can be greater than KVM_MAX_VCPUS.
>
> Use the index into the vcpu table as the bitmap index then. In fact
> it's better because then the lookup to get the vcpu pointer is trivial.

Did you mean, while setting the bitmap,

we should do
for (i = 1..n)
if (kvm->vcpus[i] == vcpu) set ith position in bitmap?

I just wanted to know whether there is any easy way to convert from
vcpu pointer to index in kvm vcpu table.

Raghavendra K T

unread,
Oct 3, 2012, 10:40:02 AM10/3/12
to
* Avi Kivity <a...@redhat.com> [2012-09-27 14:03:59]:

> On 09/27/2012 01:23 PM, Raghavendra K T wrote:
> >>
[...]
> > 2) looking at the result (comparing A & C) , I do feel we have
> > significant in iterating over vcpus (when compared to even vmexit)
> > so We still would need undercommit fix sugested by PeterZ (improving by
> > 140%). ?
>
> Looking only at the current runqueue? My worry is that it misses a lot
> of cases. Maybe try the current runqueue first and then others.
>

Okay. Do you mean we can have something like

+ if (rq->nr_running == 1 && p_rq->nr_running == 1) {
+ yielded = -ESRCH;
+ goto out_irq;
+ }

in the Peter's patch ?

( I thought lot about && or || . Both seem to have their own cons ).
But that should be only when we have short term imbalance, as PeterZ
told.

I am experimenting all these for V2 patch. Will come back with analysis
and patch.

> Or were you referring to something else?
>

Avi Kivity

unread,
Oct 3, 2012, 11:00:03 AM10/3/12
to
On 10/03/2012 04:17 PM, Raghavendra K T wrote:
> * Avi Kivity <a...@redhat.com> [2012-09-30 13:13:09]:
>
>> On 09/30/2012 01:07 PM, Gleb Natapov wrote:
>> > On Sun, Sep 30, 2012 at 10:18:17AM +0200, Avi Kivity wrote:
>> >> On 09/28/2012 08:16 AM, Raghavendra K T wrote:
>> >> >
>> >> >>
>> >> >> +struct pv_sched_info {
>> >> >> + unsigned long sched_bitmap;
>> >> >
>> >> > Thinking, whether we need something similar to cpumask here?
>> >> > Only thing is we are representing guest (v)cpumask.
>> >> >
>> >>
>> >> DECLARE_BITMAP(sched_bitmap, KVM_MAX_VCPUS)
>> >>
>> > vcpu_id can be greater than KVM_MAX_VCPUS.
>>
>> Use the index into the vcpu table as the bitmap index then. In fact
>> it's better because then the lookup to get the vcpu pointer is trivial.
>
> Did you mean, while setting the bitmap,
>
> we should do
> for (i = 1..n)
> if (kvm->vcpus[i] == vcpu) set ith position in bitmap?

You can store i in the vcpu itself:

set_bit(vcpu->index, &kvm->preempted);

>
> I just wanted to know whether there is any easy way to convert from
> vcpu pointer to index in kvm vcpu table.
>



--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Oct 3, 2012, 1:10:02 PM10/3/12
to
On 10/03/2012 02:22 PM, Raghavendra K T wrote:
>> So I think it's worth trying again with ple_window of 20000-40000.
>>
>
> Hi Avi,
>
> I ran different benchmarks increasing ple_window, and results does not
> seem to be encouraging for increasing ple_window.

Thanks for testing! Comments below.

> Results:
> 16 core PLE machine with 16 vcpu guest.
>
> base kernel = 3.6-rc5 + ple handler optimization patch
> base_pleopt_8k = base kernel + ple window = 8k
> base_pleopt_16k = base kernel + ple window = 16k
> base_pleopt_32k = base kernel + ple window = 32k
>
>
> Percentage improvements of benchmarks w.r.t base_pleopt with ple_window = 4096
>
> base_pleopt_8k base_pleopt_16k base_pleopt_32k
> -----------------------------------------------------------------
> kernbench_1x -5.54915 -15.94529 -44.31562
> kernbench_2x -7.89399 -17.75039 -37.73498

So, 44% degradation even with no overcommit? That's surprising.

> I also got perf top output to analyse the difference. Difference comes
> because of flushtlb (and also spinlock).

That's in the guest, yes?

>
> Ebizzy run for 4k ple_window
> - 87.20% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> - 100.00% _raw_spin_unlock_irqrestore
> + 52.89% release_pages
> + 47.10% pagevec_lru_move_fn
> - 5.71% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> + 86.03% default_send_IPI_mask_allbutself_phys
> + 13.96% default_send_IPI_mask_sequence_phys
> - 3.10% [kernel] [k] smp_call_function_many
> smp_call_function_many
>
>
> Ebizzy run for 32k ple_window
>
> - 91.40% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> - 100.00% _raw_spin_unlock_irqrestore
> + 53.13% release_pages
> + 46.86% pagevec_lru_move_fn
> - 4.38% [kernel] [k] smp_call_function_many
> smp_call_function_many
> - 2.51% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> + 90.76% default_send_IPI_mask_allbutself_phys
> + 9.24% default_send_IPI_mask_sequence_phys
>

Both the 4k and the 32k results are crazy. Why is
arch_local_irq_restore() so prominent? Do you have a very high
interrupt rate in the guest?




--
error compiling committee.c: too many arguments to function

Avi Kivity

unread,
Oct 3, 2012, 1:30:02 PM10/3/12
to
On 10/03/2012 04:29 PM, Raghavendra K T wrote:
> * Avi Kivity <a...@redhat.com> [2012-09-27 14:03:59]:
>
>> On 09/27/2012 01:23 PM, Raghavendra K T wrote:
>> >>
> [...]
>> > 2) looking at the result (comparing A & C) , I do feel we have
>> > significant in iterating over vcpus (when compared to even vmexit)
>> > so We still would need undercommit fix sugested by PeterZ (improving by
>> > 140%). ?
>>
>> Looking only at the current runqueue? My worry is that it misses a lot
>> of cases. Maybe try the current runqueue first and then others.
>>
>
> Okay. Do you mean we can have something like
>
> + if (rq->nr_running == 1 && p_rq->nr_running == 1) {
> + yielded = -ESRCH;
> + goto out_irq;
> + }
>
> in the Peter's patch ?
>
> ( I thought lot about && or || . Both seem to have their own cons ).
> But that should be only when we have short term imbalance, as PeterZ
> told.

I'm missing the context. What is p_rq?

What I mean was:

if can_yield_to_process_in_current_rq
do that
else if can_yield_to_process_in_other_rq
do that
else
return -ESRCH


--
error compiling committee.c: too many arguments to function

Gleb Natapov

unread,
Oct 4, 2012, 3:30:02 AM10/4/12
to
On Wed, Oct 03, 2012 at 04:56:57PM +0200, Avi Kivity wrote:
> On 10/03/2012 04:17 PM, Raghavendra K T wrote:
> > * Avi Kivity <a...@redhat.com> [2012-09-30 13:13:09]:
> >
> >> On 09/30/2012 01:07 PM, Gleb Natapov wrote:
> >> > On Sun, Sep 30, 2012 at 10:18:17AM +0200, Avi Kivity wrote:
> >> >> On 09/28/2012 08:16 AM, Raghavendra K T wrote:
> >> >> >
> >> >> >>
> >> >> >> +struct pv_sched_info {
> >> >> >> + unsigned long sched_bitmap;
> >> >> >
> >> >> > Thinking, whether we need something similar to cpumask here?
> >> >> > Only thing is we are representing guest (v)cpumask.
> >> >> >
> >> >>
> >> >> DECLARE_BITMAP(sched_bitmap, KVM_MAX_VCPUS)
> >> >>
> >> > vcpu_id can be greater than KVM_MAX_VCPUS.
> >>
> >> Use the index into the vcpu table as the bitmap index then. In fact
> >> it's better because then the lookup to get the vcpu pointer is trivial.
> >
> > Did you mean, while setting the bitmap,
> >
> > we should do
> > for (i = 1..n)
> > if (kvm->vcpus[i] == vcpu) set ith position in bitmap?
>
> You can store i in the vcpu itself:
>
> set_bit(vcpu->index, &kvm->preempted);
>
This will make the fact that vcpus are stored in an array into API
instead of implementation detail :( There were patches for vcpu
destruction that changed the array to rculist. Well, it will be still
possible to make the array rcu protected and copy it every time vcpu is
deleted/added I guess.

--
Gleb.

Raghavendra K T

unread,
Oct 4, 2012, 7:00:01 AM10/4/12
to
On 10/03/2012 10:35 PM, Avi Kivity wrote:
> On 10/03/2012 02:22 PM, Raghavendra K T wrote:
>>> So I think it's worth trying again with ple_window of 20000-40000.
>>>
>>
>> Hi Avi,
>>
>> I ran different benchmarks increasing ple_window, and results does not
>> seem to be encouraging for increasing ple_window.
>
> Thanks for testing! Comments below.
>
>> Results:
>> 16 core PLE machine with 16 vcpu guest.
>>
>> base kernel = 3.6-rc5 + ple handler optimization patch
>> base_pleopt_8k = base kernel + ple window = 8k
>> base_pleopt_16k = base kernel + ple window = 16k
>> base_pleopt_32k = base kernel + ple window = 32k
>>
>>
>> Percentage improvements of benchmarks w.r.t base_pleopt with ple_window = 4096
>>
>> base_pleopt_8k base_pleopt_16k base_pleopt_32k
>> -----------------------------------------------------------------
>> kernbench_1x -5.54915 -15.94529 -44.31562
>> kernbench_2x -7.89399 -17.75039 -37.73498
>
> So, 44% degradation even with no overcommit? That's surprising.

Yes. Kernbench was run with #threads = #vcpu * 2 as usual. Is it
spending 8 times the original ple_window cycles for 16 vcpus
significant?

>
>> I also got perf top output to analyse the difference. Difference comes
>> because of flushtlb (and also spinlock).
>
> That's in the guest, yes?

Yes. Perf is in guest.
How to measure if I have high interrupt rate in guest?
From /proc/interrupt numbers I am not able to judge :(

I went back and got the results on a 32 core machine with 32 vcpu guest.
Strangely, I got result supporting the claim that increasing ple_window
helps for non-overcommitted scenario.

32 core 32 vcpu guest 1x scenarios.

ple_gap = 0
kernbench: Elapsed Time 38.61
ebizzy: 7463 records/s

ple_window = 4k
kernbench: Elapsed Time 43.5067
ebizzy: 2528 records/s

ple_window = 32k
kernebench : Elapsed Time 39.4133
ebizzy: 7196 records/s


perf top for ebizzy for above:
ple_gap = 0
- 84.74% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
- 100.00% _raw_spin_unlock_irqrestore
+ 50.96% release_pages
+ 49.02% pagevec_lru_move_fn
- 6.57% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
+ 92.54% default_send_IPI_mask_allbutself_phys
+ 7.46% default_send_IPI_mask_sequence_phys
- 1.54% [kernel] [k] smp_call_function_many
smp_call_function_many

ple_window = 32k
- 84.47% [kernel] [k] arch_local_irq_restore
+ arch_local_irq_restore
- 6.46% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
+ 93.51% default_send_IPI_mask_allbutself_phys
+ 6.49% default_send_IPI_mask_sequence_phys
- 1.80% [kernel] [k] smp_call_function_many
- smp_call_function_many
+ 99.98% native_flush_tlb_others


ple_window = 4k
- 91.35% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
- 100.00% _raw_spin_unlock_irqrestore
+ 53.19% release_pages
+ 46.81% pagevec_lru_move_fn
- 3.90% [kernel] [k] smp_call_function_many
smp_call_function_many
- 2.94% [kernel] [k] arch_local_irq_restore
- arch_local_irq_restore
+ 93.12% default_send_IPI_mask_allbutself_phys
+ 6.88% default_send_IPI_mask_sequence_phys

Let me know if I can try something here..
/me confused :(

Raghavendra K T

unread,
Oct 4, 2012, 7:10:01 AM10/4/12
to
On 10/03/2012 10:55 PM, Avi Kivity wrote:
> On 10/03/2012 04:29 PM, Raghavendra K T wrote:
>> * Avi Kivity <a...@redhat.com> [2012-09-27 14:03:59]:
>>
>>> On 09/27/2012 01:23 PM, Raghavendra K T wrote:
>>>>>
>> [...]
>>>> 2) looking at the result (comparing A & C) , I do feel we have
>>>> significant in iterating over vcpus (when compared to even vmexit)
>>>> so We still would need undercommit fix sugested by PeterZ (improving by
>>>> 140%). ?
>>>
>>> Looking only at the current runqueue? My worry is that it misses a lot
>>> of cases. Maybe try the current runqueue first and then others.
>>>
>>
>> Okay. Do you mean we can have something like
>>
>> + if (rq->nr_running == 1 && p_rq->nr_running == 1) {
>> + yielded = -ESRCH;
>> + goto out_irq;
>> + }
>>
>> in the Peter's patch ?
>>
>> ( I thought lot about && or || . Both seem to have their own cons ).
>> But that should be only when we have short term imbalance, as PeterZ
>> told.
>
> I'm missing the context. What is p_rq?

p_rq is the run queue of target vcpu.
What I was trying below was to address Rik concern. Suppose
rq of source vcpu has one task, but target probably has two task,
with a eligible vcpu waiting to be scheduled.

>
> What I mean was:
>
> if can_yield_to_process_in_current_rq
> do that
> else if can_yield_to_process_in_other_rq
> do that
> else
> return -ESRCH

I think you are saying we have to check the run queue of the
source vcpu, if we have a vcpu belonging to same VM and try yield to
that? ignoring whatever the target vcpu we received for yield_to.

Or is it that kvm_vcpu_yield_to should now check the vcpus of same vm
belonging to same run queue first. If we don't succeed, go again for
a vcpu in different runqueue.
Does it add more overhead especially in <= 1x scenario?

Avi Kivity

unread,
Oct 4, 2012, 8:50:01 AM10/4/12
to
On 10/04/2012 12:49 PM, Raghavendra K T wrote:
> On 10/03/2012 10:35 PM, Avi Kivity wrote:
>> On 10/03/2012 02:22 PM, Raghavendra K T wrote:
>>>> So I think it's worth trying again with ple_window of 20000-40000.
>>>>
>>>
>>> Hi Avi,
>>>
>>> I ran different benchmarks increasing ple_window, and results does not
>>> seem to be encouraging for increasing ple_window.
>>
>> Thanks for testing! Comments below.
>>
>>> Results:
>>> 16 core PLE machine with 16 vcpu guest.
>>>
>>> base kernel = 3.6-rc5 + ple handler optimization patch
>>> base_pleopt_8k = base kernel + ple window = 8k
>>> base_pleopt_16k = base kernel + ple window = 16k
>>> base_pleopt_32k = base kernel + ple window = 32k
>>>
>>>
>>> Percentage improvements of benchmarks w.r.t base_pleopt with
>>> ple_window = 4096
>>>
>>> base_pleopt_8k base_pleopt_16k base_pleopt_32k
>>> -----------------------------------------------------------------
>>>
>>> kernbench_1x -5.54915 -15.94529 -44.31562
>>> kernbench_2x -7.89399 -17.75039 -37.73498
>>
>> So, 44% degradation even with no overcommit? That's surprising.
>
> Yes. Kernbench was run with #threads = #vcpu * 2 as usual. Is it
> spending 8 times the original ple_window cycles for 16 vcpus
> significant?

A PLE exit when not overcommitted cannot do any good, it is better to
spin in the guest rather that look for candidates on the host. In fact
when we benchmark we often disable PLE completely.
'vmstat 1'

>
> I went back and got the results on a 32 core machine with 32 vcpu guest.
> Strangely, I got result supporting the claim that increasing ple_window
> helps for non-overcommitted scenario.
>
> 32 core 32 vcpu guest 1x scenarios.
>
> ple_gap = 0
> kernbench: Elapsed Time 38.61
> ebizzy: 7463 records/s
>
> ple_window = 4k
> kernbench: Elapsed Time 43.5067
> ebizzy: 2528 records/s
>
> ple_window = 32k
> kernebench : Elapsed Time 39.4133
> ebizzy: 7196 records/s

So maybe something was wrong with the first measurement.

>
>
> perf top for ebizzy for above:
> ple_gap = 0
> - 84.74% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> - 100.00% _raw_spin_unlock_irqrestore
> + 50.96% release_pages
> + 49.02% pagevec_lru_move_fn
> - 6.57% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> + 92.54% default_send_IPI_mask_allbutself_phys
> + 7.46% default_send_IPI_mask_sequence_phys
> - 1.54% [kernel] [k] smp_call_function_many
> smp_call_function_many

Again the numbers are ridiculously high for arch_local_irq_restore.
Maybe there's a bad perf/kvm interaction when we're injecting an
interrupt, I can't believe we're spending 84% of the time running the
popf instruction.

>
> ple_window = 32k
> - 84.47% [kernel] [k] arch_local_irq_restore
> + arch_local_irq_restore
> - 6.46% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> + 93.51% default_send_IPI_mask_allbutself_phys
> + 6.49% default_send_IPI_mask_sequence_phys
> - 1.80% [kernel] [k] smp_call_function_many
> - smp_call_function_many
> + 99.98% native_flush_tlb_others
>
>
> ple_window = 4k
> - 91.35% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> - 100.00% _raw_spin_unlock_irqrestore
> + 53.19% release_pages
> + 46.81% pagevec_lru_move_fn
> - 3.90% [kernel] [k] smp_call_function_many
> smp_call_function_many
> - 2.94% [kernel] [k] arch_local_irq_restore
> - arch_local_irq_restore
> + 93.12% default_send_IPI_mask_allbutself_phys
> + 6.88% default_send_IPI_mask_sequence_phys
>
> Let me know if I can try something here..
> /me confused :(
>

I'm even more confused. Please try 'perf kvm' from the host, it does
fewer dirty tricks with the PMU and so may be more accurate.

--
error compiling committee.c: too many arguments to function
It is loading more messages.
0 new messages