Guest LBR Enabling
Subsystems (4)
v4 cover Guest LBR Enabling
Last Branch Recording (LBR) is a performance monitor unit (PMU) feature on Intel CPUs that captures branch related info. This patch series enables this feature to KVM guests.
Here is a conclusion of the fundamental methods that we use:
1) the LBR feature is enabled per guest via QEMU setting of KVM_CAP_X86_GUEST_LBR;
2) the LBR stack is passed through to the guest for direct accesses after the guest's first access to any of the lbr related MSRs;
3) When the guest uses the LBR feature with the user callstack mode, the host will help save/resotre the LBR stack when the vCPU is scheduled out/in.
ChangeLog:v3->v4:
- perf/x86:
- Patch 1: change the lbr msr variable type to "unsigned int";
- Patch 6: add a "no_counter" boolean attr to let callers explicitly tell the perf core to not allocate counters for the event;
- Patch 7: change "cpuc->vcpu_lbr" from "boolean" to "u8", and add the PF_VCPU and is_kernel_event checks befoer setting it;
- Patch 8: add the LBR_SELECT save/restore on vCPU switching;
- Patch 9: move lbr_select_user_callstack to .h, instead of exporting it;
- KVM/x86:
- Patch 3: use "cap->args[0]" to enable/disable the lbr feature from userspace;
- Patch 4: forbid the enabling the guest lbr when the host and guest see different lbr stack entries;
- Patch 10: in guest_access_lbr_msr, pass through the lbr stack only when it has been passed through (i.e. add the check !vcpu->arch.lbr_used).
previous:
https://lkml.org/lkml/2018/9/20/507
Like Xu (1):
KVM/x86/vPMU: Add APIs to support host save/restore the guest lbr
stack
Wei Wang (9):
perf/x86: fix the variable type of the LBR MSRs perf/x86: add a function to get the lbr stack KVM/x86: KVM_CAP_X86_GUEST_LBR
KVM/x86: intel_pmu_lbr_enable
KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest perf/x86: no counter allocation support perf/x86: save/restore LBR_SELECT on vCPU switching perf/x86: function to check lbr user callstack mode KVM/x86/lbr: lazy save the guest lbr stack
arch/x86/events/core.c | 12 +++ arch/x86/events/intel/lbr.c | 82 ++++++++--------- arch/x86/events/perf_event.h | 6 +- arch/x86/include/asm/kvm_host.h | 7 ++ arch/x86/include/asm/perf_event.h | 64 +++++++++++++ arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/cpuid.h | 8 ++ arch/x86/kvm/pmu.c | 8 ++ arch/x86/kvm/pmu.h | 10 +++ arch/x86/kvm/pmu_intel.c | 183 ++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/vmx.c | 147 ++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 14 +++ include/linux/perf_event.h | 12 +++ include/uapi/linux/kvm.h | 1 + include/uapi/linux/perf_event.h | 3 +- kernel/events/core.c | 7 -- 16 files changed, 514 insertions(+), 52 deletions(-)
Signature · 1 line
2.7.4
PATCH v4 1/10 perf/x86: fix the variable type of the LBR MSRs
The MSR variable type can be "unsigned int", which uses less memory than the longer unsigned long. The lbr nr won't be a negative number, so make it "unsigned int" as well.
--- arch/x86/events/perf_event.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/events/perf_event.h +2 -2
@@ -619,8 +619,8 @@ struct x86_pmu {/* * Intel LBR */ -unsigned long lbr_tos, lbr_from, lbr_to;/* MSR base regs */ -int lbr_nr;/* hardware stack size */ +unsigned int lbr_tos, lbr_from, lbr_to, + lbr_nr;/* lbr stack and size */ u64 lbr_sel_mask;/* LBR_SELECT valid bits */ const int *lbr_sel_map;/* lbr_select mappings */ bool lbr_double_abort;/* duplicated lbr aborts */
Signature · 1 line
2.7.4
PATCH v4 2/10 perf/x86: add a function to get the lbr stack
In reply to Wei WangThe LBR stack MSRs are architecturally specific. The perf subsystem has already assigned the abstracted MSR values based on the CPU architecture.
This patch enables a caller outside the perf subsystem to get the LBR stack info. This is useful for hyperviosrs to prepare the lbr feature for the guest.
--- arch/x86/events/intel/lbr.c | 23 +++++++++++++++++++++++ arch/x86/include/asm/perf_event.h | 14 ++++++++++++++ 2 files changed, 37 insertions(+)
arch/x86/events/intel/lbr.c +23 -0
@@ -1277,3 +1277,26 @@ void intel_pmu_lbr_init_knl(void)if (x86_pmu.intel_cap.lbr_format ==LBR_FORMAT_LIP ) x86_pmu.intel_cap.lbr_format =LBR_FORMAT_EIP_FLAGS ; } + +/** +* x86_perf_get_lbr_stack - get the lbr stack related MSRs +* +* @stack: the caller's memory to get the lbr stack +* +* Returns: 0 indicates that the lbr stack has been successfully obtained. +*/ +int x86_perf_get_lbr_stack (struct x86_perf_lbr_stack *stack) +{ + stack->nr = x86_pmu.lbr_nr; + stack->tos = x86_pmu.lbr_tos; + stack->from = x86_pmu.lbr_from; + stack->to = x86_pmu.lbr_to; + +if (x86_pmu.intel_cap.lbr_format ==LBR_FORMAT_INFO ) + stack->info =MSR_LBR_INFO_0 ; +else + stack->info =0 ; + +return 0 ; +} +EXPORT_SYMBOL_GPL (x86_perf_get_lbr_stack);
arch/x86/include/asm/perf_event.h +14 -0
@@ -275,7 +275,16 @@ struct perf_guest_switch_msr {u64 host, guest; }; +struct x86_perf_lbr_stack { +unsigned int nr; +unsigned int tos; +unsigned int from; +unsigned int to; +unsigned int info; +}; +extern struct perf_guest_switch_msr *perf_guest_get_msrs (int *nr); +extern int x86_perf_get_lbr_stack (struct x86_perf_lbr_stack *stack);extern void perf_get_x86_pmu_capability (struct x86_pmu_capability *cap);extern void perf_check_microcode (void );extern int x86_perf_rdpmc_index (struct perf_event *event);
@@ -286,6 +295,11 @@ static inline struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr)return NULL ; } +static inline int x86_perf_get_lbr_stack (struct x86_perf_lbr_stack *stack) +{ +return -1 ; +} +static inline void perf_get_x86_pmu_capability (struct x86_pmu_capability *cap) {memset (cap,0 ,sizeof (*cap));
Signature · 1 line
2.7.4
PATCH v4 3/10 KVM/x86: KVM_CAP_X86_GUEST_LBR
In reply to Wei WangIntroduce KVM_CAP_X86_GUEST_LBR to allow per-VM enabling of the guest lbr feature.
--- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/x86.c | 15 +++++++++++++++ include/uapi/linux/kvm.h | 1 + 3 files changed, 18 insertions(+)
arch/x86/include/asm/kvm_host.h +2 -0
@@ -865,6 +865,7 @@ struct kvm_arch {atomic_t vapics_in_nmi_mode;struct mutex apic_map_lock;struct kvm_apic_map *apic_map; +struct x86_perf_lbr_stack lbr_stack;bool apic_access_page_done;
@@ -873,6 +874,7 @@ struct kvm_arch {bool mwait_in_guest;bool hlt_in_guest;bool pause_in_guest; +bool lbr_in_guest;unsigned long irq_sources_bitmap;s64 kvmclock_offset;
arch/x86/kvm/x86.c +15 -0
@@ -3018,6 +3018,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)case KVM_CAP_GET_MSR_FEATURES :case KVM_CAP_MSR_PLATFORM_INFO :case KVM_CAP_EXCEPTION_PAYLOAD : +case KVM_CAP_X86_GUEST_LBR : r =1 ;break ;case KVM_CAP_SYNC_REGS :
@@ -4502,6 +4503,20 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, kvm->arch.exception_payload_enabled = cap->args[0 ]; r =0 ;break ; +case KVM_CAP_X86_GUEST_LBR : + r = -EINVAL ; +if (cap->args[0 ] && +x86_perf_get_lbr_stack (&kvm->arch.lbr_stack)) { +pr_err ("Failed to enable the guest lbr feature\n" ); +break ; + } +if (copy_to_user ((void __user *)cap->args[1 ], + &kvm->arch.lbr_stack, +sizeof (struct x86_perf_lbr_stack ))) +break ; + kvm->arch.lbr_in_guest = cap->args[0 ]; + r =0 ; +break ;default : r = -EINVAL ;break ;
include/uapi/linux/kvm.h +1 -0
@@ -975,6 +975,7 @@ struct kvm_ppc_resize_hpt {#define KVM_CAP_HYPERV_ENLIGHTENED_VMCS 163#define KVM_CAP_EXCEPTION_PAYLOAD 164#define KVM_CAP_ARM_VM_IPA_SIZE 165 +#define KVM_CAP_X86_GUEST_LBR 166#ifdef KVM_CAP_IRQ_ROUTING
Signature · 1 line
2.7.4
PATCH v4 4/10 KVM/x86: intel_pmu_lbr_enable
In reply to Wei WangThe lbr stack is architecturally specific, for example, SKX has 32 lbr stack entries while HSW has 16 entries, so a HSW guest running on a SKX machine may not get accurate perf results. Currently, we forbid the guest lbr enabling when the guest and host see different lbr stack entries.
--- arch/x86/kvm/cpuid.h | 8 ++++ arch/x86/kvm/pmu.c | 8 ++++ arch/x86/kvm/pmu.h | 2 + arch/x86/kvm/pmu_intel.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/x86.c | 3 +- 5 files changed, 136 insertions(+), 2 deletions(-)
arch/x86/kvm/cpuid.h +8 -0
@@ -123,6 +123,14 @@ static inline bool guest_cpuid_is_amd(struct kvm_vcpu *vcpu)return best && best->ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx; } +static inline bool guest_cpuid_is_intel (struct kvm_vcpu *vcpu) +{ +struct kvm_cpuid_entry2 *best; + + best =kvm_find_cpuid_entry (vcpu,0 ,0 ); +return best && best->ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx; +} +static inline int guest_cpuid_family (struct kvm_vcpu *vcpu) {struct kvm_cpuid_entry2 *best;
arch/x86/kvm/pmu.c +8 -0
@@ -299,6 +299,14 @@ int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned idx, u64 *data)return 0 ; } +bool kvm_pmu_lbr_enable (struct kvm_vcpu *vcpu) +{ +if (guest_cpuid_is_intel (vcpu)) +return kvm_x86_ops->pmu_ops->lbr_enable (vcpu); + +return false; +} +void kvm_pmu_deliver_pmi (struct kvm_vcpu *vcpu) {if (lapic_in_kernel (vcpu))
arch/x86/kvm/pmu.h +2 -0
@@ -28,6 +28,7 @@ struct kvm_pmu_ops {struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu,unsigned idx);int (*is_valid_msr_idx)(struct kvm_vcpu *vcpu,unsigned idx);bool (*is_valid_msr)(struct kvm_vcpu *vcpu,u32 msr); +bool (*lbr_enable)(struct kvm_vcpu *vcpu);int (*get_msr)(struct kvm_vcpu *vcpu,u32 msr,u64 *data);int (*set_msr)(struct kvm_vcpu *vcpu,struct msr_data *msr_info);void (*refresh)(struct kvm_vcpu *vcpu);
@@ -106,6 +107,7 @@ void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel);void reprogram_fixed_counter (struct kvm_pmc *pmc,u8 ctrl,int fixed_idx);void reprogram_counter (struct kvm_pmu *pmu,int pmc_idx); +bool kvm_pmu_lbr_enable (struct kvm_vcpu *vcpu);void kvm_pmu_deliver_pmi (struct kvm_vcpu *vcpu);void kvm_pmu_handle_event (struct kvm_vcpu *vcpu);int kvm_pmu_rdpmc (struct kvm_vcpu *vcpu,unsigned pmc,u64 *data);
arch/x86/kvm/pmu_intel.c +117 -0
135 lines not on this page · raw message
arch/x86/kvm/x86.c +1 -2
@@ -4505,8 +4505,7 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,break ;case KVM_CAP_X86_GUEST_LBR : r = -EINVAL ; -if (cap->args[0 ] && -x86_perf_get_lbr_stack (&kvm->arch.lbr_stack)) { +if (cap->args[0 ] && !kvm_pmu_lbr_enable (kvm->vcpus[0 ])) {pr_err ("Failed to enable the guest lbr feature\n" );break ; }
Signature · 1 line
2.7.4
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
arch/x86/kvm/pmu_intel.c static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) · line 187
Quoted 9 lines · Wei Wang
arch/x86/kvm/pmu_intel.c +9
-0+ +/* +* It could be possible that people have vcpus of old model run on +* physcal cpus of newer model, for example a BDW guest on a SKX +* machine (but not possible to be the other way around). +* The BDW guest may not get accurate results on a SKX machine as it +* only reads 16 entries of the lbr stack while there are 32 entries +* of recordings. So we currently forbid the lbr enabling when the +* vcpu and physical cpu see different lbr stack entries.
I think it's not enough to only check number of entries. The LBR from/to MSRs may be different even the number of entries is the same, e.g SLM and KNL.
arch/x86/kvm/pmu_intel.c static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) · line 189
Quoted 2 lines
arch/x86/kvm/pmu_intel.c +2
-0+*/ +switch (vcpu_model) {
That's a duplicate of intel_pmu_init(). I think it's better to factor out the common part if you want to check LBR MSRs and entries. Then we don't need to add the same codes in two different places when enabling new platforms.
Actually, I think we may just support LBR for guest if it has the identical CPU model as host. It should be good enough for now.
Thanks,
Kan
Quoted 2 lines
arch/x86/kvm/pmu_intel.c +2
-0+case INTEL_FAM6_CORE2_MEROM : +case INTEL_FAM6_CORE2_MEROM_L :
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 15 lines · Kan
arch/x86/kvm/pmu_intel.c static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) · line 187
Quoted 11 lines · Wei Wang
arch/x86/kvm/pmu_intel.c +6
-0+ +/* +* It could be possible that people have vcpus of old model run on +* physcal cpus of newer model, for example a BDW guest on a SKX +* machine (but not possible to be the other way around). +* The BDW guest may not get accurate results on a SKX machine as it
+ * only reads 16 entries of the lbr stack while there are 32
entriesarch/x86/kvm/pmu_intel.c +2
-0+* of recordings. So we currently forbid the lbr enabling when the +* vcpu and physical cpu see different lbr stack entries.
Quoted 1 line
I think it's not enough to only check number of entries. The LBR from/to MSRs may be different even the number of entries is the same, e.g SLM and KNL.
Yes, we could add the comparison of the FROM msrs.
Quoted 6 lines
arch/x86/kvm/pmu_intel.c static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) · line 189
Quoted 3 lines
arch/x86/kvm/pmu_intel.c +2
-0+*/ +switch (vcpu_model) {That's a duplicate of
intel_pmu_init(). I think it's better to factor out the common part if you want to check LBR MSRs and entries. Then we don't need to add the same codes in two different places when enabling new platforms.
Yes, I thought about this, but intel_pmu_init() does a lot more things in each "Case xx". Any thought about how to factor them out?
Quoted 2 lines
Actually, I think we may just support LBR for guest if it has the identical CPU model as host. It should be good enough for now.
I actually tried this in the first place but it failed to work with the existing QEMU. For example, when we specify "Broadwell" cpu from qemu, then qemu uses Broadwell core model, but the physical machine I have is Broadwell X. This patch will support this case.
Best,
Wei
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 21 lines · Wei Wang
Quoted 15 lines · Kan
Quoted 11 lines · Wei Wang
+
+ /*
+ * It could be possible that people have vcpus of old model run on + * physcal cpus of newer model, for example a BDW guest on a SKX + * machine (but not possible to be the other way around). + * The BDW guest may not get accurate results on a SKX machine as it
+ * only reads 16 entries of the lbr stack while there are 32 entries
+ * of recordings. So we currently forbid the lbr enabling when the + * vcpu and physical cpu see different lbr stack entries.Quoted 1 line
I think it's not enough to only check number of entries. The LBR from/to MSRs may be different even the number of entries is the same, e.g SLM and KNL.
Yes, we could add the comparison of the FROM msrs.
Quoted 1 line
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
+ */
+ switch (vcpu_model) {That's a duplicate of
intel_pmu_init(). I think it's better to factor out the common part if you want to check LBR MSRs and entries. Then we don't need to add the same codes in two different places when enabling new platforms.Yes, I thought about this, but
intel_pmu_init()does a lot more things in each "Case xx". Any thought about how to factor them out?
I think we may only move the "switch (boot_cpu_data.x86_model) { ... }" to a new function, e.g. __intel_pmu_init(int model, struct x86_pmu *x86_pmu)
In __intel_pmu_init, if the model != boot_cpu_data.x86_model, you only need to update x86_pmu.*. Just ignore global settings, e.g hw_cache_event_ids, mem_attr, extra_attr etc.
You may also need to introduce another new function to check if the LBR is compatible with guest in lbr.c, e.g. bool is_lbr_compatible_with_guest(int model).
bool is_lbr_compatible_with_guest(int model) {
struct x86_pmu fake_x86_pmu;
if (boot_cpu_data.x86_model == model)
return true;
__intel_pmu_init(model, &fake_x86_pmu);
if ((x86_pmu.lbr_nr == fake_x86_pmu.lbr_nr) &&
(x86_pmu.lbr_tos == fake_x86_pmu.lbr_tos) &&
(x86_pmu.lbr_from == fake_x86_pmu.lbr_from))
return true;
return false;
}Quoted 7 lines
Quoted 3 lines
Actually, I think we may just support LBR for guest if it has the identical CPU model as host. It should be good enough for now.
I actually tried this in the first place but it failed to work with the existing QEMU. For example, when we specify "Broadwell" cpu from qemu, then qemu uses Broadwell core model, but the physical machine I have is Broadwell X. This patch will support this case.
I mean is it good enough if we only support "-cpu host"?
Thanks,
Kan
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 33 lines · Kan
Quoted 30 lines · Wei Wang
Quoted 17 lines · Kan
Quoted 7 lines · Wei Wang
arch/x86/kvm/pmu_intel.c +3
-0+ +/* +* It could be possible that people have vcpus of old model run on
arch/x86/kvm/pmu_intel.c +3
-0+* physcal cpus of newer model, for example a BDW guest on a SKX +* machine (but not possible to be the other way around). +* The BDW guest may not get accurate results on a SKX machine Quoted 6 lines
as it
+ * only reads 16 entries of the lbr stack while there are 32
entries
+ * of recordings. So we currently forbid the lbr enabling when
the
+ * vcpu and physical cpu see different lbr stack entries.Quoted 1 line
I think it's not enough to only check number of entries. The LBR from/to MSRs may be different even the number of entries is the same, e.g SLM and KNL.
Yes, we could add the comparison of the FROM msrs.
Quoted 6 lines
arch/x86/kvm/pmu_intel.c static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) · line 189
Quoted 3 lines
arch/x86/kvm/pmu_intel.c +2
-0+*/ +switch (vcpu_model) {That's a duplicate of
intel_pmu_init(). I think it's better to factor out the common part if you want to check LBR MSRs and entries. Then we don't need to add the same codes in two different places when enabling new platforms.
Quoted 6 lines
Quoted 2 lines
Yes, I thought about this, but
intel_pmu_init()does a lot more things in each "Case xx". Any thought about how to factor them out?I think we may only move the "switch (boot_cpu_data.x86_model) { ... }" to a new function, e.g.
__intel_pmu_init(int model, struct x86_pmu *x86_pmu)In
__intel_pmu_init, if the model != boot_cpu_data.x86_model, you only need to update x86_pmu.*. Just ignore global settings, e.ghw_cache_event_ids,mem_attr,extra_attretc.
Thanks for sharing. I understand the point of maintaining those models at one place, but this factor-out doesn't seem very elegant to me, like below
__intel_pmu_init (int model, struct x86_pmu *x86_pmu) {
...
switch (model)
case INTEL_FAM6_NEHALEM:
case INTEL_FAM6_NEHALEM_EP:
case INTEL_FAM6_NEHALEM_EX:
intel_pmu_lbr_init(x86_pmu);
if (model != boot_cpu_data.x86_model)
return;
/* Other a lot of things init like below..*/
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
sizeof(hw_cache_extra_regs));
x86_pmu.event_constraints = intel_nehalem_event_constraints;
x86_pmu.pebs_constraints =
intel_nehalem_pebs_event_constraints;
x86_pmu.enable_all = intel_pmu_nhm_enable_all;
x86_pmu.extra_regs = intel_nehalem_extra_regs;...
Case...
}
We need insert "if (model != boot_cpu_data.x86_model)" in every "Case xx".
What would be the rationale that we only do lbr_init for "x86_pmu" when model != boot_cpu_data.x86_model?
(It looks more like a workaround to factor-out the function and get what we want)
I would prefer having them separated as this patch for now - it is logically more clear to me.
Quoted 11 lines
Quoted 8 lines
Quoted 4 lines
Actually, I think we may just support LBR for guest if it has the identical CPU model as host. It should be good enough for now.
I actually tried this in the first place but it failed to work with the existing QEMU. For example, when we specify "Broadwell" cpu from qemu, then qemu uses Broadwell core model, but the physical machine I have is Broadwell X. This patch will support this case.
I mean is it good enough if we only support "-cpu host"?
Not really. AFAIK, people don't use this usually. It is more common to specify the CPU type.
Best,
Wei
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 67 lines · Wei Wang
Quoted 33 lines · Kan
Quoted 30 lines · Wei Wang
Quoted 17 lines · Kan
Quoted 5 lines · Wei Wang
+
+ /*
+ * It could be possible that people have vcpus of old model run on
+ * physcal cpus of newer model, for example a BDW guest on a SKXQuoted 8 lines
+ * machine (but not possible to be the other way around). + * The BDW guest may not get accurate results on a SKX machine as it
+ * only reads 16 entries of the lbr stack while there are 32 entries
+ * of recordings. So we currently forbid the lbr enabling when the
+ * vcpu and physical cpu see different lbr stack entries.Quoted 1 line
I think it's not enough to only check number of entries. The LBR from/to MSRs may be different even the number of entries is the same, e.g SLM and KNL.
Yes, we could add the comparison of the FROM msrs.
Quoted 6 lines
Quoted 3 lines
+ */
+ switch (vcpu_model) {That's a duplicate of
intel_pmu_init(). I think it's better to factor out the common part if you want to check LBR MSRs and entries. Then we don't need to add the same codes in two different places when enabling new platforms.Quoted 6 lines
Quoted 2 lines
Yes, I thought about this, but
intel_pmu_init()does a lot more things in each "Case xx". Any thought about how to factor them out?I think we may only move the "switch (boot_cpu_data.x86_model) { ... }" to a new function, e.g.
__intel_pmu_init(int model, struct x86_pmu *x86_pmu)In
__intel_pmu_init, if the model != boot_cpu_data.x86_model, you only need to update x86_pmu.*. Just ignore global settings, e.ghw_cache_event_ids,mem_attr,extra_attretc.Thanks for sharing. I understand the point of maintaining those models at one place, but this factor-out doesn't seem very elegant to me, like below
__intel_pmu_init(int model, structx86_pmu*x86_pmu) {
...
switch (model)
caseINTEL_FAM6_NEHALEM:
caseINTEL_FAM6_NEHALEM_EP:
caseINTEL_FAM6_NEHALEM_EX:
intel_pmu_lbr_init(x86_pmu);
if (model != boot_cpu_data.x86_model) return;/* Other a lot of things init like below..*/
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids));memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); x86_pmu.event_constraints =intel_nehalem_event_constraints; x86_pmu.pebs_constraints =intel_nehalem_pebs_event_constraints;
x86_pmu.enable_all =intel_pmu_nhm_enable_all; x86_pmu.extra_regs =intel_nehalem_extra_regs;
...
Quoted 7 lines
Case...
}
We need insert "if (model != boot_cpu_data.x86_model)" in every "Case xx".What would be the rationale that we only do
lbr_initfor "x86_pmu" when model != boot_cpu_data.x86_model?
(It looks more like a workaround to factor-out the function and get what we want)
I thought the new function may be extended to support fake pmu as below.
It's not only for lbr. PMU has many CPU specific features. It can be used for other features, if you want to check the compatibility in future. But I don't have an example now.
__intel_pmu_init (int model, struct x86_pmu *x86_pmu)
{
bool fake_pmu = (model != boot_cpu_data.x86_model) ? true : false;
...
switch (model)
case INTEL_FAM6_NEHALEM:
case INTEL_FAM6_NEHALEM_EP:
case INTEL_FAM6_NEHALEM_EX:
intel_pmu_lbr_init(x86_pmu);
x86_pmu->event_constraints = intel_nehalem_event_constraints;
x86_pmu->pebs_constraints = intel_nehalem_pebs_event_constraints;
x86_pmu->enable_all = intel_pmu_nhm_enable_all;
x86_pmu->extra_regs = intel_nehalem_extra_regs;
if (fake_pmu)
return;
/* Global variables should not be updated for fake PMU */
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids,
sizeof(hw_cache_event_ids));
memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
sizeof(hw_cache_extra_regs));Quoted 3 lines
I would prefer having them separated as this patch for now - it is logically more clear to me.
But it will be a problem for maintenance. Perf developer probably forget to update the list in KVM. I think you have to regularly check the perf code.
Thanks,
Kan
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 46 lines · Kan
Quoted 27 lines
Thanks for sharing. I understand the point of maintaining those models at one place, but this factor-out doesn't seem very elegant to me, like below
__intel_pmu_init(int model, structx86_pmu*x86_pmu) {
...
switch (model)
caseINTEL_FAM6_NEHALEM:
caseINTEL_FAM6_NEHALEM_EP:
caseINTEL_FAM6_NEHALEM_EX:intel_pmu_lbr_init(x86_pmu); if (model != boot_cpu_data.x86_model) return; /* Other a lot of things init like below..*/ memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); x86_pmu.event_constraints = intel_nehalem_event_constraints; x86_pmu.pebs_constraints = intel_nehalem_pebs_event_constraints; x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs;...
Quoted 7 lines
Case...
}
We need insert "if (model != boot_cpu_data.x86_model)" in every "Case xx".What would be the rationale that we only do
lbr_initfor "x86_pmu" when model != boot_cpu_data.x86_model?
(It looks more like a workaround to factor-out the function and get what we want)I thought the new function may be extended to support fake pmu as below.
It's not only for lbr. PMU has many CPU specific features. It can be used for other features, if you want to check the compatibility in future. But I don't have an example now.
__intel_pmu_init(int model, structx86_pmu*x86_pmu)
{
boolfake_pmu= (model != boot_cpu_data.x86_model) ? true : false;
...
switch (model)
caseINTEL_FAM6_NEHALEM:
caseINTEL_FAM6_NEHALEM_EP:
caseINTEL_FAM6_NEHALEM_EX:
Quoted 8 lines
intel_pmu_lbr_init(x86_pmu);
x86_pmu->event_constraints = intel_nehalem_event_constraints;
x86_pmu->pebs_constraints = intel_nehalem_pebs_event_constraints;
x86_pmu->enable_all = intel_pmu_nhm_enable_all;
x86_pmu->extra_regs = intel_nehalem_extra_regs;
if (fake_pmu)
return;It looks similar as the one I shared above, the difference is that more things (e.g. constraints) are assigned to x86_fake_pmu.
I'm not sure about the logic behind it (still look like a workaround).
Quoted 9 lines
/* Global variables should not be updated for fake PMU */ memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));Quoted 1 line
Quoted 5 lines
Quoted 2 lines
I would prefer having them separated as this patch for now - it is logically more clear to me.
But it will be a problem for maintenance. Perf developer probably forget to update the list in KVM. I think you have to regularly check the perf code.
It's been very common in hypervisor development. That's why we have hypervisor developers here. When a new platform is added, we will definitely get some work like this to do.
Best,
Wei
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 52 lines · Wei Wang
Quoted 51 lines · Kan
Quoted 26 lines
Thanks for sharing. I understand the point of maintaining those models at one place, but this factor-out doesn't seem very elegant to me, like below
__intel_pmu_init(int model, structx86_pmu*x86_pmu) {
...
switch (model)
caseINTEL_FAM6_NEHALEM:
caseINTEL_FAM6_NEHALEM_EP:
caseINTEL_FAM6_NEHALEM_EX:
intel_pmu_lbr_init(x86_pmu);
if (model != boot_cpu_data.x86_model) return;/* Other a lot of things init like below..*/
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids));memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); x86_pmu.event_constraints =intel_nehalem_event_constraints; x86_pmu.pebs_constraints =intel_nehalem_pebs_event_constraints; x86_pmu.enable_all =intel_pmu_nhm_enable_all; x86_pmu.extra_regs =intel_nehalem_extra_regs;
...Quoted 7 lines
Case...
}
We need insert "if (model != boot_cpu_data.x86_model)" in every "Case xx".What would be the rationale that we only do
lbr_initfor "x86_pmu" when model != boot_cpu_data.x86_model?
(It looks more like a workaround to factor-out the function and get what we want)I thought the new function may be extended to support fake pmu as below.
It's not only for lbr. PMU has many CPU specific features. It can be used for other features, if you want to check the compatibility in future. But I don't have an example now.
__intel_pmu_init(int model, structx86_pmu*x86_pmu)
{
boolfake_pmu= (model != boot_cpu_data.x86_model) ? true : false;
...
switch (model)
caseINTEL_FAM6_NEHALEM:
caseINTEL_FAM6_NEHALEM_EP:
caseINTEL_FAM6_NEHALEM_EX:
intel_pmu_lbr_init(x86_pmu);x86_pmu->event_constraints=intel_nehalem_event_constraints;x86_pmu->pebs_constraints=intel_nehalem_pebs_event_constraints;x86_pmu->enable_all=intel_pmu_nhm_enable_all;x86_pmu->extra_regs=intel_nehalem_extra_regs;
Quoted 6 lines
Quoted 2 lines
if (
fake_pmu)
return;It looks similar as the one I shared above, the difference is that more things (e.g. constraints) are assigned to
x86_fake_pmu.
I'm not sure about the logic behind it (still look like a workaround).
The fake x86_pmu will include all the supported features in host. If you want to check other features in future, it would be useful.
Quoted 12 lines
Quoted 12 lines
/* Global variables should not be updated for fake PMU */
memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids));memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));Quoted 1 line
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
I would prefer having them separated as this patch for now - it is logically more clear to me.
But it will be a problem for maintenance. Perf developer probably forget to update the list in KVM. I think you have to regularly check the perf code.
It's been very common in hypervisor development. That's why we have hypervisor developers here. When a new platform is added, we will definitely get some work like this to do.
If that's part of your job, I'm OK with it.
Thanks,
Kan
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 56 lines · Kan
Quoted 53 lines · Wei Wang
Quoted 52 lines · Kan
Quoted 27 lines
Thanks for sharing. I understand the point of maintaining those models at one place, but this factor-out doesn't seem very elegant to me, like below
__intel_pmu_init(int model, structx86_pmu*x86_pmu) {
...
switch (model)
caseINTEL_FAM6_NEHALEM:
caseINTEL_FAM6_NEHALEM_EP:
caseINTEL_FAM6_NEHALEM_EX:intel_pmu_lbr_init(x86_pmu); if (model != boot_cpu_data.x86_model) return; /* Other a lot of things init like below..*/ memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, sizeof(hw_cache_event_ids)); memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs, sizeof(hw_cache_extra_regs)); x86_pmu.event_constraints = intel_nehalem_event_constraints; x86_pmu.pebs_constraints = intel_nehalem_pebs_event_constraints; x86_pmu.enable_all = intel_pmu_nhm_enable_all; x86_pmu.extra_regs = intel_nehalem_extra_regs;...
Quoted 7 lines
Case...
}
We need insert "if (model != boot_cpu_data.x86_model)" in every "Case xx".What would be the rationale that we only do
lbr_initfor "x86_pmu" when model != boot_cpu_data.x86_model?
(It looks more like a workaround to factor-out the function and get what we want)I thought the new function may be extended to support fake pmu as below.
It's not only for lbr. PMU has many CPU specific features. It can be used for other features, if you want to check the compatibility in future. But I don't have an example now.
__intel_pmu_init(int model, structx86_pmu*x86_pmu)
{
boolfake_pmu= (model != boot_cpu_data.x86_model) ? true : false;
...
switch (model)
caseINTEL_FAM6_NEHALEM:
caseINTEL_FAM6_NEHALEM_EP:
caseINTEL_FAM6_NEHALEM_EX:intel_pmu_lbr_init(x86_pmu); x86_pmu->event_constraints = intel_nehalem_event_constraints; x86_pmu->pebs_constraints = intel_nehalem_pebs_event_constraints; x86_pmu->enable_all = intel_pmu_nhm_enable_all; x86_pmu->extra_regs = intel_nehalem_extra_regs;
Quoted 9 lines
Quoted 6 lines
Quoted 2 lines
if (fake_pmu) return;It looks similar as the one I shared above, the difference is that more things (e.g. constraints) are assigned to
x86_fake_pmu.
I'm not sure about the logic behind it (still look like a workaround).The fake
x86_pmuwill include all the supported features in host. If you want to check other features in future, it would be useful.
OK, I'll think more about if we could have a cleaner way to factor out this.
Best,
Wei
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
In reply to Wei WangQuoted 6 lines · Wei Wang
The lbr stack is architecturally specific, for example, SKX has 32 lbr stack entries while HSW has 16 entries, so a HSW guest running on a SKX machine may not get accurate perf results. Currently, we forbid the guest lbr enabling when the guest and host see different lbr stack entries.
How do you handle live migration?
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 7 lines · Jim Mattson
Quoted 5 lines · Wei Wang
The lbr stack is architecturally specific, for example, SKX has 32 lbr stack entries while HSW has 16 entries, so a HSW guest running on a SKX machine may not get accurate perf results. Currently, we forbid the guest lbr enabling when the guest and host see different lbr stack entries.
How do you handle live migration?
This feature is gated by the QEMU "lbr=true" option. So if the lbr fails to work on the destination machine, the destination side QEMU wouldn't be able to boot, and migration will not happen.
Best,
Wei
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 8 lines · Wei Wang
Quoted 6 lines · Jim Mattson
Quoted 5 lines · Wei Wang
The lbr stack is architecturally specific, for example, SKX has 32 lbr stack entries while HSW has 16 entries, so a HSW guest running on a SKX machine may not get accurate perf results. Currently, we forbid the guest lbr enabling when the guest and host see different lbr stack entries.
Quoted 6 lines
Quoted 1 line
How do you handle live migration?
This feature is gated by the QEMU "lbr=true" option. So if the lbr fails to work on the destination machine, the destination side QEMU wouldn't be able to boot, and migration will not happen.
Yes, but then what happens?
Fast forward to, say, 2021. You're decommissioning all Broadwell servers in your data center. You have to migrate the running VMs off of those Broadwell systems onto newer hardware. But, with the current implementation, the migration cannot happen. So, what do you do? I suppose you just never enable the feature in the first place. Right?
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 7 lines
Yes, but then what happens?
Fast forward to, say, 2021. You're decommissioning all Broadwell servers in your data center. You have to migrate the running VMs off of those Broadwell systems onto newer hardware. But, with the current implementation, the migration cannot happen. So, what do you do? I suppose you just never enable the feature in the first place. Right?
There would in theory ways to handle this.
LBRs are normally not required for running correctly, they're not like instructions, so it would be actually quite reasonable to just return 0 and ignore writes for incompatible machines for them. Your profilers might return some bogus data, but that is normally acceptable.
In some cases it might be also possible to emulate LBRs of different types, but I don't think it would be worth the effort.
Yes, but the patches don't do this, so right now you should only enable it when all systems in your migration pool have compatible LBRs.
-Andi
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
In reply to Jim MattsonQuoted 13 lines · Jim Mattson
Quoted 7 lines · Wei Wang
Quoted 6 lines · Jim Mattson
Quoted 5 lines · Wei Wang
The lbr stack is architecturally specific, for example, SKX has 32 lbr stack entries while HSW has 16 entries, so a HSW guest running on a SKX machine may not get accurate perf results. Currently, we forbid the guest lbr enabling when the guest and host see different lbr stack entries.
Quoted 5 lines
Quoted 1 line
How do you handle live migration?
This feature is gated by the QEMU "lbr=true" option. So if the lbr fails to work on the destination machine, the destination side QEMU wouldn't be able to boot, and migration will not happen.
Quoted 7 lines
Yes, but then what happens?
Fast forward to, say, 2021. You're decommissioning all Broadwell servers in your data center. You have to migrate the running VMs off of those Broadwell systems onto newer hardware. But, with the current implementation, the migration cannot happen. So, what do you do? I suppose you just never enable the feature in the first place. Right?
I'm not sure if that's the way people would do with their data centers. What would be the point of decommissioning all the BDW machines when there are important BDW VMs running?
The "lbr=true" option can also be disabled via QMP, which will disable the kvm side lbr support. So if you really want to deal with the above case, you could first disable the lbr feature on the source side, and then boot the destination side QEMU without "lbr=true". The lbr feature will not be available to use by the guest at the time you decide to migrate the guest to a non-compatible physical machine.
The point of this patch is: If we couldn't offer our users accurate lbr results, we'd better to have the feature disabled rather than offering wrong results to confuse them.
Best,
Wei
Re: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 11 lines · Wei Wang
Quoted 5 lines · Jim Mattson
Fast forward to, say, 2021. You're decommissioning all Broadwell servers in your data center. You have to migrate the running VMs off of those Broadwell systems onto newer hardware. But, with the current implementation, the migration cannot happen. So, what do you do? I suppose you just never enable the feature in the first place. Right?
I'm not sure if that's the way people would do with their data centers. What would be the point of decommissioning all the BDW machines when there are important BDW VMs running?
TCO increases as hardware ages, while the TCO for each successive generation of hardware tends to be lower than its predecessor. Thus, the point of decommissioning all BDW hosts that are beyond their useful service life is to save money. Our assumption for Google Cloud is that we will always be able to emulate older Intel processors on newer Intel processors, so the running BDW VMs should not be affected by the decommissioning of BDW hardware. Obviously, that means that we won't offer features that don't have a forward migration story, such as this one.
Yes, someday Intel will drop support for some feature that we currently offer (like MPX, perhaps), and that will cause us some grief.
RE: [PATCH v4 04/10] KVM/x86: intel_pmu_lbr_enable
Quoted 22 lines · Jim Mattson
Quoted 11 lines · Wei Wang
Quoted 5 lines · Jim Mattson
Fast forward to, say, 2021. You're decommissioning all Broadwell servers in your data center. You have to migrate the running VMs off of those Broadwell systems onto newer hardware. But, with the current implementation, the migration cannot happen. So, what do you do? I suppose you just never enable the feature in the first place. Right?
I'm not sure if that's the way people would do with their data centers. What would be the point of decommissioning all the BDW machines when there are important BDW VMs running?
TCO increases as hardware ages, while the TCO for each successive generation of hardware tends to be lower than its predecessor. Thus, the point of decommissioning all BDW hosts that are beyond their useful service life is to save money. Our assumption for Google Cloud is that we will always be able to emulate older Intel processors on newer Intel processors, so the running BDW VMs should not be affected by the decommissioning of BDW hardware. Obviously, that means that we won't offer features that don't have a forward migration story, such as this one.
Quoted 2 lines
Yes, someday Intel will drop support for some feature that we currently offer (like MPX, perhaps), and that will cause us some grief.
This sounds like a pretty good opportunity to convince your customers to upgrade their VMs :)
So the solution to your above problem I have in mind currently is:
- expect QEMU's support to upgrade VMs (e.g. BDW to SKL)
- just disable the non-compatible features for non-upgraded VMs (this could be in your SLA)
Anyway, I think it would be good to get this feature online first, and then re-visit that future concern.
Best,
Wei
PATCH v4 5/10 KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
In reply to Wei WangBits [0, 5] of MSR_IA32_PERF_CAPABILITIES tell about the format of the addresses stored in the LBR stack. Expose those bits to the guest when the guest lbr feature is enabled.
--- arch/x86/include/asm/perf_event.h | 2 ++ arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/vmx.c | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-)
arch/x86/include/asm/perf_event.h +2 -0
@@ -87,6 +87,8 @@#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6#define ARCH_PERFMON_EVENTS_COUNT 7 +#define X86_PERF_CAP_MASK_LBR_FMT 0x3f +/* * Intel "Architectural Performance Monitoring" CPUID * detection/enumeration details:
arch/x86/kvm/cpuid.c +1 -1
@@ -365,7 +365,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,F (XMM3 ) |F (PCLMULQDQ ) |0 /* DTES64, MONITOR */ |0 /* DS-CPL, VMX, SMX, EST */ |0 /* TM2 */ |F (SSSE3 ) |0 /* CNXT-ID */ |0 /* Reserved */ | -F (FMA ) |F (CX16 ) |0 /* xTPR Update, PDCM */ | +F (FMA ) |F (CX16 ) |0 /* xTPR Update*/ |F (PDCM ) |F (PCID ) |0 /* Reserved, DCA */ |F (XMM4_1 ) |F (XMM4_2 ) |F (X2APIC ) |F (MOVBE ) |F (POPCNT ) | 0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) |
arch/x86/kvm/vmx.c +9 -0
@@ -4161,6 +4161,13 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)return 1 ; msr_info->data = vcpu->arch.ia32_xss;break ; +case MSR_IA32_PERF_CAPABILITIES : +if (!boot_cpu_has (X86_FEATURE_PDCM )) +return 1 ; + msr_info->data =native_read_msr (MSR_IA32_PERF_CAPABILITIES ); +if (vcpu->kvm->arch.lbr_in_guest) + msr_info->data &=X86_PERF_CAP_MASK_LBR_FMT ; +break ;case MSR_TSC_AUX :if (!msr_info->host_initiated && !guest_cpuid_has (vcpu,X86_FEATURE_RDTSCP ))
@@ -4343,6 +4350,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else clear_atomic_switch_msr (vmx,MSR_IA32_XSS );break ; +case MSR_IA32_PERF_CAPABILITIES : +return 1 ;/* RO MSR */ case MSR_TSC_AUX :if (!msr_info->host_initiated && !guest_cpuid_has (vcpu,X86_FEATURE_RDTSCP ))
Signature · 1 line
2.7.4
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 45 lines · Wei Wang
Bits [0, 5] of
MSR_IA32_PERF_CAPABILITIEStell about the format of the addresses stored in the LBR stack. Expose those bits to the guest when the guest lbr feature is enabled.Signed-off-by Wei Wang <[email protected]>Cc Paolo Bonzini <[email protected]>Cc Andi Kleen <[email protected]>--- arch/x86/include/asm/perf_event.h | 2 ++ arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/vmx.c | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-)arch/x86/include/asm/perf_event.h +2
-0@@ -87,6 +87,8 @@#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6#define ARCH_PERFMON_EVENTS_COUNT 7 +#define X86_PERF_CAP_MASK_LBR_FMT 0x3f +/* * Intel "Architectural Performance Monitoring" CPUID * detection/enumeration details: arch/x86/kvm/cpuid.c +1
-1@@ -365,7 +365,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,F (XMM3 ) |F (PCLMULQDQ ) |0 /* DTES64, MONITOR */ |0 /* DS-CPL, VMX, SMX, EST */ |0 /* TM2 */ |F (SSSE3 ) |0 /* CNXT-ID */ |0 /* Reserved */ | -F (FMA ) |F (CX16 ) |0 /* xTPR Update, PDCM */ | +F (FMA ) |F (CX16 ) |0 /* xTPR Update*/ |F (PDCM ) |F (PCID ) |0 /* Reserved, DCA */ |F (XMM4_1 ) |F (XMM4_2 ) |F (X2APIC ) |F (MOVBE ) |F (POPCNT ) | 0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) |arch/x86/kvm/vmx.c +0
-0
arch/x86/kvm/vmx.c static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4167
Quoted 7 lines
arch/x86/kvm/vmx.c +4
-0@@ -4161,6 +4161,13 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)return 1 ; msr_info->data = vcpu->arch.ia32_xss;break ; +case MSR_IA32_PERF_CAPABILITIES : +if (!boot_cpu_has (X86_FEATURE_PDCM )) +return 1 ; + msr_info->data =native_read_msr (MSR_IA32_PERF_CAPABILITIES );
Since this isn't guarded by vcpu->kvm->arch.lbr_in_guest, it breaks backwards compatibility, doesn't it?
Quoted 18 lines
arch/x86/kvm/vmx.c +5
-1+if (vcpu->kvm->arch.lbr_in_guest) + msr_info->data &=X86_PERF_CAP_MASK_LBR_FMT ; +break ;case MSR_TSC_AUX :if (!msr_info->host_initiated && !guest_cpuid_has (vcpu,X86_FEATURE_RDTSCP ))@@ -4343,6 +4350,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)else clear_atomic_switch_msr (vmx,MSR_IA32_XSS );break ; +case MSR_IA32_PERF_CAPABILITIES : +return 1 ;/* RO MSR */ case MSR_TSC_AUX :if (!msr_info->host_initiated && !guest_cpuid_has (vcpu,X86_FEATURE_RDTSCP )) --2.7.4
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 46 lines · Jim Mattson
Quoted 45 lines · Wei Wang
Bits [0, 5] of
MSR_IA32_PERF_CAPABILITIEStell about the format of the addresses stored in the LBR stack. Expose those bits to the guest when the guest lbr feature is enabled.Signed-off-by Wei Wang <[email protected]>Cc Paolo Bonzini <[email protected]>Cc Andi Kleen <[email protected]>--- arch/x86/include/asm/perf_event.h | 2 ++ arch/x86/kvm/cpuid.c | 2 +- arch/x86/kvm/vmx.c | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-)arch/x86/include/asm/perf_event.h +2
-0@@ -87,6 +87,8 @@#define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6#define ARCH_PERFMON_EVENTS_COUNT 7 +#define X86_PERF_CAP_MASK_LBR_FMT 0x3f +/* * Intel "Architectural Performance Monitoring" CPUID * detection/enumeration details: arch/x86/kvm/cpuid.c +1
-1@@ -365,7 +365,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,F (XMM3 ) |F (PCLMULQDQ ) |0 /* DTES64, MONITOR */ |0 /* DS-CPL, VMX, SMX, EST */ |0 /* TM2 */ |F (SSSE3 ) |0 /* CNXT-ID */ |0 /* Reserved */ | -F (FMA ) |F (CX16 ) |0 /* xTPR Update, PDCM */ | +F (FMA ) |F (CX16 ) |0 /* xTPR Update*/ |F (PDCM ) |F (PCID ) |0 /* Reserved, DCA */ |F (XMM4_1 ) |F (XMM4_2 ) |F (X2APIC ) |F (MOVBE ) |F (POPCNT ) | 0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) |arch/x86/kvm/vmx.c +0
-0@@ -4161,6 +4161,13 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)return 1 ;
Quoted 8 lines
arch/x86/kvm/vmx.c static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) · line 4167
Quoted 6 lines
arch/x86/kvm/vmx.c +4
-0msr_info->data = vcpu->arch.ia32_xss;break ; +case MSR_IA32_PERF_CAPABILITIES : +if (!boot_cpu_has (X86_FEATURE_PDCM )) +return 1 ; + msr_info->data =native_read_msr (MSR_IA32_PERF_CAPABILITIES );Since this isn't guarded by
vcpu->kvm->arch.lbr_in_guest, it breaks backwards compatibility, doesn't it?
Right, thanks. Probably better to change it to below:
msr_info->data = 0;
data = native_read_msr(MSR_IA32_PERF_CAPABILITIES); if (vcpu->kvm->arch.lbr_in_guest)
msr_info->data |= (data & X86_PERF_CAP_MASK_LBR_FMT);
Best,
Wei
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 7 lines · Wei Wang
Right, thanks. Probably better to change it to below:
msr_info->data= 0;
data =native_read_msr(MSR_IA32_PERF_CAPABILITIES); if (vcpu->kvm->arch.lbr_in_guest)msr_info->data |= (data & X86_PERF_CAP_MASK_LBR_FMT);
This still breaks backwards compatibility. Returning 0 and raising #GP are not the same.
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 11 lines · Jim Mattson
Quoted 7 lines · Wei Wang
Right, thanks. Probably better to change it to below:
msr_info->data= 0;
data =native_read_msr(MSR_IA32_PERF_CAPABILITIES); if (vcpu->kvm->arch.lbr_in_guest)msr_info->data |= (data & X86_PERF_CAP_MASK_LBR_FMT);This still breaks backwards compatibility. Returning 0 and raising #GP are not the same.
I'm not sure about raising GP# in this case.
This PERF_CAP msr contains more things than the lbr format. For example, a guest with lbr=false option could read it to get PEBS_FMT, which is PERF_CAP[11:8]. We should offer those bits in this case.
When lbr=false, the lbr feature is not usable by the guest, so I think whatever value (0 or other value) of the LBR_FMT bits that we give to the guest might not be important.
Best,
Wei
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 16 lines · Wei Wang
Quoted 11 lines · Jim Mattson
Quoted 7 lines · Wei Wang
Right, thanks. Probably better to change it to below:
msr_info->data= 0;
data =native_read_msr(MSR_IA32_PERF_CAPABILITIES); if (vcpu->kvm->arch.lbr_in_guest)msr_info->data |= (data & X86_PERF_CAP_MASK_LBR_FMT);This still breaks backwards compatibility. Returning 0 and raising #GP are not the same.
I'm not sure about raising GP# in this case.
Quoted 7 lines
This
PERF_CAPmsr contains more things than the lbr format. For example, a guest with lbr=false option could read it to getPEBS_FMT, which is PERF_CAP[11:8]. We should offer those bits in this case.When lbr=false, the lbr feature is not usable by the guest, so I think whatever value (0 or other value) of the
LBR_FMTbits that we give to the guest might not be important.
The issue is compatibility. Prior to your change, reading this MSR from a VM would raise #GP. After your change, it won't. That means that if you have a VM migrating between hosts with kernel versions before and after this change, the results will be inconsistent. In the forward migration path, RDMSR will first raise #GP, and later will return 0. In the backward migration path, RDMSR will first return 0, and later it will raise #GP.
To avoid these inconsistencies, the new MSR behavior should be explicitly enabled by an opt-in ioctl from userspace (not necessarily the same ioctl that enables LBR).
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 4 lines
The issue is compatibility. Prior to your change, reading this MSR from a VM would raise #GP. After your change, it won't. That means that if you have a VM migrating between hosts with kernel versions before and after this change, the results will be inconsistent. In the
No it will not be. All Linux kernel uses of this MSR are guarded by a CPUID check.
-Andi
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 8 lines · Andi Kleen
Quoted 5 lines
The issue is compatibility. Prior to your change, reading this MSR from a VM would raise #GP. After your change, it won't. That means that if you have a VM migrating between hosts with kernel versions before and after this change, the results will be inconsistent. In the
No it will not be. All Linux kernel uses of this MSR are guarded by a CPUID check.
Linux usage is irrelevant to the architected behavior of the virtual CPU. According to volume 4 of the SDM, this MSR is only supported when CPUID.01H:ECX.PDCM [bit 15] is set. Therefore, kvm should raise #GP whenever a guest tries to read this MSR and the guest's CPUID.01H:ECX.PDCM [bit 15] is clear.
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 7 lines · Jim Mattson
Quoted 6 lines · Andi Kleen
Quoted 5 lines
The issue is compatibility. Prior to your change, reading this MSR from a VM would raise #GP. After your change, it won't. That means that if you have a VM migrating between hosts with kernel versions before and after this change, the results will be inconsistent. In the
Quoted 8 lines
Quoted 2 lines
No it will not be. All Linux kernel uses of this MSR are guarded by a CPUID check.
Linux usage is irrelevant to the architected behavior of the virtual CPU. According to volume 4 of the SDM, this MSR is only supported when CPUID.01H:ECX.PDCM [bit 15] is set. Therefore, kvm should raise #GP whenever a guest tries to read this MSR and the guest's CPUID.01H:ECX.PDCM [bit 15] is clear.
That's not general practice in KVM. There are lots of MSRs that don't fault even if their CPUID doesn't support them.
It's also not generally true for instructions, where it is even impossible.
You could argue it should be done for MSRs, but that would be a much larger patch for lots of MSRs. It seems pointless to single out this particular one.
In practice I doubt it will make any difference for real software either way.
-Andi
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 12 lines · Andi Kleen
Quoted 10 lines · Jim Mattson
Quoted 8 lines · Andi Kleen
Quoted 5 lines
The issue is compatibility. Prior to your change, reading this MSR from a VM would raise #GP. After your change, it won't. That means that if you have a VM migrating between hosts with kernel versions before and after this change, the results will be inconsistent. In the
No it will not be. All Linux kernel uses of this MSR are guarded by a CPUID check.
Quoted 8 lines
Quoted 5 lines
Linux usage is irrelevant to the architected behavior of the virtual CPU. According to volume 4 of the SDM, this MSR is only supported when CPUID.01H:ECX.PDCM [bit 15] is set. Therefore, kvm should raise #GP whenever a guest tries to read this MSR and the guest's CPUID.01H:ECX.PDCM [bit 15] is clear.
That's not general practice in KVM. There are lots of MSRs that don't fault even if their CPUID doesn't support them.
KVM doesn't really have a "general practice" in this regard. True, there are lots of MSRs that don't fault even if unsupported. But there are quite a few that do fault if unsupported. On the Intel side, MSR_IA32_SPEC_CTRL, MSR_IA32_ARCH_CAPABILITIES, MSR_IA32_BNDCFGS, and MSR_TSC_AUX all check for the corresponding capabilities in guest CPUID. In the "common" code, MSR_IA32_TSC_ADJUST, MSR_AMD64_OSVW_ID_LENGTH, and MSR_AMD64_OSVW_STATUS all check for the corresponding capabilities in guest CPUID.
Quoted 2 lines
It's also not generally true for instructions, where it is even impossible.
Yes, sometimes it is impossible to #UD for instructions that are supported on the host but not in the guest. However, sometimes it is possible, and kvm sometimes does enforce this. Some examples that come to mind are RDTSCP and INVPCID. In fact, kvm goes so far as to require that the guest CPUID must enumerate PCID support in order to enumerate INVPCID support, and INVPCID will raise #UD unless both capabilities are enumerated!
Quoted 3 lines
You could argue it should be done for MSRs, but that would be a much larger patch for lots of MSRs. It seems pointless to single out this particular one.
Past sloppiness isn't really a compelling argument for continued sloppiness going forward. And there are existing MSRs that do the appropriate checks, so I'm not singling this one out.
Quoted 2 lines
In practice I doubt it will make any difference for real software either way.
Perhaps, but when the correct behavior is so easy to implement, why not just do it right in the first place?
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
In reply to Jim MattsonQuoted 5 lines · Jim Mattson
Quoted 4 lines · Andi Kleen
Quoted 4 lines
The issue is compatibility. Prior to your change, reading this MSR from a VM would raise #GP. After your change, it won't. That means that if you have a VM migrating between hosts with kernel versions before and after this change, the results will be inconsistent. In the
Quoted 8 lines
Quoted 2 lines
No it will not be. All Linux kernel uses of this MSR are guarded by a CPUID check.
Linux usage is irrelevant to the architected behavior of the virtual CPU. According to volume 4 of the SDM, this MSR is only supported when CPUID.01H:ECX.PDCM [bit 15] is set. Therefore, kvm should raise #GP whenever a guest tries to read this MSR and the guest's CPUID.01H:ECX.PDCM [bit 15] is clear.
Probably one more check would be better:
if (!boot_cpu_has(X86_FEATURE_PDCM) ||
!guest_cpuid_has(vcpu, X86_FEATURE_PDCM))
return 1;(host isn't expected to read this MSR when PDCM is not supported by the guest, so don't have "!msr_info->host_initiate" added to above)
Best,
Wei
Re: [PATCH v4 05/10] KVM/x86: expose MSR_IA32_PERF_CAPABILITIES to the guest
Quoted 16 lines · Wei Wang
Quoted 5 lines · Jim Mattson
Quoted 4 lines · Andi Kleen
Quoted 4 lines
The issue is compatibility. Prior to your change, reading this MSR from a VM would raise #GP. After your change, it won't. That means that if you have a VM migrating between hosts with kernel versions before and after this change, the results will be inconsistent. In the
Quoted 8 lines
Quoted 2 lines
No it will not be. All Linux kernel uses of this MSR are guarded by a CPUID check.
Linux usage is irrelevant to the architected behavior of the virtual CPU. According to volume 4 of the SDM, this MSR is only supported when CPUID.01H:ECX.PDCM [bit 15] is set. Therefore, kvm should raise #GP whenever a guest tries to read this MSR and the guest's CPUID.01H:ECX.PDCM [bit 15] is clear.
Quoted 5 lines
Probably one more check would be better:
if (!boot_cpu_has(X86_FEATURE_PDCM) ||
!guest_cpuid_has(vcpu, X86_FEATURE_PDCM)) return 1;
Thanks for that change!
Quoted 2 lines
(host isn't expected to read this MSR when PDCM is not supported by the guest, so don't have "!msr_info->host_initiate" added to above)
In keeping with commit 44883f01fe6ae ("KVM: x86: ensure all MSRs can always be KVM_GET/SET_MSR'd"), I think the host_initiated check should be added.
PATCH v4 6/10 perf/x86: no counter allocation support
In reply to Wei WangIn some cases, an event may be created without needing a counter allocation. For example, an lbr event may be created by the host only to help save/restore the lbr stack on the vCPU context switching.
This patch adds a "no_counter" attr boolean to let the callers explicitly tell the perf core that no counter is needed.
--- arch/x86/events/core.c | 12 ++++++++++++ include/linux/perf_event.h | 5 +++++ include/uapi/linux/perf_event.h | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-)
arch/x86/events/core.c +12 -0
@@ -410,6 +410,9 @@ int x86_setup_perfctr(struct perf_event *event)struct hw_perf_event *hwc = &event->hw;u64 config; +if (is_no_counter_event (event)) +return 0 ; +if (!is_sampling_event (event)) { hwc->sample_period = x86_pmu.max_period; hwc->last_period = hwc->sample_period;
@@ -1209,6 +1212,12 @@ static int x86_pmu_add(struct perf_event *event, int flags) hwc = &event->hw; n0 = cpuc->n_events; + +if (is_no_counter_event (event)) { + n = n0; + goto done_collect; + } + ret = n =collect_events (cpuc, event, false);if (ret <0 ) goto out;
@@ -1387,6 +1396,9 @@ static void x86_pmu_del(struct perf_event *event, int flags)if (cpuc->txn_flags &PERF_PMU_TXN_ADD ) goto do_del; +if (is_no_counter_event (event)) + goto do_del; +/* * Not a TXN, therefore cleanup properly. */
include/linux/perf_event.h +5 -0
@@ -1009,6 +1009,11 @@ static inline bool is_sampling_event(struct perf_event *event)return event->attr.sample_period !=0 ; } +static inline bool is_no_counter_event (struct perf_event *event) +{ +return event->attr.no_counter; +} +/* * Return 1 for a software event, 0 for a hardware event */
include/uapi/linux/perf_event.h +2 -1
@@ -372,7 +372,8 @@ struct perf_event_attr { context_switch : 1, /* context switch data */ write_backward : 1, /* Write ring buffer from end to beginning */ namespaces : 1, /* include namespaces data */ - __reserved_1 : 35; + no_counter : 1, /* no counter allocation */ + __reserved_1 : 34;union {__u32 wakeup_events;/* wakeup every n events */
Signature · 1 line
2.7.4
PATCH v4 7/10 KVM/x86/vPMU: Add APIs to support host save/restore the guest lbr stack
In reply to Wei WangFrom: Like Xu <[email protected]>
This patch adds support to enable/disable the host side save/restore for the guest lbr stack on vCPU switching. To enable that, the host creates a perf event for the vCPU, and the event attributes are set to the user callstack mode lbr so that all the conditions are meet in the host perf subsystem to save the lbr stack on task switching.
The host side lbr perf event are created only for the purpose of saving and restoring the lbr stack. There is no need to enable the lbr functionality for this perf event, because the feature is essentially used in the vCPU. So use "no_counter=true" to have the perf core not allocate a counter for this event.
The vcpu_lbr field is added to cpuc, to indicate if the lbr perf event is used by the vCPU only for context switching. When the perf subsystem handles this event (e.g. lbr enable or read lbr stack on PMI) and finds it's non-zero, it simply returns.
--- arch/x86/events/intel/lbr.c | 14 +++++++-- arch/x86/events/perf_event.h | 1 + arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/pmu.h | 3 ++ arch/x86/kvm/pmu_intel.c | 66 +++++++++++++++++++++++++++++++++++++++++ include/linux/perf_event.h | 7 +++++ kernel/events/core.c | 7 ----- 7 files changed, 89 insertions(+), 10 deletions(-)
arch/x86/events/intel/lbr.c +11 -3
@@ -462,6 +462,10 @@ void intel_pmu_lbr_add(struct perf_event *event)if (!x86_pmu.lbr_nr)return ; +if (is_kernel_event (event) && event->attr.exclude_guest && + (current->flags &PF_VCPU )) + cpuc->vcpu_lbr =1 ; + cpuc->br_sel = event->hw.branch_reg.reg;if (branch_user_callstack (cpuc->br_sel) && event->ctx->task_ctx_data) {
@@ -507,6 +511,10 @@ void intel_pmu_lbr_del(struct perf_event *event) task_ctx->lbr_callstack_users--; } +if (is_kernel_event (event) && event->attr.exclude_guest && + (current->flags &PF_VCPU )) + cpuc->vcpu_lbr =0 ; + cpuc->lbr_users--;WARN_ON_ONCE (cpuc->lbr_users <0 );perf_sched_cb_dec (event->ctx->pmu);
@@ -516,7 +524,7 @@ void intel_pmu_lbr_enable_all(bool pmi) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); -if (cpuc->lbr_users) +if (cpuc->lbr_users && !cpuc->vcpu_lbr)__intel_pmu_lbr_enable (pmi); }
@@ -524,7 +532,7 @@ void intel_pmu_lbr_disable_all(void) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); -if (cpuc->lbr_users) +if (cpuc->lbr_users && !cpuc->vcpu_lbr)__intel_pmu_lbr_disable (); }
@@ -658,7 +666,7 @@ void intel_pmu_lbr_read(void) {struct cpu_hw_events *cpuc =this_cpu_ptr (&cpu_hw_events); -if (!cpuc->lbr_users) +if (!cpuc->lbr_users || cpuc->vcpu_lbr)return ;if (x86_pmu.intel_cap.lbr_format ==LBR_FORMAT_32 )
arch/x86/events/perf_event.h +1 -0
@@ -210,6 +210,7 @@ struct cpu_hw_events {/* * Intel LBR bits */ +u8 vcpu_lbr;int lbr_users;struct perf_branch_stack lbr_stack;struct perf_branch_entry lbr_entries[MAX_LBR_ENTRIES ];
arch/x86/include/asm/kvm_host.h +1 -0
@@ -469,6 +469,7 @@ struct kvm_pmu {struct kvm_pmc fixed_counters[INTEL_PMC_MAX_FIXED ];struct irq_work irq_work;u64 reprogram_pmi; +struct perf_event *vcpu_lbr_event; };struct kvm_pmu_ops ;
arch/x86/kvm/pmu.h +3 -0
@@ -122,6 +122,9 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu);bool is_vmware_backdoor_pmc (u32 pmc_idx); +extern int intel_pmu_enable_save_guest_lbr (struct kvm_vcpu *vcpu); +extern void intel_pmu_disable_save_guest_lbr (struct kvm_vcpu *vcpu); +extern struct kvm_pmu_ops intel_pmu_ops;extern struct kvm_pmu_ops amd_pmu_ops;#endif /* __KVM_X86_PMU_H */
arch/x86/kvm/pmu_intel.c +66 -0
72 lines not on this page · raw message
include/linux/perf_event.h +7 -0
@@ -1014,6 +1014,13 @@ static inline bool is_no_counter_event(struct perf_event *event)return event->attr.no_counter; } +#define TASK_TOMBSTONE ((void *)-1L) + +static inline bool is_kernel_event (struct perf_event *event) +{ +return READ_ONCE (event->owner) ==TASK_TOMBSTONE ; +} +/* * Return 1 for a software event, 0 for a hardware event */
kernel/events/core.c +0 -7
@@ -165,13 +165,6 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx,raw_spin_unlock (&cpuctx->ctx.lock); } -#define TASK_TOMBSTONE ((void *)-1L) - -static bool is_kernel_event (struct perf_event *event) -{ -return READ_ONCE (event->owner) ==TASK_TOMBSTONE ; -} -/* * On task ctx scheduling... *
Signature · 1 line
2.7.4
PATCH v4 8/10 perf/x86: save/restore LBR_SELECT on vCPU switching
In reply to Wei WangThe vCPU lbr event relies on the host to save/restore all the lbr related MSRs. So add the LBR_SELECT save/restore to the related functions for the vCPU case.
--- arch/x86/events/intel/lbr.c | 7 +++++++ arch/x86/events/perf_event.h | 1 + 2 files changed, 8 insertions(+)
arch/x86/events/intel/lbr.c +7 -0
@@ -383,6 +383,9 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)wrmsrl (x86_pmu.lbr_tos, tos); task_ctx->lbr_stack_state =LBR_NONE ; + +if (cpuc->vcpu_lbr) +wrmsrl (MSR_LBR_SELECT , task_ctx->lbr_sel); }static void __intel_pmu_lbr_save (struct x86_perf_task_context *task_ctx)
@@ -409,6 +412,10 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)if (x86_pmu.intel_cap.lbr_format ==LBR_FORMAT_INFO )rdmsrl (MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]); } + +if (cpuc->vcpu_lbr) +rdmsrl (MSR_LBR_SELECT , task_ctx->lbr_sel); + task_ctx->valid_lbrs = i; task_ctx->tos = tos; task_ctx->lbr_stack_state =LBR_VALID ;
arch/x86/events/perf_event.h +1 -0
@@ -653,6 +653,7 @@ struct x86_perf_task_context {u64 lbr_from[MAX_LBR_ENTRIES ];u64 lbr_to[MAX_LBR_ENTRIES ];u64 lbr_info[MAX_LBR_ENTRIES ]; +u64 lbr_sel;int tos;int valid_lbrs;int lbr_callstack_users;
Signature · 1 line
2.7.4
PATCH v4 9/10 perf/x86: function to check lbr user callstack mode
In reply to Wei WangThis patch adds a function to check if the lbr_sel value has the user callstack mode set. The related LBR_* macros are moved to the perf_event.h as well.
--- arch/x86/events/intel/lbr.c | 38 ------------------------------- arch/x86/include/asm/perf_event.h | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 38 deletions(-)
arch/x86/events/intel/lbr.c +0 -38
@@ -27,44 +27,6 @@ static const enum { [LBR_FORMAT_EIP_FLAGS2] = LBR_EIP_FLAGS | LBR_TSX, }; -/* -* Intel LBR_SELECT bits -* Intel Vol3a, April 2011, Section 16.7 Table 16-10 -* -* Hardware branch filter (not available on all CPUs) -*/ -#define LBR_KERNEL_BIT 0/* do not capture at ring0 */ -#define LBR_USER_BIT 1/* do not capture at ring > 0 */ -#define LBR_JCC_BIT 2/* do not capture conditional branches */ -#define LBR_REL_CALL_BIT 3/* do not capture relative calls */ -#define LBR_IND_CALL_BIT 4/* do not capture indirect calls */ -#define LBR_RETURN_BIT 5/* do not capture near returns */ -#define LBR_IND_JMP_BIT 6/* do not capture indirect jumps */ -#define LBR_REL_JMP_BIT 7/* do not capture relative jumps */ -#define LBR_FAR_BIT 8/* do not capture far branches */ -#define LBR_CALL_STACK_BIT 9/* enable call stack */ - -/* -* Following bit only exists in Linux; we mask it out before writing it to -* the actual MSR. But it helps the constraint perf code to understand -* that this is a separate configuration. -*/ -#define LBR_NO_INFO_BIT 63/* don't read LBR_INFO. */ - -#define LBR_KERNEL (1 << LBR_KERNEL_BIT) -#define LBR_USER (1 << LBR_USER_BIT) -#define LBR_JCC (1 << LBR_JCC_BIT) -#define LBR_REL_CALL (1 << LBR_REL_CALL_BIT) -#define LBR_IND_CALL (1 << LBR_IND_CALL_BIT) -#define LBR_RETURN (1 << LBR_RETURN_BIT) -#define LBR_REL_JMP (1 << LBR_REL_JMP_BIT) -#define LBR_IND_JMP (1 << LBR_IND_JMP_BIT) -#define LBR_FAR (1 << LBR_FAR_BIT) -#define LBR_CALL_STACK (1 << LBR_CALL_STACK_BIT) -#define LBR_NO_INFO (1ULL << LBR_NO_INFO_BIT) - -#define LBR_PLM (LBR_KERNEL | LBR_USER) -#define LBR_SEL_MASK 0x3ff/* valid bits in LBR_SELECT */ #define LBR_NOT_SUPP -1/* LBR filter not supported */ #define LBR_IGN 0/* ignored */
arch/x86/include/asm/perf_event.h +48 -0
60 lines not on this page · raw message
Signature · 1 line
2.7.4
PATCH v4 10/10 KVM/x86/lbr: lazy save the guest lbr stack
In reply to Wei WangWhen the vCPU is scheduled in:
- if the lbr feature was used in the last vCPU time slice, set the lbr stack to be interceptible, so that the host can capture whether the lbr feature will be used in this time slice;
- if the lbr feature wasn't used in the last vCPU time slice, disable the vCPU support of the guest lbr switching.
Upon the first access to one of the lbr related MSRs (since the vCPU was scheduled in):
- record that the guest has used the lbr;
- create a host perf event to help save/restore the guest lbr stack if the guest uses the user callstack mode lbr stack;
- pass the stack through to the guest.
--- arch/x86/include/asm/kvm_host.h | 4 ++ arch/x86/kvm/pmu.h | 5 ++ arch/x86/kvm/vmx.c | 138 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+)
arch/x86/include/asm/kvm_host.h +4 -0
@@ -775,6 +775,10 @@ struct kvm_vcpu_arch {/* Flush the L1 Data cache for L1TF mitigation on VMENTER */ bool l1tf_flush_l1d; +/* Indicate if the guest is using lbr with the user callstack mode */ +bool lbr_user_callstack; +/* Indicate if the lbr msrs were accessed in this vCPU time slice */ +bool lbr_used; };struct kvm_lpage_info {
arch/x86/kvm/pmu.h +5 -0
@@ -103,6 +103,11 @@ static inline struct kvm_pmc *get_fixed_pmc(struct kvm_pmu *pmu, u32 msr)return NULL ; } +static inline bool intel_pmu_save_vcpu_lbr_enabled (struct kvm_vcpu *vcpu) +{ +return !!vcpu_to_pmu (vcpu)->vcpu_lbr_event; +} +void reprogram_gp_counter (struct kvm_pmc *pmc,u64 eventsel);void reprogram_fixed_counter (struct kvm_pmc *pmc,u8 ctrl,int fixed_idx);void reprogram_counter (struct kvm_pmu *pmu,int pmc_idx);
arch/x86/kvm/vmx.c +138 -0
174 lines not on this page · raw message
Signature · 1 line
2.7.4
Re: [PATCH v4 10/10] KVM/x86/lbr: lazy save the guest lbr stack
Thanks. This looks a lot better than the earlier versions.
Some more comments.
Quoted 6 lines · Wei Wang
When the vCPU is scheduled in:
- if the lbr feature was used in the last vCPU time slice, set the lbr stack to be interceptible, so that the host can capture whether the lbr feature will be used in this time slice;
- if the lbr feature wasn't used in the last vCPU time slice, disable the vCPU support of the guest lbr switching.
time slice is the time from exit to exit?
This might be rather short in some cases if the workload does a lot of exits (which I would expect PMU workloads to do) Would be better to use some explicit time check, or at least N exits.
Quoted 6 lines
Upon the first access to one of the lbr related MSRs (since the vCPU was scheduled in):
- record that the guest has used the lbr;
- create a host perf event to help save/restore the guest lbr stack if the guest uses the user callstack mode lbr stack;
This is a bit risky. It would be safer (but also more expensive) to always safe even for any guest LBR use independent of callstack.
Otherwise we might get into a situation where
a vCPU context switch inside the guest PMI will clear the LBRs before they can be read in the PMI, so some LBR samples will be fully or partially cleared. This would be user visible.
In theory could try to detect if the guest is inside a PMI and save/restore then, but that would likely be complicated. I would save/restore for all cases.
arch/x86/kvm/vmx.c static bool nested_vmx_is_page_fault_vmexit(struct vmcs12 *vmcs12, · line 1315
Quoted 3 lines
arch/x86/kvm/vmx.c +3
-0+static void +__always_inline vmx_set_intercept_for_msr(unsigned long *msr_bitmap, u32 msr, +int type,bool value);
__always_inline should only be used if it's needed for functionality, or in a header.
The rest looks good.
-Andi
Re: [PATCH v4 10/10] KVM/x86/lbr: lazy save the guest lbr stack
Quoted 4 lines · Andi Kleen
Thanks. This looks a lot better than the earlier versions.
Some more comments.
Quoted 8 lines
Quoted 6 lines · Wei Wang
When the vCPU is scheduled in:
- if the lbr feature was used in the last vCPU time slice, set the lbr stack to be interceptible, so that the host can capture whether the lbr feature will be used in this time slice;
- if the lbr feature wasn't used in the last vCPU time slice, disable the vCPU support of the guest lbr switching.time slice is the time from exit to exit?
It's the vCPU thread time slice (e.g. 100ms).
Quoted 4 lines
This might be rather short in some cases if the workload does a lot of exits (which I would expect PMU workloads to do) Would be better to use some explicit time check, or at least N exits.
Did you mean further increasing the lazy time to multiple host thread scheduling time slices?
What would be a good value for "N"?
Quoted 8 lines
Quoted 5 lines
Upon the first access to one of the lbr related MSRs (since the vCPU was scheduled in):
- record that the guest has used the lbr;
- create a host perf event to help save/restore the guest lbr stack if the guest uses the user callstack mode lbr stack;This is a bit risky. It would be safer (but also more expensive) to always safe even for any guest LBR use independent of callstack.
Quoted 8 lines
Otherwise we might get into a situation where
a vCPU context switch inside the guest PMI will clear the LBRs before they can be read in the PMI, so some LBR samples will be fully or partially cleared. This would be user visible.In theory could try to detect if the guest is inside a PMI and save/restore then, but that would likely be complicated. I would save/restore for all cases.
Yes, it is easier to save for all the cases. But curious for the non-callstack mode, it's just ponit sampling functions (kind of speculative in some degree). Would rarely losing a few recordings important in that case?
Quoted 6 lines
arch/x86/kvm/vmx.c static bool nested_vmx_is_page_fault_vmexit(struct vmcs12 *vmcs12, · line 1315
Quoted 4 lines
arch/x86/kvm/vmx.c +3
-0+static void +__always_inline vmx_set_intercept_for_msr(unsigned long *msr_bitmap, u32 msr, +int type,bool value);
__always_inlineshould only be used if it's needed for functionality, or in a header.
Thanks, will fix it.
Best,
Wei
Re: [PATCH v4 10/10] KVM/x86/lbr: lazy save the guest lbr stack
Quoted 12 lines · Wei Wang
Quoted 11 lines · Andi Kleen
Thanks. This looks a lot better than the earlier versions.
Some more comments.
Quoted 6 lines · Wei Wang
When the vCPU is scheduled in:
- if the lbr feature was used in the last vCPU time slice, set the lbr stack to be interceptible, so that the host can capture whether the lbr feature will be used in this time slice;
- if the lbr feature wasn't used in the last vCPU time slice, disable the vCPU support of the guest lbr switching.
Quoted 3 lines
Quoted 1 line
time slice is the time from exit to exit?
It's the vCPU thread time slice (e.g. 100ms).
I don't think the time slices are that long, but ok.
Quoted 9 lines
Quoted 5 lines
This might be rather short in some cases if the workload does a lot of exits (which I would expect PMU workloads to do) Would be better to use some explicit time check, or at least N exits.
Did you mean further increasing the lazy time to multiple host thread scheduling time slices?
What would be a good value for "N"?
I'm not sure -- i think the goal would be to find a value that optimizes performance (or rather minimizes overhead). But perhaps if it's as you say the scheduler time slice it might be good enough as it is.
I guess it could be tuned later based on more experneice.
Quoted 11 lines
Quoted 5 lines
or partially cleared. This would be user visible.
In theory could try to detect if the guest is inside a PMI and save/restore then, but that would likely be complicated. I would save/restore for all cases.
Yes, it is easier to save for all the cases. But curious for the non-callstack
mode, it's just ponit sampling functions (kind of speculative in some degree).
Would rarely losing a few recordings important in that case?
In principle no for statistical samples, but I know some tools complain for bogus samples (e.g. autofdo will). Also with perf report --branch-history it will be definitely visible. I think it's easier to always safe now than to handle the user complaints about this later.
-Andi
Re: [PATCH v4 10/10] KVM/x86/lbr: lazy save the guest lbr stack II
In reply to Wei WangActually forgot one case.
In Arch Perfmon v4 the LBR freezing is also controlled through a GLOBAL_CTRL bit. I didn't see any code handling that bit?
-Andi
RE: [PATCH v4 10/10] KVM/x86/lbr: lazy save the guest lbr stack II
Quoted 5 lines · Andi Kleen
Actually forgot one case.
In Arch Perfmon v4 the LBR freezing is also controlled through a
GLOBAL_CTRLbit.
I didn't see any code handling that bit?
That GLOBAL_STATUS.LBR_FRZ bit hasn't been supported yet. I'll add that, thanks.
Best,
Wei