virtualization.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] KVM paravirt_ops backend (v3)
@ 2007-06-21  3:04 Anthony Liguori
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
  0 siblings, 1 reply; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21  3:04 UTC (permalink / raw)
  To: kvm-devel; +Cc: virtualization

Hi,

This is an update to the paravirt_ops KVM backend series.  I've made a 
number of changes and attempted to incorporate all the feedback from the 
last review.  Some highlights:

1) Clean up the paravirt time source patch to use a more Xen-like model
2) Change the hypercall queueing to pass a PA on the flush hypercall
3) Add MMU support for release_{pt,pd} and TLB flush
4) Use KVM specific errno values
5) Switch from per_cpu to more appropriate functions

As for performance, I've got a few interesting results.  kbuild with a 
guest using 2G of memory goes from 19 minutes to 12 minutes with the 
full series applied.  Using 512mb, the build time goes from 10.75 
minutes to 9 minutes.  For 512mb, native is around 7 minutes so that's 
pretty close to what Avi had seen.  The more dramatic improvement with 
large memory guests is probably because of the increased shadow page 
table activity due to high mem.

virtbench shows major improvements but I'm not 100% confident yet in the 
results as they are not very stable.  I don't yet have a benchmark that 
shows the benefit of the CR caching so if I don't find one, I'll drop 
that from the queue.

As usual, the latest bits are available at 
http://hg.codemonkey.ws/kvm-paravirt

Regards,

Anthony Liguori

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/5] KVM paravirt_ops core infrastructure
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
@ 2007-06-21  3:05   ` Anthony Liguori
  2007-06-21  3:06   ` [PATCH 2/5] KVM: paravirt time source Anthony Liguori
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21  3:05 UTC (permalink / raw)
  To: kvm-devel; +Cc: virtualization

[-- Attachment #1: Type: text/plain, Size: 26 bytes --]

Regards,

Anthony Liguori

[-- Attachment #2: kvm-paravirt-core.diff --]
[-- Type: text/x-patch, Size: 14418 bytes --]

Subject: [PATCH] KVM paravirt_ops core infrastructure
Author: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

This patch implements paravirt_ops support for KVM and updates the current
paravirtualization support in KVM to match.  Some changes to the previous
paravirtualization support in KVM:

  1) Theoritical support for SMP guests
  2) Use CPUID to discover paravirtualization
  3) Use feature bitmap instead of versioning

Signed-off-by: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 8770a5d..97ad1e1 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -231,6 +231,13 @@ config VMI
 	  at the moment), by linking the kernel to a GPL-ed ROM module
 	  provided by the hypervisor.
 
+config KVM_GUEST
+	bool "KVM paravirt-ops support"
+	depends on PARAVIRT
+	help
+	  This option enables various optimizations for running under the KVM
+          hypervisor.
+
 config ACPI_SRAT
 	bool
 	default y
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 06da59f..12a4201 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
 obj-$(CONFIG_K8_NB)		+= k8.o
 
 obj-$(CONFIG_VMI)		+= vmi.o vmiclock.o
+obj-$(CONFIG_KVM_GUEST)		+= kvm.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt.o
 obj-y				+= pcspeaker.o
 
diff --git a/arch/i386/kernel/kvm.c b/arch/i386/kernel/kvm.c
new file mode 100644
index 0000000..04d564e
--- /dev/null
+++ b/arch/i386/kernel/kvm.c
@@ -0,0 +1,222 @@
+/*
+ * KVM paravirt_ops implementation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) 2007, Red Hat, Inc., Ingo Molnar <mingo-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
+ * Copyright IBM Corporation, 2007
+ *   Authors: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kvm_para.h>
+#include <linux/cpu.h>
+#include <linux/mm.h>
+
+struct kvm_paravirt_state
+{
+	struct kvm_vmca *vmca;
+	struct kvm_hypercall_entry *queue;
+	void (*hypercall)(void);
+
+	u64 vmca_gpa;
+};
+
+static DEFINE_PER_CPU(struct kvm_paravirt_state *, paravirt_state);
+
+static int do_nop_io_delay;
+static u64 msr_set_vmca;
+
+static long kvm_hypercall(unsigned int nr, unsigned long p1,
+			  unsigned long p2, unsigned long p3,
+			  unsigned long p4)
+{
+	struct kvm_paravirt_state *state
+		= per_cpu(paravirt_state, smp_processor_id());
+	long ret;
+
+	asm volatile("call *(%6) \n\t"
+		     : "=a"(ret)
+		     : "a" (nr),
+		     "b" (p1),
+		     "c" (p2),
+		     "d" (p3),
+		     "S" (p4),
+		     "r" (&state->hypercall)
+		     : "memory", "cc"
+		     );
+
+	return ret;
+}
+
+/*
+ * No need for any "IO delay" on KVM
+ */
+static void kvm_io_delay(void)
+{
+}
+
+static void paravirt_ops_setup(void)
+{
+	paravirt_ops.name = "KVM";
+
+	if (do_nop_io_delay)
+		paravirt_ops.io_delay = kvm_io_delay;
+
+	paravirt_ops.paravirt_enabled = 1;
+
+	/*
+	 * We call apply_paravirt again even though it's already been called
+	 * for native.
+	 */
+	apply_paravirt(__parainstructions, __parainstructions_end);
+}
+
+static void paravirt_activate(void *unused)
+{
+	struct kvm_paravirt_state *state
+		= per_cpu(paravirt_state, raw_smp_processor_id());
+	wrmsrl(msr_set_vmca, state->vmca_gpa);
+}
+
+static int paravirt_initialize(void)
+{
+	unsigned int eax, ebx, ecx, edx;
+	char signature[13];
+
+	/* verify that we're running on KVM */
+	cpuid(CPUID_HYPE_IDENT, &eax, &ebx, &ecx, &edx);
+	memcpy(signature, &ebx, 4);
+	memcpy(signature + 4, &ecx, 4);
+	memcpy(signature + 8, &edx, 4);
+	signature[12] = 0;
+
+	if (strcmp(signature, "KVMKVMKVMKVM"))
+		return -EINVAL;
+
+	/* check what features are supported */
+	cpuid(CPUID_HYPE_KVM_FEATURES, &eax, &ebx, &ecx, &edx);
+	msr_set_vmca = eax;
+
+	/* no paravirtualization is supported */
+	if (!(edx & KVM_FEATURE_VMCA))
+		return -ENOSYS;
+
+	if ((edx & KVM_FEATURE_NOP_IO_DELAY))
+		do_nop_io_delay = 1;
+
+	on_each_cpu(paravirt_activate, NULL, 0, 1);
+
+	return 0;
+}
+
+static __init void paravirt_free_state(struct kvm_paravirt_state *state)
+{
+	if (!state)
+		return;
+
+	if (state->hypercall)
+		__free_page(pfn_to_page(__pa(state->hypercall) >> PAGE_SHIFT));
+
+	if (state->vmca)
+		__free_page(pfn_to_page(__pa(state->vmca) >> PAGE_SHIFT));
+
+	__free_page(pfn_to_page(__pa(state) >> PAGE_SHIFT));
+}
+
+static __init struct kvm_paravirt_state *paravirt_alloc_state(void)
+{
+	struct kvm_paravirt_state *state;
+
+	state = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!state)
+		goto err;
+
+	state->vmca = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!state->vmca)
+		goto err;
+
+	/* FIXME: what do I need for this to be executable on 64 bit? */
+	state->hypercall = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!state->hypercall)
+		goto err;
+
+	state->vmca_gpa = __pa(state->vmca);
+	state->vmca->hypercall_gpa = __pa(state->hypercall);
+
+	return state;
+
+ err:
+	paravirt_free_state(state);
+	return NULL;
+}
+
+/* FIXME: hotplug hooks whenever KVM supports CPU hotplug */
+
+static __init void paravirt_free_area(void)
+{
+	int cpu;
+
+	for_each_online_cpu(cpu) {
+		struct kvm_paravirt_state *state;
+		state = per_cpu(paravirt_state, cpu);
+		paravirt_free_state(state);
+	}
+}
+
+static __init int paravirt_alloc_area(void)
+{
+	int cpu;
+
+	for_each_online_cpu(cpu) {
+		struct kvm_paravirt_state *state;
+
+		state = paravirt_alloc_state();
+		if (!state)
+			goto err;
+
+		per_cpu(paravirt_state, cpu) = state;
+	}
+
+	return 0;
+
+ err:
+	paravirt_free_area();
+	return -ENOMEM;
+}
+
+static int __init kvm_guest_init(void)
+{
+	int rc;
+
+	rc = paravirt_alloc_area();
+	if (rc)
+		return rc;
+
+	rc = paravirt_initialize();
+	if (rc)
+		goto err;
+
+	paravirt_ops_setup();
+
+	return rc;
+
+ err:
+	paravirt_free_area();
+	return rc;
+}
+
+core_initcall(kvm_guest_init);
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 633c2ed..1369310 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -43,6 +43,7 @@
 #include <linux/sched.h>
 #include <linux/cpumask.h>
 #include <linux/smp.h>
