[kvm-devel] [PATCH 6/8] x86: KVM guest: hypercall batching

2008-03-02 Thread Avi Kivity
From: Marcelo Tosatti <[EMAIL PROTECTED]>

Batch pte updates and tlb flushes in lazy MMU mode.

v1->v2:
- report individual hypercall error code, have multicall return number of
processed entries.
- cover entire multicall duration with slots_lock instead of
acquiring/reacquiring.

v2->v3:
- change to one ioctl per paravirt feature

v3->v4:
- adjust to mmu_op
- helper for getting para_state without debug warnings

Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]>
Signed-off-by: Avi Kivity <[EMAIL PROTECTED]>
---
 arch/x86/kernel/kvm.c |   62 +++-
 1 files changed, 60 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index e28d818..8405984 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -25,6 +25,22 @@
 #include 
 #include 
 #include 
+#include 
+
+#define MMU_QUEUE_SIZE 1024
+
+struct kvm_para_state {
+   u8 mmu_queue[MMU_QUEUE_SIZE];
+   int mmu_queue_len;
+   enum paravirt_lazy_mode mode;
+};
+
+static DEFINE_PER_CPU(struct kvm_para_state, para_state);
+
+static struct kvm_para_state *kvm_para_state(void)
+{
+   return &per_cpu(para_state, raw_smp_processor_id());
+}
 
 /*
  * No need for any "IO delay" on KVM
@@ -47,6 +63,28 @@ static void kvm_mmu_op(void *buffer, unsigned len)
} while (len);
 }
 
+static void mmu_queue_flush(struct kvm_para_state *state)
+{
+   if (state->mmu_queue_len) {
+   kvm_mmu_op(state->mmu_queue, state->mmu_queue_len);
+   state->mmu_queue_len = 0;
+   }
+}
+
+static void kvm_deferred_mmu_op(void *buffer, int len)
+{
+   struct kvm_para_state *state = kvm_para_state();
+
+   if (state->mode != PARAVIRT_LAZY_MMU) {
+   kvm_mmu_op(buffer, len);
+   return;
+   }
+   if (state->mmu_queue_len + len > sizeof state->mmu_queue)
+   mmu_queue_flush(state);
+   memcpy(state->mmu_queue + state->mmu_queue_len, buffer, len);
+   state->mmu_queue_len += len;
+}
+
 static void kvm_mmu_write(void *dest, u64 val)
 {
struct kvm_mmu_op_write_pte wpte = {
@@ -55,7 +93,7 @@ static void kvm_mmu_write(void *dest, u64 val)
.pte_val = val,
};
 
-   kvm_mmu_op(&wpte, sizeof wpte);
+   kvm_deferred_mmu_op(&wpte, sizeof wpte);
 }
 
 /*
@@ -122,7 +160,7 @@ static void kvm_flush_tlb(void)
.header.op = KVM_MMU_OP_FLUSH_TLB,
};
 
-   kvm_mmu_op(&ftlb, sizeof ftlb);
+   kvm_deferred_mmu_op(&ftlb, sizeof ftlb);
 }
 
 static void kvm_release_pt(u32 pfn)
@@ -135,6 +173,23 @@ static void kvm_release_pt(u32 pfn)
kvm_mmu_op(&rpt, sizeof rpt);
 }
 
+static void kvm_enter_lazy_mmu(void)
+{
+   struct kvm_para_state *state = kvm_para_state();
+
+   paravirt_enter_lazy_mmu();
+   state->mode = paravirt_get_lazy_mode();
+}
+
+static void kvm_leave_lazy_mmu(void)
+{
+   struct kvm_para_state *state = kvm_para_state();
+
+   mmu_queue_flush(state);
+   paravirt_leave_lazy(paravirt_get_lazy_mode());
+   state->mode = paravirt_get_lazy_mode();
+}
+
 static void paravirt_ops_setup(void)
 {
pv_info.name = "KVM";
@@ -160,6 +215,9 @@ static void paravirt_ops_setup(void)
pv_mmu_ops.flush_tlb_user = kvm_flush_tlb;
pv_mmu_ops.release_pt = kvm_release_pt;
pv_mmu_ops.release_pd = kvm_release_pt;
+
+   pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu;
+   pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu;
}
 }
 
-- 
1.5.4.2


-
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse012070mrt/direct/01/
___
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel


Re: [kvm-devel] [PATCH 6/8] x86: KVM guest: hypercall batching

2008-03-05 Thread Zhao Forrest
Hi Avi,

After reading the patch, I think the hypercall batching mechanism is as follows:
1 defer the MMU-related operations and buffer them in
kvm_para_state->mmu_queue[]
2 during the flush period, kvm_mmu_op() is called to flush operations
in kvm_para_state->mmu_queue[]
3 kvm_mmu_op() generate a hypercall for each operation in
kvm_para_state->mmu_queue[]; thus trigger a context switch from guest
mode to kernel mode for each operation.

My question is: Is it possible to only generate a single
hypercall(thus a single context switch) for all buffered MMU
operations in kvm_para_state->mmu_queue[]? This way we could further
reduce overhead, am I right?
BTW. I don't have a deep understanding of KVM. So this is just a
question out of my curiosity.

Thanks,
Forrest

On 3/3/08, Avi Kivity <[EMAIL PROTECTED]> wrote:
> From: Marcelo Tosatti <[EMAIL PROTECTED]>
>
> Batch pte updates and tlb flushes in lazy MMU mode.
>
> v1->v2:
> - report individual hypercall error code, have multicall return number of
> processed entries.
> - cover entire multicall duration with slots_lock instead of
> acquiring/reacquiring.
>
> v2->v3:
> - change to one ioctl per paravirt feature
>
> v3->v4:
> - adjust to mmu_op
> - helper for getting para_state without debug warnings
>
> Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]>
> Signed-off-by: Avi Kivity <[EMAIL PROTECTED]>
> ---
> arch/x86/kernel/kvm.c | 62
> +++-
> 1 files changed, 60 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> index e28d818..8405984 100644
> --- a/arch/x86/kernel/kvm.c
> +++ b/arch/x86/kernel/kvm.c
> @@ -25,6 +25,22 @@
> #include 
> #include 
> #include 
> +#include 
> +
> +#define MMU_QUEUE_SIZE 1024
> +
> +struct kvm_para_state {
> + u8 mmu_queue[MMU_QUEUE_SIZE];
> + int mmu_queue_len;
> + enum paravirt_lazy_mode mode;
> +};
> +
> +static DEFINE_PER_CPU(struct kvm_para_state, para_state);
> +
> +static struct kvm_para_state *kvm_para_state(void)
> +{
> + return &per_cpu(para_state, raw_smp_processor_id());
> +}
>
> /*
> * No need for any "IO delay" on KVM
> @@ -47,6 +63,28 @@ static void kvm_mmu_op(void *buffer, unsigned len)
> } while (len);
> }
>
> +static void mmu_queue_flush(struct kvm_para_state *state)
> +{
> + if (state->mmu_queue_len) {
> + kvm_mmu_op(state->mmu_queue, state->mmu_queue_len);
> + state->mmu_queue_len = 0;
> + }
> +}
> +
> +static void kvm_deferred_mmu_op(void *buffer, int len)
> +{
> + struct kvm_para_state *state = kvm_para_state();
> +
> + if (state->mode != PARAVIRT_LAZY_MMU) {
> + kvm_mmu_op(buffer, len);
> + return;
> + }
> + if (state->mmu_queue_len + len > sizeof state->mmu_queue)
> + mmu_queue_flush(state);
> + memcpy(state->mmu_queue + state->mmu_queue_len, buffer, len);
> + state->mmu_queue_len += len;
> +}
> +
> static void kvm_mmu_write(void *dest, u64 val)
> {
> struct kvm_mmu_op_write_pte wpte = {
> @@ -55,7 +93,7 @@ static void kvm_mmu_write(void *dest, u64 val)
> .pte_val = val,
> };
>
> - kvm_mmu_op(&wpte, sizeof wpte);
> + kvm_deferred_mmu_op(&wpte, sizeof wpte);
> }
>
> /*
> @@ -122,7 +160,7 @@ static void kvm_flush_tlb(void)
> .header.op = KVM_MMU_OP_FLUSH_TLB,
> };
>
> - kvm_mmu_op(&ftlb, sizeof ftlb);
> + kvm_deferred_mmu_op(&ftlb, sizeof ftlb);
> }
>
> static void kvm_release_pt(u32 pfn)
> @@ -135,6 +173,23 @@ static void kvm_release_pt(u32 pfn)
> kvm_mmu_op(&rpt, sizeof rpt);
> }
>
> +static void kvm_enter_lazy_mmu(void)
> +{
> + struct kvm_para_state *state = kvm_para_state();
> +
> + paravirt_enter_lazy_mmu();
> + state->mode = paravirt_get_lazy_mode();
> +}
> +
> +static void kvm_leave_lazy_mmu(void)
> +{
> + struct kvm_para_state *state = kvm_para_state();
> +
> + mmu_queue_flush(state);
> + paravirt_leave_lazy(paravirt_get_lazy_mode());
> + state->mode = paravirt_get_lazy_mode();
> +}
> +
> static void paravirt_ops_setup(void)
> {
> pv_info.name = "KVM";
> @@ -160,6 +215,9 @@ static void paravirt_ops_setup(void)
> pv_mmu_ops.flush_tlb_user = kvm_flush_tlb;
> pv_mmu_ops.release_pt = kvm_release_pt;
> pv_mmu_ops.release_pd = kvm_release_pt;
> +
> + pv_mmu_ops.lazy_mode.enter = kvm_enter_lazy_mmu;
> + pv_mmu_ops.lazy_mode.leave = kvm_leave_lazy_mmu;
> }
> }
>
> --
> 1.5.4.2
>
>
> -
> This SF.net email is sponsored by: Microsoft
> Defy all challenges. Microsoft(R) Visual Studio 2008.
> http://clk.atdmt.com/MRT/go/vse012070mrt/direct/01/
> ___
> kvm-devel mailing list
> kvm-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/kvm-devel
>

-
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse012070mrt/direct/01/
___

Re: [kvm-devel] [PATCH 6/8] x86: KVM guest: hypercall batching

2008-03-05 Thread Avi Kivity
Zhao Forrest wrote:
> Hi Avi,
>
> After reading the patch, I think the hypercall batching mechanism is as 
> follows:
> 1 defer the MMU-related operations and buffer them in
> kvm_para_state->mmu_queue[]
> 2 during the flush period, kvm_mmu_op() is called to flush operations
> in kvm_para_state->mmu_queue[]
> 3 kvm_mmu_op() generate a hypercall for each operation in
> kvm_para_state->mmu_queue[]; thus trigger a context switch from guest
> mode to kernel mode for each operation.
>
> My question is: Is it possible to only generate a single
> hypercall(thus a single context switch) for all buffered MMU
> operations in kvm_para_state->mmu_queue[]? This way we could further
> reduce overhead, am I right?
> BTW. I don't have a deep understanding of KVM. So this is just a
> question out of my curiosity.
>
>   

mmu_queue_flush() is called once per batch, so we only have one 
hypercall per batch (at least if the data doesn't exceed 512 bytes).

-- 
Do not meddle in the internals of kernels, for they are subtle and quick to 
panic.


-
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse012070mrt/direct/01/
___
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel