2018-06-29 10:18:15

by Wanpeng Li

[permalink] [raw]
Subject: [PATCH 0/2] KVM: x86: Add PV IPIs support

Using hypercall to send IPIs by one vmexit instead of one by one for
xAPIC/x2APIC physical mode and one vmexit per-cluster for x2APIC cluster
mode.

Even if enable qemu interrupt remapping and PV TLB Shootdown, I can still
observe ~14% performance boost by ebizzy benchmark for 64 vCPUs VM, the
total msr-induced vmexits reduce ~70%.

The patchset implements the PV IPIs for vCPUs <= 64 VM, this is really
common in cloud environment, after this patchset is applied, I can continue
to add > 64 vCPUs VM support and that implementation has to introduce more
complex logic.

Cc: Paolo Bonzini <[email protected]>
Cc: Radim Krčmář <[email protected]>
Cc: Vitaly Kuznetsov <[email protected]>

Wanpeng Li (2):
KVM: X86: Implement PV IPI in linux guest
KVM: X86: Implement PV send IPI support

Documentation/virtual/kvm/cpuid.txt | 4 +++
arch/x86/include/uapi/asm/kvm_para.h | 1 +
arch/x86/kernel/kvm.c | 63 ++++++++++++++++++++++++++++++++++++
arch/x86/kvm/cpuid.c | 3 +-
arch/x86/kvm/x86.c | 25 ++++++++++++++
include/uapi/linux/kvm_para.h | 1 +
6 files changed, 96 insertions(+), 1 deletion(-)

--
2.7.4



2018-06-29 10:29:57

by Vitaly Kuznetsov

[permalink] [raw]
Subject: Re: [PATCH 2/2] KVM: X86: Implement PV send IPI support

Wanpeng Li <[email protected]> writes:

> From: Wanpeng Li <[email protected]>
>
> Using hypercall to send IPIs by one vmexit instead of one by one for
> xAPIC/x2APIC physical mode and one vmexit per-cluster for x2APIC cluster
> mode.
>
> Even if enable qemu interrupt remapping and PV TLB Shootdown, I can still
> observe ~14% performance boost by ebizzy benchmark for 64 vCPUs VM, the
> total msr-induced vmexits reduce ~70%.
>
> Cc: Paolo Bonzini <[email protected]>
> Cc: Radim Krčmář <[email protected]>
> Cc: Vitaly Kuznetsov <[email protected]>
> Signed-off-by: Wanpeng Li <[email protected]>
> ---
> Documentation/virtual/kvm/cpuid.txt | 4 ++++
> arch/x86/kvm/cpuid.c | 3 ++-
> arch/x86/kvm/x86.c | 25 +++++++++++++++++++++++++
> include/uapi/linux/kvm_para.h | 1 +
> 4 files changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt
> index ab022dc..d72359f 100644
> --- a/Documentation/virtual/kvm/cpuid.txt
> +++ b/Documentation/virtual/kvm/cpuid.txt
> @@ -62,6 +62,10 @@ KVM_FEATURE_ASYNC_PF_VMEXIT || 10 || paravirtualized async PF VM exit
> || || can be enabled by setting bit 2
> || || when writing to msr 0x4b564d02
> ------------------------------------------------------------------------------
> +KVM_FEATURE_PV_SEND_IPI || 11 || guest checks this feature bit
> + || || before enabling paravirtualized
> + || || send IPIs.

In case we decide to apply this as-is we'll likely need a new feature
for PV IPI with > 64 vCPUs (or how else would the guest know if the host
is capable or not?)