+#include <linux/kvm_para.h>
 
 #include "x86_emulate.h"
 #include "segment_descriptor.h"
@@ -91,6 +92,11 @@ struct vfsmount *kvmfs_mnt;
 #define CR8_RESEVED_BITS (~0x0fULL)
 #define EFER_RESERVED_BITS 0xfffffffffffff2fe
 
+#define KVM_PARAVIRT_FEATURES \
+	(KVM_FEATURE_VMCA | KVM_FEATURE_NOP_IO_DELAY)
+
+#define KVM_MSR_SET_VMCA	0x87655678
+
 #ifdef CONFIG_X86_64
 // LDT or TSS descriptor in the GDT. 16 bytes.
 struct segment_descriptor_64 {
@@ -1340,12 +1346,19 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_halt);
 
+static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr,
+			      unsigned long p1, unsigned long p2,
+			      unsigned long p3, unsigned long p4)
+{
+	return -KVM_ENOSYS;
+}
+
 int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
 	unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
 
 	kvm_arch_ops->cache_regs(vcpu);
-	ret = -KVM_EINVAL;
+
 #ifdef CONFIG_X86_64
 	if (is_long_mode(vcpu)) {
 		nr = vcpu->regs[VCPU_REGS_RAX];
@@ -1358,16 +1371,17 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	} else
 #endif
 	{
-		nr = vcpu->regs[VCPU_REGS_RBX] & -1u;
-		a0 = vcpu->regs[VCPU_REGS_RAX] & -1u;
+		nr = vcpu->regs[VCPU_REGS_RAX] & -1u;
+		a0 = vcpu->regs[VCPU_REGS_RBX] & -1u;
 		a1 = vcpu->regs[VCPU_REGS_RCX] & -1u;
 		a2 = vcpu->regs[VCPU_REGS_RDX] & -1u;
 		a3 = vcpu->regs[VCPU_REGS_RSI] & -1u;
 		a4 = vcpu->regs[VCPU_REGS_RDI] & -1u;
 		a5 = vcpu->regs[VCPU_REGS_RBP] & -1u;
 	}
-	switch (nr) {
-	default:
+
+	ret = dispatch_hypercall(vcpu, nr, a0, a1, a2, a3);
+	if (ret == -KVM_ENOSYS) {
 		run->hypercall.args[0] = a0;
 		run->hypercall.args[1] = a1;
 		run->hypercall.args[2] = a2;
@@ -1456,7 +1470,7 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val,
  */
 static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
 {
-	struct kvm_vcpu_para_state *para_state;
+	struct kvm_vmca *para_state;
 	hpa_t para_state_hpa, hypercall_hpa;
 	struct page *para_state_page;
 	unsigned char *hypercall;
@@ -1476,30 +1490,14 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
 	if (is_error_hpa(para_state_hpa))
 		goto err_gp;
 
-	mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT);
 	para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT);
 	para_state = kmap_atomic(para_state_page, KM_USER0);
 
-	printk(KERN_DEBUG "....  guest version: %d\n", para_state->guest_version);
-	printk(KERN_DEBUG "....           size: %d\n", para_state->size);
-
-	para_state->host_version = KVM_PARA_API_VERSION;
-	/*
-	 * We cannot support guests that try to register themselves
-	 * with a newer API version than the host supports:
-	 */
-	if (para_state->guest_version > KVM_PARA_API_VERSION) {
-		para_state->ret = -KVM_EINVAL;
-		goto err_kunmap_skip;
-	}
-
 	hypercall_gpa = para_state->hypercall_gpa;
 	hypercall_hpa = gpa_to_hpa(vcpu, hypercall_gpa);
 	printk(KERN_DEBUG ".... hypercall_hpa: %08Lx\n", hypercall_hpa);
-	if (is_error_hpa(hypercall_hpa)) {
-		para_state->ret = -KVM_EINVAL;
+	if (is_error_hpa(hypercall_hpa))
 		goto err_kunmap_skip;
-	}
 
 	printk(KERN_DEBUG "kvm: para guest successfully registered.\n");
 	vcpu->para_state_page = para_state_page;
@@ -1512,7 +1510,6 @@ static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa)
 	kvm_arch_ops->patch_hypercall(vcpu, hypercall);
 	kunmap_atomic(hypercall, KM_USER1);
 
-	para_state->ret = 0;
 err_kunmap_skip:
 	kunmap_atomic(para_state, KM_USER0);
 	return 0;
@@ -1633,12 +1630,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 	case MSR_IA32_MISC_ENABLE:
 		vcpu->ia32_misc_enable_msr = data;
 		break;
-	/*
-	 * This is the 'probe whether the host is KVM' logic:
-	 */
-	case MSR_KVM_API_MAGIC:
-		return vcpu_register_para(vcpu, data);
-
+	case KVM_MSR_SET_VMCA:
+		vcpu_register_para(vcpu, data);
+		break;
 	default:
 		printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr);
 		return 1;
@@ -1693,6 +1687,20 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
 
 	kvm_arch_ops->cache_regs(vcpu);
 	function = vcpu->regs[VCPU_REGS_RAX];
+
+	if (function == CPUID_HYPE_IDENT) {
+		vcpu->regs[VCPU_REGS_RAX] = 0;
+		/* KVMKVMKVMKVM */
+		vcpu->regs[VCPU_REGS_RBX] = 0x4b4d564b;
+		vcpu->regs[VCPU_REGS_RCX] = 0x564b4d56;
+		vcpu->regs[VCPU_REGS_RDX] = 0x4d564b4d;
+		goto out;
+	} else if (function == CPUID_HYPE_KVM_FEATURES) {
+		vcpu->regs[VCPU_REGS_RAX] = KVM_MSR_SET_VMCA;
+		vcpu->regs[VCPU_REGS_RDX] = KVM_PARAVIRT_FEATURES;
+		goto out;
+	}
+
 	vcpu->regs[VCPU_REGS_RAX] = 0;
 	vcpu->regs[VCPU_REGS_RBX] = 0;
 	vcpu->regs[VCPU_REGS_RCX] = 0;
@@ -1717,6 +1725,7 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
 		vcpu->regs[VCPU_REGS_RCX] = best->ecx;
 		vcpu->regs[VCPU_REGS_RDX] = best->edx;
 	}
+ out:
 	kvm_arch_ops->decache_regs(vcpu);
 	kvm_arch_ops->skip_emulated_instruction(vcpu);
 }
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index 3b29256..11ebad8 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -1,6 +1,8 @@
 #ifndef __LINUX_KVM_PARA_H
 #define __LINUX_KVM_PARA_H
 
+#include <linux/errno.h>
+
 /*
  * Guest OS interface for KVM paravirtualization
  *
@@ -8,66 +10,28 @@
  *       as we make progress.
  */
 
-/*
- * Per-VCPU descriptor area shared between guest and host. Writable to
- * both guest and host. Registered with the host by the guest when
- * a guest acknowledges paravirtual mode.
- *
- * NOTE: all addresses are guest-physical addresses (gpa), to make it
- * easier for the hypervisor to map between the various addresses.
- */
-struct kvm_vcpu_para_state {
-	/*
-	 * API version information for compatibility. If there's any support
-	 * mismatch (too old host trying to execute too new guest) then
-	 * the host will deny entry into paravirtual mode. Any other
-	 * combination (new host + old guest and new host + new guest)
-	 * is supposed to work - new host versions will support all old
-	 * guest API versions.
-	 */
-	u32 guest_version;
-	u32 host_version;
-	u32 size;
-	u32 ret;
-
-	/*
-	 * The address of the vm exit instruction (VMCALL or VMMCALL),
-	 * which the host will patch according to the CPU model the
-	 * VM runs on:
-	 */
-	u64 hypercall_gpa;
-
-} __attribute__ ((aligned(PAGE_SIZE)));
+#define CPUID_HYPE_IDENT		0x40000000
+#define CPUID_HYPE_KVM_FEATURES		0x40000001
 
