|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 7/8] x86/VPMU: Save/restore VPMU only when necessary
Am Dienstag 09 April 2013, 13:26:18 schrieb Boris Ostrovsky:
> VPMU doesn't need to always be saved during context switch. If we are
> comming back to the same processor and no other VPCU has run here we can
> simply continue running. This is especailly useful on Intel processors
> where Global Control MSR is stored in VMCS, thus not requiring us to stop
> the counters during save operation. On AMD we need to explicitly stop the
> counters but we don't need to save them.
>
> Signed-off-by: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
Only minor comments below.
Dietmar.
> ---
> xen/arch/x86/domain.c | 14 ++++++--
> xen/arch/x86/hvm/svm/svm.c | 2 --
> xen/arch/x86/hvm/svm/vpmu.c | 58 +++++++++++++++++++++++++-----
> xen/arch/x86/hvm/vmx/vmx.c | 2 --
> xen/arch/x86/hvm/vmx/vpmu_core2.c | 25 +++++++++++--
> xen/arch/x86/hvm/vpmu.c | 74
> +++++++++++++++++++++++++++++++++++----
> xen/include/asm-x86/hvm/vpmu.h | 5 ++-
> 7 files changed, 155 insertions(+), 25 deletions(-)
>
> diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
> index 0d7a40c..6f9cbed 100644
> --- a/xen/arch/x86/domain.c
> +++ b/xen/arch/x86/domain.c
> @@ -1535,8 +1535,14 @@ void context_switch(struct vcpu *prev, struct vcpu
> *next)
> if (prev != next)
> update_runstate_area(prev);
>
> - if ( is_hvm_vcpu(prev) && !list_empty(&prev->arch.hvm_vcpu.tm_list) )
> - pt_save_timer(prev);
> + if ( is_hvm_vcpu(prev) )
> + {
> + if (prev != next)
> + vpmu_save(prev);
> +
> + if ( !list_empty(&prev->arch.hvm_vcpu.tm_list) )
> + pt_save_timer(prev);
> + }
>
> local_irq_disable();
>
> @@ -1574,6 +1580,10 @@ void context_switch(struct vcpu *prev, struct vcpu
> *next)
> (next->domain->domain_id != 0));
> }
>
> + if (is_hvm_vcpu(next) && (prev != next) )
> + /* Must be done with interrupts enabled */
> + vpmu_load(next);
> +
> context_saved(prev);
>
> if (prev != next)
> diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
> index 89e47b3..8123f37 100644
> --- a/xen/arch/x86/hvm/svm/svm.c
> +++ b/xen/arch/x86/hvm/svm/svm.c
> @@ -860,7 +860,6 @@ static void svm_ctxt_switch_from(struct vcpu *v)
> svm_fpu_leave(v);
>
> svm_save_dr(v);
> - vpmu_save(v);
> svm_lwp_save(v);
> svm_tsc_ratio_save(v);
>
> @@ -901,7 +900,6 @@ static void svm_ctxt_switch_to(struct vcpu *v)
> svm_vmsave(per_cpu(root_vmcb, cpu));
> svm_vmload(vmcb);
> vmcb->cleanbits.bytes = 0;
> - vpmu_load(v);
> svm_lwp_load(v);
> svm_tsc_ratio_load(v);
>
> diff --git a/xen/arch/x86/hvm/svm/vpmu.c b/xen/arch/x86/hvm/svm/vpmu.c
> index 6610806..a11a650 100644
> --- a/xen/arch/x86/hvm/svm/vpmu.c
> +++ b/xen/arch/x86/hvm/svm/vpmu.c
> @@ -188,6 +188,21 @@ static inline void context_restore(struct vcpu *v)
>
> static void amd_vpmu_restore(struct vcpu *v)
> {
> + struct vpmu_struct *vpmu = vcpu_vpmu(v);
> + struct amd_vpmu_context *ctxt = vpmu->context;
> +
> + vpmu_reset(vpmu, VPMU_STOPPED);
> +
> + if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
Trailing space.
> + {
> + int i;
> +
> + for ( i = 0; i < num_counters; i++ )
> + wrmsrl(ctrls[i], ctxt->ctrls[i]);
> +
> + return;
> + }
> +
> context_restore(v);
> }
>
> @@ -197,23 +212,40 @@ static inline void context_save(struct vcpu *v)
> struct vpmu_struct *vpmu = vcpu_vpmu(v);
> struct amd_vpmu_context *ctxt = vpmu->context;
>
> + /* No need to save controls -- they are saved in amd_vpmu_do_wrmsr */
> for ( i = 0; i < num_counters; i++ )
> - {
> - rdmsrl(ctrls[i], ctxt->ctrls[i]);
> - wrmsrl(ctrls[i], 0);
> rdmsrl(counters[i], ctxt->counters[i]);
> - }
> }
>
> -static void amd_vpmu_save(struct vcpu *v)
> +static int amd_vpmu_save(struct vcpu *v)
> {
> struct vpmu_struct *vpmu = vcpu_vpmu(v);
> struct amd_vpmu_context *ctx = vpmu->context;
> + int i;
>
> - context_save(v);
> + /*
Same here.
> + * Stop the counters. If we came here via vpmu_save_force (i.e.
> + * when VPMU_CONTEXT_SAVE is set) counters are already stopped.
> + */
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_SAVE) )
Same here.
> + {
> + vpmu_set(vpmu, VPMU_STOPPED);
>
> + for ( i = 0; i < num_counters; i++ )
> + wrmsrl(ctrls[i], 0);
> +
> + return 0;
> + }
> +
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
> + return 0;
> +
Same here.
> + context_save(v);
> +
Same here.
> if ( !vpmu_is_set(vpmu, VPMU_RUNNING) && ctx->msr_bitmap_set )
> amd_vpmu_unset_msr_bitmap(v);
> +
> + return 1;
> }
>
> static void context_read(unsigned int msr, u64 *msr_content)
> @@ -286,6 +318,7 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t
> msr_content)
> return 1;
> vpmu_set(vpmu, VPMU_RUNNING);
> apic_write(APIC_LVTPC, PMU_APIC_VECTOR);
> + vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR;
>
> if ( !((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
> amd_vpmu_set_msr_bitmap(v);
> @@ -296,16 +329,19 @@ static int amd_vpmu_do_wrmsr(unsigned int msr, uint64_t
> msr_content)
> (is_pmu_enabled(msr_content) == 0) && vpmu_is_set(vpmu,
> VPMU_RUNNING) )
> {
> apic_write(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
> + vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
> vpmu_reset(vpmu, VPMU_RUNNING);
> if ( ((struct amd_vpmu_context *)vpmu->context)->msr_bitmap_set )
> amd_vpmu_unset_msr_bitmap(v);
> release_pmu_ownship(PMU_OWNER_HVM);
> }
>
> - if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED)
> + || vpmu_is_set(vpmu, VPMU_STOPPED) )
> {
> context_restore(v);
> vpmu_set(vpmu, VPMU_CONTEXT_LOADED);
> + vpmu_reset(vpmu, VPMU_STOPPED);
> }
>
> /* Update vpmu context immediately */
> @@ -321,7 +357,13 @@ static int amd_vpmu_do_rdmsr(unsigned int msr, uint64_t
> *msr_content)
> struct vcpu *v = current;
> struct vpmu_struct *vpmu = vcpu_vpmu(v);
>
> - if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
> + if ( vpmu_is_set(vpmu, VPMU_STOPPED) )
> + {
> + context_restore(v);
> + vpmu_reset(vpmu, VPMU_STOPPED);
> + }
> +
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
Same here.
> context_read(msr, msr_content);
> else
> rdmsrl(msr, *msr_content);
> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
> index a869ed4..e36dbcb 100644
> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -615,7 +615,6 @@ static void vmx_ctxt_switch_from(struct vcpu *v)
> vmx_save_guest_msrs(v);
> vmx_restore_host_msrs();
> vmx_save_dr(v);
> - vpmu_save(v);
> }
>
> static void vmx_ctxt_switch_to(struct vcpu *v)
> @@ -640,7 +639,6 @@ static void vmx_ctxt_switch_to(struct vcpu *v)
>
> vmx_restore_guest_msrs(v);
> vmx_restore_dr(v);
> - vpmu_load(v);
> }
>
>
> diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c
> b/xen/arch/x86/hvm/vmx/vpmu_core2.c
> index 6195bfc..9f152b4 100644
> --- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
> +++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
> @@ -307,17 +307,23 @@ static inline void __core2_vpmu_save(struct vcpu *v)
> rdmsrl(MSR_IA32_PERFCTR0+i,
> core2_vpmu_cxt->arch_msr_pair[i].counter);
> }
>
> -static void core2_vpmu_save(struct vcpu *v)
> +static int core2_vpmu_save(struct vcpu *v)
> {
> struct vpmu_struct *vpmu = vcpu_vpmu(v);
>
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_SAVE) )
> + return 0;
> +
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
> + return 0;
> +
> __core2_vpmu_save(v);
>
> /* Unset PMU MSR bitmap to trap lazy load. */
> if ( !vpmu_is_set(vpmu, VPMU_RUNNING) && cpu_has_vmx_msr_bitmap )
> core2_vpmu_unset_msr_bitmap(v->arch.hvm_vmx.msr_bitmap);
>
> - return;
> + return 1;
> }
>
> static inline void __core2_vpmu_load(struct vcpu *v)
> @@ -338,6 +344,11 @@ static inline void __core2_vpmu_load(struct vcpu *v)
>
> static void core2_vpmu_load(struct vcpu *v)
> {
> + struct vpmu_struct *vpmu = vcpu_vpmu(v);
> +
> + if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
> + return;
> +
> __core2_vpmu_load(v);
> }
>
> @@ -539,9 +550,15 @@ static int core2_vpmu_do_wrmsr(unsigned int msr,
> uint64_t msr_content)
> /* Setup LVTPC in local apic */
> if ( vpmu_is_set(vpmu, VPMU_RUNNING) &&
> is_vlapic_lvtpc_enabled(vcpu_vlapic(v)) )
> + {
> apic_write_around(APIC_LVTPC, PMU_APIC_VECTOR);
> + vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR;
> + }
> else
> + {
> apic_write_around(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
> + vpmu->hw_lapic_lvtpc = PMU_APIC_VECTOR | APIC_LVT_MASKED;
> + }
>
> core2_vpmu_save_msr_context(v, type, index, msr_content);
> if ( type != MSR_TYPE_GLOBAL )
> @@ -616,6 +633,7 @@ static int core2_vpmu_do_rdmsr(unsigned int msr, uint64_t
> *msr_content)
> else
> return 0;
> }
> +
> return 1;
> }
>
> @@ -710,7 +728,8 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs
> *regs)
> }
>
> /* HW sets the MASK bit when performance counter interrupt occurs*/
> - apic_write_around(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
> + vpmu->hw_lapic_lvtpc = apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED;
> + apic_write_around(APIC_LVTPC, vpmu->hw_lapic_lvtpc);
>
> return 1;
> }
> diff --git a/xen/arch/x86/hvm/vpmu.c b/xen/arch/x86/hvm/vpmu.c
> index 6b7af68..3f269d1 100644
> --- a/xen/arch/x86/hvm/vpmu.c
> +++ b/xen/arch/x86/hvm/vpmu.c
> @@ -18,7 +18,6 @@
> *
> * Author: Haitao Shan <haitao.shan@xxxxxxxxx>
> */
> -
> #include <xen/config.h>
> #include <xen/sched.h>
> #include <xen/xenoprof.h>
> @@ -42,6 +41,8 @@ static unsigned int __read_mostly opt_vpmu_enabled;
> static void parse_vpmu_param(char *s);
> custom_param("vpmu", parse_vpmu_param);
>
> +static DEFINE_PER_CPU(struct vcpu *, last_vcpu);
> +
> static void __init parse_vpmu_param(char *s)
> {
> switch ( parse_bool(s) )
> @@ -121,30 +122,89 @@ void vpmu_do_cpuid(unsigned int input,
> vpmu->arch_vpmu_ops->do_cpuid(input, eax, ebx, ecx, edx);
> }
>
> +static void vpmu_save_force(void *arg)
> +{
> + struct vcpu *v = (struct vcpu *)arg;
> + struct vpmu_struct *vpmu = vcpu_vpmu(v);
> +
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
> + return;
> +
> + if ( vpmu->arch_vpmu_ops )
> + (void)vpmu->arch_vpmu_ops->arch_vpmu_save(v);
> +
> + vpmu_reset(vpmu, VPMU_CONTEXT_SAVE);
> +
> + per_cpu(last_vcpu, smp_processor_id()) = NULL;
> +}
> +
> void vpmu_save(struct vcpu *v)
> {
> struct vpmu_struct *vpmu = vcpu_vpmu(v);
> + int pcpu = smp_processor_id();
>
> if ( !(vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) &&
> vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED)) )
> return;
>
> + vpmu->last_pcpu = pcpu;
> + per_cpu(last_vcpu, pcpu) = v;
> +
> if ( vpmu->arch_vpmu_ops )
> - vpmu->arch_vpmu_ops->arch_vpmu_save(v);
> + if ( vpmu->arch_vpmu_ops->arch_vpmu_save(v) )
> + vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
>
> - vpmu->hw_lapic_lvtpc = apic_read(APIC_LVTPC);
> apic_write(APIC_LVTPC, PMU_APIC_VECTOR | APIC_LVT_MASKED);
> -
> - vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
> }
>
> void vpmu_load(struct vcpu *v)
> {
> struct vpmu_struct *vpmu = vcpu_vpmu(v);
> + int pcpu = smp_processor_id();
> + struct vcpu *prev = NULL;
> +
> + if ( !vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) )
> + return;
> +
> + /* First time this VCPU is running here */
> + if ( vpmu->last_pcpu != pcpu )
> + {
> + /*
> + * Get the context from last pcpu that we ran on. Note that if
> another
> + * VCPU is running there it must have saved this VPCU's context
> before
> + * startig to run (see below).
> + * There should be no race since remote pcpu will disable interrupts
> + * before saving the context.
> + */
> + if ( vpmu_is_set(vpmu, VPMU_CONTEXT_LOADED) )
> + {
> + vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
> + on_selected_cpus(cpumask_of(vpmu->last_pcpu),
> + vpmu_save_force, (void *)v, 1);
> + vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
> + }
> + }
> +
> + /* Prevent forced context save from remote CPU */
> + local_irq_disable();
> +
> + prev = per_cpu(last_vcpu, pcpu);
> +
> + if (prev != v && prev) {
> + vpmu = vcpu_vpmu(prev);
> +
> + /* Someone ran here before us */
> + vpmu_set(vpmu, VPMU_CONTEXT_SAVE);
> + vpmu_save_force(prev);
> + vpmu_reset(vpmu, VPMU_CONTEXT_LOADED);
> +
> + vpmu = vcpu_vpmu(v);
> + }
> +
> + local_irq_enable();
>
> /* Only when PMU is counting, we load PMU context immediately. */
> - if ( !(vpmu_is_set(vpmu, VPMU_CONTEXT_ALLOCATED) &&
> - vpmu_is_set(vpmu, VPMU_RUNNING)) )
> + if ( !vpmu_is_set(vpmu, VPMU_RUNNING) )
> return;
>
> if ( vpmu->arch_vpmu_ops && vpmu->arch_vpmu_ops->arch_vpmu_load )
> diff --git a/xen/include/asm-x86/hvm/vpmu.h b/xen/include/asm-x86/hvm/vpmu.h
> index 01be976..5040a49 100644
> --- a/xen/include/asm-x86/hvm/vpmu.h
> +++ b/xen/include/asm-x86/hvm/vpmu.h
> @@ -52,7 +52,7 @@ struct arch_vpmu_ops {
> unsigned int *eax, unsigned int *ebx,
> unsigned int *ecx, unsigned int *edx);
> void (*arch_vpmu_destroy)(struct vcpu *v);
> - void (*arch_vpmu_save)(struct vcpu *v);
> + int (*arch_vpmu_save)(struct vcpu *v);
> void (*arch_vpmu_load)(struct vcpu *v);
> void (*arch_vpmu_dump)(struct vcpu *v);
> };
> @@ -62,6 +62,7 @@ int svm_vpmu_initialise(struct vcpu *, unsigned int flags);
>
> struct vpmu_struct {
> u32 flags;
> + u32 last_pcpu;
> u32 hw_lapic_lvtpc;
> void *context;
> struct arch_vpmu_ops *arch_vpmu_ops;
> @@ -73,6 +74,8 @@ struct vpmu_struct {
> #define VPMU_PASSIVE_DOMAIN_ALLOCATED 0x8
> #define VPMU_CPU_HAS_DS 0x10 /* Has Debug Store */
> #define VPMU_CPU_HAS_BTS 0x20 /* Has Branch Trace Store */
> +#define VPMU_CONTEXT_SAVE 0x40 /* Force context save */
> +#define VPMU_STOPPED 0x80 /* Stop counters while VCPU
> is not running */
Would it be better to group the VPMU_ state and context flags together and move
special cpu flags behind?
>
>
> #define vpmu_set(_vpmu, _x) ((_vpmu)->flags |= (_x))
>
--
Company details: http://ts.fujitsu.com/imprint.html
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |