vPMU support for AMD system
RFC 1/1 vPMU support for AMD system
Hi Paolo and Gleb,
The attached file is a preliminary version of AMD vPMU support for KVM. Currently I am working on a formal patch set; but realized that there are some design choice to make (see below). I thought it is better to send it out now, asking for your comments before sending out patchset v1.
If you are OK with current approach, please let me know. Otherwise please share your suggestions/comments on the design choice (see suggestions below). I will send out split patch set soon.
Thanks,
-Wei
================
1. OBJECTIVE
To enable PMU for guest VMs running on AMD host. Currently only software events are supported for AMD guest VMs. This is useless to profile guest VM on AMD systems.
2. CURRENT DESIGN
The design is similar to existing vPMU support. Many data structures such as "struct kvm_pmc" and "struct kvm_pmu" are re-used for this design.
Original pmu.c code was designed with Intel PMU in mind. To avoid the confusion, the current design converts existing pmu.c into intel-pmu.c and create a similar code, named amd-pmu.c. PMU function calls in x86.c are then dispatched via function pointers (i.e. struct kvm_pmu_ops). The initial setup is done in kvm_pmu_arch_init().
3. STATUS
I have briefly tested using AMD machine and the profiling data seems to be fairly accurate. With that said, more tests are required especially on PMI and extensive HW perf events.
4. DESIGN QUESTIONS
The current design is described in (2). However it is not perfect, especially due to the code similarity between intel-pmu.c and amd-pmu.c.
I have other ideas listed below. Please review and give some suggestion:
(a) Merge intel-pmu.c and amd-pmu.c into pmu.c
* PMU will probe the architecture first before first usage;
* It will still use function pointers to dispatch global functions (e.g. kvm_pmu_reset);
* For static functions that are the same (e.g. pmc_is_gp), we will use the same copy;
* For static functions that are slightly different (e.g. global_idx_to_pmc), we will use a shared version with if-else statement, depending on Intel or AMD.
I think this approach is quite acceptable, except that there will be many if-else in the code. Not clean enough.
(b) Convert intel-pmu.c => vmx.c and convert amd-pmu.c => svm.c
* PMU function pointers will be created in kvm_x86_ops;
* The entry functions will be created inside vmx.c and svm.c respectively;
* There might be common functions defined in pmu.c.
This design is viable too. But to be honest, it is a bit messy compared with (a).
==========================
arch/x86/include/asm/kvm_host.h +30 -17
@@ -305,6 +305,12 @@ enum pmc_type { KVM_PMC_FIXED, }; +struct msr_data { +bool host_initiated; +u32 index; +u64 data; +}; +struct kvm_pmc {enum pmc_type type;u8 idx;
@@ -314,6 +320,27 @@ struct kvm_pmc {struct kvm_vcpu *vcpu; }; +/* mapping from event selection to PERF_TYPE_HAARDWARE events */ +struct kvm_event_hw_type_mapping { +u8 eventsel; +u8 unit_mask; +unsigned event_type; +bool inexact; +}; + +struct kvm_pmu_ops { +void (*pmu_cpuid_update)(struct kvm_vcpu *vcpu); +int (*pmu_read_pmc)(struct kvm_vcpu *vcpu,unsigned pmc,u64 *data); +int (*pmu_set_msr)(struct kvm_vcpu *vcpu,struct msr_data *msr_info); +int (*pmu_get_msr)(struct kvm_vcpu *vcpu,u32 index,u64 *data); +bool (*is_pmu_msr)(struct kvm_vcpu *vcpu,u32 msr); +void (*pmu_deliver_pmi)(struct kvm_vcpu *vcpu); +void (*pmu_handle_event)(struct kvm_vcpu *vcpu); +void (*pmu_reset)(struct kvm_vcpu *vcpu); +void (*pmu_init)(struct kvm_vcpu *vcpu); +void (*pmu_destroy)(struct kvm_vcpu *vcpu); +}; +struct kvm_pmu {unsigned nr_arch_gp_counters;unsigned nr_arch_fixed_counters;
@@ -654,12 +681,6 @@ struct kvm_vcpu_stat {struct x86_instruction_info ; -struct msr_data { -bool host_initiated; -u32 index; -u64 data; -}; -struct kvm_x86_ops {int (*cpu_has_kvm_support)(void );/* __init */ int (*disabled_by_bios)(void );/* __init */
@@ -780,6 +801,7 @@ struct kvm_arch_async_pf { };extern struct kvm_x86_ops *kvm_x86_ops; +extern struct kvm_pmu_ops *kvm_pmu_ops;static inline void adjust_tsc_offset_guest (struct kvm_vcpu *vcpu,s64 adjustment)
@@ -1063,15 +1085,6 @@ void kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err);int kvm_is_in_guest (void ); -void kvm_pmu_init (struct kvm_vcpu *vcpu); -void kvm_pmu_destroy (struct kvm_vcpu *vcpu); -void kvm_pmu_reset (struct kvm_vcpu *vcpu); -void kvm_pmu_cpuid_update (struct kvm_vcpu *vcpu); -bool kvm_pmu_msr (struct kvm_vcpu *vcpu,u32 msr); -int kvm_pmu_get_msr (struct kvm_vcpu *vcpu,u32 msr,u64 *data); -int kvm_pmu_set_msr (struct kvm_vcpu *vcpu,struct msr_data *msr_info); -int kvm_pmu_read_pmc (struct kvm_vcpu *vcpu,unsigned pmc,u64 *data); -void kvm_handle_pmu_event (struct kvm_vcpu *vcpu); -void kvm_deliver_pmi (struct kvm_vcpu *vcpu); - +extern struct kvm_pmu_ops intel_pmu_ops; +extern struct kvm_pmu_ops amd_pmu_ops;#endif /* _ASM_X86_KVM_HOST_H */
arch/x86/kvm/Makefile +1 -1
@@ -14,7 +14,7 @@ kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += $(KVM)/assigned-dev.o $(KVM)/iommu.o kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o kvm-y += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \ - i8254.o cpuid.o pmu.o + i8254.o cpuid.o intel-pmu.o amd-pmu.o kvm-intel-y += vmx.o kvm-amd-y += svm.o
arch/x86/kvm/amd-pmu.c new file +381 -0
381 lines not on this page · raw message
arch/x86/kvm/cpuid.c +1 -1
@@ -88,7 +88,7 @@ void kvm_update_cpuid(struct kvm_vcpu *vcpu)xstate_required_size (vcpu->arch.xcr0); } -kvm_pmu_cpuid_update (vcpu); + kvm_pmu_ops->pmu_cpuid_update (vcpu); }static int is_efer_nx (void )
arch/x86/kvm/intel-pmu.c new file +572 -0
572 lines not on this page · raw message
arch/x86/kvm/pmu.c deleted +0 -563
563 lines not on this page · raw message
arch/x86/kvm/x86.c +48 -29
177 lines not on this page · raw message
2014-09-30 21:07-0500, Wei Huang:
Quoted 13 lines
Hi Paolo and Gleb,
2. CURRENT DESIGN
The design is similar to existing vPMU support. Many data structures such as "structkvm_pmc" and "structkvm_pmu" are re-used for this design.Original
pmu.ccode was designed with Intel PMU in mind. To avoid the confusion, the current design converts existingpmu.cintointel-pmu.cand create a similar code, namedamd-pmu.c. PMU function calls inx86.care then dispatched via function pointers (i.e. structkvm_pmu_ops). The initial setup is done inkvm_pmu_arch_init().I have other ideas listed below. Please review and give some suggestion:
Quoted 9 lines
(a) Merge
intel-pmu.candamd-pmu.cintopmu.c
* PMU will probe the architecture first before first usage;
* It will still use function pointers to dispatch global functions (e.g.kvm_pmu_reset);
* For static functions that are the same (e.g.pmc_is_gp), we will use the same copy;
* For static functions that are slightly different (e.g.global_idx_to_pmc), we will use a shared version with if-else statement, depending on Intel or AMD.
(if-else forest is daunting.)
Quoted 6 lines
I think this approach is quite acceptable, except that there will be many if-else in the code. Not clean enough.
(b) Convert
intel-pmu.c=>vmx.cand convertamd-pmu.c=>svm.c
* PMU function pointers will be created inkvm_x86_ops;
* The entry functions will be created insidevmx.candsvm.crespectively;
I would be nicer to keep them in separate files and link to vmx/svm.
Quoted 4 lines
* There might be common functions defined in
pmu.c.This design is viable too. But to be honest, it is a bit messy compared with (a).
This makes sense as we will use only vmx+intel_pmu and svm+amd_pmu, so we'd have less code loaded in both cases.
I consider design (c) strictly better than the current one (2):
(c) keep {intel,amd}-pmu.c and introduce pmu.[hc] that joins duplicate functions and wraps kvm_pmu_ops
And if we decide to move VMX/SVM related code into their respective modules, we won't have to change callers.
Quoted 17 lines
(if-else forest is daunting.)
Quoted 6 lines
I think this approach is quite acceptable, except that there will be many if-else in the code. Not clean enough.
(b) Convert
intel-pmu.c=>vmx.cand convertamd-pmu.c=>svm.c
* PMU function pointers will be created inkvm_x86_ops;
* The entry functions will be created insidevmx.candsvm.crespectively;I would be nicer to keep them in separate files and link to vmx/svm.
Quoted 4 lines
* There might be common functions defined in
pmu.c.This design is viable too. But to be honest, it is a bit messy compared with (a).
Quoted 6 lines
This makes sense as we will use only vmx+intel_pmu and svm+amd_pmu, so we'd have less code loaded in both cases.
I consider design (c) strictly better than the current one (2):
(c) keep {intel,amd}-pmu.c and introduce pmu.[hc] that joins duplicate functions and wrapskvm_pmu_ops
Thanks for the suggestion. I will take this into consideration. Your suggestion is similar to existing svm.c/vmx.c/x86.c, which split distinct functions in vmx.c/svm.c; but in the meanwhile merging them in x86.c for common code.
Quoted 4 lines
And if we decide to move VMX/SVM related code into their respective modules, we won't have to change callers.
Yes.
Hi,
Quoted 11 lines · Wei Huang
Hi Paolo and Gleb,
The attached file is a preliminary version of AMD vPMU support for KVM. Currently I am working on a formal patch set; but realized that there are some design choice to make (see below). I thought it is better to send it out now, asking for your comments before sending out patchset v1.
If you are OK with current approach, please let me know. Otherwise please share your suggestions/comments on the design choice (see suggestions below). I will send out split patch set soon.
I am not very familiar with AMD PMU, but IIRC is lacks architectural PMU, so the first question that comes to my mind is:
arch/x86/kvm/amd-pmu.c line 29
Quoted 9 lines
arch/x86/kvm/amd-pmu.c new file +9
-0+static struct kvm_event_hw_type_mapping amd_event_mapping[] = { + [0 ] = {0x76 ,0x00 ,PERF_COUNT_HW_CPU_CYCLES }, + [1 ] = {0xc0 ,0x00 ,PERF_COUNT_HW_INSTRUCTIONS }, + [3 ] = {0x80 ,0x00 ,PERF_COUNT_HW_CACHE_REFERENCES }, + [4 ] = {0x81 ,0x00 ,PERF_COUNT_HW_CACHE_MISSES }, + [5 ] = {0xc4 ,0x00 ,PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, + [6 ] = {0xc5 ,0x00 ,PERF_COUNT_HW_BRANCH_MISSES }, +}; +
Are those evens count exactly same things on all AMD cpus?
--
Gleb.
This
Quoted 17 lines · Gleb Natapov
Hi,
Quoted 11 lines · Wei Huang
Hi Paolo and Gleb,
The attached file is a preliminary version of AMD vPMU support for KVM. Currently I am working on a formal patch set; but realized that there are some design choice to make (see below). I thought it is better to send it out now, asking for your comments before sending out patchset v1.
If you are OK with current approach, please let me know. Otherwise please share your suggestions/comments on the design choice (see suggestions below). I will send out split patch set soon.
I am not very familiar with AMD PMU, but IIRC is lacks architectural PMU, so the first question that comes to my mind is:
Quoted 10 lines
arch/x86/kvm/amd-pmu.c line 29
Quoted 9 lines
arch/x86/kvm/amd-pmu.c new file +9
-0+static struct kvm_event_hw_type_mapping amd_event_mapping[] = { + [0 ] = {0x76 ,0x00 ,PERF_COUNT_HW_CPU_CYCLES }, + [1 ] = {0xc0 ,0x00 ,PERF_COUNT_HW_INSTRUCTIONS }, + [3 ] = {0x80 ,0x00 ,PERF_COUNT_HW_CACHE_REFERENCES }, + [4 ] = {0x81 ,0x00 ,PERF_COUNT_HW_CACHE_MISSES }, + [5 ] = {0xc4 ,0x00 ,PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, + [6 ] = {0xc5 ,0x00 ,PERF_COUNT_HW_BRANCH_MISSES }, +}; +Are those evens count exactly same things on all AMD cpus?
These mappings were pulled off from Linux perf code. From the code and several AMD BKDGs I read, they were consistent across CPU families.
If there is no guaranteed consistency, I think we can fall back to raw perf counters. So this amd_event_mapping table can be removed.
-Wei
Quoted 5 lines
--
Gleb.