-#define KVM_PARA_API_VERSION 1
+#define KVM_FEATURE_VMCA		(1UL << 0)
+#define KVM_FEATURE_NOP_IO_DELAY	(1UL << 1)
 
-/*
- * This is used for an RDMSR's ECX parameter to probe for a KVM host.
- * Hopefully no CPU vendor will use up this number. This is placed well
- * out of way of the typical space occupied by CPU vendors' MSR indices,
- * and we think (or at least hope) it wont be occupied in the future
- * either.
- */
-#define MSR_KVM_API_MAGIC 0x87655678
-
-#define KVM_EINVAL 1
+struct kvm_vmca
+{
+	u64 hypercall_gpa;
+};
 
 /*
  * Hypercall calling convention:
  *
- * Each hypercall may have 0-6 parameters.
+ * Each hypercall may have 0-4 parameters.
  *
- * 64-bit hypercall index is in RAX, goes from 0 to __NR_hypercalls-1
- *
- * 64-bit parameters 1-6 are in the standard gcc x86_64 calling convention
- * order: RDI, RSI, RDX, RCX, R8, R9.
- *
- * 32-bit index is EBX, parameters are: EAX, ECX, EDX, ESI, EDI, EBP.
- * (the first 3 are according to the gcc regparm calling convention)
+ * 32-bit index is EAX, parameters are: EBX, ECX, EDX, ESI.
  *
  * No registers are clobbered by the hypercall, except that the
  * return value is in RAX.
  */
-#define __NR_hypercalls			0
+
+#define KVM_ENOSYS	ENOSYS
 
 #endif