> +------------------------------------------------------------------------------
> KVM_FEATURE_CLOCKSOURCE_STABLE_BIT || 24 || host will warn if no guest-side
> || || per-cpu warps are expected in
> || || kvmclock.
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 7e042e3..7bcfa61 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -621,7 +621,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
> (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) |
> (1 << KVM_FEATURE_PV_UNHALT) |
> (1 << KVM_FEATURE_PV_TLB_FLUSH) |
> - (1 << KVM_FEATURE_ASYNC_PF_VMEXIT);
> + (1 << KVM_FEATURE_ASYNC_PF_VMEXIT) |
> + (1 << KVM_FEATURE_PV_SEND_IPI);
>
> if (sched_info_on())
> entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 0046aa7..c2e6cdb 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -6689,6 +6689,27 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
> kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
> }
>
> +static void kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap, u8 vector)
> +{
> + struct kvm_apic_map *map;
> + struct kvm_vcpu *vcpu;
> + struct kvm_lapic_irq lapic_irq = {0};
> + int i;
> +
> + lapic_irq.delivery_mode = APIC_DM_FIXED;
> + lapic_irq.vector = vector;
> +
> + rcu_read_lock();
> + map = rcu_dereference(kvm->arch.apic_map);
> +
> + for_each_set_bit(i, &ipi_bitmap, sizeof(unsigned long)) {
> + vcpu = map->phys_map[i]->vcpu;
> + kvm_apic_set_irq(vcpu, &lapic_irq, NULL);
> + }
> +
> + rcu_read_unlock();
> +}
> +
> void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
> {
> vcpu->arch.apicv_active = false;
> @@ -6738,6 +6759,10 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
> ret = kvm_pv_clock_pairing(vcpu, a0, a1);
> break;
> #endif
> + case KVM_HC_SEND_IPI:
> + kvm_pv_send_ipi(vcpu->kvm, a0, a1);
> + ret = 0;
> + break;
> default:
> ret = -KVM_ENOSYS;
> break;
> diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
> index dcf629d..7395f38 100644
> --- a/include/uapi/linux/kvm_para.h
> +++ b/include/uapi/linux/kvm_para.h
> @@ -26,6 +26,7 @@
> #define KVM_HC_MIPS_EXIT_VM 7
> #define KVM_HC_MIPS_CONSOLE_OUTPUT 8
> #define KVM_HC_CLOCK_PAIRING 9
> +#define KVM_HC_SEND_IPI 10
>
> /*
> * hypercalls use architecture specific

--
Vitaly

2018-06-29 10:47:36

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 2/2] KVM: X86: Implement PV send IPI support

On 29/06/2018 11:51, Wanpeng Li wrote:
> From: Wanpeng Li <[email protected]>
>
> Using hypercall to send IPIs by one vmexit instead of one by one for
> xAPIC/x2APIC physical mode and one vmexit per-cluster for x2APIC cluster
> mode.
>
> Even if enable qemu interrupt remapping and PV TLB Shootdown, I can still
> observe ~14% performance boost by ebizzy benchmark for 64 vCPUs VM, the
> total msr-induced vmexits reduce ~70%.
>
> Cc: Paolo Bonzini <[email protected]>
> Cc: Radim Krčmář <[email protected]>
> Cc: Vitaly Kuznetsov <[email protected]>
> Signed-off-by: Wanpeng Li <[email protected]>
> ---
> Documentation/virtual/kvm/cpuid.txt | 4 ++++
> arch/x86/kvm/cpuid.c | 3 ++-
> arch/x86/kvm/x86.c | 25 +++++++++++++++++++++++++
> include/uapi/linux/kvm_para.h | 1 +
> 4 files changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt
> index ab022dc..d72359f 100644
> --- a/Documentation/virtual/kvm/cpuid.txt
> +++ b/Documentation/virtual/kvm/cpuid.txt
> @@ -62,6 +62,10 @@ KVM_FEATURE_ASYNC_PF_VMEXIT || 10 || paravirtualized async PF VM exit
> || || can be enabled by setting bit 2
> || || when writing to msr 0x4b564d02
> ------------------------------------------------------------------------------
> +KVM_FEATURE_PV_SEND_IPI || 11 || guest checks this feature bit
> + || || before enabling paravirtualized
> + || || send IPIs.

It's not "enabling" but "using". You also need to document the
hypercall itself.

Paolo

> +------------------------------------------------------------------------------
> KVM_FEATURE_CLOCKSOURCE_STABLE_BIT || 24 || host will warn if no guest-side
> || || per-cpu warps are expected in
> || || kvmclock.
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 7e042e3..7bcfa61 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -621,7 +621,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
> (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) |
> (1 << KVM_FEATURE_PV_UNHALT) |
> (1 << KVM_FEATURE_PV_TLB_FLUSH) |
> - (1 << KVM_FEATURE_ASYNC_PF_VMEXIT);
> + (1 << KVM_FEATURE_ASYNC_PF_VMEXIT) |
> + (1 << KVM_FEATURE_PV_SEND_IPI);
>
> if (sched_info_on())
> entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 0046aa7..c2e6cdb 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -6689,6 +6689,27 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
> kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
> }
>
> +static void kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap, u8 vector)
> +{
> + struct kvm_apic_map *map;
> + struct kvm_vcpu *vcpu;
> + struct kvm_lapic_irq lapic_irq = {0};
> + int i;
> +
> + lapic_irq.delivery_mode = APIC_DM_FIXED;
> + lapic_irq.vector = vector;
> +
> + rcu_read_lock();
> + map = rcu_dereference(kvm->arch.apic_map);
> +
> + for_each_set_bit(i, &ipi_bitmap, sizeof(unsigned long)) {
> + vcpu = map->phys_map[i]->vcpu;
> + kvm_apic_set_irq(vcpu, &lapic_irq, NULL);
> + }
> +
> + rcu_read_unlock();
> +}
> +
> void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
> {
> vcpu->arch.apicv_active = false;
> @@ -6738,6 +6759,10 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
> ret = kvm_pv_clock_pairing(vcpu, a0, a1);
> break;
> #endif
> + case KVM_HC_SEND_IPI:
> + kvm_pv_send_ipi(vcpu->kvm, a0, a1);
> + ret = 0;
> + break;
> default:
> ret = -KVM_ENOSYS;
> break;
> diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
> index dcf629d..7395f38 100644
> --- a/include/uapi/linux/kvm_para.h
> +++ b/include/uapi/linux/kvm_para.h
> @@ -26,6 +26,7 @@
> #define KVM_HC_MIPS_EXIT_VM 7
> #define KVM_HC_MIPS_CONSOLE_OUTPUT 8
> #define KVM_HC_CLOCK_PAIRING 9
> +#define KVM_HC_SEND_IPI 10
>
> /*
> * hypercalls use architecture specific
>


2018-06-29 10:50:03

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 2/2] KVM: X86: Implement PV send IPI support

On 29/06/2018 12:09, Vitaly Kuznetsov wrote:
>> +KVM_FEATURE_PV_SEND_IPI || 11 || guest checks this feature bit
>> + || || before enabling paravirtualized
>> + || || send IPIs.
> In case we decide to apply this as-is we'll likely need a new feature
> for PV IPI with > 64 vCPUs (or how else would the guest know if the host
> is capable or not?)
>

Yes, it makes sense. Perhaps we can do one of the following, or both:

1) add an argument for a "base vCPU id", so that you can use the
hypercall to send the IPI to CPUs 64..127, 128..191 etc.

2) have two bitmask arguments so that one hypercall handles 128 vCPUs.

to remove or limit the need for the more generic hypercall.

Paolo

2018-06-29 11:16:27

by Wanpeng Li

[permalink] [raw]
Subject: [PATCH 1/2] KVM: X86: Implement PV IPI in linux guest

From: Wanpeng Li <[email protected]>

Implement PV IPIs in guest kernel.

Cc: Paolo Bonzini <[email protected]>
Cc: Radim Krčmář <[email protected]>
Cc: Vitaly Kuznetsov <[email protected]>
Signed-off-by: Wanpeng Li <[email protected]>
---
arch/x86/include/uapi/asm/kvm_para.h | 1 +
arch/x86/kernel/kvm.c | 63 ++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+)

diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h
index 0ede697..19980ec 100644
--- a/arch/x86/include/uapi/asm/kvm_para.h
+++ b/arch/x86/include/uapi/asm/kvm_para.h
@@ -28,6 +28,7 @@
#define KVM_FEATURE_PV_UNHALT 7
#define KVM_FEATURE_PV_TLB_FLUSH 9
#define KVM_FEATURE_ASYNC_PF_VMEXIT 10
+#define KVM_FEATURE_PV_SEND_IPI 11

#define KVM_HINTS_REALTIME 0

diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 5b2300b..b4f8dc3 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -454,6 +454,57 @@ static void __init sev_map_percpu_data(void)
}

#ifdef CONFIG_SMP
+
+static void __send_ipi_mask(const struct cpumask *mask, int vector)
+{
+ unsigned long flags, ipi_bitmap = 0;
+ int cpu;
+
+ local_irq_save(flags);
+
+ for_each_cpu(cpu, mask)
+ __set_bit(per_cpu(x86_cpu_to_apicid, cpu), &ipi_bitmap);
+ kvm_hypercall2(KVM_HC_SEND_IPI, ipi_bitmap, vector);
+
+ local_irq_restore(flags);
+}
+
+static void kvm_send_ipi_mask(const struct cpumask *mask, int vector)
+{
+ __send_ipi_mask(mask, vector);
+}
+
+static void kvm_send_ipi_mask_allbutself(const struct cpumask *mask, int vector)
+{
+ unsigned int this_cpu = smp_processor_id();
+ struct cpumask new_mask;
+ const struct cpumask *local_mask;
+
+ cpumask_copy(&new_mask, mask);
+ cpumask_clear_cpu(this_cpu, &new_mask);
+ local_mask = &new_mask;
+ __send_ipi_mask(local_mask, vector);
+}
+
+static void kvm_send_ipi_allbutself(int vector)
+{
+ kvm_send_ipi_mask_allbutself(cpu_online_mask, vector);
+}
+
+static void kvm_send_ipi_all(int vector)
+{
+ __send_ipi_mask(cpu_online_mask, vector);
+}
+
+static void kvm_setup_pv_ipi(void)
+{
+ apic->send_IPI_mask = kvm_send_ipi_mask;
+ apic->send_IPI_mask_allbutself = kvm_send_ipi_mask_allbutself;
+ apic->send_IPI_allbutself = kvm_send_ipi_allbutself;
+ apic->send_IPI_all = kvm_send_ipi_all;
+ printk("KVM setup pv IPIs\n");
+}
+
static void __init kvm_smp_prepare_cpus(unsigned int max_cpus)
{
native_smp_prepare_cpus(max_cpus);
@@ -624,12 +675,24 @@ static uint32_t __init kvm_detect(void)
return kvm_cpuid_base();
}

+static void __init kvm_apic_init(void)
+{
+ if (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI))
+ kvm_setup_pv_ipi();
+}
+
+static void __init kvm_init_platform(void)
+{
+ x86_platform.apic_post_init = kvm_apic_init;
+}
+
const __initconst struct hypervisor_x86 x86_hyper_kvm = {
.name = "KVM",
.detect = kvm_detect,
.type = X86_HYPER_KVM,
.init.guest_late_init = kvm_guest_init,
.init.x2apic_available = kvm_para_available,
+ .init.init_platform = kvm_init_platform,
};

static __init int activate_jump_labels(void)
--
2.7.4


2018-06-29 11:32:12

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 1/2] KVM: X86: Implement PV IPI in linux guest

Hi Wanpeng,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on kvm/linux-next]
[also build test ERROR on v4.18-rc2 next-20180629]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Wanpeng-Li/KVM-x86-Add-PV-IPIs-support/20180629-185314
base: https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
config: x86_64-randconfig-x003-201825 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64

All errors (new ones prefixed by >>):

arch/x86/kernel/kvm.c: In function 'kvm_apic_init':
>> arch/x86/kernel/kvm.c:681:3: error: implicit declaration of function 'kvm_setup_pv_ipi'; did you mean 'idt_setup_traps'? [-Werror=implicit-function-declaration]
kvm_setup_pv_ipi();
^~~~~~~~~~~~~~~~
idt_setup_traps
cc1: some warnings being treated as errors

vim +681 arch/x86/kernel/kvm.c

677
678 static void __init kvm_apic_init(void)
679 {
680 if (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI))
> 681 kvm_setup_pv_ipi();
682 }
683

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.37 kB)
.config.gz (31.73 kB)
Download all attachments

2018-06-29 13:10:12

by Wanpeng Li

[permalink] [raw]
Subject: [PATCH 2/2] KVM: X86: Implement PV send IPI support

From: Wanpeng Li <[email protected]>

Using hypercall to send IPIs by one vmexit instead of one by one for
xAPIC/x2APIC physical mode and one vmexit per-cluster for x2APIC cluster
mode.

Even if enable qemu interrupt remapping and PV TLB Shootdown, I can still
observe ~14% performance boost by ebizzy benchmark for 64 vCPUs VM, the
total msr-induced vmexits reduce ~70%.

Cc: Paolo Bonzini <[email protected]>
Cc: Radim Krčmář <[email protected]>
Cc: Vitaly Kuznetsov <[email protected]>
Signed-off-by: Wanpeng Li <[email protected]>
---
Documentation/virtual/kvm/cpuid.txt | 4 ++++
arch/x86/kvm/cpuid.c | 3 ++-
arch/x86/kvm/x86.c | 25 +++++++++++++++++++++++++
include/uapi/linux/kvm_para.h | 1 +
4 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt
index ab022dc..d72359f 100644
--- a/Documentation/virtual/kvm/cpuid.txt
+++ b/Documentation/virtual/kvm/cpuid.txt
@@ -62,6 +62,10 @@ KVM_FEATURE_ASYNC_PF_VMEXIT || 10 || paravirtualized async PF VM exit
|| || can be enabled by setting bit 2
|| || when writing to msr 0x4b564d02
------------------------------------------------------------------------------
+KVM_FEATURE_PV_SEND_IPI || 11 || guest checks this feature bit
+ || || before enabling paravirtualized
+ || || send IPIs.
+------------------------------------------------------------------------------
KVM_FEATURE_CLOCKSOURCE_STABLE_BIT || 24 || host will warn if no guest-side
|| || per-cpu warps are expected in
|| || kvmclock.
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 7e042e3..7bcfa61 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -621,7 +621,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
(1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) |
(1 << KVM_FEATURE_PV_UNHALT) |
(1 << KVM_FEATURE_PV_TLB_FLUSH) |
- (1 << KVM_FEATURE_ASYNC_PF_VMEXIT);
+ (1 << KVM_FEATURE_ASYNC_PF_VMEXIT) |
+ (1 << KVM_FEATURE_PV_SEND_IPI);

if (sched_info_on())
entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0046aa7..c2e6cdb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6689,6 +6689,27 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
}

+static void kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap, u8 vector)
+{
+ struct kvm_apic_map *map;
+ struct kvm_vcpu *vcpu;
+ struct kvm_lapic_irq lapic_irq = {0};
+ int i;
+
+ lapic_irq.delivery_mode = APIC_DM_FIXED;
+ lapic_irq.vector = vector;
+
+ rcu_read_lock();
+ map = rcu_dereference(kvm->arch.apic_map);
+
+ for_each_set_bit(i, &ipi_bitmap, sizeof(unsigned long)) {
+ vcpu = map->phys_map[i]->vcpu;
+ kvm_apic_set_irq(vcpu, &lapic_irq, NULL);
+ }
+
+ rcu_read_unlock();
+}
+
void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
{
vcpu->arch.apicv_active = false;
@@ -6738,6 +6759,10 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
ret = kvm_pv_clock_pairing(vcpu, a0, a1);
break;
#endif
+ case KVM_HC_SEND_IPI:
+ kvm_pv_send_ipi(vcpu->kvm, a0, a1);
+ ret = 0;
+ break;
default:
ret = -KVM_ENOSYS;
break;
diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
index dcf629d..7395f38 100644
--- a/include/uapi/linux/kvm_para.h
+++ b/include/uapi/linux/kvm_para.h
@@ -26,6 +26,7 @@
#define KVM_HC_MIPS_EXIT_VM 7
#define KVM_HC_MIPS_CONSOLE_OUTPUT 8
#define KVM_HC_CLOCK_PAIRING 9
+#define KVM_HC_SEND_IPI 10

/*
* hypercalls use architecture specific
--
2.7.4


2018-06-29 13:16:17

by Vitaly Kuznetsov

[permalink] [raw]
Subject: Re: [PATCH 1/2] KVM: X86: Implement PV IPI in linux guest

Wanpeng Li <[email protected]> writes:

> From: Wanpeng Li <[email protected]>
>
> Implement PV IPIs in guest kernel.
>
> Cc: Paolo Bonzini <[email protected]>
> Cc: Radim Krčmář <[email protected]>
> Cc: Vitaly Kuznetsov <[email protected]>
> Signed-off-by: Wanpeng Li <[email protected]>
> ---
> arch/x86/include/uapi/asm/kvm_para.h | 1 +
> arch/x86/kernel/kvm.c | 63 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 64 insertions(+)
>
> diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h
> index 0ede697..19980ec 100644
> --- a/arch/x86/include/uapi/asm/kvm_para.h
> +++ b/arch/x86/include/uapi/asm/kvm_para.h
> @@ -28,6 +28,7 @@
> #define KVM_FEATURE_PV_UNHALT 7
> #define KVM_FEATURE_PV_TLB_FLUSH 9
> #define KVM_FEATURE_ASYNC_PF_VMEXIT 10
> +#define KVM_FEATURE_PV_SEND_IPI 11
>
> #define KVM_HINTS_REALTIME 0
>
> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> index 5b2300b..b4f8dc3 100644
> --- a/arch/x86/kernel/kvm.c
> +++ b/arch/x86/kernel/kvm.c
> @@ -454,6 +454,57 @@ static void __init sev_map_percpu_data(void)
> }
>
> #ifdef CONFIG_SMP
> +
> +static void __send_ipi_mask(const struct cpumask *mask, int vector)
> +{
> + unsigned long flags, ipi_bitmap = 0;
> + int cpu;
> +
> + local_irq_save(flags);
> +
> + for_each_cpu(cpu, mask)
> + __set_bit(per_cpu(x86_cpu_to_apicid, cpu), &ipi_bitmap);

We need a protection against per_cpu(x86_cpu_to_apicid, cpu) > here.

> + kvm_hypercall2(KVM_HC_SEND_IPI, ipi_bitmap, vector);
> +
> + local_irq_restore(flags);
> +}
> +
> +static void kvm_send_ipi_mask(const struct cpumask *mask, int vector)
> +{
> + __send_ipi_mask(mask, vector);
> +}
> +
> +static void kvm_send_ipi_mask_allbutself(const struct cpumask *mask, int vector)
> +{
> + unsigned int this_cpu = smp_processor_id();
> + struct cpumask new_mask;
> + const struct cpumask *local_mask;
> +
> + cpumask_copy(&new_mask, mask);
> + cpumask_clear_cpu(this_cpu, &new_mask);
> + local_mask = &new_mask;
> + __send_ipi_mask(local_mask, vector);
> +}
> +
> +static void kvm_send_ipi_allbutself(int vector)
> +{
> + kvm_send_ipi_mask_allbutself(cpu_online_mask, vector);
> +}
> +
> +static void kvm_send_ipi_all(int vector)
> +{
> + __send_ipi_mask(cpu_online_mask, vector);
> +}
> +
> +static void kvm_setup_pv_ipi(void)
> +{
> + apic->send_IPI_mask = kvm_send_ipi_mask;
> + apic->send_IPI_mask_allbutself = kvm_send_ipi_mask_allbutself;
> + apic->send_IPI_allbutself = kvm_send_ipi_allbutself;
> + apic->send_IPI_all = kvm_send_ipi_all;
> + printk("KVM setup pv IPIs\n");
> +}
> +
> static void __init kvm_smp_prepare_cpus(unsigned int max_cpus)
> {
> native_smp_prepare_cpus(max_cpus);
> @@ -624,12 +675,24 @@ static uint32_t __init kvm_detect(void)
> return kvm_cpuid_base();
> }
>
> +static void __init kvm_apic_init(void)
> +{
> + if (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI))
> + kvm_setup_pv_ipi();
> +}
> +
> +static void __init kvm_init_platform(void)
> +{
> + x86_platform.apic_post_init = kvm_apic_init;
> +}
> +
> const __initconst struct hypervisor_x86 x86_hyper_kvm = {
> .name = "KVM",
> .detect = kvm_detect,
> .type = X86_HYPER_KVM,
> .init.guest_late_init = kvm_guest_init,
> .init.x2apic_available = kvm_para_available,
> + .init.init_platform = kvm_init_platform,
> };
>
> static __init int activate_jump_labels(void)

--
Vitaly

2018-06-29 15:59:43

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH 1/2] KVM: X86: Implement PV IPI in linux guest

Hi Wanpeng,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on kvm/linux-next]
[also build test ERROR on v4.18-rc2 next-20180629]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Wanpeng-Li/KVM-x86-Add-PV-IPIs-support/20180629-185314
base: https://git.kernel.org/pub/scm/virt/kvm/kvm.git linux-next
config: i386-randconfig-a0-201825 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
# save the attached .config to linux build tree
make ARCH=i386

All errors (new ones prefixed by >>):

arch/x86//kernel/kvm.c: In function 'kvm_apic_init':
>> arch/x86//kernel/kvm.c:681:3: error: implicit declaration of function 'kvm_setup_pv_ipi' [-Werror=implicit-function-declaration]
kvm_setup_pv_ipi();
^
cc1: some warnings being treated as errors

vim +/kvm_setup_pv_ipi +681 arch/x86//kernel/kvm.c

677
678 static void __init kvm_apic_init(void)
679 {
680 if (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI))
> 681 kvm_setup_pv_ipi();
682 }
683

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation


Attachments:
(No filename) (1.31 kB)
.config.gz (27.02 kB)
Download all attachments

2018-06-30 10:06:26

by Wanpeng Li

[permalink] [raw]
Subject: Re: [PATCH 1/2] KVM: X86: Implement PV IPI in linux guest

On Fri, 29 Jun 2018 at 18:10, Vitaly Kuznetsov <[email protected]> wrote:
>
> Wanpeng Li <[email protected]> writes:
>
> > From: Wanpeng Li <[email protected]>
> >
> > Implement PV IPIs in guest kernel.
> >
> > Cc: Paolo Bonzini <[email protected]>
> > Cc: Radim Krčmář <[email protected]>
> > Cc: Vitaly Kuznetsov <[email protected]>
> > Signed-off-by: Wanpeng Li <[email protected]>
> > ---
> > arch/x86/include/uapi/asm/kvm_para.h | 1 +
> > arch/x86/kernel/kvm.c | 63 ++++++++++++++++++++++++++++++++++++
> > 2 files changed, 64 insertions(+)
> >
> > diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h
> > index 0ede697..19980ec 100644
> > --- a/arch/x86/include/uapi/asm/kvm_para.h
> > +++ b/arch/x86/include/uapi/asm/kvm_para.h
> > @@ -28,6 +28,7 @@
> > #define KVM_FEATURE_PV_UNHALT 7
> > #define KVM_FEATURE_PV_TLB_FLUSH 9
> > #define KVM_FEATURE_ASYNC_PF_VMEXIT 10
> > +#define KVM_FEATURE_PV_SEND_IPI 11
> >
> > #define KVM_HINTS_REALTIME 0
> >
> > diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> > index 5b2300b..b4f8dc3 100644
> > --- a/arch/x86/kernel/kvm.c
> > +++ b/arch/x86/kernel/kvm.c
> > @@ -454,6 +454,57 @@ static void __init sev_map_percpu_data(void)
> > }
> >
> > #ifdef CONFIG_SMP
> > +
> > +static void __send_ipi_mask(const struct cpumask *mask, int vector)
> > +{
> > + unsigned long flags, ipi_bitmap = 0;
> > + int cpu;
> > +
> > + local_irq_save(flags);
> > +
> > + for_each_cpu(cpu, mask)
> > + __set_bit(per_cpu(x86_cpu_to_apicid, cpu), &ipi_bitmap);
>
> We need a protection against per_cpu(x86_cpu_to_apicid, cpu) > here.

Will do in v2.

Regards,
Wanpeng Li

2018-06-30 10:09:08

by Wanpeng Li

[permalink] [raw]
Subject: Re: [PATCH 2/2] KVM: X86: Implement PV send IPI support

On Fri, 29 Jun 2018 at 18:49, Paolo Bonzini <[email protected]> wrote:
>
> On 29/06/2018 12:09, Vitaly Kuznetsov wrote:
> >> +KVM_FEATURE_PV_SEND_IPI || 11 || guest checks this feature bit
> >> + || || before enabling paravirtualized
> >> + || || send IPIs.
> > In case we decide to apply this as-is we'll likely need a new feature
> > for PV IPI with > 64 vCPUs (or how else would the guest know if the host
> > is capable or not?)
> >
>
> Yes, it makes sense. Perhaps we can do one of the following, or both:
>
> 1) add an argument for a "base vCPU id", so that you can use the
> hypercall to send the IPI to CPUs 64..127, 128..191 etc.
>
> 2) have two bitmask arguments so that one hypercall handles 128 vCPUs.
>
> to remove or limit the need for the more generic hypercall.

Have already done 2) in v2, will send out later.

Regards,
Wanpeng Li

2018-06-30 10:33:39

by Wanpeng Li

[permalink] [raw]
Subject: Re: [PATCH 2/2] KVM: X86: Implement PV send IPI support

On Fri, 29 Jun 2018 at 18:45, Paolo Bonzini <[email protected]> wrote:
>
> On 29/06/2018 11:51, Wanpeng Li wrote:
> > From: Wanpeng Li <[email protected]>
> >
> > Using hypercall to send IPIs by one vmexit instead of one by one for
> > xAPIC/x2APIC physical mode and one vmexit per-cluster for x2APIC cluster
> > mode.
> >
> > Even if enable qemu interrupt remapping and PV TLB Shootdown, I can still
> > observe ~14% performance boost by ebizzy benchmark for 64 vCPUs VM, the
> > total msr-induced vmexits reduce ~70%.
> >
> > Cc: Paolo Bonzini <[email protected]>
> > Cc: Radim Krčmář <[email protected]>
> > Cc: Vitaly Kuznetsov <[email protected]>
> > Signed-off-by: Wanpeng Li <[email protected]>
> > ---
> > Documentation/virtual/kvm/cpuid.txt | 4 ++++
> > arch/x86/kvm/cpuid.c | 3 ++-
> > arch/x86/kvm/x86.c | 25 +++++++++++++++++++++++++
> > include/uapi/linux/kvm_para.h | 1 +
> > 4 files changed, 32 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/virtual/kvm/cpuid.txt b/Documentation/virtual/kvm/cpuid.txt
> > index ab022dc..d72359f 100644
> > --- a/Documentation/virtual/kvm/cpuid.txt
> > +++ b/Documentation/virtual/kvm/cpuid.txt
> > @@ -62,6 +62,10 @@ KVM_FEATURE_ASYNC_PF_VMEXIT || 10 || paravirtualized async PF VM exit
> > || || can be enabled by setting bit 2
> > || || when writing to msr 0x4b564d02
> > ------------------------------------------------------------------------------
> > +KVM_FEATURE_PV_SEND_IPI || 11 || guest checks this feature bit
> > + || || before enabling paravirtualized
> > + || || send IPIs.
>
> It's not "enabling" but "using". You also need to document the
> hypercall itself.

Will fix it in v2.

Regards,
Wanpeng Li