[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v5 rebased 3/4] nested vmx: optimize for bulk access of virtual VMCS



Acked-by Eddie Dong <eddie.dong@xxxxxxxxx>

> -----Original Message-----
> From: Xu, Dongxiao
> Sent: Wednesday, January 23, 2013 10:32 PM
> To: xen-devel@xxxxxxxxxxxxxxxxxxx
> Cc: Dong, Eddie; Nakajima, Jun; Zhang, Xiantao; JBeulich@xxxxxxxx
> Subject: [PATCH v5 rebased 3/4] nested vmx: optimize for bulk access of
> virtual VMCS
> 
> After we use the VMREAD/VMWRITE to build up the virtual VMCS, each
> access to the virtual VMCS needs two VMPTRLD and one VMCLEAR to
> switch the environment, which might be an overhead to performance.
> This commit tries to handle multiple virtual VMCS access together
> to improve the performance.
> 
> Signed-off-by: Dongxiao Xu <dongxiao.xu@xxxxxxxxx>
> ---
>  xen/arch/x86/hvm/vmx/vmcs.c        |   10 +++
>  xen/arch/x86/hvm/vmx/vvmx.c        |  126
> +++++++++++++++++++++++++++++++-----
>  xen/include/asm-x86/hvm/vmx/vvmx.h |    2 +
>  3 files changed, 122 insertions(+), 16 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
> index 82a8d91..f89ea93 100644
> --- a/xen/arch/x86/hvm/vmx/vmcs.c
> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
> @@ -31,6 +31,7 @@
>  #include <asm/hvm/io.h>
>  #include <asm/hvm/support.h>
>  #include <asm/hvm/vmx/vmx.h>
> +#include <asm/hvm/vmx/vvmx.h>
>  #include <asm/hvm/vmx/vmcs.h>
>  #include <asm/flushtlb.h>
>  #include <xen/event.h>
> @@ -423,6 +424,13 @@ static void vmx_load_vmcs(struct vcpu *v)
> 
>  int vmx_cpu_up_prepare(unsigned int cpu)
>  {
> +    /*
> +     * If nvmx_cpu_up_prepare() failed, do not return failure and just
> fallback
> +     * to legacy mode for vvmcs synchronization.
> +     */
> +    if ( nvmx_cpu_up_prepare(cpu) != 0 )
> +        printk("CPU%d: Could not allocate virtual VMCS buffer.\n", cpu);
> +
>      if ( per_cpu(vmxon_region, cpu) != NULL )
>          return 0;
> 
> @@ -431,6 +439,7 @@ int vmx_cpu_up_prepare(unsigned int cpu)
>          return 0;
> 
>      printk("CPU%d: Could not allocate host VMCS\n", cpu);
> +    nvmx_cpu_dead(cpu);
>      return -ENOMEM;
>  }
> 
> @@ -438,6 +447,7 @@ void vmx_cpu_dead(unsigned int cpu)
>  {
>      vmx_free_vmcs(per_cpu(vmxon_region, cpu));
>      per_cpu(vmxon_region, cpu) = NULL;
> +    nvmx_cpu_dead(cpu);
>  }
> 
>  int vmx_cpu_up(void)
> diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c
> index 8000f84..1e1ad56 100644
> --- a/xen/arch/x86/hvm/vmx/vvmx.c
> +++ b/xen/arch/x86/hvm/vmx/vvmx.c
> @@ -28,8 +28,31 @@
>  #include <asm/hvm/vmx/vvmx.h>
>  #include <asm/hvm/nestedhvm.h>
> 
> +static DEFINE_PER_CPU(u64 *, vvmcs_buf);
> +
>  static void nvmx_purge_vvmcs(struct vcpu *v);
> 
> +#define VMCS_BUF_SIZE 100
> +
> +int nvmx_cpu_up_prepare(unsigned int cpu)
> +{
> +    if ( per_cpu(vvmcs_buf, cpu) != NULL )
> +        return 0;
> +
> +    per_cpu(vvmcs_buf, cpu) = xzalloc_array(u64, VMCS_BUF_SIZE);
> +
> +    if ( per_cpu(vvmcs_buf, cpu) != NULL )
> +        return 0;
> +
> +    return -ENOMEM;
> +}
> +
> +void nvmx_cpu_dead(unsigned int cpu)
> +{
> +    xfree(per_cpu(vvmcs_buf, cpu));
> +    per_cpu(vvmcs_buf, cpu) = NULL;
> +}
> +
>  int nvmx_vcpu_initialise(struct vcpu *v)
>  {
>      struct nestedvmx *nvmx = &vcpu_2_nvmx(v);
> @@ -834,6 +857,40 @@ static void vvmcs_to_shadow(void *vvmcs, unsigned
> int field)
>      __vmwrite(field, value);
>  }
> 
> +static void vvmcs_to_shadow_bulk(struct vcpu *v, unsigned int n,
> +                                 const u16 *field)
> +{
> +    struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
> +    void *vvmcs = nvcpu->nv_vvmcx;
> +    u64 *value = this_cpu(vvmcs_buf);
> +    unsigned int i;
> +
> +    if ( !cpu_has_vmx_vmcs_shadowing )
> +        goto fallback;
> +
> +    if ( !value || n > VMCS_BUF_SIZE )
> +    {
> +        gdprintk(XENLOG_DEBUG, "vmcs sync fall back to non-bulk mode,
> \
> +                 buffer: %p, buffer size: %d, fields number: %d.\n",
> +                 value, VMCS_BUF_SIZE, n);
> +        goto fallback;
> +    }
> +
> +    virtual_vmcs_enter(vvmcs);
> +    for ( i = 0; i < n; i++ )
> +        value[i] = __vmread(field[i]);
> +    virtual_vmcs_exit(vvmcs);
> +
> +    for ( i = 0; i < n; i++ )
> +        __vmwrite(field[i], value[i]);
> +
> +    return;
> +
> +fallback:
> +    for ( i = 0; i < n; i++ )
> +        vvmcs_to_shadow(vvmcs, field[i]);
> +}
> +
>  static void shadow_to_vvmcs(void *vvmcs, unsigned int field)
>  {
>      u64 value;
> @@ -844,6 +901,40 @@ static void shadow_to_vvmcs(void *vvmcs, unsigned
> int field)
>          __set_vvmcs(vvmcs, field, value);
>  }
> 
> +static void shadow_to_vvmcs_bulk(struct vcpu *v, unsigned int n,
> +                                 const u16 *field)
> +{
> +    struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
> +    void *vvmcs = nvcpu->nv_vvmcx;
> +    u64 *value = this_cpu(vvmcs_buf);
> +    unsigned int i;
> +
> +    if ( !cpu_has_vmx_vmcs_shadowing )
> +        goto fallback;
> +
> +    if ( !value || n > VMCS_BUF_SIZE )
> +    {
> +        gdprintk(XENLOG_DEBUG, "vmcs sync fall back to non-bulk mode,
> \
> +                 buffer: %p, buffer size: %d, fields number: %d.\n",
> +                 value, VMCS_BUF_SIZE, n);
> +        goto fallback;
> +    }
> +
> +    for ( i = 0; i < n; i++ )
> +        value[i] = __vmread(field[i]);
> +
> +    virtual_vmcs_enter(vvmcs);
> +    for ( i = 0; i < n; i++ )
> +        __vmwrite(field[i], value[i]);
> +    virtual_vmcs_exit(vvmcs);
> +
> +    return;
> +
> +fallback:
> +    for ( i = 0; i < n; i++ )
> +        shadow_to_vvmcs(vvmcs, field[i]);
> +}
> +
>  static void load_shadow_control(struct vcpu *v)
>  {
>      /*
> @@ -867,13 +958,18 @@ static void load_shadow_guest_state(struct vcpu
> *v)
>  {
>      struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
>      void *vvmcs = nvcpu->nv_vvmcx;
> -    int i;
>      u32 control;
>      u64 cr_gh_mask, cr_read_shadow;
> 
> +    static const u16 vmentry_fields[] = {
> +        VM_ENTRY_INTR_INFO,
> +        VM_ENTRY_EXCEPTION_ERROR_CODE,
> +        VM_ENTRY_INSTRUCTION_LEN,
> +    };
> +
>      /* vvmcs.gstate to shadow vmcs.gstate */
> -    for ( i = 0; i < ARRAY_SIZE(vmcs_gstate_field); i++ )
> -        vvmcs_to_shadow(vvmcs, vmcs_gstate_field[i]);
> +    vvmcs_to_shadow_bulk(v, ARRAY_SIZE(vmcs_gstate_field),
> +                         vmcs_gstate_field);
> 
>      hvm_set_cr0(__get_vvmcs(vvmcs, GUEST_CR0));
>      hvm_set_cr4(__get_vvmcs(vvmcs, GUEST_CR4));
> @@ -887,9 +983,7 @@ static void load_shadow_guest_state(struct vcpu *v)
> 
>      hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
> 
> -    vvmcs_to_shadow(vvmcs, VM_ENTRY_INTR_INFO);
> -    vvmcs_to_shadow(vvmcs, VM_ENTRY_EXCEPTION_ERROR_CODE);
> -    vvmcs_to_shadow(vvmcs, VM_ENTRY_INSTRUCTION_LEN);
> +    vvmcs_to_shadow_bulk(v, ARRAY_SIZE(vmentry_fields),
> vmentry_fields);
> 
>      /*
>       * While emulate CR0 and CR4 for nested virtualization, set the
> CR0/CR4
> @@ -909,10 +1003,13 @@ static void load_shadow_guest_state(struct vcpu
> *v)
>      if ( nvmx_ept_enabled(v) && hvm_pae_enabled(v) &&
>           (v->arch.hvm_vcpu.guest_efer & EFER_LMA) )
>      {
> -        vvmcs_to_shadow(vvmcs, GUEST_PDPTR0);
> -        vvmcs_to_shadow(vvmcs, GUEST_PDPTR1);
> -        vvmcs_to_shadow(vvmcs, GUEST_PDPTR2);
> -        vvmcs_to_shadow(vvmcs, GUEST_PDPTR3);
> +        static const u16 gpdptr_fields[] = {
> +            GUEST_PDPTR0,
> +            GUEST_PDPTR1,
> +            GUEST_PDPTR2,
> +            GUEST_PDPTR3,
> +        };
> +        vvmcs_to_shadow_bulk(v, ARRAY_SIZE(gpdptr_fields),
> gpdptr_fields);
>      }
> 
>      /* TODO: CR3 target control */
> @@ -1003,13 +1100,12 @@ static void virtual_vmentry(struct cpu_user_regs
> *regs)
> 
>  static void sync_vvmcs_guest_state(struct vcpu *v, struct cpu_user_regs
> *regs)
>  {
> -    int i;
>      struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
>      void *vvmcs = nvcpu->nv_vvmcx;
> 
>      /* copy shadow vmcs.gstate back to vvmcs.gstate */
> -    for ( i = 0; i < ARRAY_SIZE(vmcs_gstate_field); i++ )
> -        shadow_to_vvmcs(vvmcs, vmcs_gstate_field[i]);
> +    shadow_to_vvmcs_bulk(v, ARRAY_SIZE(vmcs_gstate_field),
> +                         vmcs_gstate_field);
>      /* RIP, RSP are in user regs */
>      __set_vvmcs(vvmcs, GUEST_RIP, regs->eip);
>      __set_vvmcs(vvmcs, GUEST_RSP, regs->esp);
> @@ -1021,13 +1117,11 @@ static void sync_vvmcs_guest_state(struct vcpu
> *v, struct cpu_user_regs *regs)
> 
>  static void sync_vvmcs_ro(struct vcpu *v)
>  {
> -    int i;
>      struct nestedvcpu *nvcpu = &vcpu_nestedhvm(v);
>      struct nestedvmx *nvmx = &vcpu_2_nvmx(v);
>      void *vvmcs = nvcpu->nv_vvmcx;
> 
> -    for ( i = 0; i < ARRAY_SIZE(vmcs_ro_field); i++ )
> -        shadow_to_vvmcs(nvcpu->nv_vvmcx, vmcs_ro_field[i]);
> +    shadow_to_vvmcs_bulk(v, ARRAY_SIZE(vmcs_ro_field), vmcs_ro_field);
> 
>      /* Adjust exit_reason/exit_qualifciation for violation case */
>      if ( __get_vvmcs(vvmcs, VM_EXIT_REASON) ==
> EXIT_REASON_EPT_VIOLATION )
> diff --git a/xen/include/asm-x86/hvm/vmx/vvmx.h
> b/xen/include/asm-x86/hvm/vmx/vvmx.h
> index 73a67cc..3874525 100644
> --- a/xen/include/asm-x86/hvm/vmx/vvmx.h
> +++ b/xen/include/asm-x86/hvm/vmx/vvmx.h
> @@ -229,5 +229,7 @@ int nept_translate_l2ga(struct vcpu *v, paddr_t l2ga,
>                          unsigned int *page_order, uint32_t rwx_acc,
>                          unsigned long *l1gfn, uint8_t *p2m_acc,
>                          uint64_t *exit_qual, uint32_t *exit_reason);
> +int nvmx_cpu_up_prepare(unsigned int cpu);
> +void nvmx_cpu_dead(unsigned int cpu);
>  #endif /* __ASM_X86_HVM_VVMX_H__ */
> 
> --
> 1.7.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.