[-- Attachment #3: Type: text/plain, Size: 286 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/5] KVM: paravirt time source
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
  2007-06-21  3:05   ` [PATCH 1/5] KVM paravirt_ops core infrastructure Anthony Liguori
@ 2007-06-21  3:06   ` Anthony Liguori
  2007-06-21  3:07   ` [PATCH 3/5] KVM: Implement CR read caching for KVM paravirt_ops Anthony Liguori
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21  3:06 UTC (permalink / raw)
  To: kvm-devel; +Cc: virtualization

[-- Attachment #1: Type: text/plain, Size: 134 bytes --]

This helps a lot on modern kernels where Linux is much more finicky 
about using the TSC as a time source.

Regards,

Anthony Liguori

[-- Attachment #2: kvm-paravirt-time.diff --]
[-- Type: text/x-patch, Size: 4435 bytes --]

Subject: [PATCH] KVM: paravirt time source
Author: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

This patch implements a paravirtual time source based on a new field added to
the VMCA.  The host provides time in nanoseconds to the guest.

Signed-off-by: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/arch/i386/kernel/kvm.c b/arch/i386/kernel/kvm.c
index 22ea647..62c3b5b 100644
--- a/arch/i386/kernel/kvm.c
+++ b/arch/i386/kernel/kvm.c
@@ -26,6 +26,18 @@
 #include <linux/cpu.h>
 #include <linux/mm.h>
 
+#include <linux/clocksource.h>
+#include <linux/workqueue.h>
+#include <linux/cpufreq.h>
+#include <linux/jiffies.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/acpi_pmtmr.h>
+
+#include "mach_timer.h"
+
+#define KVM_SCALE 22
+
 struct kvm_paravirt_state
 {
 	struct kvm_vmca *vmca;
@@ -38,6 +50,7 @@ struct kvm_paravirt_state
 static DEFINE_PER_CPU(struct kvm_paravirt_state *, paravirt_state);
 
 static int do_nop_io_delay;
+static int do_paravirt_clock;
 static u64 msr_set_vmca;
 
 static long kvm_hypercall(unsigned int nr, unsigned long p1,
@@ -62,6 +75,28 @@ static long kvm_hypercall(unsigned int nr, unsigned long p1,
 	return ret;
 }
 
+static cycle_t kvm_clocksource_read(void)
+{
+	struct kvm_paravirt_state *state = get_cpu_var(paravirt_state);
+	cycle_t ret;
+
+	kvm_hypercall(KVM_HYPERCALL_UPDATE_TIME, 0, 0, 0, 0);
+	ret = state->vmca->real_nsecs;
+	put_cpu_var(paravirt_state);
+
+	return ret;
+}
+
+static struct clocksource clocksource_kvm = {
+	.name			= "kvm",
+	.rating			= 200,
+	.read			= kvm_clocksource_read,
+	.mask			= CLOCKSOURCE_MASK(64),
+	.mult			= 1 << KVM_SCALE,
+	.shift			= KVM_SCALE,
+	.flags			= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
 /*
  * No need for any "IO delay" on KVM
  */
@@ -76,6 +111,14 @@ static void paravirt_ops_setup(void)
 	if (do_nop_io_delay)
 		paravirt_ops.io_delay = kvm_io_delay;
 
+	if (do_paravirt_clock) {
+		int err;
+
+		err = clocksource_register(&clocksource_kvm);
+		WARN_ON(err);
+		printk(KERN_INFO "KVM: using paravirt clock source\n");
+	}
+
 	paravirt_ops.paravirt_enabled = 1;
 
 	apply_paravirt(__parainstructions, __parainstructions_end);
@@ -114,6 +157,9 @@ static int paravirt_initialize(void)
 	if ((edx & KVM_FEATURE_NOP_IO_DELAY))
 		do_nop_io_delay = 1;
 
+	if ((edx & KVM_FEATURE_PARAVIRT_CLOCK))
+		do_paravirt_clock = 1;
+
 	on_each_cpu(paravirt_activate, NULL, 0, 1);
 
 	return 0;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 1369310..e455fca 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -44,6 +44,7 @@
 #include <linux/cpumask.h>
 #include <linux/smp.h>
 #include <linux/kvm_para.h>
+#include <linux/delay.h>
 
 #include "x86_emulate.h"
 #include "segment_descriptor.h"
@@ -93,7 +94,8 @@ struct vfsmount *kvmfs_mnt;
 #define EFER_RESERVED_BITS 0xfffffffffffff2fe
 
 #define KVM_PARAVIRT_FEATURES \
-	(KVM_FEATURE_VMCA | KVM_FEATURE_NOP_IO_DELAY)
+	(KVM_FEATURE_VMCA | KVM_FEATURE_NOP_IO_DELAY | \
+	 KVM_FEATURE_PARAVIRT_CLOCK)
 
 #define KVM_MSR_SET_VMCA	0x87655678
 
@@ -1346,10 +1348,34 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_halt);
 
+static int kvm_hypercall_update_time(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vmca *vmca;
+	struct timespec now;
+
+	if (unlikely(!vcpu->para_state_page))
+		return -KVM_EINVAL;
+
+	ktime_get_ts(&now);
+
+	vmca = kmap(vcpu->para_state_page);
+
+	vmca->real_nsecs = now.tv_nsec + now.tv_sec * (cycles_t)1e9;
+
+	mark_page_dirty(vcpu->kvm, vcpu->para_state_gpa >> PAGE_SHIFT);
+	kunmap(vcpu->para_state_page);
+
+	return 0;
+}
+
 static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr,
 			      unsigned long p1, unsigned long p2,
 			      unsigned long p3, unsigned long p4)
 {
+	switch (nr) {
+	case KVM_HYPERCALL_UPDATE_TIME:
+		return kvm_hypercall_update_time(vcpu);
+	}
 	return -KVM_ENOSYS;
 }
 
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index 11ebad8..4f27fb1 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -15,10 +15,12 @@
 
 #define KVM_FEATURE_VMCA		(1UL << 0)
 #define KVM_FEATURE_NOP_IO_DELAY	(1UL << 1)
+#define KVM_FEATURE_PARAVIRT_CLOCK	(1UL << 2)
 
 struct kvm_vmca
 {
 	u64 hypercall_gpa;
+	u64 real_nsecs;
 };
 
 /*
@@ -33,5 +35,8 @@ struct kvm_vmca
  */
 
 #define KVM_ENOSYS	ENOSYS
+#define KVM_EINVAL	EINVAL
+
+#define KVM_HYPERCALL_UPDATE_TIME	0
 
 #endif

[-- Attachment #3: Type: text/plain, Size: 286 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/5] KVM: Implement CR read caching for KVM paravirt_ops
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
  2007-06-21  3:05   ` [PATCH 1/5] KVM paravirt_ops core infrastructure Anthony Liguori
  2007-06-21  3:06   ` [PATCH 2/5] KVM: paravirt time source Anthony Liguori
@ 2007-06-21  3:07   ` Anthony Liguori
  2007-06-21  3:08   ` [PATCH 4/5] KVM: Add paravirt MMU write support Anthony Liguori
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21  3:07 UTC (permalink / raw)
  To: kvm-devel; +Cc: virtualization

[-- Attachment #1: Type: text/plain, Size: 26 bytes --]

Regards,

Anthony Liguori

[-- Attachment #2: kvm-cr-caching.diff --]
[-- Type: text/x-patch, Size: 4532 bytes --]

Subject: [PATCH] KVM: Implement CR read caching for KVM paravirt_ops
Author: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

With hardware virtualization, CR reads often times require a VMEXIT which is
rather expensive.  Instead of reading CR and taking the VMEXIT, maintain a
copy of each CR and return that on CR reads.

Signed-off-by: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/arch/i386/kernel/kvm.c b/arch/i386/kernel/kvm.c
index 62c3b5b..dcc45cd 100644
--- a/arch/i386/kernel/kvm.c
+++ b/arch/i386/kernel/kvm.c
@@ -38,8 +38,13 @@
 
 #define KVM_SCALE 22
 
+#define CR0_TS_MASK (1ULL << 3)
+
 struct kvm_paravirt_state
 {
+	unsigned long cached_cr[5];
+	int cr_valid[5];
+
 	struct kvm_vmca *vmca;
 	struct kvm_hypercall_entry *queue;
 	void (*hypercall)(void);
@@ -49,6 +54,7 @@ struct kvm_paravirt_state
 
 static DEFINE_PER_CPU(struct kvm_paravirt_state *, paravirt_state);
 
+static int do_cr_read_caching;
 static int do_nop_io_delay;
 static int do_paravirt_clock;
 static u64 msr_set_vmca;
@@ -104,6 +110,93 @@ static void kvm_io_delay(void)
 {
 }
 
+/*
+ * Control register reads can be trapped.  Since trapping is relatively
+ * expensive, we can avoid paying the cost by caching logically.
+ */
+static __always_inline unsigned long kvm_read_cr(int reg)
+{
+	struct kvm_paravirt_state *state = x86_read_percpu(paravirt_state);
+
+	if (unlikely(!state->cr_valid[reg])) {
+		switch (reg) {
+		case 0:
+			state->cached_cr[reg] = native_read_cr0();
+			break;
+		case 3:
+			state->cached_cr[reg] = native_read_cr3();
+			break;
+		case 4:
+			state->cached_cr[reg] = native_read_cr4();
+			break;
+		default:
+			BUG();
+		}
+		state->cr_valid[reg] = 1;
+	}
+	return state->cached_cr[reg];
+}
+
+static __always_inline void kvm_write_cr(int reg, unsigned long value)
+{
+	struct kvm_paravirt_state *state = x86_read_percpu(paravirt_state);
+
+	state->cr_valid[reg] = 1;
+	state->cached_cr[reg] = value;
+
+	switch (reg) {
+	case 0:
+		native_write_cr0(value);
+		break;
+	case 3:
+		native_write_cr3(value);
+		break;
+	case 4:
+		native_write_cr4(value);
+		break;
+	default:
+		BUG();
+	}
+}
+
+static unsigned long kvm_read_cr0(void)
+{
+	return kvm_read_cr(0);
+}
+
+static void kvm_write_cr0(unsigned long value)
+{
+	kvm_write_cr(0, value);
+}
+
+/*
+ * We trap clts to ensure that our cached cr0 remains consistent.
+ */
+static void kvm_clts(void)
+{
+	write_cr0(read_cr0() & ~CR0_TS_MASK);
+}
+
+static unsigned long kvm_read_cr3(void)
+{
+	return kvm_read_cr(3);
+}
+
+static void kvm_write_cr3(unsigned long value)
+{
+	kvm_write_cr(3, value);
+}
+
+static unsigned long kvm_read_cr4(void)
+{
+	return kvm_read_cr(4);
+}
+
+static void kvm_write_cr4(unsigned long value)
+{
+	kvm_write_cr(4, value);
+}
+
 static void paravirt_ops_setup(void)
 {
 	paravirt_ops.name = "KVM";
@@ -119,6 +212,19 @@ static void paravirt_ops_setup(void)
 		printk(KERN_INFO "KVM: using paravirt clock source\n");
 	}
 
+	if (do_cr_read_caching) {
+		paravirt_ops.clts = kvm_clts;
+		paravirt_ops.read_cr0 = kvm_read_cr0;
+		paravirt_ops.write_cr0 = kvm_write_cr0;
+		paravirt_ops.read_cr3 = kvm_read_cr3;
+		paravirt_ops.write_cr3 = kvm_write_cr3;
+		paravirt_ops.read_cr4 = kvm_read_cr4;
+		paravirt_ops.write_cr4 = kvm_write_cr4;
+
+		/* CR4 always exists in a KVM guest */
+		paravirt_ops.read_cr4_safe = kvm_read_cr4;
+	}
+
 	paravirt_ops.paravirt_enabled = 1;
 
 	apply_paravirt(__parainstructions, __parainstructions_end);
@@ -160,6 +266,9 @@ static int paravirt_initialize(void)
 	if ((edx & KVM_FEATURE_PARAVIRT_CLOCK))
 		do_paravirt_clock = 1;
 
+	if ((edx & KVM_FEATURE_CR_READ_CACHE))
+		do_cr_read_caching = 1;
+
 	on_each_cpu(paravirt_activate, NULL, 0, 1);
 
 	return 0;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index e455fca..35d73b8 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -95,7 +95,7 @@ struct vfsmount *kvmfs_mnt;
 
 #define KVM_PARAVIRT_FEATURES \
 	(KVM_FEATURE_VMCA | KVM_FEATURE_NOP_IO_DELAY | \
-	 KVM_FEATURE_PARAVIRT_CLOCK)
+	 KVM_FEATURE_PARAVIRT_CLOCK | KVM_FEATURE_CR_READ_CACHE)
 
 #define KVM_MSR_SET_VMCA	0x87655678
 
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index 4f27fb1..be185da 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -16,6 +16,7 @@
 #define KVM_FEATURE_VMCA		(1UL << 0)
 #define KVM_FEATURE_NOP_IO_DELAY	(1UL << 1)
 #define KVM_FEATURE_PARAVIRT_CLOCK	(1UL << 2)
+#define KVM_FEATURE_CR_READ_CACHE	(1UL << 3)
 
 struct kvm_vmca
 {

[-- Attachment #3: Type: text/plain, Size: 286 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 4/5] KVM: Add paravirt MMU write support
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
                     ` (2 preceding siblings ...)
  2007-06-21  3:07   ` [PATCH 3/5] KVM: Implement CR read caching for KVM paravirt_ops Anthony Liguori
@ 2007-06-21  3:08   ` Anthony Liguori
  2007-06-21  3:09   ` [PATCH 5/5] KVM: Add hypercall queue for paravirt_ops implementation Anthony Liguori
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21  3:08 UTC (permalink / raw)
  To: kvm-devel; +Cc: virtualization

[-- Attachment #1: Type: text/plain, Size: 26 bytes --]

Regards,

Anthony Liguori

[-- Attachment #2: kvm-mmu-write.diff --]
[-- Type: text/x-patch, Size: 7990 bytes --]

Subject: [PATCH] KVM: Add paravirt MMU write support
Author: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

On at least AMD hardware, hypercall based manipulation of page table memory
is significantly faster than taking a page fault.  Additionally, using
hypercalls to manipulation page table memory provides the infrastructure needed
to do lazy MMU updates.

Signed-off-by: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/arch/i386/kernel/kvm.c b/arch/i386/kernel/kvm.c
index bf77159..21133e4 100644
--- a/arch/i386/kernel/kvm.c
+++ b/arch/i386/kernel/kvm.c
@@ -25,6 +25,7 @@
 #include <linux/kvm_para.h>
 #include <linux/cpu.h>
 #include <linux/mm.h>
+#include <asm/tlbflush.h>
 
 #include <linux/clocksource.h>
 #include <linux/workqueue.h>
@@ -54,6 +55,7 @@ struct kvm_paravirt_state
 
 static DEFINE_PER_CPU(struct kvm_paravirt_state *, paravirt_state);
 
+static int do_mmu_write;
 static int do_cr_read_caching;
 static int do_nop_io_delay;
 static int do_paravirt_clock;
@@ -197,6 +199,84 @@ static void kvm_write_cr4(unsigned long value)
 	kvm_write_cr(4, value);
 }
 
+static void kvm_mmu_write(void *dest, const void *src, size_t size)
+{
+	const uint8_t *p = src;
+	u32 a1 = 0;
+
+	size >>= 2;
+	if (size == 2)
+		a1 = *(u32 *)&p[4];
+
+	kvm_hypercall(KVM_HYPERCALL_MMU_WRITE, (u32)dest, size, *(u32 *)p, a1);
+}
+
+/*
+ * We only need to hook operations that are MMU writes.  We hook these so that
+ * we can use lazy MMU mode to batch these operations.  We could probably
+ * improve the performance of the host code if we used some of the information
+ * here to simplify processing of batched writes.
+ */
+static void kvm_set_pte(pte_t *ptep, pte_t pte)
+{
+	kvm_mmu_write(ptep, &pte, sizeof(pte));
+}
+
+static void kvm_set_pte_at(struct mm_struct *mm, unsigned long addr,
+			   pte_t *ptep, pte_t pte)
+{
+	kvm_mmu_write(ptep, &pte, sizeof(pte));
+}
+
+static void kvm_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+	kvm_mmu_write(ptep, &pte, sizeof(pte));
+}
+
+static void kvm_set_pte_present(struct mm_struct *mm, unsigned long addr,
+				pte_t *ptep, pte_t pte)
+{
+	kvm_mmu_write(ptep, &pte, sizeof(pte));
+}
+
+static void kvm_pte_clear(struct mm_struct *mm,
+			  unsigned long addr, pte_t *ptep)
+{
+	pte_t pte = __pte(0);
+	kvm_mmu_write(ptep, &pte, sizeof(pte));
+}
+
+static void kvm_set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+	kvm_mmu_write(pmdp, &pmd, sizeof(pmd));
+}
+
+static void kvm_set_pud(pud_t *pudp, pud_t pud)
+{
+	kvm_mmu_write(pudp, &pud, sizeof(pud));
+}
+
+static void kvm_pmd_clear(pmd_t *pmdp)
+{
+	pmd_t pmd = __pmd(0);
+	kvm_mmu_write(pmdp, &pmd, sizeof(pmd));
+}
+
+static void kvm_flush_tlb(void)
+{
+	kvm_hypercall(KVM_HYPERCALL_FLUSH_TLB, 0, 0, 0, 0);
+}
+
+static void kvm_flush_tlb_single(unsigned long addr)
+{
+	kvm_hypercall(KVM_HYPERCALL_FLUSH_TLB_SINGLE, addr, 0, 0, 0);
+}
+
+static void kvm_release_pt(u32 pfn)
+{
+	kvm_hypercall(KVM_HYPERCALL_RELEASE_PT, pfn << PAGE_SHIFT, 0, 0, 0);
+}
+
 static void paravirt_ops_setup(void)
 {
 	paravirt_ops.name = "KVM";
@@ -225,6 +305,21 @@ static void paravirt_ops_setup(void)
 		paravirt_ops.read_cr4_safe = kvm_read_cr4;
 	}
 
+	if (do_mmu_write) {
+		paravirt_ops.set_pte = kvm_set_pte;
+		paravirt_ops.set_pte_at = kvm_set_pte_at;
+		paravirt_ops.set_pte_atomic = kvm_set_pte_atomic;
+		paravirt_ops.set_pte_present = kvm_set_pte_present;
+		paravirt_ops.pte_clear = kvm_pte_clear;
+		paravirt_ops.set_pmd = kvm_set_pmd;
+		paravirt_ops.pmd_clear = kvm_pmd_clear;
+		paravirt_ops.set_pud = kvm_set_pud;
+		paravirt_ops.flush_tlb_user = kvm_flush_tlb;
+		paravirt_ops.flush_tlb_single = kvm_flush_tlb_single;
+		paravirt_ops.release_pt = kvm_release_pt;
+		paravirt_ops.release_pd = kvm_release_pt;
+	}
+
 	paravirt_ops.paravirt_enabled = 1;
 }
 
@@ -267,6 +362,9 @@ static int paravirt_initialize(void)
 	if ((edx & KVM_FEATURE_CR_READ_CACHE))
 		do_cr_read_caching = 1;
 
+	if ((edx & KVM_FEATURE_MMU_WRITE))
+		do_mmu_write = 1;
+
 	on_each_cpu(paravirt_activate, NULL, 0, 1);
 
 	return 0;
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index b08272b..9a7462a 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -538,6 +538,7 @@ void kvm_resched(struct kvm_vcpu *vcpu);
 void kvm_load_guest_fpu(struct kvm_vcpu *vcpu);
 void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
 void kvm_flush_remote_tlbs(struct kvm *kvm);
+void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn);
 
 int kvm_read_guest(struct kvm_vcpu *vcpu,
 	       gva_t addr,
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 35d73b8..91aec56 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -95,7 +95,8 @@ struct vfsmount *kvmfs_mnt;
 
 #define KVM_PARAVIRT_FEATURES \
 	(KVM_FEATURE_VMCA | KVM_FEATURE_NOP_IO_DELAY | \
-	 KVM_FEATURE_PARAVIRT_CLOCK | KVM_FEATURE_CR_READ_CACHE)
+	 KVM_FEATURE_PARAVIRT_CLOCK | KVM_FEATURE_CR_READ_CACHE | \
+	 KVM_FEATURE_MMU_WRITE)
 
 #define KVM_MSR_SET_VMCA	0x87655678
 
@@ -1348,6 +1349,28 @@ int kvm_emulate_halt(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_emulate_halt);
 
+static int kvm_hypercall_mmu_write(struct kvm_vcpu *vcpu, gva_t addr,
+				   unsigned long size, unsigned long a0,
+				   unsigned long a1)
+{
+	gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+	u64 value;
+
+	if (gpa == UNMAPPED_GVA)
+		return -KVM_EFAULT;
+	if (size == 1) {
+		if (!emulator_write_phys(vcpu, gpa, &a0, sizeof(a0)))
+			return -KVM_EFAULT;
+	} else if (size == 2) {
+		value = (u64)a1 << 32 | a0;
+		if (!emulator_write_phys(vcpu, gpa, &value, sizeof(value)))
+			return -KVM_EFAULT;
+	} else
+		return -KVM_E2BIG;
+
+	return 0;
+}
+
 static int kvm_hypercall_update_time(struct kvm_vcpu *vcpu)
 {
 	struct kvm_vmca *vmca;
@@ -1368,13 +1391,40 @@ static int kvm_hypercall_update_time(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+static int kvm_hypercall_flush_tlb(struct kvm_vcpu *vcpu)
+{
+	kvm_arch_ops->tlb_flush(vcpu);
+	return 0;
+}
+
+static int kvm_hypercall_flush_tlb_single(struct kvm_vcpu *vcpu, gva_t addr)
+{
+	if (kvm_arch_ops->invlpg)
+		kvm_arch_ops->invlpg(vcpu, addr);
+	return 0;
+}
+
+static int kvm_hypercall_release_pt(struct kvm_vcpu *vcpu, gpa_t addr)
+{
+	mmu_unshadow(vcpu, addr >> PAGE_SHIFT);
+	return 0;
+}
+
 static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr,
 			      unsigned long p1, unsigned long p2,
 			      unsigned long p3, unsigned long p4)
 {
 	switch (nr) {
+	case KVM_HYPERCALL_MMU_WRITE:
+		return kvm_hypercall_mmu_write(vcpu, p1, p2, p3, p4);
 	case KVM_HYPERCALL_UPDATE_TIME:
 		return kvm_hypercall_update_time(vcpu);
+	case KVM_HYPERCALL_FLUSH_TLB:
+		return kvm_hypercall_flush_tlb(vcpu);
+	case KVM_HYPERCALL_FLUSH_TLB_SINGLE:
+		return kvm_hypercall_flush_tlb_single(vcpu, p1);
+	case KVM_HYPERCALL_RELEASE_PT:
+		return kvm_hypercall_release_pt(vcpu, p1);
 	}
 	return -KVM_ENOSYS;
 }
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index ad50cfd..1581286 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -728,7 +728,7 @@ static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
 	return r;
 }
 
-static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
+void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
 {
 	struct kvm_mmu_page *page;
 
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index d4aa7e8..560de6a 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -26,6 +26,7 @@ static int __init kvm_guest_init(void)
 #define KVM_FEATURE_NOP_IO_DELAY	(1UL << 1)
 #define KVM_FEATURE_PARAVIRT_CLOCK	(1UL << 2)
 #define KVM_FEATURE_CR_READ_CACHE	(1UL << 3)
+#define KVM_FEATURE_MMU_WRITE		(1UL << 4)
 
 struct kvm_vmca
 {
@@ -46,7 +47,13 @@ struct kvm_vmca
 
 #define KVM_ENOSYS	ENOSYS
 #define KVM_EINVAL	EINVAL
+#define KVM_EFAULT	EFAULT
+#define KVM_E2BIG	E2BIG
 
 #define KVM_HYPERCALL_UPDATE_TIME	0
+#define KVM_HYPERCALL_MMU_WRITE		1
+#define KVM_HYPERCALL_FLUSH_TLB		2
+#define KVM_HYPERCALL_FLUSH_TLB_SINGLE	3
+#define KVM_HYPERCALL_RELEASE_PT	4
 
 #endif

[-- Attachment #3: Type: text/plain, Size: 286 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 5/5] KVM: Add hypercall queue for paravirt_ops implementation
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
                     ` (3 preceding siblings ...)
  2007-06-21  3:08   ` [PATCH 4/5] KVM: Add paravirt MMU write support Anthony Liguori
@ 2007-06-21  3:09   ` Anthony Liguori
  2007-06-21  3:16   ` [PATCH 0/5] KVM paravirt_ops backend (v3) Anthony Liguori
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21  3:09 UTC (permalink / raw)
  To: kvm-devel; +Cc: virtualization

[-- Attachment #1: Type: text/plain, Size: 27 bytes --]

Regards,

Anthony Liguori


[-- Attachment #2: kvm-hypercall-queue.diff --]
[-- Type: text/x-patch, Size: 10160 bytes --]

Subject: [PATCH] KVM: Add hypercall queue for paravirt_ops implementation
Author: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

Implemented a hypercall queue that can be used when paravirt_ops lazy mode
is enabled.  This patch enables queueing of MMU write operations and CR
updates.  This results in about a 50% bump in kernbench performance.

Signed-off-by: Anthony Liguori <aliguori-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org>

diff --git a/arch/i386/kernel/kvm.c b/arch/i386/kernel/kvm.c
index 21133e4..52eb50d 100644
--- a/arch/i386/kernel/kvm.c
+++ b/arch/i386/kernel/kvm.c
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/dmi.h>
 #include <linux/acpi_pmtmr.h>
+#include <linux/hardirq.h>
 
 #include "mach_timer.h"
 
@@ -46,8 +47,12 @@ struct kvm_paravirt_state
 	unsigned long cached_cr[5];
 	int cr_valid[5];
 
-	struct kvm_vmca *vmca;
+	enum paravirt_lazy_mode mode;
 	struct kvm_hypercall_entry *queue;
+	int queue_index;
+	int max_queue_index;
+
+	struct kvm_vmca *vmca;
 	void (*hypercall)(void);
 
 	u64 vmca_gpa;
@@ -55,18 +60,18 @@ struct kvm_paravirt_state
 
 static DEFINE_PER_CPU(struct kvm_paravirt_state *, paravirt_state);
 
+static int do_hypercall_batching;
 static int do_mmu_write;
 static int do_cr_read_caching;
 static int do_nop_io_delay;
 static int do_paravirt_clock;
 static u64 msr_set_vmca;
 
-static long kvm_hypercall(unsigned int nr, unsigned long p1,
-			  unsigned long p2, unsigned long p3,
-			  unsigned long p4)
+static long _kvm_hypercall(struct kvm_paravirt_state *state,
+			   unsigned int nr, unsigned long p1,
+			   unsigned long p2, unsigned long p3,
+			   unsigned long p4)
 {
-	struct kvm_paravirt_state *state
-		= per_cpu(paravirt_state, smp_processor_id());
 	long ret;
 
 	asm volatile("call *(%6) \n\t"
@@ -83,6 +88,69 @@ static long kvm_hypercall(unsigned int nr, unsigned long p1,
 	return ret;
 }
 
+static int can_defer_hypercall(struct kvm_paravirt_state *state,
+			       unsigned int nr)
+{
+	if (state->mode == PARAVIRT_LAZY_MMU) {
+		switch (nr) {
+		case KVM_HYPERCALL_MMU_WRITE:
+		case KVM_HYPERCALL_FLUSH_TLB:
+		case KVM_HYPERCALL_FLUSH_TLB_SINGLE:
+			return 1;
+		}
+	} else if (state->mode == PARAVIRT_LAZY_CPU) {
+		if (nr == KVM_HYPERCALL_SET_CR)
+			return 1;
+	}
+
+	return 0;
+}
+
+static void hypercall_queue_flush(struct kvm_paravirt_state *state)
+{
+	if (state->queue_index) {
+		_kvm_hypercall(state, KVM_HYPERCALL_FLUSH, __pa(state->queue),
+			       state->queue_index, 0, 0);
+		state->queue_index = 0;
+	}
+}
+
+static void _kvm_hypercall_defer(struct kvm_paravirt_state *state,
+				 unsigned int nr,
+				 unsigned long p1, unsigned long p2,
+				 unsigned long p3, unsigned long p4)
+{
+	struct kvm_hypercall_entry *entry;
+
+	BUG_ON(preemptible());
+
+	if (state->queue_index == state->max_queue_index)
+		hypercall_queue_flush(state);
+
+	entry = &state->queue[state->queue_index++];
+	entry->nr = nr;
+	entry->p1 = p1;
+	entry->p2 = p2;
+	entry->p3 = p3;
+	entry->p4 = p4;
+}
+
+static long kvm_hypercall(unsigned int nr, unsigned long p1,
+			  unsigned long p2, unsigned long p3,
+			  unsigned long p4)
+{
+	struct kvm_paravirt_state *state = get_cpu_var(paravirt_state);
+	long ret = 0;
+
+	if (can_defer_hypercall(state, nr))
+		_kvm_hypercall_defer(state, nr, p1, p2, p3, p4);
+	else
+		ret = _kvm_hypercall(state, nr, p1, p2, p3, p4);
+
+	put_cpu_var(paravirt_state);
+	return ret;
+}
+
 static cycle_t kvm_clocksource_read(void)
 {
 	struct kvm_paravirt_state *state = get_cpu_var(paravirt_state);
@@ -146,18 +214,22 @@ static __always_inline void kvm_write_cr(int reg, unsigned long value)
 	state->cr_valid[reg] = 1;
 	state->cached_cr[reg] = value;
 
-	switch (reg) {
-	case 0:
-		native_write_cr0(value);
-		break;
-	case 3:
-		native_write_cr3(value);
-		break;
-	case 4:
-		native_write_cr4(value);
-		break;
-	default:
-		BUG();
+	if (state->mode == PARAVIRT_LAZY_CPU)
+		kvm_hypercall(KVM_HYPERCALL_SET_CR, reg, value, 0, 0);
+	else {
+		switch (reg) {
+		case 0:
+			native_write_cr0(value);
+			break;
+		case 3:
+			native_write_cr3(value);
+			break;
+		case 4:
+			native_write_cr4(value);
+			break;
+		default:
+			BUG();
+		}
 	}
 }
 
@@ -269,7 +341,24 @@ static void kvm_flush_tlb(void)
 
 static void kvm_flush_tlb_single(unsigned long addr)
 {
-	kvm_hypercall(KVM_HYPERCALL_FLUSH_TLB_SINGLE, addr, 0, 0, 0);
+	int mode = x86_read_percpu(paravirt_state)->mode;
+
+	if (mode == PARAVIRT_LAZY_MMU)
+		kvm_hypercall(KVM_HYPERCALL_FLUSH_TLB_SINGLE, addr, 0, 0, 0);
+	else
+		__native_flush_tlb_single(addr);
+}
+
+static void kvm_set_lazy_mode(enum paravirt_lazy_mode mode)
+{
+	struct kvm_paravirt_state *state
+		= per_cpu(paravirt_state, smp_processor_id());
+
+	if (mode == PARAVIRT_LAZY_FLUSH || mode == PARAVIRT_LAZY_NONE)
+		hypercall_queue_flush(state);
+
+	if (mode != PARAVIRT_LAZY_FLUSH)
+		state->mode = mode;
 }
 
 static void kvm_release_pt(u32 pfn)
@@ -320,6 +409,9 @@ static void paravirt_ops_setup(void)
 		paravirt_ops.release_pd = kvm_release_pt;
 	}
 
+	if (do_hypercall_batching)
+		paravirt_ops.set_lazy_mode = kvm_set_lazy_mode;
+
 	paravirt_ops.paravirt_enabled = 1;
 }
 
@@ -365,6 +457,9 @@ static int paravirt_initialize(void)
 	if ((edx & KVM_FEATURE_MMU_WRITE))
 		do_mmu_write = 1;
 
+	if ((edx & KVM_FEATURE_HYPERCALL_BATCHING))
+		do_hypercall_batching = 1;
+
 	on_each_cpu(paravirt_activate, NULL, 0, 1);
 
 	return 0;
@@ -375,6 +470,9 @@ static __init void paravirt_free_state(struct kvm_paravirt_state *state)
 	if (!state)
 		return;
 
+	if (state->queue)
+		__free_page(pfn_to_page(__pa(state->queue) >> PAGE_SHIFT));
+
 	if (state->hypercall)
 		__free_page(pfn_to_page(__pa(state->hypercall) >> PAGE_SHIFT));
 
@@ -401,8 +499,15 @@ static __init struct kvm_paravirt_state *paravirt_alloc_state(void)
 	if (!state->hypercall)
 		goto err;
 
+	state->queue = (void *)get_zeroed_page(GFP_KERNEL);
+	if (!state->queue)
+		goto err;
+
 	state->vmca_gpa = __pa(state->vmca);
 	state->vmca->hypercall_gpa = __pa(state->hypercall);
+	state->queue_index = 0;
+	state->max_queue_index
+		= (PAGE_SIZE / sizeof(struct kvm_hypercall_entry));
 
 	return state;
 
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 9a7462a..7e53374 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -291,6 +291,7 @@ struct kvm_vcpu {
 	gpa_t para_state_gpa;
 	struct page *para_state_page;
 	gpa_t hypercall_gpa;
+	struct page *queue_page;
 	unsigned long cr4;
 	unsigned long cr8;
 	u64 pdptrs[4]; /* pae */
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 91aec56..e3afbde 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -96,7 +96,7 @@ struct vfsmount *kvmfs_mnt;
 #define KVM_PARAVIRT_FEATURES \
 	(KVM_FEATURE_VMCA | KVM_FEATURE_NOP_IO_DELAY | \
 	 KVM_FEATURE_PARAVIRT_CLOCK | KVM_FEATURE_CR_READ_CACHE | \
-	 KVM_FEATURE_MMU_WRITE)
+	 KVM_FEATURE_MMU_WRITE | KVM_FEATURE_HYPERCALL_BATCHING)
 
 #define KVM_MSR_SET_VMCA	0x87655678
 
@@ -1410,6 +1410,24 @@ static int kvm_hypercall_release_pt(struct kvm_vcpu *vcpu, gpa_t addr)
 	return 0;
 }
 
+static int kvm_hypercall_set_cr(struct kvm_vcpu *vcpu,
+				u32 reg, unsigned long value)
+{
+	switch (reg) {
+	case 0:
+		set_cr0(vcpu, value);
+		break;
+	case 3:
+		set_cr3(vcpu, value);
+		break;
+	case 4:
+		set_cr4(vcpu, value);
+		break;
+	}
+
+	return 0;
+}
+
 static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr,
 			      unsigned long p1, unsigned long p2,
 			      unsigned long p3, unsigned long p4)
@@ -1419,6 +1437,8 @@ static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr,
 		return kvm_hypercall_mmu_write(vcpu, p1, p2, p3, p4);
 	case KVM_HYPERCALL_UPDATE_TIME:
 		return kvm_hypercall_update_time(vcpu);
+	case KVM_HYPERCALL_SET_CR:
+		return kvm_hypercall_set_cr(vcpu, p1, p2);
 	case KVM_HYPERCALL_FLUSH_TLB:
 		return kvm_hypercall_flush_tlb(vcpu);
 	case KVM_HYPERCALL_FLUSH_TLB_SINGLE:
@@ -1429,6 +1449,39 @@ static int dispatch_hypercall(struct kvm_vcpu *vcpu, unsigned long nr,
 	return -KVM_ENOSYS;
 }
 
+static int kvm_hypercall_flush(struct kvm_vcpu *vcpu, gva_t addr, u32 nb_queue)
+{
+	struct kvm_hypercall_entry *queue;
+	struct page *queue_page;
+	hpa_t queue_hpa;
+	int ret = 0;
+	int i;
+
+	if (nb_queue > (PAGE_SIZE / sizeof(struct kvm_hypercall_entry)))
+		return -KVM_EFAULT;
+
+	queue_hpa = gpa_to_hpa(vcpu, addr);
+	if (is_error_hpa(queue_hpa))
+		return -KVM_EFAULT;
+
+	queue_page = pfn_to_page(queue_hpa >> PAGE_SHIFT);
+	queue = kmap(queue_page);
+
+	for (i = 0; i < nb_queue; i++)
+		ret |= dispatch_hypercall(vcpu, queue[i].nr, queue[i].p1,
+					  queue[i].p2, queue[i].p3,
+					  queue[i].p4);
+
+	if (ret < 0)
+		ret = -KVM_EINVAL;
+	else
+		ret = 0;
+
+	kunmap(queue_page);
+
+	return ret;
+}
+
 int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
 {
 	unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
@@ -1456,7 +1509,11 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
 		a5 = vcpu->regs[VCPU_REGS_RBP] & -1u;
 	}
 
-	ret = dispatch_hypercall(vcpu, nr, a0, a1, a2, a3);
+	if (nr == KVM_HYPERCALL_FLUSH)
+		ret = kvm_hypercall_flush(vcpu, a0, a1);
+	else
+		ret = dispatch_hypercall(vcpu, nr, a0, a1, a2, a3);
+
 	if (ret == -KVM_ENOSYS) {
 		run->hypercall.args[0] = a0;
 		run->hypercall.args[1] = a1;
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index 560de6a..e220832 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -27,6 +27,7 @@ static int __init kvm_guest_init(void)
 #define KVM_FEATURE_PARAVIRT_CLOCK	(1UL << 2)
 #define KVM_FEATURE_CR_READ_CACHE	(1UL << 3)
 #define KVM_FEATURE_MMU_WRITE		(1UL << 4)
+#define KVM_FEATURE_HYPERCALL_BATCHING	(1UL << 5)
 
 struct kvm_vmca
 {
@@ -34,6 +35,15 @@ struct kvm_vmca
 	u64 real_nsecs;
 };
 
+struct kvm_hypercall_entry
+{
+	unsigned long nr;
+	unsigned long p1;
+	unsigned long p2;
+	unsigned long p3;
+	unsigned long p4;
+};
+
 /*
  * Hypercall calling convention:
  *
@@ -55,5 +65,7 @@ struct kvm_vmca
 #define KVM_HYPERCALL_FLUSH_TLB		2
 #define KVM_HYPERCALL_FLUSH_TLB_SINGLE	3
 #define KVM_HYPERCALL_RELEASE_PT	4
+#define KVM_HYPERCALL_SET_CR		5
+#define KVM_HYPERCALL_FLUSH		6
 
 #endif

[-- Attachment #3: Type: text/plain, Size: 286 bytes --]

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

[-- Attachment #4: Type: text/plain, Size: 186 bytes --]

_______________________________________________
kvm-devel mailing list
kvm-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/kvm-devel

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/5] KVM paravirt_ops backend (v3)
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
                     ` (4 preceding siblings ...)
  2007-06-21  3:09   ` [PATCH 5/5] KVM: Add hypercall queue for paravirt_ops implementation Anthony Liguori
@ 2007-06-21  3:16   ` Anthony Liguori
  2007-06-21  9:18   ` Avi Kivity
  2007-06-21  9:26   ` Li, Xin B
  7 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21  3:16 UTC (permalink / raw)
  To: kvm-devel; +Cc: virtualization

Anthony Liguori wrote:
> As usual, the latest bits are available at 
> http://hg.codemonkey.ws/kvm-paravirt

I neglected to mention that the major missing piece right now is 
save/restore support.  Since the VMCA is set with an MSR, I think I can 
just expose this MSR to userspace and add another save/restore device in 
QEMU.  I'll need to get the real_time too to ensure that the paravirt 
clock remains monotonic.  I figure I could make this an MSR too although 
that's a bit ugly.

Regards,

Anthony Liguori

> Regards,
>
> Anthony Liguori
>


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/5] KVM paravirt_ops backend (v3)
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
                     ` (5 preceding siblings ...)
  2007-06-21  3:16   ` [PATCH 0/5] KVM paravirt_ops backend (v3) Anthony Liguori
@ 2007-06-21  9:18   ` Avi Kivity
       [not found]     ` <467A4280.9060503-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
  2007-06-21  9:26   ` Li, Xin B
  7 siblings, 1 reply; 10+ messages in thread
From: Avi Kivity @ 2007-06-21  9:18 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: kvm-devel, virtualization

Anthony Liguori wrote:
> Hi,
>
> This is an update to the paravirt_ops KVM backend series.  I've made a 
> number of changes and attempted to incorporate all the feedback from 
> the last review.  Some highlights:
>
> 1) Clean up the paravirt time source patch to use a more Xen-like model
> 2) Change the hypercall queueing to pass a PA on the flush hypercall
> 3) Add MMU support for release_{pt,pd} and TLB flush
> 4) Use KVM specific errno values
> 5) Switch from per_cpu to more appropriate functions
>
> As for performance, I've got a few interesting results.  kbuild with a 
> guest using 2G of memory goes from 19 minutes to 12 minutes with the 
> full series applied.  Using 512mb, the build time goes from 10.75 
> minutes to 9 minutes.  For 512mb, native is around 7 minutes so that's 
> pretty close to what Avi had seen.  The more dramatic improvement with 
> large memory guests is probably because of the increased shadow page 
> table activity due to high mem.

Ah, that explains why we were getting such different results.  My tests 
were on x86-64.

>
> virtbench shows major improvements but I'm not 100% confident yet in 
> the results as they are not very stable.  I don't yet have a benchmark 
> that shows the benefit of the CR caching so if I don't find one, I'll 
> drop that from the queue.
>

The only barrier to merging is that we're introducing yet another stable 
ABI.  Since we can turn off things that turn out not so good later, and 
expect the guest to survive, I'm not to worried, so I'm inclined to 
merge this.


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


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/5] KVM paravirt_ops backend (v3)
       [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
                     ` (6 preceding siblings ...)
  2007-06-21  9:18   ` Avi Kivity
@ 2007-06-21  9:26   ` Li, Xin B
  7 siblings, 0 replies; 10+ messages in thread
From: Li, Xin B @ 2007-06-21  9:26 UTC (permalink / raw)
  To: Anthony Liguori, kvm-devel; +Cc: virtualization

>As for performance, I've got a few interesting results.  kbuild with a 
>guest using 2G of memory goes from 19 minutes to 12 minutes with the 
>full series applied.  Using 512mb, the build time goes from 10.75 
>minutes to 9 minutes.  For 512mb, native is around 7 minutes so that's 
>pretty close to what Avi had seen.  The more dramatic improvement with 
>large memory guests is probably because of the increased shadow page 
>table activity due to high mem.

Exactly, physical memory above 896M on x86_32 are mapped using temp
mapping, which needs lots of invlpg instructions.
On xen, it needs to wake all the shadows to find the shadow of high mem,
since Xen doesn't use reverse map. On KVM, should be much better.
-Xin

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 0/5] KVM paravirt_ops backend (v3)
       [not found]     ` <467A4280.9060503-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
@ 2007-06-21 13:19       ` Anthony Liguori
  0 siblings, 0 replies; 10+ messages in thread
From: Anthony Liguori @ 2007-06-21 13:19 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm-devel, virtualization

Avi Kivity wrote:
> Anthony Liguori wrote:
>> Hi,
>>
>> This is an update to the paravirt_ops KVM backend series.  I've made 
>> a number of changes and attempted to incorporate all the feedback 
>> from the last review.  Some highlights:
>>
>> 1) Clean up the paravirt time source patch to use a more Xen-like model
>> 2) Change the hypercall queueing to pass a PA on the flush hypercall
>> 3) Add MMU support for release_{pt,pd} and TLB flush
>> 4) Use KVM specific errno values
>> 5) Switch from per_cpu to more appropriate functions
>>
>> As for performance, I've got a few interesting results.  kbuild with 
>> a guest using 2G of memory goes from 19 minutes to 12 minutes with 
>> the full series applied.  Using 512mb, the build time goes from 10.75 
>> minutes to 9 minutes.  For 512mb, native is around 7 minutes so 
>> that's pretty close to what Avi had seen.  The more dramatic 
>> improvement with large memory guests is probably because of the 
>> increased shadow page table activity due to high mem.
>
> Ah, that explains why we were getting such different results.  My 
> tests were on x86-64.
>
>>
>> virtbench shows major improvements but I'm not 100% confident yet in 
>> the results as they are not very stable.  I don't yet have a 
>> benchmark that shows the benefit of the CR caching so if I don't find 
>> one, I'll drop that from the queue.
>>
>
> The only barrier to merging is that we're introducing yet another 
> stable ABI.  Since we can turn off things that turn out not so good 
> later, and expect the guest to survive, I'm not to worried, so I'm 
> inclined to merge this.

Some unsigned longs are in kvm_para.h so x86_64 won't work ATM as a 
host.  I'll fix that and do proper testing on a 64 bit host for the next 
posting (along with save/restore support).

Regards,

Anthony Liguori


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2007-06-21 13:19 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-21  3:04 [PATCH 0/5] KVM paravirt_ops backend (v3) Anthony Liguori
     [not found] ` <4679EAAF.2060103-rdkfGonbjUSkNkDKm+mE6A@public.gmane.org>
2007-06-21  3:05   ` [PATCH 1/5] KVM paravirt_ops core infrastructure Anthony Liguori
2007-06-21  3:06   ` [PATCH 2/5] KVM: paravirt time source Anthony Liguori
2007-06-21  3:07   ` [PATCH 3/5] KVM: Implement CR read caching for KVM paravirt_ops Anthony Liguori
2007-06-21  3:08   ` [PATCH 4/5] KVM: Add paravirt MMU write support Anthony Liguori
2007-06-21  3:09   ` [PATCH 5/5] KVM: Add hypercall queue for paravirt_ops implementation Anthony Liguori
2007-06-21  3:16   ` [PATCH 0/5] KVM paravirt_ops backend (v3) Anthony Liguori
2007-06-21  9:18   ` Avi Kivity
     [not found]     ` <467A4280.9060503-atKUWr5tajBWk0Htik3J/w@public.gmane.org>
2007-06-21 13:19       ` Anthony Liguori
2007-06-21  9:26   ` Li, Xin B

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).