* [PATCH v8 0/3] KVM: perf: kvm events analysis tool
@ 2012-09-17 8:31 Dong Hao
2012-09-17 8:31 ` [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace Dong Hao
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: Dong Hao @ 2012-09-17 8:31 UTC (permalink / raw)
To: acme, dsahern, mtosatti, avi, mingo, linux-kernel, kvm
Cc: xiaoguangrong, runzhen
From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
Changelog:
the changes from Avi's comments:
- move the definition of x86 fault vector to asm/kvm.h
- drop the second patch which introduced new tracpoints
the changes from David's comments:
- use scnprintf instead of snprintf
- drop exclusive check for '-a' and '-p', after this, we should
append -a to track all guest, -p to track the specified guest
- improve the help usage
- fix a possible memory leak
- some cleanups
the changes from Andrew Jones's comments:
- move stat related code to util/stat.c
Thank you very much for your patience!
This patchset introduces a perf-based tool (perf kvm stat record/report)
which can analyze kvm events more smartly. Below is the presentation slice
on 2012 Japan LinuxCon:
http://events.linuxfoundation.org/images/stories/pdf/lcjp2012_guangrong.pdf
You can get more details from it. If any questions/comments, please feel free
to let us know.
This patchset is based on Arnaldo's git tree perf/core branch.
Usage:
- kvm stat
run a command and gather performance counter statistics, it is the alias of
perf stat
- trace kvm events:
perf kvm stat record, or, if other tracepoints are interesting as well, we
can append the events like this:
perf kvm stat record -e timer:* -a
If many guests are running, we can track the specified guest by using -p or
--pid. -a is used to track events generated by all guests.
- show the result:
perf kvm stat report
The output example is following:
# pgrep qemu
13005
13059
total 2 guests are running on the host
Then, track the guest whose pid is 13059:
# ./perf kvm stat record -p 13059
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.253 MB perf.data.guest (~11065 samples) ]
See the vmexit events:
# ./perf kvm stat report --event=vmexit
Analyze events for all VCPUs:
VM-EXIT Samples Samples% Time% Avg time
APIC_ACCESS 460 70.55% 0.01% 22.44us ( +- 1.75% )
HLT 93 14.26% 99.98% 832077.26us ( +- 10.42% )
EXTERNAL_INTERRUPT 64 9.82% 0.00% 35.35us ( +- 14.21% )
PENDING_INTERRUPT 24 3.68% 0.00% 9.29us ( +- 31.39% )
CR_ACCESS 7 1.07% 0.00% 8.12us ( +- 5.76% )
IO_INSTRUCTION 3 0.46% 0.00% 18.00us ( +- 11.79% )
EXCEPTION_NMI 1 0.15% 0.00% 5.83us ( +- -nan% )
Total Samples:652, Total events handled time:77396109.80us.
See the mmio events:
# ./perf kvm stat report --event=mmio
Analyze events for all VCPUs:
MMIO Access Samples Samples% Time% Avg time
0xfee00380:W 387 84.31% 79.28% 8.29us ( +- 3.32% )
0xfee00300:W 24 5.23% 9.96% 16.79us ( +- 1.97% )
0xfee00300:R 24 5.23% 7.83% 13.20us ( +- 3.00% )
0xfee00310:W 24 5.23% 2.93% 4.94us ( +- 3.84% )
Total Samples:459, Total events handled time:4044.59us.
See the ioport event:
# ./perf kvm stat report --event=ioport
Analyze events for all VCPUs:
IO Port Access Samples Samples% Time% Avg time
0xc050:POUT 3 100.00% 100.00% 13.75us ( +- 10.83% )
Total Samples:3, Total events handled time:41.26us.
And, --vcpu is used to track the specified vcpu and --key is used to sort the
result:
# ./perf kvm stat report --event=vmexit --vcpu=0 --key=time
Analyze events for VCPU 0:
VM-EXIT Samples Samples% Time% Avg time
HLT 27 13.85% 99.97% 405790.24us ( +- 12.70% )
EXTERNAL_INTERRUPT 13 6.67% 0.00% 27.94us ( +- 22.26% )
APIC_ACCESS 146 74.87% 0.03% 21.69us ( +- 2.91% )
IO_INSTRUCTION 2 1.03% 0.00% 17.77us ( +- 20.56% )
CR_ACCESS 2 1.03% 0.00% 8.55us ( +- 6.47% )
PENDING_INTERRUPT 5 2.56% 0.00% 6.27us ( +- 3.94% )
Total Samples:195, Total events handled time:10959950.90us.
Dong Hao (3):
KVM: x86: export svm/vmx exit code and vector code to userspace
perf: move stat related code to util/stat.c
KVM: perf: kvm events analysis tool
arch/x86/include/asm/kvm.h | 16 +
arch/x86/include/asm/kvm_host.h | 16 -
arch/x86/include/asm/svm.h | 205 +++++---
arch/x86/include/asm/vmx.h | 127 ++++--
arch/x86/kvm/trace.h | 89 ----
tools/perf/Documentation/perf-kvm.txt | 30 ++-
tools/perf/MANIFEST | 3 +
tools/perf/Makefile | 1 +
tools/perf/builtin-kvm.c | 840 ++++++++++++++++++++++++++++++++-
tools/perf/builtin-stat.c | 56 +---
tools/perf/util/header.c | 59 +++-
tools/perf/util/header.h | 1 +
tools/perf/util/stat.c | 57 +++
tools/perf/util/stat.h | 16 +
tools/perf/util/thread.h | 2 +
15 files changed, 1235 insertions(+), 283 deletions(-)
create mode 100644 tools/perf/util/stat.c
create mode 100644 tools/perf/util/stat.h
--
1.7.2.5
^ permalink raw reply [flat|nested] 14+ messages in thread* [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace 2012-09-17 8:31 [PATCH v8 0/3] KVM: perf: kvm events analysis tool Dong Hao @ 2012-09-17 8:31 ` Dong Hao 2012-09-17 14:58 ` Arnaldo Carvalho de Melo 2012-09-27 4:26 ` [tip:perf/core] KVM: x86: Export svm/ vmx " tip-bot for Xiao Guangrong 2012-09-17 8:31 ` [PATCH v8 2/3] perf: move stat related code to util/stat.c Dong Hao 2012-09-17 8:31 ` [PATCH v8 3/3] KVM: perf: kvm events analysis tool Dong Hao 2 siblings, 2 replies; 14+ messages in thread From: Dong Hao @ 2012-09-17 8:31 UTC (permalink / raw) To: acme, dsahern, mtosatti, avi, mingo, linux-kernel, kvm Cc: xiaoguangrong, runzhen From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Exporting KVM exit information to userspace to be consumed by perf. [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> --- arch/x86/include/asm/kvm.h | 16 +++ arch/x86/include/asm/kvm_host.h | 16 --- arch/x86/include/asm/svm.h | 205 +++++++++++++++++++++++++-------------- arch/x86/include/asm/vmx.h | 127 ++++++++++++++++-------- arch/x86/kvm/trace.h | 89 ----------------- 5 files changed, 230 insertions(+), 223 deletions(-) diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index 246617e..41e08cb 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -9,6 +9,22 @@ #include <linux/types.h> #include <linux/ioctl.h> +#define DE_VECTOR 0 +#define DB_VECTOR 1 +#define BP_VECTOR 3 +#define OF_VECTOR 4 +#define BR_VECTOR 5 +#define UD_VECTOR 6 +#define NM_VECTOR 7 +#define DF_VECTOR 8 +#define TS_VECTOR 10 +#define NP_VECTOR 11 +#define SS_VECTOR 12 +#define GP_VECTOR 13 +#define PF_VECTOR 14 +#define MF_VECTOR 16 +#define MC_VECTOR 18 + /* Select x86 specific features in <linux/kvm.h> */ #define __KVM_HAVE_PIT #define __KVM_HAVE_IOAPIC diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 09155d6..1eaa6b0 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -75,22 +75,6 @@ #define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1)) #define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE) -#define DE_VECTOR 0 -#define DB_VECTOR 1 -#define BP_VECTOR 3 -#define OF_VECTOR 4 -#define BR_VECTOR 5 -#define UD_VECTOR 6 -#define NM_VECTOR 7 -#define DF_VECTOR 8 -#define TS_VECTOR 10 -#define NP_VECTOR 11 -#define SS_VECTOR 12 -#define GP_VECTOR 13 -#define PF_VECTOR 14 -#define MF_VECTOR 16 -#define MC_VECTOR 18 - #define SELECTOR_TI_MASK (1 << 2) #define SELECTOR_RPL_MASK 0x03 diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index f2b83bc..cdf5674 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -1,6 +1,135 @@ #ifndef __SVM_H #define __SVM_H +#define SVM_EXIT_READ_CR0 0x000 +#define SVM_EXIT_READ_CR3 0x003 +#define SVM_EXIT_READ_CR4 0x004 +#define SVM_EXIT_READ_CR8 0x008 +#define SVM_EXIT_WRITE_CR0 0x010 +#define SVM_EXIT_WRITE_CR3 0x013 +#define SVM_EXIT_WRITE_CR4 0x014 +#define SVM_EXIT_WRITE_CR8 0x018 +#define SVM_EXIT_READ_DR0 0x020 +#define SVM_EXIT_READ_DR1 0x021 +#define SVM_EXIT_READ_DR2 0x022 +#define SVM_EXIT_READ_DR3 0x023 +#define SVM_EXIT_READ_DR4 0x024 +#define SVM_EXIT_READ_DR5 0x025 +#define SVM_EXIT_READ_DR6 0x026 +#define SVM_EXIT_READ_DR7 0x027 +#define SVM_EXIT_WRITE_DR0 0x030 +#define SVM_EXIT_WRITE_DR1 0x031 +#define SVM_EXIT_WRITE_DR2 0x032 +#define SVM_EXIT_WRITE_DR3 0x033 +#define SVM_EXIT_WRITE_DR4 0x034 +#define SVM_EXIT_WRITE_DR5 0x035 +#define SVM_EXIT_WRITE_DR6 0x036 +#define SVM_EXIT_WRITE_DR7 0x037 +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_INTR 0x060 +#define SVM_EXIT_NMI 0x061 +#define SVM_EXIT_SMI 0x062 +#define SVM_EXIT_INIT 0x063 +#define SVM_EXIT_VINTR 0x064 +#define SVM_EXIT_CR0_SEL_WRITE 0x065 +#define SVM_EXIT_IDTR_READ 0x066 +#define SVM_EXIT_GDTR_READ 0x067 +#define SVM_EXIT_LDTR_READ 0x068 +#define SVM_EXIT_TR_READ 0x069 +#define SVM_EXIT_IDTR_WRITE 0x06a +#define SVM_EXIT_GDTR_WRITE 0x06b +#define SVM_EXIT_LDTR_WRITE 0x06c +#define SVM_EXIT_TR_WRITE 0x06d +#define SVM_EXIT_RDTSC 0x06e +#define SVM_EXIT_RDPMC 0x06f +#define SVM_EXIT_PUSHF 0x070 +#define SVM_EXIT_POPF 0x071 +#define SVM_EXIT_CPUID 0x072 +#define SVM_EXIT_RSM 0x073 +#define SVM_EXIT_IRET 0x074 +#define SVM_EXIT_SWINT 0x075 +#define SVM_EXIT_INVD 0x076 +#define SVM_EXIT_PAUSE 0x077 +#define SVM_EXIT_HLT 0x078 +#define SVM_EXIT_INVLPG 0x079 +#define SVM_EXIT_INVLPGA 0x07a +#define SVM_EXIT_IOIO 0x07b +#define SVM_EXIT_MSR 0x07c +#define SVM_EXIT_TASK_SWITCH 0x07d +#define SVM_EXIT_FERR_FREEZE 0x07e +#define SVM_EXIT_SHUTDOWN 0x07f +#define SVM_EXIT_VMRUN 0x080 +#define SVM_EXIT_VMMCALL 0x081 +#define SVM_EXIT_VMLOAD 0x082 +#define SVM_EXIT_VMSAVE 0x083 +#define SVM_EXIT_STGI 0x084 +#define SVM_EXIT_CLGI 0x085 +#define SVM_EXIT_SKINIT 0x086 +#define SVM_EXIT_RDTSCP 0x087 +#define SVM_EXIT_ICEBP 0x088 +#define SVM_EXIT_WBINVD 0x089 +#define SVM_EXIT_MONITOR 0x08a +#define SVM_EXIT_MWAIT 0x08b +#define SVM_EXIT_MWAIT_COND 0x08c +#define SVM_EXIT_XSETBV 0x08d +#define SVM_EXIT_NPF 0x400 + +#define SVM_EXIT_ERR -1 + +#define SVM_EXIT_REASONS \ + { SVM_EXIT_READ_CR0, "read_cr0" }, \ + { SVM_EXIT_READ_CR3, "read_cr3" }, \ + { SVM_EXIT_READ_CR4, "read_cr4" }, \ + { SVM_EXIT_READ_CR8, "read_cr8" }, \ + { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ + { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ + { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ + { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ + { SVM_EXIT_READ_DR0, "read_dr0" }, \ + { SVM_EXIT_READ_DR1, "read_dr1" }, \ + { SVM_EXIT_READ_DR2, "read_dr2" }, \ + { SVM_EXIT_READ_DR3, "read_dr3" }, \ + { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ + { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ + { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ + { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ + { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ + { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ + { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ + { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ + { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ + { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ + { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ + { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ + { SVM_EXIT_INTR, "interrupt" }, \ + { SVM_EXIT_NMI, "nmi" }, \ + { SVM_EXIT_SMI, "smi" }, \ + { SVM_EXIT_INIT, "init" }, \ + { SVM_EXIT_VINTR, "vintr" }, \ + { SVM_EXIT_CPUID, "cpuid" }, \ + { SVM_EXIT_INVD, "invd" }, \ + { SVM_EXIT_HLT, "hlt" }, \ + { SVM_EXIT_INVLPG, "invlpg" }, \ + { SVM_EXIT_INVLPGA, "invlpga" }, \ + { SVM_EXIT_IOIO, "io" }, \ + { SVM_EXIT_MSR, "msr" }, \ + { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ + { SVM_EXIT_SHUTDOWN, "shutdown" }, \ + { SVM_EXIT_VMRUN, "vmrun" }, \ + { SVM_EXIT_VMMCALL, "hypercall" }, \ + { SVM_EXIT_VMLOAD, "vmload" }, \ + { SVM_EXIT_VMSAVE, "vmsave" }, \ + { SVM_EXIT_STGI, "stgi" }, \ + { SVM_EXIT_CLGI, "clgi" }, \ + { SVM_EXIT_SKINIT, "skinit" }, \ + { SVM_EXIT_WBINVD, "wbinvd" }, \ + { SVM_EXIT_MONITOR, "monitor" }, \ + { SVM_EXIT_MWAIT, "mwait" }, \ + { SVM_EXIT_XSETBV, "xsetbv" }, \ + { SVM_EXIT_NPF, "npf" } + +#ifdef __KERNEL__ + enum { INTERCEPT_INTR, INTERCEPT_NMI, @@ -264,81 +393,6 @@ struct __attribute__ ((__packed__)) vmcb { #define SVM_EXITINFO_REG_MASK 0x0F -#define SVM_EXIT_READ_CR0 0x000 -#define SVM_EXIT_READ_CR3 0x003 -#define SVM_EXIT_READ_CR4 0x004 -#define SVM_EXIT_READ_CR8 0x008 -#define SVM_EXIT_WRITE_CR0 0x010 -#define SVM_EXIT_WRITE_CR3 0x013 -#define SVM_EXIT_WRITE_CR4 0x014 -#define SVM_EXIT_WRITE_CR8 0x018 -#define SVM_EXIT_READ_DR0 0x020 -#define SVM_EXIT_READ_DR1 0x021 -#define SVM_EXIT_READ_DR2 0x022 -#define SVM_EXIT_READ_DR3 0x023 -#define SVM_EXIT_READ_DR4 0x024 -#define SVM_EXIT_READ_DR5 0x025 -#define SVM_EXIT_READ_DR6 0x026 -#define SVM_EXIT_READ_DR7 0x027 -#define SVM_EXIT_WRITE_DR0 0x030 -#define SVM_EXIT_WRITE_DR1 0x031 -#define SVM_EXIT_WRITE_DR2 0x032 -#define SVM_EXIT_WRITE_DR3 0x033 -#define SVM_EXIT_WRITE_DR4 0x034 -#define SVM_EXIT_WRITE_DR5 0x035 -#define SVM_EXIT_WRITE_DR6 0x036 -#define SVM_EXIT_WRITE_DR7 0x037 -#define SVM_EXIT_EXCP_BASE 0x040 -#define SVM_EXIT_INTR 0x060 -#define SVM_EXIT_NMI 0x061 -#define SVM_EXIT_SMI 0x062 -#define SVM_EXIT_INIT 0x063 -#define SVM_EXIT_VINTR 0x064 -#define SVM_EXIT_CR0_SEL_WRITE 0x065 -#define SVM_EXIT_IDTR_READ 0x066 -#define SVM_EXIT_GDTR_READ 0x067 -#define SVM_EXIT_LDTR_READ 0x068 -#define SVM_EXIT_TR_READ 0x069 -#define SVM_EXIT_IDTR_WRITE 0x06a -#define SVM_EXIT_GDTR_WRITE 0x06b -#define SVM_EXIT_LDTR_WRITE 0x06c -#define SVM_EXIT_TR_WRITE 0x06d -#define SVM_EXIT_RDTSC 0x06e -#define SVM_EXIT_RDPMC 0x06f -#define SVM_EXIT_PUSHF 0x070 -#define SVM_EXIT_POPF 0x071 -#define SVM_EXIT_CPUID 0x072 -#define SVM_EXIT_RSM 0x073 -#define SVM_EXIT_IRET 0x074 -#define SVM_EXIT_SWINT 0x075 -#define SVM_EXIT_INVD 0x076 -#define SVM_EXIT_PAUSE 0x077 -#define SVM_EXIT_HLT 0x078 -#define SVM_EXIT_INVLPG 0x079 -#define SVM_EXIT_INVLPGA 0x07a -#define SVM_EXIT_IOIO 0x07b -#define SVM_EXIT_MSR 0x07c -#define SVM_EXIT_TASK_SWITCH 0x07d -#define SVM_EXIT_FERR_FREEZE 0x07e -#define SVM_EXIT_SHUTDOWN 0x07f -#define SVM_EXIT_VMRUN 0x080 -#define SVM_EXIT_VMMCALL 0x081 -#define SVM_EXIT_VMLOAD 0x082 -#define SVM_EXIT_VMSAVE 0x083 -#define SVM_EXIT_STGI 0x084 -#define SVM_EXIT_CLGI 0x085 -#define SVM_EXIT_SKINIT 0x086 -#define SVM_EXIT_RDTSCP 0x087 -#define SVM_EXIT_ICEBP 0x088 -#define SVM_EXIT_WBINVD 0x089 -#define SVM_EXIT_MONITOR 0x08a -#define SVM_EXIT_MWAIT 0x08b -#define SVM_EXIT_MWAIT_COND 0x08c -#define SVM_EXIT_XSETBV 0x08d -#define SVM_EXIT_NPF 0x400 - -#define SVM_EXIT_ERR -1 - #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP) #define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" @@ -350,3 +404,4 @@ struct __attribute__ ((__packed__)) vmcb { #endif +#endif diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 74fcb96..36ec21c 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -25,6 +25,88 @@ * */ +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 + +#define EXIT_REASON_EXCEPTION_NMI 0 +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 +#define EXIT_REASON_TRIPLE_FAULT 2 + +#define EXIT_REASON_PENDING_INTERRUPT 7 +#define EXIT_REASON_NMI_WINDOW 8 +#define EXIT_REASON_TASK_SWITCH 9 +#define EXIT_REASON_CPUID 10 +#define EXIT_REASON_HLT 12 +#define EXIT_REASON_INVD 13 +#define EXIT_REASON_INVLPG 14 +#define EXIT_REASON_RDPMC 15 +#define EXIT_REASON_RDTSC 16 +#define EXIT_REASON_VMCALL 18 +#define EXIT_REASON_VMCLEAR 19 +#define EXIT_REASON_VMLAUNCH 20 +#define EXIT_REASON_VMPTRLD 21 +#define EXIT_REASON_VMPTRST 22 +#define EXIT_REASON_VMREAD 23 +#define EXIT_REASON_VMRESUME 24 +#define EXIT_REASON_VMWRITE 25 +#define EXIT_REASON_VMOFF 26 +#define EXIT_REASON_VMON 27 +#define EXIT_REASON_CR_ACCESS 28 +#define EXIT_REASON_DR_ACCESS 29 +#define EXIT_REASON_IO_INSTRUCTION 30 +#define EXIT_REASON_MSR_READ 31 +#define EXIT_REASON_MSR_WRITE 32 +#define EXIT_REASON_INVALID_STATE 33 +#define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_MONITOR_INSTRUCTION 39 +#define EXIT_REASON_PAUSE_INSTRUCTION 40 +#define EXIT_REASON_MCE_DURING_VMENTRY 41 +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 +#define EXIT_REASON_APIC_ACCESS 44 +#define EXIT_REASON_EPT_VIOLATION 48 +#define EXIT_REASON_EPT_MISCONFIG 49 +#define EXIT_REASON_WBINVD 54 +#define EXIT_REASON_XSETBV 55 +#define EXIT_REASON_INVPCID 58 + +#define VMX_EXIT_REASONS \ + { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ + { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ + { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ + { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ + { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ + { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ + { EXIT_REASON_CPUID, "CPUID" }, \ + { EXIT_REASON_HLT, "HLT" }, \ + { EXIT_REASON_INVLPG, "INVLPG" }, \ + { EXIT_REASON_RDPMC, "RDPMC" }, \ + { EXIT_REASON_RDTSC, "RDTSC" }, \ + { EXIT_REASON_VMCALL, "VMCALL" }, \ + { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ + { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ + { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ + { EXIT_REASON_VMPTRST, "VMPTRST" }, \ + { EXIT_REASON_VMREAD, "VMREAD" }, \ + { EXIT_REASON_VMRESUME, "VMRESUME" }, \ + { EXIT_REASON_VMWRITE, "VMWRITE" }, \ + { EXIT_REASON_VMOFF, "VMOFF" }, \ + { EXIT_REASON_VMON, "VMON" }, \ + { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ + { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ + { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ + { EXIT_REASON_MSR_READ, "MSR_READ" }, \ + { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ + { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ + { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ + { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ + { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ + { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ + { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ + { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ + { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ + { EXIT_REASON_WBINVD, "WBINVD" } + +#ifdef __KERNEL__ + #include <linux/types.h> /* @@ -241,49 +323,6 @@ enum vmcs_field { HOST_RIP = 0x00006c16, }; -#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 - -#define EXIT_REASON_EXCEPTION_NMI 0 -#define EXIT_REASON_EXTERNAL_INTERRUPT 1 -#define EXIT_REASON_TRIPLE_FAULT 2 - -#define EXIT_REASON_PENDING_INTERRUPT 7 -#define EXIT_REASON_NMI_WINDOW 8 -#define EXIT_REASON_TASK_SWITCH 9 -#define EXIT_REASON_CPUID 10 -#define EXIT_REASON_HLT 12 -#define EXIT_REASON_INVD 13 -#define EXIT_REASON_INVLPG 14 -#define EXIT_REASON_RDPMC 15 -#define EXIT_REASON_RDTSC 16 -#define EXIT_REASON_VMCALL 18 -#define EXIT_REASON_VMCLEAR 19 -#define EXIT_REASON_VMLAUNCH 20 -#define EXIT_REASON_VMPTRLD 21 -#define EXIT_REASON_VMPTRST 22 -#define EXIT_REASON_VMREAD 23 -#define EXIT_REASON_VMRESUME 24 -#define EXIT_REASON_VMWRITE 25 -#define EXIT_REASON_VMOFF 26 -#define EXIT_REASON_VMON 27 -#define EXIT_REASON_CR_ACCESS 28 -#define EXIT_REASON_DR_ACCESS 29 -#define EXIT_REASON_IO_INSTRUCTION 30 -#define EXIT_REASON_MSR_READ 31 -#define EXIT_REASON_MSR_WRITE 32 -#define EXIT_REASON_INVALID_STATE 33 -#define EXIT_REASON_MWAIT_INSTRUCTION 36 -#define EXIT_REASON_MONITOR_INSTRUCTION 39 -#define EXIT_REASON_PAUSE_INSTRUCTION 40 -#define EXIT_REASON_MCE_DURING_VMENTRY 41 -#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 -#define EXIT_REASON_APIC_ACCESS 44 -#define EXIT_REASON_EPT_VIOLATION 48 -#define EXIT_REASON_EPT_MISCONFIG 49 -#define EXIT_REASON_WBINVD 54 -#define EXIT_REASON_XSETBV 55 -#define EXIT_REASON_INVPCID 58 - /* * Interruption-information format */ @@ -488,3 +527,5 @@ enum vm_instruction_error_number { }; #endif + +#endif diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index a71faf7..bca63f0 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -183,95 +183,6 @@ TRACE_EVENT(kvm_apic, #define KVM_ISA_VMX 1 #define KVM_ISA_SVM 2 -#define VMX_EXIT_REASONS \ - { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ - { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ - { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ - { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ - { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ - { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ - { EXIT_REASON_CPUID, "CPUID" }, \ - { EXIT_REASON_HLT, "HLT" }, \ - { EXIT_REASON_INVLPG, "INVLPG" }, \ - { EXIT_REASON_RDPMC, "RDPMC" }, \ - { EXIT_REASON_RDTSC, "RDTSC" }, \ - { EXIT_REASON_VMCALL, "VMCALL" }, \ - { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ - { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ - { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ - { EXIT_REASON_VMPTRST, "VMPTRST" }, \ - { EXIT_REASON_VMREAD, "VMREAD" }, \ - { EXIT_REASON_VMRESUME, "VMRESUME" }, \ - { EXIT_REASON_VMWRITE, "VMWRITE" }, \ - { EXIT_REASON_VMOFF, "VMOFF" }, \ - { EXIT_REASON_VMON, "VMON" }, \ - { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ - { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ - { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ - { EXIT_REASON_MSR_READ, "MSR_READ" }, \ - { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ - { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ - { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ - { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ - { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ - { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ - { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ - { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ - { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ - { EXIT_REASON_WBINVD, "WBINVD" } - -#define SVM_EXIT_REASONS \ - { SVM_EXIT_READ_CR0, "read_cr0" }, \ - { SVM_EXIT_READ_CR3, "read_cr3" }, \ - { SVM_EXIT_READ_CR4, "read_cr4" }, \ - { SVM_EXIT_READ_CR8, "read_cr8" }, \ - { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ - { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ - { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ - { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ - { SVM_EXIT_READ_DR0, "read_dr0" }, \ - { SVM_EXIT_READ_DR1, "read_dr1" }, \ - { SVM_EXIT_READ_DR2, "read_dr2" }, \ - { SVM_EXIT_READ_DR3, "read_dr3" }, \ - { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ - { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ - { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ - { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ - { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ - { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ - { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ - { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ - { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ - { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ - { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ - { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ - { SVM_EXIT_INTR, "interrupt" }, \ - { SVM_EXIT_NMI, "nmi" }, \ - { SVM_EXIT_SMI, "smi" }, \ - { SVM_EXIT_INIT, "init" }, \ - { SVM_EXIT_VINTR, "vintr" }, \ - { SVM_EXIT_CPUID, "cpuid" }, \ - { SVM_EXIT_INVD, "invd" }, \ - { SVM_EXIT_HLT, "hlt" }, \ - { SVM_EXIT_INVLPG, "invlpg" }, \ - { SVM_EXIT_INVLPGA, "invlpga" }, \ - { SVM_EXIT_IOIO, "io" }, \ - { SVM_EXIT_MSR, "msr" }, \ - { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ - { SVM_EXIT_SHUTDOWN, "shutdown" }, \ - { SVM_EXIT_VMRUN, "vmrun" }, \ - { SVM_EXIT_VMMCALL, "hypercall" }, \ - { SVM_EXIT_VMLOAD, "vmload" }, \ - { SVM_EXIT_VMSAVE, "vmsave" }, \ - { SVM_EXIT_STGI, "stgi" }, \ - { SVM_EXIT_CLGI, "clgi" }, \ - { SVM_EXIT_SKINIT, "skinit" }, \ - { SVM_EXIT_WBINVD, "wbinvd" }, \ - { SVM_EXIT_MONITOR, "monitor" }, \ - { SVM_EXIT_MWAIT, "mwait" }, \ - { SVM_EXIT_XSETBV, "xsetbv" }, \ - { SVM_EXIT_NPF, "npf" } - /* * Tracepoint for kvm guest exit: */ -- 1.7.2.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace 2012-09-17 8:31 ` [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace Dong Hao @ 2012-09-17 14:58 ` Arnaldo Carvalho de Melo 2012-09-20 12:51 ` Marcelo Tosatti 2012-09-27 4:26 ` [tip:perf/core] KVM: x86: Export svm/ vmx " tip-bot for Xiao Guangrong 1 sibling, 1 reply; 14+ messages in thread From: Arnaldo Carvalho de Melo @ 2012-09-17 14:58 UTC (permalink / raw) To: Dong Hao Cc: dsahern, mtosatti, avi, mingo, linux-kernel, kvm, xiaoguangrong, runzhen Em Mon, Sep 17, 2012 at 04:31:13PM +0800, Dong Hao escreveu: > From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > > Exporting KVM exit information to userspace to be consumed by perf. > > [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] > Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> > Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Do we have acked/reviewed-by for this parth? Marcelo? Avi? > arch/x86/include/asm/kvm.h | 16 +++ > arch/x86/include/asm/kvm_host.h | 16 --- > arch/x86/include/asm/svm.h | 205 +++++++++++++++++++++++++-------------- > arch/x86/include/asm/vmx.h | 127 ++++++++++++++++-------- > arch/x86/kvm/trace.h | 89 ----------------- > 5 files changed, 230 insertions(+), 223 deletions(-) > > diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h > index 246617e..41e08cb 100644 > --- a/arch/x86/include/asm/kvm.h > +++ b/arch/x86/include/asm/kvm.h > @@ -9,6 +9,22 @@ > #include <linux/types.h> > #include <linux/ioctl.h> > > +#define DE_VECTOR 0 > +#define DB_VECTOR 1 > +#define BP_VECTOR 3 > +#define OF_VECTOR 4 > +#define BR_VECTOR 5 > +#define UD_VECTOR 6 > +#define NM_VECTOR 7 > +#define DF_VECTOR 8 > +#define TS_VECTOR 10 > +#define NP_VECTOR 11 > +#define SS_VECTOR 12 > +#define GP_VECTOR 13 > +#define PF_VECTOR 14 > +#define MF_VECTOR 16 > +#define MC_VECTOR 18 > + > /* Select x86 specific features in <linux/kvm.h> */ > #define __KVM_HAVE_PIT > #define __KVM_HAVE_IOAPIC > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 09155d6..1eaa6b0 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -75,22 +75,6 @@ > #define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1)) > #define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE) > > -#define DE_VECTOR 0 > -#define DB_VECTOR 1 > -#define BP_VECTOR 3 > -#define OF_VECTOR 4 > -#define BR_VECTOR 5 > -#define UD_VECTOR 6 > -#define NM_VECTOR 7 > -#define DF_VECTOR 8 > -#define TS_VECTOR 10 > -#define NP_VECTOR 11 > -#define SS_VECTOR 12 > -#define GP_VECTOR 13 > -#define PF_VECTOR 14 > -#define MF_VECTOR 16 > -#define MC_VECTOR 18 > - > #define SELECTOR_TI_MASK (1 << 2) > #define SELECTOR_RPL_MASK 0x03 > > diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h > index f2b83bc..cdf5674 100644 > --- a/arch/x86/include/asm/svm.h > +++ b/arch/x86/include/asm/svm.h > @@ -1,6 +1,135 @@ > #ifndef __SVM_H > #define __SVM_H > > +#define SVM_EXIT_READ_CR0 0x000 > +#define SVM_EXIT_READ_CR3 0x003 > +#define SVM_EXIT_READ_CR4 0x004 > +#define SVM_EXIT_READ_CR8 0x008 > +#define SVM_EXIT_WRITE_CR0 0x010 > +#define SVM_EXIT_WRITE_CR3 0x013 > +#define SVM_EXIT_WRITE_CR4 0x014 > +#define SVM_EXIT_WRITE_CR8 0x018 > +#define SVM_EXIT_READ_DR0 0x020 > +#define SVM_EXIT_READ_DR1 0x021 > +#define SVM_EXIT_READ_DR2 0x022 > +#define SVM_EXIT_READ_DR3 0x023 > +#define SVM_EXIT_READ_DR4 0x024 > +#define SVM_EXIT_READ_DR5 0x025 > +#define SVM_EXIT_READ_DR6 0x026 > +#define SVM_EXIT_READ_DR7 0x027 > +#define SVM_EXIT_WRITE_DR0 0x030 > +#define SVM_EXIT_WRITE_DR1 0x031 > +#define SVM_EXIT_WRITE_DR2 0x032 > +#define SVM_EXIT_WRITE_DR3 0x033 > +#define SVM_EXIT_WRITE_DR4 0x034 > +#define SVM_EXIT_WRITE_DR5 0x035 > +#define SVM_EXIT_WRITE_DR6 0x036 > +#define SVM_EXIT_WRITE_DR7 0x037 > +#define SVM_EXIT_EXCP_BASE 0x040 > +#define SVM_EXIT_INTR 0x060 > +#define SVM_EXIT_NMI 0x061 > +#define SVM_EXIT_SMI 0x062 > +#define SVM_EXIT_INIT 0x063 > +#define SVM_EXIT_VINTR 0x064 > +#define SVM_EXIT_CR0_SEL_WRITE 0x065 > +#define SVM_EXIT_IDTR_READ 0x066 > +#define SVM_EXIT_GDTR_READ 0x067 > +#define SVM_EXIT_LDTR_READ 0x068 > +#define SVM_EXIT_TR_READ 0x069 > +#define SVM_EXIT_IDTR_WRITE 0x06a > +#define SVM_EXIT_GDTR_WRITE 0x06b > +#define SVM_EXIT_LDTR_WRITE 0x06c > +#define SVM_EXIT_TR_WRITE 0x06d > +#define SVM_EXIT_RDTSC 0x06e > +#define SVM_EXIT_RDPMC 0x06f > +#define SVM_EXIT_PUSHF 0x070 > +#define SVM_EXIT_POPF 0x071 > +#define SVM_EXIT_CPUID 0x072 > +#define SVM_EXIT_RSM 0x073 > +#define SVM_EXIT_IRET 0x074 > +#define SVM_EXIT_SWINT 0x075 > +#define SVM_EXIT_INVD 0x076 > +#define SVM_EXIT_PAUSE 0x077 > +#define SVM_EXIT_HLT 0x078 > +#define SVM_EXIT_INVLPG 0x079 > +#define SVM_EXIT_INVLPGA 0x07a > +#define SVM_EXIT_IOIO 0x07b > +#define SVM_EXIT_MSR 0x07c > +#define SVM_EXIT_TASK_SWITCH 0x07d > +#define SVM_EXIT_FERR_FREEZE 0x07e > +#define SVM_EXIT_SHUTDOWN 0x07f > +#define SVM_EXIT_VMRUN 0x080 > +#define SVM_EXIT_VMMCALL 0x081 > +#define SVM_EXIT_VMLOAD 0x082 > +#define SVM_EXIT_VMSAVE 0x083 > +#define SVM_EXIT_STGI 0x084 > +#define SVM_EXIT_CLGI 0x085 > +#define SVM_EXIT_SKINIT 0x086 > +#define SVM_EXIT_RDTSCP 0x087 > +#define SVM_EXIT_ICEBP 0x088 > +#define SVM_EXIT_WBINVD 0x089 > +#define SVM_EXIT_MONITOR 0x08a > +#define SVM_EXIT_MWAIT 0x08b > +#define SVM_EXIT_MWAIT_COND 0x08c > +#define SVM_EXIT_XSETBV 0x08d > +#define SVM_EXIT_NPF 0x400 > + > +#define SVM_EXIT_ERR -1 > + > +#define SVM_EXIT_REASONS \ > + { SVM_EXIT_READ_CR0, "read_cr0" }, \ > + { SVM_EXIT_READ_CR3, "read_cr3" }, \ > + { SVM_EXIT_READ_CR4, "read_cr4" }, \ > + { SVM_EXIT_READ_CR8, "read_cr8" }, \ > + { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ > + { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ > + { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ > + { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ > + { SVM_EXIT_READ_DR0, "read_dr0" }, \ > + { SVM_EXIT_READ_DR1, "read_dr1" }, \ > + { SVM_EXIT_READ_DR2, "read_dr2" }, \ > + { SVM_EXIT_READ_DR3, "read_dr3" }, \ > + { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ > + { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ > + { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ > + { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ > + { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ > + { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ > + { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ > + { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ > + { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ > + { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ > + { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ > + { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ > + { SVM_EXIT_INTR, "interrupt" }, \ > + { SVM_EXIT_NMI, "nmi" }, \ > + { SVM_EXIT_SMI, "smi" }, \ > + { SVM_EXIT_INIT, "init" }, \ > + { SVM_EXIT_VINTR, "vintr" }, \ > + { SVM_EXIT_CPUID, "cpuid" }, \ > + { SVM_EXIT_INVD, "invd" }, \ > + { SVM_EXIT_HLT, "hlt" }, \ > + { SVM_EXIT_INVLPG, "invlpg" }, \ > + { SVM_EXIT_INVLPGA, "invlpga" }, \ > + { SVM_EXIT_IOIO, "io" }, \ > + { SVM_EXIT_MSR, "msr" }, \ > + { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ > + { SVM_EXIT_SHUTDOWN, "shutdown" }, \ > + { SVM_EXIT_VMRUN, "vmrun" }, \ > + { SVM_EXIT_VMMCALL, "hypercall" }, \ > + { SVM_EXIT_VMLOAD, "vmload" }, \ > + { SVM_EXIT_VMSAVE, "vmsave" }, \ > + { SVM_EXIT_STGI, "stgi" }, \ > + { SVM_EXIT_CLGI, "clgi" }, \ > + { SVM_EXIT_SKINIT, "skinit" }, \ > + { SVM_EXIT_WBINVD, "wbinvd" }, \ > + { SVM_EXIT_MONITOR, "monitor" }, \ > + { SVM_EXIT_MWAIT, "mwait" }, \ > + { SVM_EXIT_XSETBV, "xsetbv" }, \ > + { SVM_EXIT_NPF, "npf" } > + > +#ifdef __KERNEL__ > + > enum { > INTERCEPT_INTR, > INTERCEPT_NMI, > @@ -264,81 +393,6 @@ struct __attribute__ ((__packed__)) vmcb { > > #define SVM_EXITINFO_REG_MASK 0x0F > > -#define SVM_EXIT_READ_CR0 0x000 > -#define SVM_EXIT_READ_CR3 0x003 > -#define SVM_EXIT_READ_CR4 0x004 > -#define SVM_EXIT_READ_CR8 0x008 > -#define SVM_EXIT_WRITE_CR0 0x010 > -#define SVM_EXIT_WRITE_CR3 0x013 > -#define SVM_EXIT_WRITE_CR4 0x014 > -#define SVM_EXIT_WRITE_CR8 0x018 > -#define SVM_EXIT_READ_DR0 0x020 > -#define SVM_EXIT_READ_DR1 0x021 > -#define SVM_EXIT_READ_DR2 0x022 > -#define SVM_EXIT_READ_DR3 0x023 > -#define SVM_EXIT_READ_DR4 0x024 > -#define SVM_EXIT_READ_DR5 0x025 > -#define SVM_EXIT_READ_DR6 0x026 > -#define SVM_EXIT_READ_DR7 0x027 > -#define SVM_EXIT_WRITE_DR0 0x030 > -#define SVM_EXIT_WRITE_DR1 0x031 > -#define SVM_EXIT_WRITE_DR2 0x032 > -#define SVM_EXIT_WRITE_DR3 0x033 > -#define SVM_EXIT_WRITE_DR4 0x034 > -#define SVM_EXIT_WRITE_DR5 0x035 > -#define SVM_EXIT_WRITE_DR6 0x036 > -#define SVM_EXIT_WRITE_DR7 0x037 > -#define SVM_EXIT_EXCP_BASE 0x040 > -#define SVM_EXIT_INTR 0x060 > -#define SVM_EXIT_NMI 0x061 > -#define SVM_EXIT_SMI 0x062 > -#define SVM_EXIT_INIT 0x063 > -#define SVM_EXIT_VINTR 0x064 > -#define SVM_EXIT_CR0_SEL_WRITE 0x065 > -#define SVM_EXIT_IDTR_READ 0x066 > -#define SVM_EXIT_GDTR_READ 0x067 > -#define SVM_EXIT_LDTR_READ 0x068 > -#define SVM_EXIT_TR_READ 0x069 > -#define SVM_EXIT_IDTR_WRITE 0x06a > -#define SVM_EXIT_GDTR_WRITE 0x06b > -#define SVM_EXIT_LDTR_WRITE 0x06c > -#define SVM_EXIT_TR_WRITE 0x06d > -#define SVM_EXIT_RDTSC 0x06e > -#define SVM_EXIT_RDPMC 0x06f > -#define SVM_EXIT_PUSHF 0x070 > -#define SVM_EXIT_POPF 0x071 > -#define SVM_EXIT_CPUID 0x072 > -#define SVM_EXIT_RSM 0x073 > -#define SVM_EXIT_IRET 0x074 > -#define SVM_EXIT_SWINT 0x075 > -#define SVM_EXIT_INVD 0x076 > -#define SVM_EXIT_PAUSE 0x077 > -#define SVM_EXIT_HLT 0x078 > -#define SVM_EXIT_INVLPG 0x079 > -#define SVM_EXIT_INVLPGA 0x07a > -#define SVM_EXIT_IOIO 0x07b > -#define SVM_EXIT_MSR 0x07c > -#define SVM_EXIT_TASK_SWITCH 0x07d > -#define SVM_EXIT_FERR_FREEZE 0x07e > -#define SVM_EXIT_SHUTDOWN 0x07f > -#define SVM_EXIT_VMRUN 0x080 > -#define SVM_EXIT_VMMCALL 0x081 > -#define SVM_EXIT_VMLOAD 0x082 > -#define SVM_EXIT_VMSAVE 0x083 > -#define SVM_EXIT_STGI 0x084 > -#define SVM_EXIT_CLGI 0x085 > -#define SVM_EXIT_SKINIT 0x086 > -#define SVM_EXIT_RDTSCP 0x087 > -#define SVM_EXIT_ICEBP 0x088 > -#define SVM_EXIT_WBINVD 0x089 > -#define SVM_EXIT_MONITOR 0x08a > -#define SVM_EXIT_MWAIT 0x08b > -#define SVM_EXIT_MWAIT_COND 0x08c > -#define SVM_EXIT_XSETBV 0x08d > -#define SVM_EXIT_NPF 0x400 > - > -#define SVM_EXIT_ERR -1 > - > #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP) > > #define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" > @@ -350,3 +404,4 @@ struct __attribute__ ((__packed__)) vmcb { > > #endif > > +#endif > diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h > index 74fcb96..36ec21c 100644 > --- a/arch/x86/include/asm/vmx.h > +++ b/arch/x86/include/asm/vmx.h > @@ -25,6 +25,88 @@ > * > */ > > +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 > + > +#define EXIT_REASON_EXCEPTION_NMI 0 > +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 > +#define EXIT_REASON_TRIPLE_FAULT 2 > + > +#define EXIT_REASON_PENDING_INTERRUPT 7 > +#define EXIT_REASON_NMI_WINDOW 8 > +#define EXIT_REASON_TASK_SWITCH 9 > +#define EXIT_REASON_CPUID 10 > +#define EXIT_REASON_HLT 12 > +#define EXIT_REASON_INVD 13 > +#define EXIT_REASON_INVLPG 14 > +#define EXIT_REASON_RDPMC 15 > +#define EXIT_REASON_RDTSC 16 > +#define EXIT_REASON_VMCALL 18 > +#define EXIT_REASON_VMCLEAR 19 > +#define EXIT_REASON_VMLAUNCH 20 > +#define EXIT_REASON_VMPTRLD 21 > +#define EXIT_REASON_VMPTRST 22 > +#define EXIT_REASON_VMREAD 23 > +#define EXIT_REASON_VMRESUME 24 > +#define EXIT_REASON_VMWRITE 25 > +#define EXIT_REASON_VMOFF 26 > +#define EXIT_REASON_VMON 27 > +#define EXIT_REASON_CR_ACCESS 28 > +#define EXIT_REASON_DR_ACCESS 29 > +#define EXIT_REASON_IO_INSTRUCTION 30 > +#define EXIT_REASON_MSR_READ 31 > +#define EXIT_REASON_MSR_WRITE 32 > +#define EXIT_REASON_INVALID_STATE 33 > +#define EXIT_REASON_MWAIT_INSTRUCTION 36 > +#define EXIT_REASON_MONITOR_INSTRUCTION 39 > +#define EXIT_REASON_PAUSE_INSTRUCTION 40 > +#define EXIT_REASON_MCE_DURING_VMENTRY 41 > +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 > +#define EXIT_REASON_APIC_ACCESS 44 > +#define EXIT_REASON_EPT_VIOLATION 48 > +#define EXIT_REASON_EPT_MISCONFIG 49 > +#define EXIT_REASON_WBINVD 54 > +#define EXIT_REASON_XSETBV 55 > +#define EXIT_REASON_INVPCID 58 > + > +#define VMX_EXIT_REASONS \ > + { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ > + { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ > + { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ > + { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ > + { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ > + { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ > + { EXIT_REASON_CPUID, "CPUID" }, \ > + { EXIT_REASON_HLT, "HLT" }, \ > + { EXIT_REASON_INVLPG, "INVLPG" }, \ > + { EXIT_REASON_RDPMC, "RDPMC" }, \ > + { EXIT_REASON_RDTSC, "RDTSC" }, \ > + { EXIT_REASON_VMCALL, "VMCALL" }, \ > + { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ > + { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ > + { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ > + { EXIT_REASON_VMPTRST, "VMPTRST" }, \ > + { EXIT_REASON_VMREAD, "VMREAD" }, \ > + { EXIT_REASON_VMRESUME, "VMRESUME" }, \ > + { EXIT_REASON_VMWRITE, "VMWRITE" }, \ > + { EXIT_REASON_VMOFF, "VMOFF" }, \ > + { EXIT_REASON_VMON, "VMON" }, \ > + { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ > + { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ > + { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ > + { EXIT_REASON_MSR_READ, "MSR_READ" }, \ > + { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ > + { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ > + { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ > + { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ > + { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ > + { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ > + { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ > + { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ > + { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ > + { EXIT_REASON_WBINVD, "WBINVD" } > + > +#ifdef __KERNEL__ > + > #include <linux/types.h> > > /* > @@ -241,49 +323,6 @@ enum vmcs_field { > HOST_RIP = 0x00006c16, > }; > > -#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 > - > -#define EXIT_REASON_EXCEPTION_NMI 0 > -#define EXIT_REASON_EXTERNAL_INTERRUPT 1 > -#define EXIT_REASON_TRIPLE_FAULT 2 > - > -#define EXIT_REASON_PENDING_INTERRUPT 7 > -#define EXIT_REASON_NMI_WINDOW 8 > -#define EXIT_REASON_TASK_SWITCH 9 > -#define EXIT_REASON_CPUID 10 > -#define EXIT_REASON_HLT 12 > -#define EXIT_REASON_INVD 13 > -#define EXIT_REASON_INVLPG 14 > -#define EXIT_REASON_RDPMC 15 > -#define EXIT_REASON_RDTSC 16 > -#define EXIT_REASON_VMCALL 18 > -#define EXIT_REASON_VMCLEAR 19 > -#define EXIT_REASON_VMLAUNCH 20 > -#define EXIT_REASON_VMPTRLD 21 > -#define EXIT_REASON_VMPTRST 22 > -#define EXIT_REASON_VMREAD 23 > -#define EXIT_REASON_VMRESUME 24 > -#define EXIT_REASON_VMWRITE 25 > -#define EXIT_REASON_VMOFF 26 > -#define EXIT_REASON_VMON 27 > -#define EXIT_REASON_CR_ACCESS 28 > -#define EXIT_REASON_DR_ACCESS 29 > -#define EXIT_REASON_IO_INSTRUCTION 30 > -#define EXIT_REASON_MSR_READ 31 > -#define EXIT_REASON_MSR_WRITE 32 > -#define EXIT_REASON_INVALID_STATE 33 > -#define EXIT_REASON_MWAIT_INSTRUCTION 36 > -#define EXIT_REASON_MONITOR_INSTRUCTION 39 > -#define EXIT_REASON_PAUSE_INSTRUCTION 40 > -#define EXIT_REASON_MCE_DURING_VMENTRY 41 > -#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 > -#define EXIT_REASON_APIC_ACCESS 44 > -#define EXIT_REASON_EPT_VIOLATION 48 > -#define EXIT_REASON_EPT_MISCONFIG 49 > -#define EXIT_REASON_WBINVD 54 > -#define EXIT_REASON_XSETBV 55 > -#define EXIT_REASON_INVPCID 58 > - > /* > * Interruption-information format > */ > @@ -488,3 +527,5 @@ enum vm_instruction_error_number { > }; > > #endif > + > +#endif > diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h > index a71faf7..bca63f0 100644 > --- a/arch/x86/kvm/trace.h > +++ b/arch/x86/kvm/trace.h > @@ -183,95 +183,6 @@ TRACE_EVENT(kvm_apic, > #define KVM_ISA_VMX 1 > #define KVM_ISA_SVM 2 > > -#define VMX_EXIT_REASONS \ > - { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ > - { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ > - { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ > - { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ > - { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ > - { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ > - { EXIT_REASON_CPUID, "CPUID" }, \ > - { EXIT_REASON_HLT, "HLT" }, \ > - { EXIT_REASON_INVLPG, "INVLPG" }, \ > - { EXIT_REASON_RDPMC, "RDPMC" }, \ > - { EXIT_REASON_RDTSC, "RDTSC" }, \ > - { EXIT_REASON_VMCALL, "VMCALL" }, \ > - { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ > - { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ > - { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ > - { EXIT_REASON_VMPTRST, "VMPTRST" }, \ > - { EXIT_REASON_VMREAD, "VMREAD" }, \ > - { EXIT_REASON_VMRESUME, "VMRESUME" }, \ > - { EXIT_REASON_VMWRITE, "VMWRITE" }, \ > - { EXIT_REASON_VMOFF, "VMOFF" }, \ > - { EXIT_REASON_VMON, "VMON" }, \ > - { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ > - { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ > - { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ > - { EXIT_REASON_MSR_READ, "MSR_READ" }, \ > - { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ > - { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ > - { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ > - { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ > - { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ > - { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ > - { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ > - { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ > - { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ > - { EXIT_REASON_WBINVD, "WBINVD" } > - > -#define SVM_EXIT_REASONS \ > - { SVM_EXIT_READ_CR0, "read_cr0" }, \ > - { SVM_EXIT_READ_CR3, "read_cr3" }, \ > - { SVM_EXIT_READ_CR4, "read_cr4" }, \ > - { SVM_EXIT_READ_CR8, "read_cr8" }, \ > - { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ > - { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ > - { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ > - { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ > - { SVM_EXIT_READ_DR0, "read_dr0" }, \ > - { SVM_EXIT_READ_DR1, "read_dr1" }, \ > - { SVM_EXIT_READ_DR2, "read_dr2" }, \ > - { SVM_EXIT_READ_DR3, "read_dr3" }, \ > - { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ > - { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ > - { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ > - { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ > - { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ > - { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ > - { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ > - { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ > - { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ > - { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ > - { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ > - { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ > - { SVM_EXIT_INTR, "interrupt" }, \ > - { SVM_EXIT_NMI, "nmi" }, \ > - { SVM_EXIT_SMI, "smi" }, \ > - { SVM_EXIT_INIT, "init" }, \ > - { SVM_EXIT_VINTR, "vintr" }, \ > - { SVM_EXIT_CPUID, "cpuid" }, \ > - { SVM_EXIT_INVD, "invd" }, \ > - { SVM_EXIT_HLT, "hlt" }, \ > - { SVM_EXIT_INVLPG, "invlpg" }, \ > - { SVM_EXIT_INVLPGA, "invlpga" }, \ > - { SVM_EXIT_IOIO, "io" }, \ > - { SVM_EXIT_MSR, "msr" }, \ > - { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ > - { SVM_EXIT_SHUTDOWN, "shutdown" }, \ > - { SVM_EXIT_VMRUN, "vmrun" }, \ > - { SVM_EXIT_VMMCALL, "hypercall" }, \ > - { SVM_EXIT_VMLOAD, "vmload" }, \ > - { SVM_EXIT_VMSAVE, "vmsave" }, \ > - { SVM_EXIT_STGI, "stgi" }, \ > - { SVM_EXIT_CLGI, "clgi" }, \ > - { SVM_EXIT_SKINIT, "skinit" }, \ > - { SVM_EXIT_WBINVD, "wbinvd" }, \ > - { SVM_EXIT_MONITOR, "monitor" }, \ > - { SVM_EXIT_MWAIT, "mwait" }, \ > - { SVM_EXIT_XSETBV, "xsetbv" }, \ > - { SVM_EXIT_NPF, "npf" } > - > /* > * Tracepoint for kvm guest exit: > */ > -- > 1.7.2.5 ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace 2012-09-17 14:58 ` Arnaldo Carvalho de Melo @ 2012-09-20 12:51 ` Marcelo Tosatti 0 siblings, 0 replies; 14+ messages in thread From: Marcelo Tosatti @ 2012-09-20 12:51 UTC (permalink / raw) To: Arnaldo Carvalho de Melo, Avi Kivity Cc: Dong Hao, dsahern, avi, mingo, linux-kernel, kvm, xiaoguangrong, runzhen On Mon, Sep 17, 2012 at 07:58:57AM -0700, Arnaldo Carvalho de Melo wrote: > Em Mon, Sep 17, 2012 at 04:31:13PM +0800, Dong Hao escreveu: > > From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > > > > Exporting KVM exit information to userspace to be consumed by perf. > > > > [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] > > Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> > > Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > > Do we have acked/reviewed-by for this parth? Marcelo? Avi? Code move... ACK. > > > arch/x86/include/asm/kvm.h | 16 +++ > > arch/x86/include/asm/kvm_host.h | 16 --- > > arch/x86/include/asm/svm.h | 205 +++++++++++++++++++++++++-------------- > > arch/x86/include/asm/vmx.h | 127 ++++++++++++++++-------- > > arch/x86/kvm/trace.h | 89 ----------------- > > 5 files changed, 230 insertions(+), 223 deletions(-) > > > > diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h > > index 246617e..41e08cb 100644 > > --- a/arch/x86/include/asm/kvm.h > > +++ b/arch/x86/include/asm/kvm.h > > @@ -9,6 +9,22 @@ > > #include <linux/types.h> > > #include <linux/ioctl.h> > > > > +#define DE_VECTOR 0 > > +#define DB_VECTOR 1 > > +#define BP_VECTOR 3 > > +#define OF_VECTOR 4 > > +#define BR_VECTOR 5 > > +#define UD_VECTOR 6 > > +#define NM_VECTOR 7 > > +#define DF_VECTOR 8 > > +#define TS_VECTOR 10 > > +#define NP_VECTOR 11 > > +#define SS_VECTOR 12 > > +#define GP_VECTOR 13 > > +#define PF_VECTOR 14 > > +#define MF_VECTOR 16 > > +#define MC_VECTOR 18 > > + > > /* Select x86 specific features in <linux/kvm.h> */ > > #define __KVM_HAVE_PIT > > #define __KVM_HAVE_IOAPIC > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > > index 09155d6..1eaa6b0 100644 > > --- a/arch/x86/include/asm/kvm_host.h > > +++ b/arch/x86/include/asm/kvm_host.h > > @@ -75,22 +75,6 @@ > > #define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1)) > > #define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE) > > > > -#define DE_VECTOR 0 > > -#define DB_VECTOR 1 > > -#define BP_VECTOR 3 > > -#define OF_VECTOR 4 > > -#define BR_VECTOR 5 > > -#define UD_VECTOR 6 > > -#define NM_VECTOR 7 > > -#define DF_VECTOR 8 > > -#define TS_VECTOR 10 > > -#define NP_VECTOR 11 > > -#define SS_VECTOR 12 > > -#define GP_VECTOR 13 > > -#define PF_VECTOR 14 > > -#define MF_VECTOR 16 > > -#define MC_VECTOR 18 > > - > > #define SELECTOR_TI_MASK (1 << 2) > > #define SELECTOR_RPL_MASK 0x03 > > > > diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h > > index f2b83bc..cdf5674 100644 > > --- a/arch/x86/include/asm/svm.h > > +++ b/arch/x86/include/asm/svm.h > > @@ -1,6 +1,135 @@ > > #ifndef __SVM_H > > #define __SVM_H > > > > +#define SVM_EXIT_READ_CR0 0x000 > > +#define SVM_EXIT_READ_CR3 0x003 > > +#define SVM_EXIT_READ_CR4 0x004 > > +#define SVM_EXIT_READ_CR8 0x008 > > +#define SVM_EXIT_WRITE_CR0 0x010 > > +#define SVM_EXIT_WRITE_CR3 0x013 > > +#define SVM_EXIT_WRITE_CR4 0x014 > > +#define SVM_EXIT_WRITE_CR8 0x018 > > +#define SVM_EXIT_READ_DR0 0x020 > > +#define SVM_EXIT_READ_DR1 0x021 > > +#define SVM_EXIT_READ_DR2 0x022 > > +#define SVM_EXIT_READ_DR3 0x023 > > +#define SVM_EXIT_READ_DR4 0x024 > > +#define SVM_EXIT_READ_DR5 0x025 > > +#define SVM_EXIT_READ_DR6 0x026 > > +#define SVM_EXIT_READ_DR7 0x027 > > +#define SVM_EXIT_WRITE_DR0 0x030 > > +#define SVM_EXIT_WRITE_DR1 0x031 > > +#define SVM_EXIT_WRITE_DR2 0x032 > > +#define SVM_EXIT_WRITE_DR3 0x033 > > +#define SVM_EXIT_WRITE_DR4 0x034 > > +#define SVM_EXIT_WRITE_DR5 0x035 > > +#define SVM_EXIT_WRITE_DR6 0x036 > > +#define SVM_EXIT_WRITE_DR7 0x037 > > +#define SVM_EXIT_EXCP_BASE 0x040 > > +#define SVM_EXIT_INTR 0x060 > > +#define SVM_EXIT_NMI 0x061 > > +#define SVM_EXIT_SMI 0x062 > > +#define SVM_EXIT_INIT 0x063 > > +#define SVM_EXIT_VINTR 0x064 > > +#define SVM_EXIT_CR0_SEL_WRITE 0x065 > > +#define SVM_EXIT_IDTR_READ 0x066 > > +#define SVM_EXIT_GDTR_READ 0x067 > > +#define SVM_EXIT_LDTR_READ 0x068 > > +#define SVM_EXIT_TR_READ 0x069 > > +#define SVM_EXIT_IDTR_WRITE 0x06a > > +#define SVM_EXIT_GDTR_WRITE 0x06b > > +#define SVM_EXIT_LDTR_WRITE 0x06c > > +#define SVM_EXIT_TR_WRITE 0x06d > > +#define SVM_EXIT_RDTSC 0x06e > > +#define SVM_EXIT_RDPMC 0x06f > > +#define SVM_EXIT_PUSHF 0x070 > > +#define SVM_EXIT_POPF 0x071 > > +#define SVM_EXIT_CPUID 0x072 > > +#define SVM_EXIT_RSM 0x073 > > +#define SVM_EXIT_IRET 0x074 > > +#define SVM_EXIT_SWINT 0x075 > > +#define SVM_EXIT_INVD 0x076 > > +#define SVM_EXIT_PAUSE 0x077 > > +#define SVM_EXIT_HLT 0x078 > > +#define SVM_EXIT_INVLPG 0x079 > > +#define SVM_EXIT_INVLPGA 0x07a > > +#define SVM_EXIT_IOIO 0x07b > > +#define SVM_EXIT_MSR 0x07c > > +#define SVM_EXIT_TASK_SWITCH 0x07d > > +#define SVM_EXIT_FERR_FREEZE 0x07e > > +#define SVM_EXIT_SHUTDOWN 0x07f > > +#define SVM_EXIT_VMRUN 0x080 > > +#define SVM_EXIT_VMMCALL 0x081 > > +#define SVM_EXIT_VMLOAD 0x082 > > +#define SVM_EXIT_VMSAVE 0x083 > > +#define SVM_EXIT_STGI 0x084 > > +#define SVM_EXIT_CLGI 0x085 > > +#define SVM_EXIT_SKINIT 0x086 > > +#define SVM_EXIT_RDTSCP 0x087 > > +#define SVM_EXIT_ICEBP 0x088 > > +#define SVM_EXIT_WBINVD 0x089 > > +#define SVM_EXIT_MONITOR 0x08a > > +#define SVM_EXIT_MWAIT 0x08b > > +#define SVM_EXIT_MWAIT_COND 0x08c > > +#define SVM_EXIT_XSETBV 0x08d > > +#define SVM_EXIT_NPF 0x400 > > + > > +#define SVM_EXIT_ERR -1 > > + > > +#define SVM_EXIT_REASONS \ > > + { SVM_EXIT_READ_CR0, "read_cr0" }, \ > > + { SVM_EXIT_READ_CR3, "read_cr3" }, \ > > + { SVM_EXIT_READ_CR4, "read_cr4" }, \ > > + { SVM_EXIT_READ_CR8, "read_cr8" }, \ > > + { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ > > + { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ > > + { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ > > + { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ > > + { SVM_EXIT_READ_DR0, "read_dr0" }, \ > > + { SVM_EXIT_READ_DR1, "read_dr1" }, \ > > + { SVM_EXIT_READ_DR2, "read_dr2" }, \ > > + { SVM_EXIT_READ_DR3, "read_dr3" }, \ > > + { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ > > + { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ > > + { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ > > + { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ > > + { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ > > + { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ > > + { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ > > + { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ > > + { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ > > + { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ > > + { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ > > + { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ > > + { SVM_EXIT_INTR, "interrupt" }, \ > > + { SVM_EXIT_NMI, "nmi" }, \ > > + { SVM_EXIT_SMI, "smi" }, \ > > + { SVM_EXIT_INIT, "init" }, \ > > + { SVM_EXIT_VINTR, "vintr" }, \ > > + { SVM_EXIT_CPUID, "cpuid" }, \ > > + { SVM_EXIT_INVD, "invd" }, \ > > + { SVM_EXIT_HLT, "hlt" }, \ > > + { SVM_EXIT_INVLPG, "invlpg" }, \ > > + { SVM_EXIT_INVLPGA, "invlpga" }, \ > > + { SVM_EXIT_IOIO, "io" }, \ > > + { SVM_EXIT_MSR, "msr" }, \ > > + { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ > > + { SVM_EXIT_SHUTDOWN, "shutdown" }, \ > > + { SVM_EXIT_VMRUN, "vmrun" }, \ > > + { SVM_EXIT_VMMCALL, "hypercall" }, \ > > + { SVM_EXIT_VMLOAD, "vmload" }, \ > > + { SVM_EXIT_VMSAVE, "vmsave" }, \ > > + { SVM_EXIT_STGI, "stgi" }, \ > > + { SVM_EXIT_CLGI, "clgi" }, \ > > + { SVM_EXIT_SKINIT, "skinit" }, \ > > + { SVM_EXIT_WBINVD, "wbinvd" }, \ > > + { SVM_EXIT_MONITOR, "monitor" }, \ > > + { SVM_EXIT_MWAIT, "mwait" }, \ > > + { SVM_EXIT_XSETBV, "xsetbv" }, \ > > + { SVM_EXIT_NPF, "npf" } > > + > > +#ifdef __KERNEL__ > > + > > enum { > > INTERCEPT_INTR, > > INTERCEPT_NMI, > > @@ -264,81 +393,6 @@ struct __attribute__ ((__packed__)) vmcb { > > > > #define SVM_EXITINFO_REG_MASK 0x0F > > > > -#define SVM_EXIT_READ_CR0 0x000 > > -#define SVM_EXIT_READ_CR3 0x003 > > -#define SVM_EXIT_READ_CR4 0x004 > > -#define SVM_EXIT_READ_CR8 0x008 > > -#define SVM_EXIT_WRITE_CR0 0x010 > > -#define SVM_EXIT_WRITE_CR3 0x013 > > -#define SVM_EXIT_WRITE_CR4 0x014 > > -#define SVM_EXIT_WRITE_CR8 0x018 > > -#define SVM_EXIT_READ_DR0 0x020 > > -#define SVM_EXIT_READ_DR1 0x021 > > -#define SVM_EXIT_READ_DR2 0x022 > > -#define SVM_EXIT_READ_DR3 0x023 > > -#define SVM_EXIT_READ_DR4 0x024 > > -#define SVM_EXIT_READ_DR5 0x025 > > -#define SVM_EXIT_READ_DR6 0x026 > > -#define SVM_EXIT_READ_DR7 0x027 > > -#define SVM_EXIT_WRITE_DR0 0x030 > > -#define SVM_EXIT_WRITE_DR1 0x031 > > -#define SVM_EXIT_WRITE_DR2 0x032 > > -#define SVM_EXIT_WRITE_DR3 0x033 > > -#define SVM_EXIT_WRITE_DR4 0x034 > > -#define SVM_EXIT_WRITE_DR5 0x035 > > -#define SVM_EXIT_WRITE_DR6 0x036 > > -#define SVM_EXIT_WRITE_DR7 0x037 > > -#define SVM_EXIT_EXCP_BASE 0x040 > > -#define SVM_EXIT_INTR 0x060 > > -#define SVM_EXIT_NMI 0x061 > > -#define SVM_EXIT_SMI 0x062 > > -#define SVM_EXIT_INIT 0x063 > > -#define SVM_EXIT_VINTR 0x064 > > -#define SVM_EXIT_CR0_SEL_WRITE 0x065 > > -#define SVM_EXIT_IDTR_READ 0x066 > > -#define SVM_EXIT_GDTR_READ 0x067 > > -#define SVM_EXIT_LDTR_READ 0x068 > > -#define SVM_EXIT_TR_READ 0x069 > > -#define SVM_EXIT_IDTR_WRITE 0x06a > > -#define SVM_EXIT_GDTR_WRITE 0x06b > > -#define SVM_EXIT_LDTR_WRITE 0x06c > > -#define SVM_EXIT_TR_WRITE 0x06d > > -#define SVM_EXIT_RDTSC 0x06e > > -#define SVM_EXIT_RDPMC 0x06f > > -#define SVM_EXIT_PUSHF 0x070 > > -#define SVM_EXIT_POPF 0x071 > > -#define SVM_EXIT_CPUID 0x072 > > -#define SVM_EXIT_RSM 0x073 > > -#define SVM_EXIT_IRET 0x074 > > -#define SVM_EXIT_SWINT 0x075 > > -#define SVM_EXIT_INVD 0x076 > > -#define SVM_EXIT_PAUSE 0x077 > > -#define SVM_EXIT_HLT 0x078 > > -#define SVM_EXIT_INVLPG 0x079 > > -#define SVM_EXIT_INVLPGA 0x07a > > -#define SVM_EXIT_IOIO 0x07b > > -#define SVM_EXIT_MSR 0x07c > > -#define SVM_EXIT_TASK_SWITCH 0x07d > > -#define SVM_EXIT_FERR_FREEZE 0x07e > > -#define SVM_EXIT_SHUTDOWN 0x07f > > -#define SVM_EXIT_VMRUN 0x080 > > -#define SVM_EXIT_VMMCALL 0x081 > > -#define SVM_EXIT_VMLOAD 0x082 > > -#define SVM_EXIT_VMSAVE 0x083 > > -#define SVM_EXIT_STGI 0x084 > > -#define SVM_EXIT_CLGI 0x085 > > -#define SVM_EXIT_SKINIT 0x086 > > -#define SVM_EXIT_RDTSCP 0x087 > > -#define SVM_EXIT_ICEBP 0x088 > > -#define SVM_EXIT_WBINVD 0x089 > > -#define SVM_EXIT_MONITOR 0x08a > > -#define SVM_EXIT_MWAIT 0x08b > > -#define SVM_EXIT_MWAIT_COND 0x08c > > -#define SVM_EXIT_XSETBV 0x08d > > -#define SVM_EXIT_NPF 0x400 > > - > > -#define SVM_EXIT_ERR -1 > > - > > #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP) > > > > #define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" > > @@ -350,3 +404,4 @@ struct __attribute__ ((__packed__)) vmcb { > > > > #endif > > > > +#endif > > diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h > > index 74fcb96..36ec21c 100644 > > --- a/arch/x86/include/asm/vmx.h > > +++ b/arch/x86/include/asm/vmx.h > > @@ -25,6 +25,88 @@ > > * > > */ > > > > +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 > > + > > +#define EXIT_REASON_EXCEPTION_NMI 0 > > +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 > > +#define EXIT_REASON_TRIPLE_FAULT 2 > > + > > +#define EXIT_REASON_PENDING_INTERRUPT 7 > > +#define EXIT_REASON_NMI_WINDOW 8 > > +#define EXIT_REASON_TASK_SWITCH 9 > > +#define EXIT_REASON_CPUID 10 > > +#define EXIT_REASON_HLT 12 > > +#define EXIT_REASON_INVD 13 > > +#define EXIT_REASON_INVLPG 14 > > +#define EXIT_REASON_RDPMC 15 > > +#define EXIT_REASON_RDTSC 16 > > +#define EXIT_REASON_VMCALL 18 > > +#define EXIT_REASON_VMCLEAR 19 > > +#define EXIT_REASON_VMLAUNCH 20 > > +#define EXIT_REASON_VMPTRLD 21 > > +#define EXIT_REASON_VMPTRST 22 > > +#define EXIT_REASON_VMREAD 23 > > +#define EXIT_REASON_VMRESUME 24 > > +#define EXIT_REASON_VMWRITE 25 > > +#define EXIT_REASON_VMOFF 26 > > +#define EXIT_REASON_VMON 27 > > +#define EXIT_REASON_CR_ACCESS 28 > > +#define EXIT_REASON_DR_ACCESS 29 > > +#define EXIT_REASON_IO_INSTRUCTION 30 > > +#define EXIT_REASON_MSR_READ 31 > > +#define EXIT_REASON_MSR_WRITE 32 > > +#define EXIT_REASON_INVALID_STATE 33 > > +#define EXIT_REASON_MWAIT_INSTRUCTION 36 > > +#define EXIT_REASON_MONITOR_INSTRUCTION 39 > > +#define EXIT_REASON_PAUSE_INSTRUCTION 40 > > +#define EXIT_REASON_MCE_DURING_VMENTRY 41 > > +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 > > +#define EXIT_REASON_APIC_ACCESS 44 > > +#define EXIT_REASON_EPT_VIOLATION 48 > > +#define EXIT_REASON_EPT_MISCONFIG 49 > > +#define EXIT_REASON_WBINVD 54 > > +#define EXIT_REASON_XSETBV 55 > > +#define EXIT_REASON_INVPCID 58 > > + > > +#define VMX_EXIT_REASONS \ > > + { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ > > + { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ > > + { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ > > + { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ > > + { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ > > + { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ > > + { EXIT_REASON_CPUID, "CPUID" }, \ > > + { EXIT_REASON_HLT, "HLT" }, \ > > + { EXIT_REASON_INVLPG, "INVLPG" }, \ > > + { EXIT_REASON_RDPMC, "RDPMC" }, \ > > + { EXIT_REASON_RDTSC, "RDTSC" }, \ > > + { EXIT_REASON_VMCALL, "VMCALL" }, \ > > + { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ > > + { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ > > + { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ > > + { EXIT_REASON_VMPTRST, "VMPTRST" }, \ > > + { EXIT_REASON_VMREAD, "VMREAD" }, \ > > + { EXIT_REASON_VMRESUME, "VMRESUME" }, \ > > + { EXIT_REASON_VMWRITE, "VMWRITE" }, \ > > + { EXIT_REASON_VMOFF, "VMOFF" }, \ > > + { EXIT_REASON_VMON, "VMON" }, \ > > + { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ > > + { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ > > + { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ > > + { EXIT_REASON_MSR_READ, "MSR_READ" }, \ > > + { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ > > + { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ > > + { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ > > + { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ > > + { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ > > + { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ > > + { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ > > + { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ > > + { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ > > + { EXIT_REASON_WBINVD, "WBINVD" } > > + > > +#ifdef __KERNEL__ > > + > > #include <linux/types.h> > > > > /* > > @@ -241,49 +323,6 @@ enum vmcs_field { > > HOST_RIP = 0x00006c16, > > }; > > > > -#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 > > - > > -#define EXIT_REASON_EXCEPTION_NMI 0 > > -#define EXIT_REASON_EXTERNAL_INTERRUPT 1 > > -#define EXIT_REASON_TRIPLE_FAULT 2 > > - > > -#define EXIT_REASON_PENDING_INTERRUPT 7 > > -#define EXIT_REASON_NMI_WINDOW 8 > > -#define EXIT_REASON_TASK_SWITCH 9 > > -#define EXIT_REASON_CPUID 10 > > -#define EXIT_REASON_HLT 12 > > -#define EXIT_REASON_INVD 13 > > -#define EXIT_REASON_INVLPG 14 > > -#define EXIT_REASON_RDPMC 15 > > -#define EXIT_REASON_RDTSC 16 > > -#define EXIT_REASON_VMCALL 18 > > -#define EXIT_REASON_VMCLEAR 19 > > -#define EXIT_REASON_VMLAUNCH 20 > > -#define EXIT_REASON_VMPTRLD 21 > > -#define EXIT_REASON_VMPTRST 22 > > -#define EXIT_REASON_VMREAD 23 > > -#define EXIT_REASON_VMRESUME 24 > > -#define EXIT_REASON_VMWRITE 25 > > -#define EXIT_REASON_VMOFF 26 > > -#define EXIT_REASON_VMON 27 > > -#define EXIT_REASON_CR_ACCESS 28 > > -#define EXIT_REASON_DR_ACCESS 29 > > -#define EXIT_REASON_IO_INSTRUCTION 30 > > -#define EXIT_REASON_MSR_READ 31 > > -#define EXIT_REASON_MSR_WRITE 32 > > -#define EXIT_REASON_INVALID_STATE 33 > > -#define EXIT_REASON_MWAIT_INSTRUCTION 36 > > -#define EXIT_REASON_MONITOR_INSTRUCTION 39 > > -#define EXIT_REASON_PAUSE_INSTRUCTION 40 > > -#define EXIT_REASON_MCE_DURING_VMENTRY 41 > > -#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 > > -#define EXIT_REASON_APIC_ACCESS 44 > > -#define EXIT_REASON_EPT_VIOLATION 48 > > -#define EXIT_REASON_EPT_MISCONFIG 49 > > -#define EXIT_REASON_WBINVD 54 > > -#define EXIT_REASON_XSETBV 55 > > -#define EXIT_REASON_INVPCID 58 > > - > > /* > > * Interruption-information format > > */ > > @@ -488,3 +527,5 @@ enum vm_instruction_error_number { > > }; > > > > #endif > > + > > +#endif > > diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h > > index a71faf7..bca63f0 100644 > > --- a/arch/x86/kvm/trace.h > > +++ b/arch/x86/kvm/trace.h > > @@ -183,95 +183,6 @@ TRACE_EVENT(kvm_apic, > > #define KVM_ISA_VMX 1 > > #define KVM_ISA_SVM 2 > > > > -#define VMX_EXIT_REASONS \ > > - { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ > > - { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ > > - { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ > > - { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ > > - { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ > > - { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ > > - { EXIT_REASON_CPUID, "CPUID" }, \ > > - { EXIT_REASON_HLT, "HLT" }, \ > > - { EXIT_REASON_INVLPG, "INVLPG" }, \ > > - { EXIT_REASON_RDPMC, "RDPMC" }, \ > > - { EXIT_REASON_RDTSC, "RDTSC" }, \ > > - { EXIT_REASON_VMCALL, "VMCALL" }, \ > > - { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ > > - { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ > > - { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ > > - { EXIT_REASON_VMPTRST, "VMPTRST" }, \ > > - { EXIT_REASON_VMREAD, "VMREAD" }, \ > > - { EXIT_REASON_VMRESUME, "VMRESUME" }, \ > > - { EXIT_REASON_VMWRITE, "VMWRITE" }, \ > > - { EXIT_REASON_VMOFF, "VMOFF" }, \ > > - { EXIT_REASON_VMON, "VMON" }, \ > > - { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ > > - { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ > > - { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ > > - { EXIT_REASON_MSR_READ, "MSR_READ" }, \ > > - { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ > > - { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ > > - { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ > > - { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ > > - { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ > > - { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ > > - { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ > > - { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ > > - { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ > > - { EXIT_REASON_WBINVD, "WBINVD" } > > - > > -#define SVM_EXIT_REASONS \ > > - { SVM_EXIT_READ_CR0, "read_cr0" }, \ > > - { SVM_EXIT_READ_CR3, "read_cr3" }, \ > > - { SVM_EXIT_READ_CR4, "read_cr4" }, \ > > - { SVM_EXIT_READ_CR8, "read_cr8" }, \ > > - { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ > > - { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ > > - { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ > > - { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ > > - { SVM_EXIT_READ_DR0, "read_dr0" }, \ > > - { SVM_EXIT_READ_DR1, "read_dr1" }, \ > > - { SVM_EXIT_READ_DR2, "read_dr2" }, \ > > - { SVM_EXIT_READ_DR3, "read_dr3" }, \ > > - { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ > > - { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ > > - { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ > > - { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ > > - { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ > > - { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ > > - { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ > > - { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ > > - { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ > > - { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ > > - { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ > > - { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ > > - { SVM_EXIT_INTR, "interrupt" }, \ > > - { SVM_EXIT_NMI, "nmi" }, \ > > - { SVM_EXIT_SMI, "smi" }, \ > > - { SVM_EXIT_INIT, "init" }, \ > > - { SVM_EXIT_VINTR, "vintr" }, \ > > - { SVM_EXIT_CPUID, "cpuid" }, \ > > - { SVM_EXIT_INVD, "invd" }, \ > > - { SVM_EXIT_HLT, "hlt" }, \ > > - { SVM_EXIT_INVLPG, "invlpg" }, \ > > - { SVM_EXIT_INVLPGA, "invlpga" }, \ > > - { SVM_EXIT_IOIO, "io" }, \ > > - { SVM_EXIT_MSR, "msr" }, \ > > - { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ > > - { SVM_EXIT_SHUTDOWN, "shutdown" }, \ > > - { SVM_EXIT_VMRUN, "vmrun" }, \ > > - { SVM_EXIT_VMMCALL, "hypercall" }, \ > > - { SVM_EXIT_VMLOAD, "vmload" }, \ > > - { SVM_EXIT_VMSAVE, "vmsave" }, \ > > - { SVM_EXIT_STGI, "stgi" }, \ > > - { SVM_EXIT_CLGI, "clgi" }, \ > > - { SVM_EXIT_SKINIT, "skinit" }, \ > > - { SVM_EXIT_WBINVD, "wbinvd" }, \ > > - { SVM_EXIT_MONITOR, "monitor" }, \ > > - { SVM_EXIT_MWAIT, "mwait" }, \ > > - { SVM_EXIT_XSETBV, "xsetbv" }, \ > > - { SVM_EXIT_NPF, "npf" } > > - > > /* > > * Tracepoint for kvm guest exit: > > */ > > -- > > 1.7.2.5 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [tip:perf/core] KVM: x86: Export svm/ vmx exit code and vector code to userspace 2012-09-17 8:31 ` [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace Dong Hao 2012-09-17 14:58 ` Arnaldo Carvalho de Melo @ 2012-09-27 4:26 ` tip-bot for Xiao Guangrong 1 sibling, 0 replies; 14+ messages in thread From: tip-bot for Xiao Guangrong @ 2012-09-27 4:26 UTC (permalink / raw) To: linux-tip-commits Cc: acme, linux-kernel, hpa, mingo, runzhen, xiaoguangrong, haodong, mtosatti, dsahern, tglx, avi Commit-ID: 26bf264e871a4b9a8ac09c21a2b518e7f23830d5 Gitweb: http://git.kernel.org/tip/26bf264e871a4b9a8ac09c21a2b518e7f23830d5 Author: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> AuthorDate: Mon, 17 Sep 2012 16:31:13 +0800 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Fri, 21 Sep 2012 12:48:09 -0300 KVM: x86: Export svm/vmx exit code and vector code to userspace Exporting KVM exit information to userspace to be consumed by perf. Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Acked-by: Marcelo Tosatti <mtosatti@redhat.com> Cc: Avi Kivity <avi@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: kvm@vger.kernel.org Cc: Runzhen Wang <runzhen@linux.vnet.ibm.com> Link: http://lkml.kernel.org/r/1347870675-31495-2-git-send-email-haodong@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- arch/x86/include/asm/kvm.h | 16 +++ arch/x86/include/asm/kvm_host.h | 16 --- arch/x86/include/asm/svm.h | 205 +++++++++++++++++++++++++-------------- arch/x86/include/asm/vmx.h | 127 ++++++++++++++++-------- arch/x86/kvm/trace.h | 89 ----------------- 5 files changed, 230 insertions(+), 223 deletions(-) diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h index 246617e..41e08cb 100644 --- a/arch/x86/include/asm/kvm.h +++ b/arch/x86/include/asm/kvm.h @@ -9,6 +9,22 @@ #include <linux/types.h> #include <linux/ioctl.h> +#define DE_VECTOR 0 +#define DB_VECTOR 1 +#define BP_VECTOR 3 +#define OF_VECTOR 4 +#define BR_VECTOR 5 +#define UD_VECTOR 6 +#define NM_VECTOR 7 +#define DF_VECTOR 8 +#define TS_VECTOR 10 +#define NP_VECTOR 11 +#define SS_VECTOR 12 +#define GP_VECTOR 13 +#define PF_VECTOR 14 +#define MF_VECTOR 16 +#define MC_VECTOR 18 + /* Select x86 specific features in <linux/kvm.h> */ #define __KVM_HAVE_PIT #define __KVM_HAVE_IOAPIC diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 09155d6..1eaa6b0 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -75,22 +75,6 @@ #define KVM_HPAGE_MASK(x) (~(KVM_HPAGE_SIZE(x) - 1)) #define KVM_PAGES_PER_HPAGE(x) (KVM_HPAGE_SIZE(x) / PAGE_SIZE) -#define DE_VECTOR 0 -#define DB_VECTOR 1 -#define BP_VECTOR 3 -#define OF_VECTOR 4 -#define BR_VECTOR 5 -#define UD_VECTOR 6 -#define NM_VECTOR 7 -#define DF_VECTOR 8 -#define TS_VECTOR 10 -#define NP_VECTOR 11 -#define SS_VECTOR 12 -#define GP_VECTOR 13 -#define PF_VECTOR 14 -#define MF_VECTOR 16 -#define MC_VECTOR 18 - #define SELECTOR_TI_MASK (1 << 2) #define SELECTOR_RPL_MASK 0x03 diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index f2b83bc..cdf5674 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -1,6 +1,135 @@ #ifndef __SVM_H #define __SVM_H +#define SVM_EXIT_READ_CR0 0x000 +#define SVM_EXIT_READ_CR3 0x003 +#define SVM_EXIT_READ_CR4 0x004 +#define SVM_EXIT_READ_CR8 0x008 +#define SVM_EXIT_WRITE_CR0 0x010 +#define SVM_EXIT_WRITE_CR3 0x013 +#define SVM_EXIT_WRITE_CR4 0x014 +#define SVM_EXIT_WRITE_CR8 0x018 +#define SVM_EXIT_READ_DR0 0x020 +#define SVM_EXIT_READ_DR1 0x021 +#define SVM_EXIT_READ_DR2 0x022 +#define SVM_EXIT_READ_DR3 0x023 +#define SVM_EXIT_READ_DR4 0x024 +#define SVM_EXIT_READ_DR5 0x025 +#define SVM_EXIT_READ_DR6 0x026 +#define SVM_EXIT_READ_DR7 0x027 +#define SVM_EXIT_WRITE_DR0 0x030 +#define SVM_EXIT_WRITE_DR1 0x031 +#define SVM_EXIT_WRITE_DR2 0x032 +#define SVM_EXIT_WRITE_DR3 0x033 +#define SVM_EXIT_WRITE_DR4 0x034 +#define SVM_EXIT_WRITE_DR5 0x035 +#define SVM_EXIT_WRITE_DR6 0x036 +#define SVM_EXIT_WRITE_DR7 0x037 +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_INTR 0x060 +#define SVM_EXIT_NMI 0x061 +#define SVM_EXIT_SMI 0x062 +#define SVM_EXIT_INIT 0x063 +#define SVM_EXIT_VINTR 0x064 +#define SVM_EXIT_CR0_SEL_WRITE 0x065 +#define SVM_EXIT_IDTR_READ 0x066 +#define SVM_EXIT_GDTR_READ 0x067 +#define SVM_EXIT_LDTR_READ 0x068 +#define SVM_EXIT_TR_READ 0x069 +#define SVM_EXIT_IDTR_WRITE 0x06a +#define SVM_EXIT_GDTR_WRITE 0x06b +#define SVM_EXIT_LDTR_WRITE 0x06c +#define SVM_EXIT_TR_WRITE 0x06d +#define SVM_EXIT_RDTSC 0x06e +#define SVM_EXIT_RDPMC 0x06f +#define SVM_EXIT_PUSHF 0x070 +#define SVM_EXIT_POPF 0x071 +#define SVM_EXIT_CPUID 0x072 +#define SVM_EXIT_RSM 0x073 +#define SVM_EXIT_IRET 0x074 +#define SVM_EXIT_SWINT 0x075 +#define SVM_EXIT_INVD 0x076 +#define SVM_EXIT_PAUSE 0x077 +#define SVM_EXIT_HLT 0x078 +#define SVM_EXIT_INVLPG 0x079 +#define SVM_EXIT_INVLPGA 0x07a +#define SVM_EXIT_IOIO 0x07b +#define SVM_EXIT_MSR 0x07c +#define SVM_EXIT_TASK_SWITCH 0x07d +#define SVM_EXIT_FERR_FREEZE 0x07e +#define SVM_EXIT_SHUTDOWN 0x07f +#define SVM_EXIT_VMRUN 0x080 +#define SVM_EXIT_VMMCALL 0x081 +#define SVM_EXIT_VMLOAD 0x082 +#define SVM_EXIT_VMSAVE 0x083 +#define SVM_EXIT_STGI 0x084 +#define SVM_EXIT_CLGI 0x085 +#define SVM_EXIT_SKINIT 0x086 +#define SVM_EXIT_RDTSCP 0x087 +#define SVM_EXIT_ICEBP 0x088 +#define SVM_EXIT_WBINVD 0x089 +#define SVM_EXIT_MONITOR 0x08a +#define SVM_EXIT_MWAIT 0x08b +#define SVM_EXIT_MWAIT_COND 0x08c +#define SVM_EXIT_XSETBV 0x08d +#define SVM_EXIT_NPF 0x400 + +#define SVM_EXIT_ERR -1 + +#define SVM_EXIT_REASONS \ + { SVM_EXIT_READ_CR0, "read_cr0" }, \ + { SVM_EXIT_READ_CR3, "read_cr3" }, \ + { SVM_EXIT_READ_CR4, "read_cr4" }, \ + { SVM_EXIT_READ_CR8, "read_cr8" }, \ + { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ + { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ + { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ + { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ + { SVM_EXIT_READ_DR0, "read_dr0" }, \ + { SVM_EXIT_READ_DR1, "read_dr1" }, \ + { SVM_EXIT_READ_DR2, "read_dr2" }, \ + { SVM_EXIT_READ_DR3, "read_dr3" }, \ + { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ + { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ + { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ + { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ + { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ + { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ + { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ + { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ + { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ + { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ + { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ + { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ + { SVM_EXIT_INTR, "interrupt" }, \ + { SVM_EXIT_NMI, "nmi" }, \ + { SVM_EXIT_SMI, "smi" }, \ + { SVM_EXIT_INIT, "init" }, \ + { SVM_EXIT_VINTR, "vintr" }, \ + { SVM_EXIT_CPUID, "cpuid" }, \ + { SVM_EXIT_INVD, "invd" }, \ + { SVM_EXIT_HLT, "hlt" }, \ + { SVM_EXIT_INVLPG, "invlpg" }, \ + { SVM_EXIT_INVLPGA, "invlpga" }, \ + { SVM_EXIT_IOIO, "io" }, \ + { SVM_EXIT_MSR, "msr" }, \ + { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ + { SVM_EXIT_SHUTDOWN, "shutdown" }, \ + { SVM_EXIT_VMRUN, "vmrun" }, \ + { SVM_EXIT_VMMCALL, "hypercall" }, \ + { SVM_EXIT_VMLOAD, "vmload" }, \ + { SVM_EXIT_VMSAVE, "vmsave" }, \ + { SVM_EXIT_STGI, "stgi" }, \ + { SVM_EXIT_CLGI, "clgi" }, \ + { SVM_EXIT_SKINIT, "skinit" }, \ + { SVM_EXIT_WBINVD, "wbinvd" }, \ + { SVM_EXIT_MONITOR, "monitor" }, \ + { SVM_EXIT_MWAIT, "mwait" }, \ + { SVM_EXIT_XSETBV, "xsetbv" }, \ + { SVM_EXIT_NPF, "npf" } + +#ifdef __KERNEL__ + enum { INTERCEPT_INTR, INTERCEPT_NMI, @@ -264,81 +393,6 @@ struct __attribute__ ((__packed__)) vmcb { #define SVM_EXITINFO_REG_MASK 0x0F -#define SVM_EXIT_READ_CR0 0x000 -#define SVM_EXIT_READ_CR3 0x003 -#define SVM_EXIT_READ_CR4 0x004 -#define SVM_EXIT_READ_CR8 0x008 -#define SVM_EXIT_WRITE_CR0 0x010 -#define SVM_EXIT_WRITE_CR3 0x013 -#define SVM_EXIT_WRITE_CR4 0x014 -#define SVM_EXIT_WRITE_CR8 0x018 -#define SVM_EXIT_READ_DR0 0x020 -#define SVM_EXIT_READ_DR1 0x021 -#define SVM_EXIT_READ_DR2 0x022 -#define SVM_EXIT_READ_DR3 0x023 -#define SVM_EXIT_READ_DR4 0x024 -#define SVM_EXIT_READ_DR5 0x025 -#define SVM_EXIT_READ_DR6 0x026 -#define SVM_EXIT_READ_DR7 0x027 -#define SVM_EXIT_WRITE_DR0 0x030 -#define SVM_EXIT_WRITE_DR1 0x031 -#define SVM_EXIT_WRITE_DR2 0x032 -#define SVM_EXIT_WRITE_DR3 0x033 -#define SVM_EXIT_WRITE_DR4 0x034 -#define SVM_EXIT_WRITE_DR5 0x035 -#define SVM_EXIT_WRITE_DR6 0x036 -#define SVM_EXIT_WRITE_DR7 0x037 -#define SVM_EXIT_EXCP_BASE 0x040 -#define SVM_EXIT_INTR 0x060 -#define SVM_EXIT_NMI 0x061 -#define SVM_EXIT_SMI 0x062 -#define SVM_EXIT_INIT 0x063 -#define SVM_EXIT_VINTR 0x064 -#define SVM_EXIT_CR0_SEL_WRITE 0x065 -#define SVM_EXIT_IDTR_READ 0x066 -#define SVM_EXIT_GDTR_READ 0x067 -#define SVM_EXIT_LDTR_READ 0x068 -#define SVM_EXIT_TR_READ 0x069 -#define SVM_EXIT_IDTR_WRITE 0x06a -#define SVM_EXIT_GDTR_WRITE 0x06b -#define SVM_EXIT_LDTR_WRITE 0x06c -#define SVM_EXIT_TR_WRITE 0x06d -#define SVM_EXIT_RDTSC 0x06e -#define SVM_EXIT_RDPMC 0x06f -#define SVM_EXIT_PUSHF 0x070 -#define SVM_EXIT_POPF 0x071 -#define SVM_EXIT_CPUID 0x072 -#define SVM_EXIT_RSM 0x073 -#define SVM_EXIT_IRET 0x074 -#define SVM_EXIT_SWINT 0x075 -#define SVM_EXIT_INVD 0x076 -#define SVM_EXIT_PAUSE 0x077 -#define SVM_EXIT_HLT 0x078 -#define SVM_EXIT_INVLPG 0x079 -#define SVM_EXIT_INVLPGA 0x07a -#define SVM_EXIT_IOIO 0x07b -#define SVM_EXIT_MSR 0x07c -#define SVM_EXIT_TASK_SWITCH 0x07d -#define SVM_EXIT_FERR_FREEZE 0x07e -#define SVM_EXIT_SHUTDOWN 0x07f -#define SVM_EXIT_VMRUN 0x080 -#define SVM_EXIT_VMMCALL 0x081 -#define SVM_EXIT_VMLOAD 0x082 -#define SVM_EXIT_VMSAVE 0x083 -#define SVM_EXIT_STGI 0x084 -#define SVM_EXIT_CLGI 0x085 -#define SVM_EXIT_SKINIT 0x086 -#define SVM_EXIT_RDTSCP 0x087 -#define SVM_EXIT_ICEBP 0x088 -#define SVM_EXIT_WBINVD 0x089 -#define SVM_EXIT_MONITOR 0x08a -#define SVM_EXIT_MWAIT 0x08b -#define SVM_EXIT_MWAIT_COND 0x08c -#define SVM_EXIT_XSETBV 0x08d -#define SVM_EXIT_NPF 0x400 - -#define SVM_EXIT_ERR -1 - #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP) #define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda" @@ -350,3 +404,4 @@ struct __attribute__ ((__packed__)) vmcb { #endif +#endif diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 74fcb96..36ec21c 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -25,6 +25,88 @@ * */ +#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 + +#define EXIT_REASON_EXCEPTION_NMI 0 +#define EXIT_REASON_EXTERNAL_INTERRUPT 1 +#define EXIT_REASON_TRIPLE_FAULT 2 + +#define EXIT_REASON_PENDING_INTERRUPT 7 +#define EXIT_REASON_NMI_WINDOW 8 +#define EXIT_REASON_TASK_SWITCH 9 +#define EXIT_REASON_CPUID 10 +#define EXIT_REASON_HLT 12 +#define EXIT_REASON_INVD 13 +#define EXIT_REASON_INVLPG 14 +#define EXIT_REASON_RDPMC 15 +#define EXIT_REASON_RDTSC 16 +#define EXIT_REASON_VMCALL 18 +#define EXIT_REASON_VMCLEAR 19 +#define EXIT_REASON_VMLAUNCH 20 +#define EXIT_REASON_VMPTRLD 21 +#define EXIT_REASON_VMPTRST 22 +#define EXIT_REASON_VMREAD 23 +#define EXIT_REASON_VMRESUME 24 +#define EXIT_REASON_VMWRITE 25 +#define EXIT_REASON_VMOFF 26 +#define EXIT_REASON_VMON 27 +#define EXIT_REASON_CR_ACCESS 28 +#define EXIT_REASON_DR_ACCESS 29 +#define EXIT_REASON_IO_INSTRUCTION 30 +#define EXIT_REASON_MSR_READ 31 +#define EXIT_REASON_MSR_WRITE 32 +#define EXIT_REASON_INVALID_STATE 33 +#define EXIT_REASON_MWAIT_INSTRUCTION 36 +#define EXIT_REASON_MONITOR_INSTRUCTION 39 +#define EXIT_REASON_PAUSE_INSTRUCTION 40 +#define EXIT_REASON_MCE_DURING_VMENTRY 41 +#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 +#define EXIT_REASON_APIC_ACCESS 44 +#define EXIT_REASON_EPT_VIOLATION 48 +#define EXIT_REASON_EPT_MISCONFIG 49 +#define EXIT_REASON_WBINVD 54 +#define EXIT_REASON_XSETBV 55 +#define EXIT_REASON_INVPCID 58 + +#define VMX_EXIT_REASONS \ + { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ + { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ + { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ + { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ + { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ + { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ + { EXIT_REASON_CPUID, "CPUID" }, \ + { EXIT_REASON_HLT, "HLT" }, \ + { EXIT_REASON_INVLPG, "INVLPG" }, \ + { EXIT_REASON_RDPMC, "RDPMC" }, \ + { EXIT_REASON_RDTSC, "RDTSC" }, \ + { EXIT_REASON_VMCALL, "VMCALL" }, \ + { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ + { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ + { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ + { EXIT_REASON_VMPTRST, "VMPTRST" }, \ + { EXIT_REASON_VMREAD, "VMREAD" }, \ + { EXIT_REASON_VMRESUME, "VMRESUME" }, \ + { EXIT_REASON_VMWRITE, "VMWRITE" }, \ + { EXIT_REASON_VMOFF, "VMOFF" }, \ + { EXIT_REASON_VMON, "VMON" }, \ + { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ + { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ + { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ + { EXIT_REASON_MSR_READ, "MSR_READ" }, \ + { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ + { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ + { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ + { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ + { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ + { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ + { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ + { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ + { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ + { EXIT_REASON_WBINVD, "WBINVD" } + +#ifdef __KERNEL__ + #include <linux/types.h> /* @@ -241,49 +323,6 @@ enum vmcs_field { HOST_RIP = 0x00006c16, }; -#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000 - -#define EXIT_REASON_EXCEPTION_NMI 0 -#define EXIT_REASON_EXTERNAL_INTERRUPT 1 -#define EXIT_REASON_TRIPLE_FAULT 2 - -#define EXIT_REASON_PENDING_INTERRUPT 7 -#define EXIT_REASON_NMI_WINDOW 8 -#define EXIT_REASON_TASK_SWITCH 9 -#define EXIT_REASON_CPUID 10 -#define EXIT_REASON_HLT 12 -#define EXIT_REASON_INVD 13 -#define EXIT_REASON_INVLPG 14 -#define EXIT_REASON_RDPMC 15 -#define EXIT_REASON_RDTSC 16 -#define EXIT_REASON_VMCALL 18 -#define EXIT_REASON_VMCLEAR 19 -#define EXIT_REASON_VMLAUNCH 20 -#define EXIT_REASON_VMPTRLD 21 -#define EXIT_REASON_VMPTRST 22 -#define EXIT_REASON_VMREAD 23 -#define EXIT_REASON_VMRESUME 24 -#define EXIT_REASON_VMWRITE 25 -#define EXIT_REASON_VMOFF 26 -#define EXIT_REASON_VMON 27 -#define EXIT_REASON_CR_ACCESS 28 -#define EXIT_REASON_DR_ACCESS 29 -#define EXIT_REASON_IO_INSTRUCTION 30 -#define EXIT_REASON_MSR_READ 31 -#define EXIT_REASON_MSR_WRITE 32 -#define EXIT_REASON_INVALID_STATE 33 -#define EXIT_REASON_MWAIT_INSTRUCTION 36 -#define EXIT_REASON_MONITOR_INSTRUCTION 39 -#define EXIT_REASON_PAUSE_INSTRUCTION 40 -#define EXIT_REASON_MCE_DURING_VMENTRY 41 -#define EXIT_REASON_TPR_BELOW_THRESHOLD 43 -#define EXIT_REASON_APIC_ACCESS 44 -#define EXIT_REASON_EPT_VIOLATION 48 -#define EXIT_REASON_EPT_MISCONFIG 49 -#define EXIT_REASON_WBINVD 54 -#define EXIT_REASON_XSETBV 55 -#define EXIT_REASON_INVPCID 58 - /* * Interruption-information format */ @@ -488,3 +527,5 @@ enum vm_instruction_error_number { }; #endif + +#endif diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index a71faf7..bca63f0 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -183,95 +183,6 @@ TRACE_EVENT(kvm_apic, #define KVM_ISA_VMX 1 #define KVM_ISA_SVM 2 -#define VMX_EXIT_REASONS \ - { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ - { EXIT_REASON_EXTERNAL_INTERRUPT, "EXTERNAL_INTERRUPT" }, \ - { EXIT_REASON_TRIPLE_FAULT, "TRIPLE_FAULT" }, \ - { EXIT_REASON_PENDING_INTERRUPT, "PENDING_INTERRUPT" }, \ - { EXIT_REASON_NMI_WINDOW, "NMI_WINDOW" }, \ - { EXIT_REASON_TASK_SWITCH, "TASK_SWITCH" }, \ - { EXIT_REASON_CPUID, "CPUID" }, \ - { EXIT_REASON_HLT, "HLT" }, \ - { EXIT_REASON_INVLPG, "INVLPG" }, \ - { EXIT_REASON_RDPMC, "RDPMC" }, \ - { EXIT_REASON_RDTSC, "RDTSC" }, \ - { EXIT_REASON_VMCALL, "VMCALL" }, \ - { EXIT_REASON_VMCLEAR, "VMCLEAR" }, \ - { EXIT_REASON_VMLAUNCH, "VMLAUNCH" }, \ - { EXIT_REASON_VMPTRLD, "VMPTRLD" }, \ - { EXIT_REASON_VMPTRST, "VMPTRST" }, \ - { EXIT_REASON_VMREAD, "VMREAD" }, \ - { EXIT_REASON_VMRESUME, "VMRESUME" }, \ - { EXIT_REASON_VMWRITE, "VMWRITE" }, \ - { EXIT_REASON_VMOFF, "VMOFF" }, \ - { EXIT_REASON_VMON, "VMON" }, \ - { EXIT_REASON_CR_ACCESS, "CR_ACCESS" }, \ - { EXIT_REASON_DR_ACCESS, "DR_ACCESS" }, \ - { EXIT_REASON_IO_INSTRUCTION, "IO_INSTRUCTION" }, \ - { EXIT_REASON_MSR_READ, "MSR_READ" }, \ - { EXIT_REASON_MSR_WRITE, "MSR_WRITE" }, \ - { EXIT_REASON_MWAIT_INSTRUCTION, "MWAIT_INSTRUCTION" }, \ - { EXIT_REASON_MONITOR_INSTRUCTION, "MONITOR_INSTRUCTION" }, \ - { EXIT_REASON_PAUSE_INSTRUCTION, "PAUSE_INSTRUCTION" }, \ - { EXIT_REASON_MCE_DURING_VMENTRY, "MCE_DURING_VMENTRY" }, \ - { EXIT_REASON_TPR_BELOW_THRESHOLD, "TPR_BELOW_THRESHOLD" }, \ - { EXIT_REASON_APIC_ACCESS, "APIC_ACCESS" }, \ - { EXIT_REASON_EPT_VIOLATION, "EPT_VIOLATION" }, \ - { EXIT_REASON_EPT_MISCONFIG, "EPT_MISCONFIG" }, \ - { EXIT_REASON_WBINVD, "WBINVD" } - -#define SVM_EXIT_REASONS \ - { SVM_EXIT_READ_CR0, "read_cr0" }, \ - { SVM_EXIT_READ_CR3, "read_cr3" }, \ - { SVM_EXIT_READ_CR4, "read_cr4" }, \ - { SVM_EXIT_READ_CR8, "read_cr8" }, \ - { SVM_EXIT_WRITE_CR0, "write_cr0" }, \ - { SVM_EXIT_WRITE_CR3, "write_cr3" }, \ - { SVM_EXIT_WRITE_CR4, "write_cr4" }, \ - { SVM_EXIT_WRITE_CR8, "write_cr8" }, \ - { SVM_EXIT_READ_DR0, "read_dr0" }, \ - { SVM_EXIT_READ_DR1, "read_dr1" }, \ - { SVM_EXIT_READ_DR2, "read_dr2" }, \ - { SVM_EXIT_READ_DR3, "read_dr3" }, \ - { SVM_EXIT_WRITE_DR0, "write_dr0" }, \ - { SVM_EXIT_WRITE_DR1, "write_dr1" }, \ - { SVM_EXIT_WRITE_DR2, "write_dr2" }, \ - { SVM_EXIT_WRITE_DR3, "write_dr3" }, \ - { SVM_EXIT_WRITE_DR5, "write_dr5" }, \ - { SVM_EXIT_WRITE_DR7, "write_dr7" }, \ - { SVM_EXIT_EXCP_BASE + DB_VECTOR, "DB excp" }, \ - { SVM_EXIT_EXCP_BASE + BP_VECTOR, "BP excp" }, \ - { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ - { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ - { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ - { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ - { SVM_EXIT_INTR, "interrupt" }, \ - { SVM_EXIT_NMI, "nmi" }, \ - { SVM_EXIT_SMI, "smi" }, \ - { SVM_EXIT_INIT, "init" }, \ - { SVM_EXIT_VINTR, "vintr" }, \ - { SVM_EXIT_CPUID, "cpuid" }, \ - { SVM_EXIT_INVD, "invd" }, \ - { SVM_EXIT_HLT, "hlt" }, \ - { SVM_EXIT_INVLPG, "invlpg" }, \ - { SVM_EXIT_INVLPGA, "invlpga" }, \ - { SVM_EXIT_IOIO, "io" }, \ - { SVM_EXIT_MSR, "msr" }, \ - { SVM_EXIT_TASK_SWITCH, "task_switch" }, \ - { SVM_EXIT_SHUTDOWN, "shutdown" }, \ - { SVM_EXIT_VMRUN, "vmrun" }, \ - { SVM_EXIT_VMMCALL, "hypercall" }, \ - { SVM_EXIT_VMLOAD, "vmload" }, \ - { SVM_EXIT_VMSAVE, "vmsave" }, \ - { SVM_EXIT_STGI, "stgi" }, \ - { SVM_EXIT_CLGI, "clgi" }, \ - { SVM_EXIT_SKINIT, "skinit" }, \ - { SVM_EXIT_WBINVD, "wbinvd" }, \ - { SVM_EXIT_MONITOR, "monitor" }, \ - { SVM_EXIT_MWAIT, "mwait" }, \ - { SVM_EXIT_XSETBV, "xsetbv" }, \ - { SVM_EXIT_NPF, "npf" } - /* * Tracepoint for kvm guest exit: */ ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v8 2/3] perf: move stat related code to util/stat.c 2012-09-17 8:31 [PATCH v8 0/3] KVM: perf: kvm events analysis tool Dong Hao 2012-09-17 8:31 ` [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace Dong Hao @ 2012-09-17 8:31 ` Dong Hao 2012-09-18 14:01 ` David Ahern ` (2 more replies) 2012-09-17 8:31 ` [PATCH v8 3/3] KVM: perf: kvm events analysis tool Dong Hao 2 siblings, 3 replies; 14+ messages in thread From: Dong Hao @ 2012-09-17 8:31 UTC (permalink / raw) To: acme, dsahern, mtosatti, avi, mingo, linux-kernel, kvm Cc: xiaoguangrong, runzhen From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Then, the code can be shared between kvm events and perf stat [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> --- tools/perf/Makefile | 1 + tools/perf/builtin-stat.c | 56 +------------------------------------------ tools/perf/util/stat.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/stat.h | 16 ++++++++++++ 4 files changed, 76 insertions(+), 54 deletions(-) create mode 100644 tools/perf/util/stat.c create mode 100644 tools/perf/util/stat.h diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 209774b..5077f8e 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -406,6 +406,7 @@ LIB_OBJS += $(OUTPUT)util/target.o LIB_OBJS += $(OUTPUT)util/rblist.o LIB_OBJS += $(OUTPUT)util/intlist.o LIB_OBJS += $(OUTPUT)util/vdso.o +LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)ui/helpline.o LIB_OBJS += $(OUTPUT)ui/hist.o diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index dab347d..3c43a35 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -51,13 +51,13 @@ #include "util/evsel.h" #include "util/debug.h" #include "util/color.h" +#include "util/stat.h" #include "util/header.h" #include "util/cpumap.h" #include "util/thread.h" #include "util/thread_map.h" #include <sys/prctl.h> -#include <math.h> #include <locale.h> #define DEFAULT_SEPARATOR " " @@ -199,11 +199,6 @@ static int output_fd; static volatile int done = 0; -struct stats -{ - double n, mean, M2; -}; - struct perf_stat { struct stats res_stats[3]; }; @@ -220,50 +215,6 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) evsel->priv = NULL; } -static void update_stats(struct stats *stats, u64 val) -{ - double delta; - - stats->n++; - delta = val - stats->mean; - stats->mean += delta / stats->n; - stats->M2 += delta*(val - stats->mean); -} - -static double avg_stats(struct stats *stats) -{ - return stats->mean; -} - -/* - * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance - * - * (\Sum n_i^2) - ((\Sum n_i)^2)/n - * s^2 = ------------------------------- - * n - 1 - * - * http://en.wikipedia.org/wiki/Stddev - * - * The std dev of the mean is related to the std dev by: - * - * s - * s_mean = ------- - * sqrt(n) - * - */ -static double stddev_stats(struct stats *stats) -{ - double variance, variance_mean; - - if (!stats->n) - return 0.0; - - variance = stats->M2 / (stats->n - 1); - variance_mean = variance / stats->n; - - return sqrt(variance_mean); -} - static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; static struct stats runtime_cycles_stats[MAX_NR_CPUS]; static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; @@ -559,10 +510,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) static void print_noise_pct(double total, double avg) { - double pct = 0.0; - - if (avg) - pct = 100.0*total/avg; + double pct = rel_stddev_stats(total, avg); if (csv_output) fprintf(output, "%s%.2f%%", csv_sep, pct); diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c new file mode 100644 index 0000000..2374212 --- /dev/null +++ b/tools/perf/util/stat.c @@ -0,0 +1,57 @@ +#include <math.h> + +#include "stat.h" + +void update_stats(struct stats *stats, u64 val) +{ + double delta; + + stats->n++; + delta = val - stats->mean; + stats->mean += delta / stats->n; + stats->M2 += delta*(val - stats->mean); +} + +double avg_stats(struct stats *stats) +{ + return stats->mean; +} + +/* + * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance + * + * (\Sum n_i^2) - ((\Sum n_i)^2)/n + * s^2 = ------------------------------- + * n - 1 + * + * http://en.wikipedia.org/wiki/Stddev + * + * The std dev of the mean is related to the std dev by: + * + * s + * s_mean = ------- + * sqrt(n) + * + */ +double stddev_stats(struct stats *stats) +{ + double variance, variance_mean; + + if (!stats->n) + return 0.0; + + variance = stats->M2 / (stats->n - 1); + variance_mean = variance / stats->n; + + return sqrt(variance_mean); +} + +double rel_stddev_stats(double stddev, double avg) +{ + double pct = 0.0; + + if (avg) + pct = 100.0 * stddev/avg; + + return pct; +} diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h new file mode 100644 index 0000000..588367c --- /dev/null +++ b/tools/perf/util/stat.h @@ -0,0 +1,16 @@ +#ifndef __PERF_STATS_H +#define __PERF_STATS_H + +#include "types.h" + +struct stats +{ + double n, mean, M2; +}; + +void update_stats(struct stats *stats, u64 val); +double avg_stats(struct stats *stats); +double stddev_stats(struct stats *stats); +double rel_stddev_stats(double stddev, double avg); + +#endif -- 1.7.2.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v8 2/3] perf: move stat related code to util/stat.c 2012-09-17 8:31 ` [PATCH v8 2/3] perf: move stat related code to util/stat.c Dong Hao @ 2012-09-18 14:01 ` David Ahern 2012-09-18 19:18 ` David Ahern 2012-09-19 15:18 ` [tip:perf/core] perf stat: Move stats " tip-bot for Xiao Guangrong 2 siblings, 0 replies; 14+ messages in thread From: David Ahern @ 2012-09-18 14:01 UTC (permalink / raw) To: Dong Hao Cc: acme, mtosatti, avi, mingo, linux-kernel, kvm, xiaoguangrong, runzhen On 9/17/12 2:31 AM, Dong Hao wrote: > From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > > Then, the code can be shared between kvm events and perf stat > > [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] > Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> > --- > tools/perf/Makefile | 1 + > tools/perf/builtin-stat.c | 56 +------------------------------------------ > tools/perf/util/stat.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ > tools/perf/util/stat.h | 16 ++++++++++++ > 4 files changed, 76 insertions(+), 54 deletions(-) > create mode 100644 tools/perf/util/stat.c > create mode 100644 tools/perf/util/stat.h > > diff --git a/tools/perf/Makefile b/tools/perf/Makefile > index 209774b..5077f8e 100644 > --- a/tools/perf/Makefile > +++ b/tools/perf/Makefile > @@ -406,6 +406,7 @@ LIB_OBJS += $(OUTPUT)util/target.o > LIB_OBJS += $(OUTPUT)util/rblist.o > LIB_OBJS += $(OUTPUT)util/intlist.o > LIB_OBJS += $(OUTPUT)util/vdso.o > +LIB_OBJS += $(OUTPUT)util/stat.o > > LIB_OBJS += $(OUTPUT)ui/helpline.o > LIB_OBJS += $(OUTPUT)ui/hist.o > diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c > index dab347d..3c43a35 100644 > --- a/tools/perf/builtin-stat.c > +++ b/tools/perf/builtin-stat.c > @@ -51,13 +51,13 @@ > #include "util/evsel.h" > #include "util/debug.h" > #include "util/color.h" > +#include "util/stat.h" > #include "util/header.h" > #include "util/cpumap.h" > #include "util/thread.h" > #include "util/thread_map.h" > > #include <sys/prctl.h> > -#include <math.h> > #include <locale.h> > > #define DEFAULT_SEPARATOR " " > @@ -199,11 +199,6 @@ static int output_fd; > > static volatile int done = 0; > > -struct stats > -{ > - double n, mean, M2; > -}; > - > struct perf_stat { > struct stats res_stats[3]; > }; > @@ -220,50 +215,6 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) > evsel->priv = NULL; > } > > -static void update_stats(struct stats *stats, u64 val) > -{ > - double delta; > - > - stats->n++; > - delta = val - stats->mean; > - stats->mean += delta / stats->n; > - stats->M2 += delta*(val - stats->mean); > -} > - > -static double avg_stats(struct stats *stats) > -{ > - return stats->mean; > -} > - > -/* > - * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance > - * > - * (\Sum n_i^2) - ((\Sum n_i)^2)/n > - * s^2 = ------------------------------- > - * n - 1 > - * > - * http://en.wikipedia.org/wiki/Stddev > - * > - * The std dev of the mean is related to the std dev by: > - * > - * s > - * s_mean = ------- > - * sqrt(n) > - * > - */ > -static double stddev_stats(struct stats *stats) > -{ > - double variance, variance_mean; > - > - if (!stats->n) > - return 0.0; > - > - variance = stats->M2 / (stats->n - 1); > - variance_mean = variance / stats->n; > - > - return sqrt(variance_mean); > -} > - > static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; > static struct stats runtime_cycles_stats[MAX_NR_CPUS]; > static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; > @@ -559,10 +510,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) > > static void print_noise_pct(double total, double avg) > { > - double pct = 0.0; > - > - if (avg) > - pct = 100.0*total/avg; > + double pct = rel_stddev_stats(total, avg); > > if (csv_output) > fprintf(output, "%s%.2f%%", csv_sep, pct); > diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c > new file mode 100644 > index 0000000..2374212 > --- /dev/null > +++ b/tools/perf/util/stat.c > @@ -0,0 +1,57 @@ > +#include <math.h> > + > +#include "stat.h" > + > +void update_stats(struct stats *stats, u64 val) > +{ > + double delta; > + > + stats->n++; > + delta = val - stats->mean; > + stats->mean += delta / stats->n; > + stats->M2 += delta*(val - stats->mean); > +} > + > +double avg_stats(struct stats *stats) > +{ > + return stats->mean; > +} > + > +/* > + * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance > + * > + * (\Sum n_i^2) - ((\Sum n_i)^2)/n > + * s^2 = ------------------------------- > + * n - 1 > + * > + * http://en.wikipedia.org/wiki/Stddev > + * > + * The std dev of the mean is related to the std dev by: > + * > + * s > + * s_mean = ------- > + * sqrt(n) > + * > + */ > +double stddev_stats(struct stats *stats) > +{ > + double variance, variance_mean; > + > + if (!stats->n) > + return 0.0; > + > + variance = stats->M2 / (stats->n - 1); > + variance_mean = variance / stats->n; > + > + return sqrt(variance_mean); > +} > + > +double rel_stddev_stats(double stddev, double avg) > +{ > + double pct = 0.0; > + > + if (avg) > + pct = 100.0 * stddev/avg; > + > + return pct; > +} rel_stddev_stats should take the struct stats as an input and use elements from it to compute the return value. perf-stat's relative stddev sites can be fixed later. > diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h > new file mode 100644 > index 0000000..588367c > --- /dev/null > +++ b/tools/perf/util/stat.h > @@ -0,0 +1,16 @@ > +#ifndef __PERF_STATS_H > +#define __PERF_STATS_H > + > +#include "types.h" > + > +struct stats > +{ > + double n, mean, M2; > +}; > + > +void update_stats(struct stats *stats, u64 val); > +double avg_stats(struct stats *stats); > +double stddev_stats(struct stats *stats); > +double rel_stddev_stats(double stddev, double avg); > + > +#endif > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v8 2/3] perf: move stat related code to util/stat.c 2012-09-17 8:31 ` [PATCH v8 2/3] perf: move stat related code to util/stat.c Dong Hao 2012-09-18 14:01 ` David Ahern @ 2012-09-18 19:18 ` David Ahern 2012-09-19 1:53 ` Xiao Guangrong 2012-09-19 15:18 ` [tip:perf/core] perf stat: Move stats " tip-bot for Xiao Guangrong 2 siblings, 1 reply; 14+ messages in thread From: David Ahern @ 2012-09-18 19:18 UTC (permalink / raw) To: Dong Hao Cc: acme, mtosatti, avi, mingo, linux-kernel, kvm, xiaoguangrong, runzhen On 9/17/12 2:31 AM, Dong Hao wrote: > From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > > Then, the code can be shared between kvm events and perf stat > > [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] > Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> > --- > tools/perf/Makefile | 1 + > tools/perf/builtin-stat.c | 56 +------------------------------------------ > tools/perf/util/stat.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ > tools/perf/util/stat.h | 16 ++++++++++++ > 4 files changed, 76 insertions(+), 54 deletions(-) > create mode 100644 tools/perf/util/stat.c > create mode 100644 tools/perf/util/stat.h Does not apply to Arnaldo's latest perf/core branch. David ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v8 2/3] perf: move stat related code to util/stat.c 2012-09-18 19:18 ` David Ahern @ 2012-09-19 1:53 ` Xiao Guangrong 2012-09-19 4:00 ` David Ahern 0 siblings, 1 reply; 14+ messages in thread From: Xiao Guangrong @ 2012-09-19 1:53 UTC (permalink / raw) To: David Ahern Cc: Dong Hao, acme, mtosatti, avi, mingo, linux-kernel, kvm, runzhen On 09/19/2012 03:18 AM, David Ahern wrote: > On 9/17/12 2:31 AM, Dong Hao wrote: >> From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> >> >> Then, the code can be shared between kvm events and perf stat >> >> [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] >> Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> >> Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> >> --- >> tools/perf/Makefile | 1 + >> tools/perf/builtin-stat.c | 56 +------------------------------------------ >> tools/perf/util/stat.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ >> tools/perf/util/stat.h | 16 ++++++++++++ >> 4 files changed, 76 insertions(+), 54 deletions(-) >> create mode 100644 tools/perf/util/stat.c >> create mode 100644 tools/perf/util/stat.h > > Does not apply to Arnaldo's latest perf/core branch. The patch has already been applied to this branch: http://git.kernel.org/?p=linux/kernel/git/acme/linux.git;a=commit;h=0007eceaceb11520071d053acfe06ee3326b1d13 You or we can improve rel_stddev_stats after perf-stat's code is fixed. :) ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v8 2/3] perf: move stat related code to util/stat.c 2012-09-19 1:53 ` Xiao Guangrong @ 2012-09-19 4:00 ` David Ahern 0 siblings, 0 replies; 14+ messages in thread From: David Ahern @ 2012-09-19 4:00 UTC (permalink / raw) To: Xiao Guangrong Cc: Dong Hao, acme, mtosatti, avi, mingo, linux-kernel, kvm, runzhen On 9/18/12 7:53 PM, Xiao Guangrong wrote: >> Does not apply to Arnaldo's latest perf/core branch. > > The patch has already been applied to this branch: > http://git.kernel.org/?p=linux/kernel/git/acme/linux.git;a=commit;h=0007eceaceb11520071d053acfe06ee3326b1d13 Did not expect that. ok. I'll try patch 3 tomorrow. ^ permalink raw reply [flat|nested] 14+ messages in thread
* [tip:perf/core] perf stat: Move stats related code to util/stat.c 2012-09-17 8:31 ` [PATCH v8 2/3] perf: move stat related code to util/stat.c Dong Hao 2012-09-18 14:01 ` David Ahern 2012-09-18 19:18 ` David Ahern @ 2012-09-19 15:18 ` tip-bot for Xiao Guangrong 2 siblings, 0 replies; 14+ messages in thread From: tip-bot for Xiao Guangrong @ 2012-09-19 15:18 UTC (permalink / raw) To: linux-tip-commits Cc: acme, linux-kernel, hpa, mingo, runzhen, xiaoguangrong, haodong, mtosatti, dsahern, tglx, avi Commit-ID: 0007eceaceb11520071d053acfe06ee3326b1d13 Gitweb: http://git.kernel.org/tip/0007eceaceb11520071d053acfe06ee3326b1d13 Author: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> AuthorDate: Mon, 17 Sep 2012 16:31:14 +0800 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Mon, 17 Sep 2012 13:10:03 -0300 perf stat: Move stats related code to util/stat.c Then, the code can be shared between kvm events and perf stat. Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> [ Dong Hao <haodong@linux.vnet.ibm.com>: rebase it on acme's git tree ] Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> Cc: Avi Kivity <avi@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: kvm@vger.kernel.org Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: Runzhen Wang <runzhen@linux.vnet.ibm.com> Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/1347870675-31495-3-git-send-email-haodong@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/Makefile | 1 + tools/perf/builtin-stat.c | 56 +------------------------------------------ tools/perf/util/stat.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/stat.h | 16 ++++++++++++ 4 files changed, 76 insertions(+), 54 deletions(-) diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 209774b..5077f8e 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -406,6 +406,7 @@ LIB_OBJS += $(OUTPUT)util/target.o LIB_OBJS += $(OUTPUT)util/rblist.o LIB_OBJS += $(OUTPUT)util/intlist.o LIB_OBJS += $(OUTPUT)util/vdso.o +LIB_OBJS += $(OUTPUT)util/stat.o LIB_OBJS += $(OUTPUT)ui/helpline.o LIB_OBJS += $(OUTPUT)ui/hist.o diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index dab347d..3c43a35 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -51,13 +51,13 @@ #include "util/evsel.h" #include "util/debug.h" #include "util/color.h" +#include "util/stat.h" #include "util/header.h" #include "util/cpumap.h" #include "util/thread.h" #include "util/thread_map.h" #include <sys/prctl.h> -#include <math.h> #include <locale.h> #define DEFAULT_SEPARATOR " " @@ -199,11 +199,6 @@ static int output_fd; static volatile int done = 0; -struct stats -{ - double n, mean, M2; -}; - struct perf_stat { struct stats res_stats[3]; }; @@ -220,50 +215,6 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) evsel->priv = NULL; } -static void update_stats(struct stats *stats, u64 val) -{ - double delta; - - stats->n++; - delta = val - stats->mean; - stats->mean += delta / stats->n; - stats->M2 += delta*(val - stats->mean); -} - -static double avg_stats(struct stats *stats) -{ - return stats->mean; -} - -/* - * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance - * - * (\Sum n_i^2) - ((\Sum n_i)^2)/n - * s^2 = ------------------------------- - * n - 1 - * - * http://en.wikipedia.org/wiki/Stddev - * - * The std dev of the mean is related to the std dev by: - * - * s - * s_mean = ------- - * sqrt(n) - * - */ -static double stddev_stats(struct stats *stats) -{ - double variance, variance_mean; - - if (!stats->n) - return 0.0; - - variance = stats->M2 / (stats->n - 1); - variance_mean = variance / stats->n; - - return sqrt(variance_mean); -} - static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; static struct stats runtime_cycles_stats[MAX_NR_CPUS]; static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS]; @@ -559,10 +510,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) static void print_noise_pct(double total, double avg) { - double pct = 0.0; - - if (avg) - pct = 100.0*total/avg; + double pct = rel_stddev_stats(total, avg); if (csv_output) fprintf(output, "%s%.2f%%", csv_sep, pct); diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c new file mode 100644 index 0000000..2374212 --- /dev/null +++ b/tools/perf/util/stat.c @@ -0,0 +1,57 @@ +#include <math.h> + +#include "stat.h" + +void update_stats(struct stats *stats, u64 val) +{ + double delta; + + stats->n++; + delta = val - stats->mean; + stats->mean += delta / stats->n; + stats->M2 += delta*(val - stats->mean); +} + +double avg_stats(struct stats *stats) +{ + return stats->mean; +} + +/* + * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance + * + * (\Sum n_i^2) - ((\Sum n_i)^2)/n + * s^2 = ------------------------------- + * n - 1 + * + * http://en.wikipedia.org/wiki/Stddev + * + * The std dev of the mean is related to the std dev by: + * + * s + * s_mean = ------- + * sqrt(n) + * + */ +double stddev_stats(struct stats *stats) +{ + double variance, variance_mean; + + if (!stats->n) + return 0.0; + + variance = stats->M2 / (stats->n - 1); + variance_mean = variance / stats->n; + + return sqrt(variance_mean); +} + +double rel_stddev_stats(double stddev, double avg) +{ + double pct = 0.0; + + if (avg) + pct = 100.0 * stddev/avg; + + return pct; +} diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h new file mode 100644 index 0000000..588367c --- /dev/null +++ b/tools/perf/util/stat.h @@ -0,0 +1,16 @@ +#ifndef __PERF_STATS_H +#define __PERF_STATS_H + +#include "types.h" + +struct stats +{ + double n, mean, M2; +}; + +void update_stats(struct stats *stats, u64 val); +double avg_stats(struct stats *stats); +double stddev_stats(struct stats *stats); +double rel_stddev_stats(double stddev, double avg); + +#endif ^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH v8 3/3] KVM: perf: kvm events analysis tool 2012-09-17 8:31 [PATCH v8 0/3] KVM: perf: kvm events analysis tool Dong Hao 2012-09-17 8:31 ` [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace Dong Hao 2012-09-17 8:31 ` [PATCH v8 2/3] perf: move stat related code to util/stat.c Dong Hao @ 2012-09-17 8:31 ` Dong Hao 2012-09-20 13:34 ` David Ahern 2012-09-27 4:27 ` [tip:perf/core] perf kvm: Events " tip-bot for Xiao Guangrong 2 siblings, 2 replies; 14+ messages in thread From: Dong Hao @ 2012-09-17 8:31 UTC (permalink / raw) To: acme, dsahern, mtosatti, avi, mingo, linux-kernel, kvm Cc: xiaoguangrong, runzhen From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Add 'perf kvm stat' support to analyze kvm vmexit/mmio/ioport smartly Usage: - kvm stat run a command and gather performance counter statistics, it is the alias of perf stat - trace kvm events: perf kvm stat record, or, if other tracepoints are interesting as well, we can append the events like this: perf kvm stat record -e timer:* -a If many guests are running, we can track the specified guest by using -p or --pid, -a is used to track events generated by all guests. - show the result: perf kvm stat report The output example is following: # pgrep qemu 13005 13059 total 2 guests are running on the host Then, track the guest whose pid is 13059: # ./perf kvm stat record -p 13059 ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.253 MB perf.data.guest (~11065 samples) ] See the vmexit events: # ./perf kvm stat report --event=vmexit Analyze events for all VCPUs: VM-EXIT Samples Samples% Time% Avg time APIC_ACCESS 460 70.55% 0.01% 22.44us ( +- 1.75% ) HLT 93 14.26% 99.98% 832077.26us ( +- 10.42% ) EXTERNAL_INTERRUPT 64 9.82% 0.00% 35.35us ( +- 14.21% ) PENDING_INTERRUPT 24 3.68% 0.00% 9.29us ( +- 31.39% ) CR_ACCESS 7 1.07% 0.00% 8.12us ( +- 5.76% ) IO_INSTRUCTION 3 0.46% 0.00% 18.00us ( +- 11.79% ) EXCEPTION_NMI 1 0.15% 0.00% 5.83us ( +- -nan% ) Total Samples:652, Total events handled time:77396109.80us. See the mmio events: # ./perf kvm stat report --event=mmio Analyze events for all VCPUs: MMIO Access Samples Samples% Time% Avg time 0xfee00380:W 387 84.31% 79.28% 8.29us ( +- 3.32% ) 0xfee00300:W 24 5.23% 9.96% 16.79us ( +- 1.97% ) 0xfee00300:R 24 5.23% 7.83% 13.20us ( +- 3.00% ) 0xfee00310:W 24 5.23% 2.93% 4.94us ( +- 3.84% ) Total Samples:459, Total events handled time:4044.59us. See the ioport event: # ./perf kvm stat report --event=ioport Analyze events for all VCPUs: IO Port Access Samples Samples% Time% Avg time 0xc050:POUT 3 100.00% 100.00% 13.75us ( +- 10.83% ) Total Samples:3, Total events handled time:41.26us. And, --vcpu is used to track the specified vcpu and --key is used to sort the result: # ./perf kvm stat report --event=vmexit --vcpu=0 --key=time Analyze events for VCPU 0: VM-EXIT Samples Samples% Time% Avg time HLT 27 13.85% 99.97% 405790.24us ( +- 12.70% ) EXTERNAL_INTERRUPT 13 6.67% 0.00% 27.94us ( +- 22.26% ) APIC_ACCESS 146 74.87% 0.03% 21.69us ( +- 2.91% ) IO_INSTRUCTION 2 1.03% 0.00% 17.77us ( +- 20.56% ) CR_ACCESS 2 1.03% 0.00% 8.55us ( +- 6.47% ) PENDING_INTERRUPT 5 2.56% 0.00% 6.27us ( +- 3.94% ) Total Samples:195, Total events handled time:10959950.90us. [ Dong Hao <haodong@linux.vnet.ibm.com> Runzhen Wang <runzhen@linux.vnet.ibm.com>: - rebase it on current acme's tree - fix the compiling-error on i386 ] Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> Signed-off-by: Runzhen Wang <runzhen@linux.vnet.ibm.com> --- tools/perf/Documentation/perf-kvm.txt | 30 ++- tools/perf/MANIFEST | 3 + tools/perf/builtin-kvm.c | 840 ++++++++++++++++++++++++++++++++- tools/perf/util/header.c | 59 +++- tools/perf/util/header.h | 1 + tools/perf/util/thread.h | 2 + 6 files changed, 929 insertions(+), 6 deletions(-) diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index dd84cb2..326f2cb 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt @@ -12,7 +12,7 @@ SYNOPSIS [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] {top|record|report|diff|buildid-list} 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> - | --guestvmlinux=<path>] {top|record|report|diff|buildid-list} + | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} DESCRIPTION ----------- @@ -38,6 +38,18 @@ There are a couple of variants of perf kvm: so that other tools can be used to fetch packages with matching symbol tables for use by perf report. + 'perf kvm stat <command>' to run a command and gather performance counter + statistics. + Especially, perf 'kvm stat record/report' generates a statistical analysis + of KVM events. Currently, vmexit, mmio and ioport events are supported. + 'perf kvm stat record <command>' records kvm events and the events between + start and end <command>. + And this command produces a file which contains tracing results of kvm + events. + + 'perf kvm stat report' reports statistical data which includes events + handled time, samples, and so on. + OPTIONS ------- -i:: @@ -68,7 +80,21 @@ OPTIONS --guestvmlinux=<path>:: Guest os kernel vmlinux. +STAT REPORT OPTIONS +------------------- +--vcpu=<value>:: + analyze events which occures on this vcpu. (default: all vcpus) + +--events=<value>:: + events to be analyzed. Possible values: vmexit, mmio, ioport. + (default: vmexit) +-k:: +--key=<value>:: + Sorting key. Possible values: sample (default, sort by samples + number), time (sort by average time). + SEE ALSO -------- linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1], -linkperf:perf-diff[1], linkperf:perf-buildid-list[1] +linkperf:perf-diff[1], linkperf:perf-buildid-list[1], +linkperf:perf-stat[1] diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 0518079..80db3f4 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -16,3 +16,6 @@ arch/*/lib/memset*.S include/linux/poison.h include/linux/magic.h include/linux/hw_breakpoint.h +arch/x86/include/asm/svm.h +arch/x86/include/asm/vmx.h +arch/x86/include/asm/kvm_host.h diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 4d2aa2c..1878947 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "perf.h" +#include "util/evsel.h" #include "util/util.h" #include "util/cache.h" #include "util/symbol.h" @@ -10,8 +11,10 @@ #include "util/parse-options.h" #include "util/trace-event.h" - #include "util/debug.h" +#include "util/debugfs.h" +#include "util/tool.h" +#include "util/stat.h" #include <sys/prctl.h> @@ -19,11 +22,840 @@ #include <pthread.h> #include <math.h> -static const char *file_name; +#include "../../arch/x86/include/asm/svm.h" +#include "../../arch/x86/include/asm/vmx.h" +#include "../../arch/x86/include/asm/kvm.h" + +struct event_key { + #define INVALID_KEY (~0ULL) + u64 key; + int info; +}; + +struct kvm_events_ops { + bool (*is_begin_event)(struct event_format *event, void *data, + struct event_key *key); + bool (*is_end_event)(struct event_format *event, void *data, + struct event_key *key); + void (*decode_key)(struct event_key *key, char decode[20]); + const char *name; +}; + +static void exit_event_get_key(struct event_format *event, void *data, + struct event_key *key) +{ + key->info = 0; + key->key = raw_field_value(event, "exit_reason", data); +} + +static bool kvm_exit_event(struct event_format *event) +{ + return !strcmp(event->name, "kvm_exit"); +} + +static bool exit_event_begin(struct event_format *event, void *data, + struct event_key *key) +{ + if (kvm_exit_event(event)) { + exit_event_get_key(event, data, key); + return true; + } + + return false; +} + +static bool kvm_entry_event(struct event_format *event) +{ + return !strcmp(event->name, "kvm_entry"); +} + +static bool exit_event_end(struct event_format *event, void *data __maybe_unused, + struct event_key *key __maybe_unused) +{ + return kvm_entry_event(event); +} + +struct exit_reasons_table { + unsigned long exit_code; + const char *reason; +}; + +struct exit_reasons_table vmx_exit_reasons[] = { + VMX_EXIT_REASONS +}; + +struct exit_reasons_table svm_exit_reasons[] = { + SVM_EXIT_REASONS +}; + +static int cpu_isa; + +static const char *get_exit_reason(u64 exit_code) +{ + int table_size = ARRAY_SIZE(svm_exit_reasons); + struct exit_reasons_table *table = svm_exit_reasons; + + if (cpu_isa == 1) { + table = vmx_exit_reasons; + table_size = ARRAY_SIZE(vmx_exit_reasons); + } + + while (table_size--) { + if (table->exit_code == exit_code) + return table->reason; + table++; + } + + pr_err("unknown kvm exit code:%lld on %s\n", + (unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM"); + return "UNKNOWN"; +} + +static void exit_event_decode_key(struct event_key *key, char decode[20]) +{ + const char *exit_reason = get_exit_reason(key->key); + + scnprintf(decode, 20, "%s", exit_reason); +} + +static struct kvm_events_ops exit_events = { + .is_begin_event = exit_event_begin, + .is_end_event = exit_event_end, + .decode_key = exit_event_decode_key, + .name = "VM-EXIT" +}; + + /* + * For the mmio events, we treat: + * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry + * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). + */ +static void mmio_event_get_key(struct event_format *event, void *data, + struct event_key *key) +{ + key->key = raw_field_value(event, "gpa", data); + key->info = raw_field_value(event, "type", data); +} + +#define KVM_TRACE_MMIO_READ_UNSATISFIED 0 +#define KVM_TRACE_MMIO_READ 1 +#define KVM_TRACE_MMIO_WRITE 2 + +static bool mmio_event_begin(struct event_format *event, void *data, + struct event_key *key) +{ + /* MMIO read begin event in kernel. */ + if (kvm_exit_event(event)) + return true; + + /* MMIO write begin event in kernel. */ + if (!strcmp(event->name, "kvm_mmio") && + raw_field_value(event, "type", data) == KVM_TRACE_MMIO_WRITE) { + mmio_event_get_key(event, data, key); + return true; + } + + return false; +} + +static bool mmio_event_end(struct event_format *event, void *data, + struct event_key *key) +{ + /* MMIO write end event in kernel. */ + if (kvm_entry_event(event)) + return true; + + /* MMIO read end event in kernel.*/ + if (!strcmp(event->name, "kvm_mmio") && + raw_field_value(event, "type", data) == KVM_TRACE_MMIO_READ) { + mmio_event_get_key(event, data, key); + return true; + } + + return false; +} + +static void mmio_event_decode_key(struct event_key *key, char decode[20]) +{ + scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, + key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); +} + +static struct kvm_events_ops mmio_events = { + .is_begin_event = mmio_event_begin, + .is_end_event = mmio_event_end, + .decode_key = mmio_event_decode_key, + .name = "MMIO Access" +}; + + /* The time of emulation pio access is from kvm_pio to kvm_entry. */ +static void ioport_event_get_key(struct event_format *event, void *data, + struct event_key *key) +{ + key->key = raw_field_value(event, "port", data); + key->info = raw_field_value(event, "rw", data); +} + +static bool ioport_event_begin(struct event_format *event, void *data, + struct event_key *key) +{ + if (!strcmp(event->name, "kvm_pio")) { + ioport_event_get_key(event, data, key); + return true; + } + + return false; +} + +static bool ioport_event_end(struct event_format *event, void *data __maybe_unused, + struct event_key *key __maybe_unused) +{ + if (kvm_entry_event(event)) + return true; + + return false; +} + +static void ioport_event_decode_key(struct event_key *key, char decode[20]) +{ + scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, + key->info ? "POUT" : "PIN"); +} + +static struct kvm_events_ops ioport_events = { + .is_begin_event = ioport_event_begin, + .is_end_event = ioport_event_end, + .decode_key = ioport_event_decode_key, + .name = "IO Port Access" +}; + +static const char *report_event = "vmexit"; +struct kvm_events_ops *events_ops; + +static bool register_kvm_events_ops(void) +{ + bool ret = true; + + if (!strcmp(report_event, "vmexit")) + events_ops = &exit_events; + else if (!strcmp(report_event, "mmio")) + events_ops = &mmio_events; + else if (!strcmp(report_event, "ioport")) + events_ops = &ioport_events; + else { + pr_err("Unknown report event:%s\n", report_event); + ret = false; + } + + return ret; +} + +struct kvm_event_stats { + u64 time; + struct stats stats; +}; + +struct kvm_event { + struct list_head hash_entry; + struct rb_node rb; + + struct event_key key; + + struct kvm_event_stats total; + + #define DEFAULT_VCPU_NUM 8 + int max_vcpu; + struct kvm_event_stats *vcpu; +}; + +struct vcpu_event_record { + int vcpu_id; + u64 start_time; + struct kvm_event *last_event; +}; + +#define EVENTS_BITS 12 +#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) + +static u64 total_time; +static u64 total_count; +static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; + +static void init_kvm_event_record(void) +{ + int i; + + for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) + INIT_LIST_HEAD(&kvm_events_cache[i]); +} + +static int kvm_events_hash_fn(u64 key) +{ + return key & (EVENTS_CACHE_SIZE - 1); +} + +static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) +{ + int old_max_vcpu = event->max_vcpu; + + if (vcpu_id < event->max_vcpu) + return true; + + while (event->max_vcpu <= vcpu_id) + event->max_vcpu += DEFAULT_VCPU_NUM; + + event->vcpu = realloc(event->vcpu, + event->max_vcpu * sizeof(*event->vcpu)); + if (!event->vcpu) { + pr_err("Not enough memory\n"); + return false; + } + + memset(event->vcpu + old_max_vcpu, 0, + (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu)); + return true; +} + +static struct kvm_event *kvm_alloc_init_event(struct event_key *key) +{ + struct kvm_event *event; + + event = zalloc(sizeof(*event)); + if (!event) { + pr_err("Not enough memory\n"); + return NULL; + } + + event->key = *key; + return event; +} + +static struct kvm_event *find_create_kvm_event(struct event_key *key) +{ + struct kvm_event *event; + struct list_head *head; + + BUG_ON(key->key == INVALID_KEY); + + head = &kvm_events_cache[kvm_events_hash_fn(key->key)]; + list_for_each_entry(event, head, hash_entry) + if (event->key.key == key->key && event->key.info == key->info) + return event; + + event = kvm_alloc_init_event(key); + if (!event) + return NULL; + + list_add(&event->hash_entry, head); + return event; +} + +static bool handle_begin_event(struct vcpu_event_record *vcpu_record, + struct event_key *key, u64 timestamp) +{ + struct kvm_event *event = NULL; + + if (key->key != INVALID_KEY) + event = find_create_kvm_event(key); + + vcpu_record->last_event = event; + vcpu_record->start_time = timestamp; + return true; +} + +static void +kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff) +{ + kvm_stats->time += time_diff; + update_stats(&kvm_stats->stats, time_diff); +} + +static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event) +{ + struct kvm_event_stats *kvm_stats = &event->total; + + if (vcpu_id != -1) + kvm_stats = &event->vcpu[vcpu_id]; + + return rel_stddev_stats(stddev_stats(&kvm_stats->stats), + avg_stats(&kvm_stats->stats)); +} + +static bool update_kvm_event(struct kvm_event *event, int vcpu_id, + u64 time_diff) +{ + kvm_update_event_stats(&event->total, time_diff); + + if (!kvm_event_expand(event, vcpu_id)) + return false; + + kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff); + return true; +} + +static bool handle_end_event(struct vcpu_event_record *vcpu_record, + struct event_key *key, u64 timestamp) +{ + struct kvm_event *event; + u64 time_begin, time_diff; + + event = vcpu_record->last_event; + time_begin = vcpu_record->start_time; + + /* The begin event is not caught. */ + if (!time_begin) + return true; + + /* + * In some case, the 'begin event' only records the start timestamp, + * the actual event is recognized in the 'end event' (e.g. mmio-event). + */ + + /* Both begin and end events did not get the key. */ + if (!event && key->key == INVALID_KEY) + return true; + + if (!event) + event = find_create_kvm_event(key); + + if (!event) + return false; + + vcpu_record->last_event = NULL; + vcpu_record->start_time = 0; + + BUG_ON(timestamp < time_begin); + + time_diff = timestamp - time_begin; + return update_kvm_event(event, vcpu_record->vcpu_id, time_diff); +} + +static struct vcpu_event_record +*per_vcpu_record(struct thread *thread, struct event_format *event, void *data) +{ + /* Only kvm_entry records vcpu id. */ + if (!thread->priv && kvm_entry_event(event)) { + struct vcpu_event_record *vcpu_record; + + vcpu_record = zalloc(sizeof(struct vcpu_event_record)); + if (!vcpu_record) { + pr_err("Not enough memory\n"); + return NULL; + } + + vcpu_record->vcpu_id = raw_field_value(event, "vcpu_id", data); + thread->priv = vcpu_record; + } + + return (struct vcpu_event_record *)thread->priv; +} + +static bool handle_kvm_event(struct thread *thread, struct event_format *event, + void *data, u64 timestamp) +{ + struct vcpu_event_record *vcpu_record; + struct event_key key = {.key = INVALID_KEY}; + + vcpu_record = per_vcpu_record(thread, event, data); + if (!vcpu_record) + return true; + + if (events_ops->is_begin_event(event, data, &key)) + return handle_begin_event(vcpu_record, &key, timestamp); + + if (events_ops->is_end_event(event, data, &key)) + return handle_end_event(vcpu_record, &key, timestamp); + + return true; +} + +typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); +struct kvm_event_key { + const char *name; + key_cmp_fun key; +}; + +static int trace_vcpu = -1; +#define GET_EVENT_KEY(func, field) \ +static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ +{ \ + if (vcpu == -1) \ + return event->total.field; \ + \ + if (vcpu >= event->max_vcpu) \ + return 0; \ + \ + return event->vcpu[vcpu].field; \ +} + +#define COMPARE_EVENT_KEY(func, field) \ +GET_EVENT_KEY(func, field) \ +static int compare_kvm_event_ ## func(struct kvm_event *one, \ + struct kvm_event *two, int vcpu)\ +{ \ + return get_event_ ##func(one, vcpu) > \ + get_event_ ##func(two, vcpu); \ +} + +GET_EVENT_KEY(time, time); +COMPARE_EVENT_KEY(count, stats.n); +COMPARE_EVENT_KEY(mean, stats.mean); + +#define DEF_SORT_NAME_KEY(name, compare_key) \ + { #name, compare_kvm_event_ ## compare_key } + +static struct kvm_event_key keys[] = { + DEF_SORT_NAME_KEY(sample, count), + DEF_SORT_NAME_KEY(time, mean), + { NULL, NULL } +}; + +static const char *sort_key = "sample"; +static key_cmp_fun compare; + +static bool select_key(void) +{ + int i; + + for (i = 0; keys[i].name; i++) { + if (!strcmp(keys[i].name, sort_key)) { + compare = keys[i].key; + return true; + } + } + + pr_err("Unknown compare key:%s\n", sort_key); + return false; +} + +static struct rb_root result; +static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, + int vcpu) +{ + struct rb_node **rb = &result.rb_node; + struct rb_node *parent = NULL; + struct kvm_event *p; + + while (*rb) { + p = container_of(*rb, struct kvm_event, rb); + parent = *rb; + + if (bigger(event, p, vcpu)) + rb = &(*rb)->rb_left; + else + rb = &(*rb)->rb_right; + } + + rb_link_node(&event->rb, parent, rb); + rb_insert_color(&event->rb, &result); +} + +static void update_total_count(struct kvm_event *event, int vcpu) +{ + total_count += get_event_count(event, vcpu); + total_time += get_event_time(event, vcpu); +} + +static bool event_is_valid(struct kvm_event *event, int vcpu) +{ + return !!get_event_count(event, vcpu); +} + +static void sort_result(int vcpu) +{ + unsigned int i; + struct kvm_event *event; + + for (i = 0; i < EVENTS_CACHE_SIZE; i++) + list_for_each_entry(event, &kvm_events_cache[i], hash_entry) + if (event_is_valid(event, vcpu)) { + update_total_count(event, vcpu); + insert_to_result(event, compare, vcpu); + } +} + +/* returns left most element of result, and erase it */ +static struct kvm_event *pop_from_result(void) +{ + struct rb_node *node = rb_first(&result); + + if (!node) + return NULL; + + rb_erase(node, &result); + return container_of(node, struct kvm_event, rb); +} + +static void print_vcpu_info(int vcpu) +{ + pr_info("Analyze events for "); + + if (vcpu == -1) + pr_info("all VCPUs:\n\n"); + else + pr_info("VCPU %d:\n\n", vcpu); +} + +static void print_result(int vcpu) +{ + char decode[20]; + struct kvm_event *event; + + pr_info("\n\n"); + print_vcpu_info(vcpu); + pr_info("%20s ", events_ops->name); + pr_info("%10s ", "Samples"); + pr_info("%9s ", "Samples%"); + + pr_info("%9s ", "Time%"); + pr_info("%16s ", "Avg time"); + pr_info("\n\n"); + + while ((event = pop_from_result())) { + u64 ecount, etime; + + ecount = get_event_count(event, vcpu); + etime = get_event_time(event, vcpu); + + events_ops->decode_key(&event->key, decode); + pr_info("%20s ", decode); + pr_info("%10llu ", (unsigned long long)ecount); + pr_info("%8.2f%% ", (double)ecount / total_count * 100); + pr_info("%8.2f%% ", (double)etime / total_time * 100); + pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, + kvm_event_rel_stddev(vcpu, event)); + pr_info("\n"); + } + + pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", + (unsigned long long)total_count, total_time / 1e3); +} + +static int process_sample_event(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine) +{ + struct thread *thread = machine__findnew_thread(machine, sample->tid); + + if (thread == NULL) { + pr_debug("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + if (!handle_kvm_event(thread, evsel->tp_format, sample->raw_data, + sample->time)) + return -1; + + return 0; +} + +static struct perf_tool eops = { + .sample = process_sample_event, + .comm = perf_event__process_comm, + .ordered_samples = true, +}; + +static int get_cpu_isa(struct perf_session *session) +{ + char *cpuid; + int isa; + + cpuid = perf_header__read_feature(session, HEADER_CPUID); + + if (!cpuid) { + pr_err("read HEADER_CPUID failed.\n"); + return -ENOTSUP; + } + + if (strstr(cpuid, "Intel")) + isa = 1; + else if (strstr(cpuid, "AMD")) + isa = 0; + else { + pr_err("CPU %s is not supported.\n", cpuid); + isa = -ENOTSUP; + } + + free(cpuid); + return isa; +} + +static const char *file_name; + +static int read_events(void) +{ + struct perf_session *kvm_session; + int ret; + + kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops); + if (!kvm_session) { + pr_err("Initializing perf session failed\n"); + return -EINVAL; + } + + if (!perf_session__has_traces(kvm_session, "kvm record")) + return -EINVAL; + + /* + * Do not use 'isa' recorded in kvm_exit tracepoint since it is not + * traced in the old kernel. + */ + ret = get_cpu_isa(kvm_session); + + if (ret < 0) + return ret; + + cpu_isa = ret; + + return perf_session__process_events(kvm_session, &eops); +} + +static bool verify_vcpu(int vcpu) +{ + if (vcpu != -1 && vcpu < 0) { + pr_err("Invalid vcpu:%d.\n", vcpu); + return false; + } + + return true; +} + +static int kvm_events_report_vcpu(int vcpu) +{ + int ret = -EINVAL; + + if (!verify_vcpu(vcpu)) + goto exit; + + if (!select_key()) + goto exit; + + if (!register_kvm_events_ops()) + goto exit; + + init_kvm_event_record(); + setup_pager(); + + ret = read_events(); + if (ret) + goto exit; + + sort_result(vcpu); + print_result(vcpu); +exit: + return ret; +} + +static const char * const record_args[] = { + "record", + "-R", + "-f", + "-m", "1024", + "-c", "1", + "-e", "kvm:kvm_entry", + "-e", "kvm:kvm_exit", + "-e", "kvm:kvm_mmio", + "-e", "kvm:kvm_pio", +}; + +#define STRDUP_FAIL_EXIT(s) \ + ({ char *_p; \ + _p = strdup(s); \ + if (!_p) \ + return -ENOMEM; \ + _p; \ + }) + +static int kvm_events_record(int argc, const char **argv) +{ + unsigned int rec_argc, i, j; + const char **rec_argv; + + rec_argc = ARRAY_SIZE(record_args) + argc + 2; + rec_argv = calloc(rec_argc + 1, sizeof(char *)); + + if (rec_argv == NULL) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(record_args); i++) + rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); + + rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); + rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); + + for (j = 1; j < (unsigned int)argc; j++, i++) + rec_argv[i] = argv[j]; + + return cmd_record(i, rec_argv, NULL); +} + +static const char * const kvm_events_report_usage[] = { + "perf kvm stat report [<options>]", + NULL +}; + +static const struct option kvm_events_report_options[] = { + OPT_STRING(0, "event", &report_event, "report event", + "event for reporting: vmexit, mmio, ioport"), + OPT_INTEGER(0, "vcpu", &trace_vcpu, + "vcpu id to report"), + OPT_STRING('k', "key", &sort_key, "sort-key", + "key for sorting: sample(sort by samples number)" + " time (sort by avg time)"), + OPT_END() +}; + +static int kvm_events_report(int argc, const char **argv) +{ + symbol__init(); + + if (argc) { + argc = parse_options(argc, argv, + kvm_events_report_options, + kvm_events_report_usage, 0); + if (argc) + usage_with_options(kvm_events_report_usage, + kvm_events_report_options); + } + + return kvm_events_report_vcpu(trace_vcpu); +} + +static void print_kvm_stat_usage(void) +{ + printf("Usage: perf kvm stat <command>\n\n"); + + printf("# Available commands:\n"); + printf("\trecord: record kvm events\n"); + printf("\treport: report statistical data of kvm events\n"); + + printf("\nOtherwise, it is the alias of 'perf stat':\n"); +} + +static int kvm_cmd_stat(int argc, const char **argv) +{ + if (argc == 1) { + print_kvm_stat_usage(); + goto perf_stat; + } + + if (!strncmp(argv[1], "rec", 3)) + return kvm_events_record(argc - 1, argv + 1); + + if (!strncmp(argv[1], "rep", 3)) + return kvm_events_report(argc - 1 , argv + 1); + +perf_stat: + return cmd_stat(argc, argv, NULL); +} + static char name_buffer[256]; static const char * const kvm_usage[] = { - "perf kvm [<options>] {top|record|report|diff|buildid-list}", + "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", NULL }; @@ -135,6 +967,8 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) return cmd_top(argc, argv, NULL); else if (!strncmp(argv[0], "buildid-list", 12)) return __cmd_buildid_list(argc, argv); + else if (!strncmp(argv[0], "stat", 4)) + return kvm_cmd_stat(argc, argv); else usage_with_options(kvm_usage, kvm_options); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index acbf633..ad72b28 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1673,6 +1673,11 @@ static int process_build_id(struct perf_file_section *section, return 0; } +static char *read_cpuid(struct perf_header *ph, int fd) +{ + return do_read_string(fd, ph); +} + static struct perf_evsel * perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) { @@ -1726,6 +1731,7 @@ process_event_desc(struct perf_file_section *section __maybe_unused, struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); + char *(*read)(struct perf_header *h, int fd); int (*process)(struct perf_file_section *section, struct perf_header *h, int feat, int fd, void *data); const char *name; @@ -1740,6 +1746,9 @@ struct feature_ops { #define FEAT_OPF(n, func) \ [n] = { .name = #n, .write = write_##func, .print = print_##func, \ .full_only = true } +#define FEAT_OPA_R(n, func) \ + [n] = { .name = #n, .write = write_##func, .print = print_##func, \ + .read = read_##func } /* feature_ops not implemented: */ #define print_tracing_data NULL @@ -1754,7 +1763,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPA(HEADER_ARCH, arch), FEAT_OPA(HEADER_NRCPUS, nrcpus), FEAT_OPA(HEADER_CPUDESC, cpudesc), - FEAT_OPA(HEADER_CPUID, cpuid), + FEAT_OPA_R(HEADER_CPUID, cpuid), FEAT_OPA(HEADER_TOTAL_MEM, total_mem), FEAT_OPP(HEADER_EVENT_DESC, event_desc), FEAT_OPA(HEADER_CMDLINE, cmdline), @@ -1809,6 +1818,54 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) return 0; } +struct header_read_data { + int feat; + char *result; +}; + +static int perf_file_section__read_feature(struct perf_file_section *section, + struct perf_header *ph, + int feat, int fd, void *data) +{ + struct header_read_data *hd = data; + + if (feat != hd->feat) + return 0; + + if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { + pr_debug("Failed to lseek to %" PRIu64 " offset for feature " + "%d, continuing...\n", section->offset, feat); + return 0; + } + + if (feat >= HEADER_LAST_FEATURE) { + pr_warning("unknown feature %d\n", feat); + return 0; + } + + if (!feat_ops[feat].read) { + pr_warning("read is not supported for feature %d\n", feat); + return 0; + } + + hd->result = feat_ops[feat].read(ph, fd); + return 0; +} + +char *perf_header__read_feature(struct perf_session *session, int feat) +{ + struct perf_header *header = &session->header; + struct header_read_data hd; + int fd = session->fd; + + hd.feat = feat; + hd.result = NULL; + + perf_header__process_sections(header, fd, &hd, + perf_file_section__read_feature); + return hd.result; +} + static int do_write_feat(int fd, struct perf_header *h, int type, struct perf_file_section **p, struct perf_evlist *evlist) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 209dad4..58de08b 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -94,6 +94,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, int feat, int fd, void *data)); int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); +char *perf_header__read_feature(struct perf_session *session, int feat); int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, const char *name, bool is_kallsyms, bool is_vdso); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 70c2c13..f66610b 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -16,6 +16,8 @@ struct thread { bool comm_set; char *comm; int comm_len; + + void *priv; }; struct machine; -- 1.7.2.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v8 3/3] KVM: perf: kvm events analysis tool 2012-09-17 8:31 ` [PATCH v8 3/3] KVM: perf: kvm events analysis tool Dong Hao @ 2012-09-20 13:34 ` David Ahern 2012-09-27 4:27 ` [tip:perf/core] perf kvm: Events " tip-bot for Xiao Guangrong 1 sibling, 0 replies; 14+ messages in thread From: David Ahern @ 2012-09-20 13:34 UTC (permalink / raw) To: Dong Hao, acme Cc: mtosatti, avi, mingo, linux-kernel, kvm, xiaoguangrong, runzhen On 9/17/12 2:31 AM, Dong Hao wrote: > From: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > > Add 'perf kvm stat' support to analyze kvm vmexit/mmio/ioport smartly > > Usage: > - kvm stat > run a command and gather performance counter statistics, it is the alias of > perf stat > > - trace kvm events: > perf kvm stat record, or, if other tracepoints are interesting as well, we > can append the events like this: > perf kvm stat record -e timer:* -a > > If many guests are running, we can track the specified guest by using -p or > --pid, -a is used to track events generated by all guests. > > - show the result: > perf kvm stat report > > The output example is following: > # pgrep qemu > 13005 > 13059 > > total 2 guests are running on the host > > Then, track the guest whose pid is 13059: > # ./perf kvm stat record -p 13059 > ^C[ perf record: Woken up 1 times to write data ] > [ perf record: Captured and wrote 0.253 MB perf.data.guest (~11065 samples) ] > > See the vmexit events: > # ./perf kvm stat report --event=vmexit > > > Analyze events for all VCPUs: > > VM-EXIT Samples Samples% Time% Avg time > > APIC_ACCESS 460 70.55% 0.01% 22.44us ( +- 1.75% ) > HLT 93 14.26% 99.98% 832077.26us ( +- 10.42% ) > EXTERNAL_INTERRUPT 64 9.82% 0.00% 35.35us ( +- 14.21% ) > PENDING_INTERRUPT 24 3.68% 0.00% 9.29us ( +- 31.39% ) > CR_ACCESS 7 1.07% 0.00% 8.12us ( +- 5.76% ) > IO_INSTRUCTION 3 0.46% 0.00% 18.00us ( +- 11.79% ) > EXCEPTION_NMI 1 0.15% 0.00% 5.83us ( +- -nan% ) > > Total Samples:652, Total events handled time:77396109.80us. > > See the mmio events: > # ./perf kvm stat report --event=mmio > > > Analyze events for all VCPUs: > > MMIO Access Samples Samples% Time% Avg time > > 0xfee00380:W 387 84.31% 79.28% 8.29us ( +- 3.32% ) > 0xfee00300:W 24 5.23% 9.96% 16.79us ( +- 1.97% ) > 0xfee00300:R 24 5.23% 7.83% 13.20us ( +- 3.00% ) > 0xfee00310:W 24 5.23% 2.93% 4.94us ( +- 3.84% ) > > Total Samples:459, Total events handled time:4044.59us. > > See the ioport event: > # ./perf kvm stat report --event=ioport > > > Analyze events for all VCPUs: > > IO Port Access Samples Samples% Time% Avg time > > 0xc050:POUT 3 100.00% 100.00% 13.75us ( +- 10.83% ) > > Total Samples:3, Total events handled time:41.26us. > > And, --vcpu is used to track the specified vcpu and --key is used to sort the > result: > # ./perf kvm stat report --event=vmexit --vcpu=0 --key=time > > > Analyze events for VCPU 0: > > VM-EXIT Samples Samples% Time% Avg time > > HLT 27 13.85% 99.97% 405790.24us ( +- 12.70% ) > EXTERNAL_INTERRUPT 13 6.67% 0.00% 27.94us ( +- 22.26% ) > APIC_ACCESS 146 74.87% 0.03% 21.69us ( +- 2.91% ) > IO_INSTRUCTION 2 1.03% 0.00% 17.77us ( +- 20.56% ) > CR_ACCESS 2 1.03% 0.00% 8.55us ( +- 6.47% ) > PENDING_INTERRUPT 5 2.56% 0.00% 6.27us ( +- 3.94% ) > > Total Samples:195, Total events handled time:10959950.90us. > > [ Dong Hao <haodong@linux.vnet.ibm.com> > Runzhen Wang <runzhen@linux.vnet.ibm.com>: > > - rebase it on current acme's tree > > - fix the compiling-error on i386 > > ] > > Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> > Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> > Signed-off-by: Runzhen Wang <runzhen@linux.vnet.ibm.com> > --- > tools/perf/Documentation/perf-kvm.txt | 30 ++- > tools/perf/MANIFEST | 3 + > tools/perf/builtin-kvm.c | 840 ++++++++++++++++++++++++++++++++- > tools/perf/util/header.c | 59 +++- > tools/perf/util/header.h | 1 + > tools/perf/util/thread.h | 2 + > 6 files changed, 929 insertions(+), 6 deletions(-) > Acked-by: David Ahern <dsahern@gmail.com> ^ permalink raw reply [flat|nested] 14+ messages in thread
* [tip:perf/core] perf kvm: Events analysis tool 2012-09-17 8:31 ` [PATCH v8 3/3] KVM: perf: kvm events analysis tool Dong Hao 2012-09-20 13:34 ` David Ahern @ 2012-09-27 4:27 ` tip-bot for Xiao Guangrong 1 sibling, 0 replies; 14+ messages in thread From: tip-bot for Xiao Guangrong @ 2012-09-27 4:27 UTC (permalink / raw) To: linux-tip-commits Cc: acme, linux-kernel, hpa, mingo, runzhen, xiaoguangrong, haodong, mtosatti, dsahern, tglx, avi Commit-ID: bcf6edcd6fdb8965290f0b635a530fa3c6c212e1 Gitweb: http://git.kernel.org/tip/bcf6edcd6fdb8965290f0b635a530fa3c6c212e1 Author: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> AuthorDate: Mon, 17 Sep 2012 16:31:15 +0800 Committer: Arnaldo Carvalho de Melo <acme@redhat.com> CommitDate: Fri, 21 Sep 2012 12:51:22 -0300 perf kvm: Events analysis tool Add 'perf kvm stat' support to analyze kvm vmexit/mmio/ioport smartly Usage: - kvm stat run a command and gather performance counter statistics, it is the alias of perf stat - trace kvm events: perf kvm stat record, or, if other tracepoints are interesting as well, we can append the events like this: perf kvm stat record -e timer:* -a If many guests are running, we can track the specified guest by using -p or --pid, -a is used to track events generated by all guests. - show the result: perf kvm stat report The output example is following: 13005 13059 total 2 guests are running on the host Then, track the guest whose pid is 13059: ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.253 MB perf.data.guest (~11065 samples) ] See the vmexit events: Analyze events for all VCPUs: VM-EXIT Samples Samples% Time% Avg time APIC_ACCESS 460 70.55% 0.01% 22.44us ( +- 1.75% ) HLT 93 14.26% 99.98% 832077.26us ( +- 10.42% ) EXTERNAL_INTERRUPT 64 9.82% 0.00% 35.35us ( +- 14.21% ) PENDING_INTERRUPT 24 3.68% 0.00% 9.29us ( +- 31.39% ) CR_ACCESS 7 1.07% 0.00% 8.12us ( +- 5.76% ) IO_INSTRUCTION 3 0.46% 0.00% 18.00us ( +- 11.79% ) EXCEPTION_NMI 1 0.15% 0.00% 5.83us ( +- -nan% ) Total Samples:652, Total events handled time:77396109.80us. See the mmio events: Analyze events for all VCPUs: MMIO Access Samples Samples% Time% Avg time 0xfee00380:W 387 84.31% 79.28% 8.29us ( +- 3.32% ) 0xfee00300:W 24 5.23% 9.96% 16.79us ( +- 1.97% ) 0xfee00300:R 24 5.23% 7.83% 13.20us ( +- 3.00% ) 0xfee00310:W 24 5.23% 2.93% 4.94us ( +- 3.84% ) Total Samples:459, Total events handled time:4044.59us. See the ioport event: Analyze events for all VCPUs: IO Port Access Samples Samples% Time% Avg time 0xc050:POUT 3 100.00% 100.00% 13.75us ( +- 10.83% ) Total Samples:3, Total events handled time:41.26us. And, --vcpu is used to track the specified vcpu and --key is used to sort the result: Analyze events for VCPU 0: VM-EXIT Samples Samples% Time% Avg time HLT 27 13.85% 99.97% 405790.24us ( +- 12.70% ) EXTERNAL_INTERRUPT 13 6.67% 0.00% 27.94us ( +- 22.26% ) APIC_ACCESS 146 74.87% 0.03% 21.69us ( +- 2.91% ) IO_INSTRUCTION 2 1.03% 0.00% 17.77us ( +- 20.56% ) CR_ACCESS 2 1.03% 0.00% 8.55us ( +- 6.47% ) PENDING_INTERRUPT 5 2.56% 0.00% 6.27us ( +- 3.94% ) Total Samples:195, Total events handled time:10959950.90us. Signed-off-by: Dong Hao <haodong@linux.vnet.ibm.com> Signed-off-by: Runzhen Wang <runzhen@linux.vnet.ibm.com> [ Dong Hao <haodong@linux.vnet.ibm.com> Runzhen Wang <runzhen@linux.vnet.ibm.com>: - rebase it on current acme's tree - fix the compiling-error on i386 ] Signed-off-by: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com> Acked-by: David Ahern <dsahern@gmail.com> Cc: Avi Kivity <avi@redhat.com> Cc: David Ahern <dsahern@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Marcelo Tosatti <mtosatti@redhat.com> Cc: kvm@vger.kernel.org Cc: Runzhen Wang <runzhen@linux.vnet.ibm.com> Link: http://lkml.kernel.org/r/1347870675-31495-4-git-send-email-haodong@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> --- tools/perf/Documentation/perf-kvm.txt | 30 ++- tools/perf/MANIFEST | 3 + tools/perf/builtin-kvm.c | 840 ++++++++++++++++++++++++++++++++- tools/perf/util/header.c | 59 +++- tools/perf/util/header.h | 1 + tools/perf/util/thread.h | 2 + 6 files changed, 929 insertions(+), 6 deletions(-) diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index dd84cb2..326f2cb 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt @@ -12,7 +12,7 @@ SYNOPSIS [--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]] {top|record|report|diff|buildid-list} 'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path> - | --guestvmlinux=<path>] {top|record|report|diff|buildid-list} + | --guestvmlinux=<path>] {top|record|report|diff|buildid-list|stat} DESCRIPTION ----------- @@ -38,6 +38,18 @@ There are a couple of variants of perf kvm: so that other tools can be used to fetch packages with matching symbol tables for use by perf report. + 'perf kvm stat <command>' to run a command and gather performance counter + statistics. + Especially, perf 'kvm stat record/report' generates a statistical analysis + of KVM events. Currently, vmexit, mmio and ioport events are supported. + 'perf kvm stat record <command>' records kvm events and the events between + start and end <command>. + And this command produces a file which contains tracing results of kvm + events. + + 'perf kvm stat report' reports statistical data which includes events + handled time, samples, and so on. + OPTIONS ------- -i:: @@ -68,7 +80,21 @@ OPTIONS --guestvmlinux=<path>:: Guest os kernel vmlinux. +STAT REPORT OPTIONS +------------------- +--vcpu=<value>:: + analyze events which occures on this vcpu. (default: all vcpus) + +--events=<value>:: + events to be analyzed. Possible values: vmexit, mmio, ioport. + (default: vmexit) +-k:: +--key=<value>:: + Sorting key. Possible values: sample (default, sort by samples + number), time (sort by average time). + SEE ALSO -------- linkperf:perf-top[1], linkperf:perf-record[1], linkperf:perf-report[1], -linkperf:perf-diff[1], linkperf:perf-buildid-list[1] +linkperf:perf-diff[1], linkperf:perf-buildid-list[1], +linkperf:perf-stat[1] diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 0518079..80db3f4 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -16,3 +16,6 @@ arch/*/lib/memset*.S include/linux/poison.h include/linux/magic.h include/linux/hw_breakpoint.h +arch/x86/include/asm/svm.h +arch/x86/include/asm/vmx.h +arch/x86/include/asm/kvm_host.h diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 4d2aa2c..1878947 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1,6 +1,7 @@ #include "builtin.h" #include "perf.h" +#include "util/evsel.h" #include "util/util.h" #include "util/cache.h" #include "util/symbol.h" @@ -10,8 +11,10 @@ #include "util/parse-options.h" #include "util/trace-event.h" - #include "util/debug.h" +#include "util/debugfs.h" +#include "util/tool.h" +#include "util/stat.h" #include <sys/prctl.h> @@ -19,11 +22,840 @@ #include <pthread.h> #include <math.h> -static const char *file_name; +#include "../../arch/x86/include/asm/svm.h" +#include "../../arch/x86/include/asm/vmx.h" +#include "../../arch/x86/include/asm/kvm.h" + +struct event_key { + #define INVALID_KEY (~0ULL) + u64 key; + int info; +}; + +struct kvm_events_ops { + bool (*is_begin_event)(struct event_format *event, void *data, + struct event_key *key); + bool (*is_end_event)(struct event_format *event, void *data, + struct event_key *key); + void (*decode_key)(struct event_key *key, char decode[20]); + const char *name; +}; + +static void exit_event_get_key(struct event_format *event, void *data, + struct event_key *key) +{ + key->info = 0; + key->key = raw_field_value(event, "exit_reason", data); +} + +static bool kvm_exit_event(struct event_format *event) +{ + return !strcmp(event->name, "kvm_exit"); +} + +static bool exit_event_begin(struct event_format *event, void *data, + struct event_key *key) +{ + if (kvm_exit_event(event)) { + exit_event_get_key(event, data, key); + return true; + } + + return false; +} + +static bool kvm_entry_event(struct event_format *event) +{ + return !strcmp(event->name, "kvm_entry"); +} + +static bool exit_event_end(struct event_format *event, void *data __maybe_unused, + struct event_key *key __maybe_unused) +{ + return kvm_entry_event(event); +} + +struct exit_reasons_table { + unsigned long exit_code; + const char *reason; +}; + +struct exit_reasons_table vmx_exit_reasons[] = { + VMX_EXIT_REASONS +}; + +struct exit_reasons_table svm_exit_reasons[] = { + SVM_EXIT_REASONS +}; + +static int cpu_isa; + +static const char *get_exit_reason(u64 exit_code) +{ + int table_size = ARRAY_SIZE(svm_exit_reasons); + struct exit_reasons_table *table = svm_exit_reasons; + + if (cpu_isa == 1) { + table = vmx_exit_reasons; + table_size = ARRAY_SIZE(vmx_exit_reasons); + } + + while (table_size--) { + if (table->exit_code == exit_code) + return table->reason; + table++; + } + + pr_err("unknown kvm exit code:%lld on %s\n", + (unsigned long long)exit_code, cpu_isa ? "VMX" : "SVM"); + return "UNKNOWN"; +} + +static void exit_event_decode_key(struct event_key *key, char decode[20]) +{ + const char *exit_reason = get_exit_reason(key->key); + + scnprintf(decode, 20, "%s", exit_reason); +} + +static struct kvm_events_ops exit_events = { + .is_begin_event = exit_event_begin, + .is_end_event = exit_event_end, + .decode_key = exit_event_decode_key, + .name = "VM-EXIT" +}; + + /* + * For the mmio events, we treat: + * the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry + * the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...). + */ +static void mmio_event_get_key(struct event_format *event, void *data, + struct event_key *key) +{ + key->key = raw_field_value(event, "gpa", data); + key->info = raw_field_value(event, "type", data); +} + +#define KVM_TRACE_MMIO_READ_UNSATISFIED 0 +#define KVM_TRACE_MMIO_READ 1 +#define KVM_TRACE_MMIO_WRITE 2 + +static bool mmio_event_begin(struct event_format *event, void *data, + struct event_key *key) +{ + /* MMIO read begin event in kernel. */ + if (kvm_exit_event(event)) + return true; + + /* MMIO write begin event in kernel. */ + if (!strcmp(event->name, "kvm_mmio") && + raw_field_value(event, "type", data) == KVM_TRACE_MMIO_WRITE) { + mmio_event_get_key(event, data, key); + return true; + } + + return false; +} + +static bool mmio_event_end(struct event_format *event, void *data, + struct event_key *key) +{ + /* MMIO write end event in kernel. */ + if (kvm_entry_event(event)) + return true; + + /* MMIO read end event in kernel.*/ + if (!strcmp(event->name, "kvm_mmio") && + raw_field_value(event, "type", data) == KVM_TRACE_MMIO_READ) { + mmio_event_get_key(event, data, key); + return true; + } + + return false; +} + +static void mmio_event_decode_key(struct event_key *key, char decode[20]) +{ + scnprintf(decode, 20, "%#lx:%s", (unsigned long)key->key, + key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R"); +} + +static struct kvm_events_ops mmio_events = { + .is_begin_event = mmio_event_begin, + .is_end_event = mmio_event_end, + .decode_key = mmio_event_decode_key, + .name = "MMIO Access" +}; + + /* The time of emulation pio access is from kvm_pio to kvm_entry. */ +static void ioport_event_get_key(struct event_format *event, void *data, + struct event_key *key) +{ + key->key = raw_field_value(event, "port", data); + key->info = raw_field_value(event, "rw", data); +} + +static bool ioport_event_begin(struct event_format *event, void *data, + struct event_key *key) +{ + if (!strcmp(event->name, "kvm_pio")) { + ioport_event_get_key(event, data, key); + return true; + } + + return false; +} + +static bool ioport_event_end(struct event_format *event, void *data __maybe_unused, + struct event_key *key __maybe_unused) +{ + if (kvm_entry_event(event)) + return true; + + return false; +} + +static void ioport_event_decode_key(struct event_key *key, char decode[20]) +{ + scnprintf(decode, 20, "%#llx:%s", (unsigned long long)key->key, + key->info ? "POUT" : "PIN"); +} + +static struct kvm_events_ops ioport_events = { + .is_begin_event = ioport_event_begin, + .is_end_event = ioport_event_end, + .decode_key = ioport_event_decode_key, + .name = "IO Port Access" +}; + +static const char *report_event = "vmexit"; +struct kvm_events_ops *events_ops; + +static bool register_kvm_events_ops(void) +{ + bool ret = true; + + if (!strcmp(report_event, "vmexit")) + events_ops = &exit_events; + else if (!strcmp(report_event, "mmio")) + events_ops = &mmio_events; + else if (!strcmp(report_event, "ioport")) + events_ops = &ioport_events; + else { + pr_err("Unknown report event:%s\n", report_event); + ret = false; + } + + return ret; +} + +struct kvm_event_stats { + u64 time; + struct stats stats; +}; + +struct kvm_event { + struct list_head hash_entry; + struct rb_node rb; + + struct event_key key; + + struct kvm_event_stats total; + + #define DEFAULT_VCPU_NUM 8 + int max_vcpu; + struct kvm_event_stats *vcpu; +}; + +struct vcpu_event_record { + int vcpu_id; + u64 start_time; + struct kvm_event *last_event; +}; + +#define EVENTS_BITS 12 +#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS) + +static u64 total_time; +static u64 total_count; +static struct list_head kvm_events_cache[EVENTS_CACHE_SIZE]; + +static void init_kvm_event_record(void) +{ + int i; + + for (i = 0; i < (int)EVENTS_CACHE_SIZE; i++) + INIT_LIST_HEAD(&kvm_events_cache[i]); +} + +static int kvm_events_hash_fn(u64 key) +{ + return key & (EVENTS_CACHE_SIZE - 1); +} + +static bool kvm_event_expand(struct kvm_event *event, int vcpu_id) +{ + int old_max_vcpu = event->max_vcpu; + + if (vcpu_id < event->max_vcpu) + return true; + + while (event->max_vcpu <= vcpu_id) + event->max_vcpu += DEFAULT_VCPU_NUM; + + event->vcpu = realloc(event->vcpu, + event->max_vcpu * sizeof(*event->vcpu)); + if (!event->vcpu) { + pr_err("Not enough memory\n"); + return false; + } + + memset(event->vcpu + old_max_vcpu, 0, + (event->max_vcpu - old_max_vcpu) * sizeof(*event->vcpu)); + return true; +} + +static struct kvm_event *kvm_alloc_init_event(struct event_key *key) +{ + struct kvm_event *event; + + event = zalloc(sizeof(*event)); + if (!event) { + pr_err("Not enough memory\n"); + return NULL; + } + + event->key = *key; + return event; +} + +static struct kvm_event *find_create_kvm_event(struct event_key *key) +{ + struct kvm_event *event; + struct list_head *head; + + BUG_ON(key->key == INVALID_KEY); + + head = &kvm_events_cache[kvm_events_hash_fn(key->key)]; + list_for_each_entry(event, head, hash_entry) + if (event->key.key == key->key && event->key.info == key->info) + return event; + + event = kvm_alloc_init_event(key); + if (!event) + return NULL; + + list_add(&event->hash_entry, head); + return event; +} + +static bool handle_begin_event(struct vcpu_event_record *vcpu_record, + struct event_key *key, u64 timestamp) +{ + struct kvm_event *event = NULL; + + if (key->key != INVALID_KEY) + event = find_create_kvm_event(key); + + vcpu_record->last_event = event; + vcpu_record->start_time = timestamp; + return true; +} + +static void +kvm_update_event_stats(struct kvm_event_stats *kvm_stats, u64 time_diff) +{ + kvm_stats->time += time_diff; + update_stats(&kvm_stats->stats, time_diff); +} + +static double kvm_event_rel_stddev(int vcpu_id, struct kvm_event *event) +{ + struct kvm_event_stats *kvm_stats = &event->total; + + if (vcpu_id != -1) + kvm_stats = &event->vcpu[vcpu_id]; + + return rel_stddev_stats(stddev_stats(&kvm_stats->stats), + avg_stats(&kvm_stats->stats)); +} + +static bool update_kvm_event(struct kvm_event *event, int vcpu_id, + u64 time_diff) +{ + kvm_update_event_stats(&event->total, time_diff); + + if (!kvm_event_expand(event, vcpu_id)) + return false; + + kvm_update_event_stats(&event->vcpu[vcpu_id], time_diff); + return true; +} + +static bool handle_end_event(struct vcpu_event_record *vcpu_record, + struct event_key *key, u64 timestamp) +{ + struct kvm_event *event; + u64 time_begin, time_diff; + + event = vcpu_record->last_event; + time_begin = vcpu_record->start_time; + + /* The begin event is not caught. */ + if (!time_begin) + return true; + + /* + * In some case, the 'begin event' only records the start timestamp, + * the actual event is recognized in the 'end event' (e.g. mmio-event). + */ + + /* Both begin and end events did not get the key. */ + if (!event && key->key == INVALID_KEY) + return true; + + if (!event) + event = find_create_kvm_event(key); + + if (!event) + return false; + + vcpu_record->last_event = NULL; + vcpu_record->start_time = 0; + + BUG_ON(timestamp < time_begin); + + time_diff = timestamp - time_begin; + return update_kvm_event(event, vcpu_record->vcpu_id, time_diff); +} + +static struct vcpu_event_record +*per_vcpu_record(struct thread *thread, struct event_format *event, void *data) +{ + /* Only kvm_entry records vcpu id. */ + if (!thread->priv && kvm_entry_event(event)) { + struct vcpu_event_record *vcpu_record; + + vcpu_record = zalloc(sizeof(struct vcpu_event_record)); + if (!vcpu_record) { + pr_err("Not enough memory\n"); + return NULL; + } + + vcpu_record->vcpu_id = raw_field_value(event, "vcpu_id", data); + thread->priv = vcpu_record; + } + + return (struct vcpu_event_record *)thread->priv; +} + +static bool handle_kvm_event(struct thread *thread, struct event_format *event, + void *data, u64 timestamp) +{ + struct vcpu_event_record *vcpu_record; + struct event_key key = {.key = INVALID_KEY}; + + vcpu_record = per_vcpu_record(thread, event, data); + if (!vcpu_record) + return true; + + if (events_ops->is_begin_event(event, data, &key)) + return handle_begin_event(vcpu_record, &key, timestamp); + + if (events_ops->is_end_event(event, data, &key)) + return handle_end_event(vcpu_record, &key, timestamp); + + return true; +} + +typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int); +struct kvm_event_key { + const char *name; + key_cmp_fun key; +}; + +static int trace_vcpu = -1; +#define GET_EVENT_KEY(func, field) \ +static u64 get_event_ ##func(struct kvm_event *event, int vcpu) \ +{ \ + if (vcpu == -1) \ + return event->total.field; \ + \ + if (vcpu >= event->max_vcpu) \ + return 0; \ + \ + return event->vcpu[vcpu].field; \ +} + +#define COMPARE_EVENT_KEY(func, field) \ +GET_EVENT_KEY(func, field) \ +static int compare_kvm_event_ ## func(struct kvm_event *one, \ + struct kvm_event *two, int vcpu)\ +{ \ + return get_event_ ##func(one, vcpu) > \ + get_event_ ##func(two, vcpu); \ +} + +GET_EVENT_KEY(time, time); +COMPARE_EVENT_KEY(count, stats.n); +COMPARE_EVENT_KEY(mean, stats.mean); + +#define DEF_SORT_NAME_KEY(name, compare_key) \ + { #name, compare_kvm_event_ ## compare_key } + +static struct kvm_event_key keys[] = { + DEF_SORT_NAME_KEY(sample, count), + DEF_SORT_NAME_KEY(time, mean), + { NULL, NULL } +}; + +static const char *sort_key = "sample"; +static key_cmp_fun compare; + +static bool select_key(void) +{ + int i; + + for (i = 0; keys[i].name; i++) { + if (!strcmp(keys[i].name, sort_key)) { + compare = keys[i].key; + return true; + } + } + + pr_err("Unknown compare key:%s\n", sort_key); + return false; +} + +static struct rb_root result; +static void insert_to_result(struct kvm_event *event, key_cmp_fun bigger, + int vcpu) +{ + struct rb_node **rb = &result.rb_node; + struct rb_node *parent = NULL; + struct kvm_event *p; + + while (*rb) { + p = container_of(*rb, struct kvm_event, rb); + parent = *rb; + + if (bigger(event, p, vcpu)) + rb = &(*rb)->rb_left; + else + rb = &(*rb)->rb_right; + } + + rb_link_node(&event->rb, parent, rb); + rb_insert_color(&event->rb, &result); +} + +static void update_total_count(struct kvm_event *event, int vcpu) +{ + total_count += get_event_count(event, vcpu); + total_time += get_event_time(event, vcpu); +} + +static bool event_is_valid(struct kvm_event *event, int vcpu) +{ + return !!get_event_count(event, vcpu); +} + +static void sort_result(int vcpu) +{ + unsigned int i; + struct kvm_event *event; + + for (i = 0; i < EVENTS_CACHE_SIZE; i++) + list_for_each_entry(event, &kvm_events_cache[i], hash_entry) + if (event_is_valid(event, vcpu)) { + update_total_count(event, vcpu); + insert_to_result(event, compare, vcpu); + } +} + +/* returns left most element of result, and erase it */ +static struct kvm_event *pop_from_result(void) +{ + struct rb_node *node = rb_first(&result); + + if (!node) + return NULL; + + rb_erase(node, &result); + return container_of(node, struct kvm_event, rb); +} + +static void print_vcpu_info(int vcpu) +{ + pr_info("Analyze events for "); + + if (vcpu == -1) + pr_info("all VCPUs:\n\n"); + else + pr_info("VCPU %d:\n\n", vcpu); +} + +static void print_result(int vcpu) +{ + char decode[20]; + struct kvm_event *event; + + pr_info("\n\n"); + print_vcpu_info(vcpu); + pr_info("%20s ", events_ops->name); + pr_info("%10s ", "Samples"); + pr_info("%9s ", "Samples%"); + + pr_info("%9s ", "Time%"); + pr_info("%16s ", "Avg time"); + pr_info("\n\n"); + + while ((event = pop_from_result())) { + u64 ecount, etime; + + ecount = get_event_count(event, vcpu); + etime = get_event_time(event, vcpu); + + events_ops->decode_key(&event->key, decode); + pr_info("%20s ", decode); + pr_info("%10llu ", (unsigned long long)ecount); + pr_info("%8.2f%% ", (double)ecount / total_count * 100); + pr_info("%8.2f%% ", (double)etime / total_time * 100); + pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3, + kvm_event_rel_stddev(vcpu, event)); + pr_info("\n"); + } + + pr_info("\nTotal Samples:%lld, Total events handled time:%.2fus.\n\n", + (unsigned long long)total_count, total_time / 1e3); +} + +static int process_sample_event(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct machine *machine) +{ + struct thread *thread = machine__findnew_thread(machine, sample->tid); + + if (thread == NULL) { + pr_debug("problem processing %d event, skipping it.\n", + event->header.type); + return -1; + } + + if (!handle_kvm_event(thread, evsel->tp_format, sample->raw_data, + sample->time)) + return -1; + + return 0; +} + +static struct perf_tool eops = { + .sample = process_sample_event, + .comm = perf_event__process_comm, + .ordered_samples = true, +}; + +static int get_cpu_isa(struct perf_session *session) +{ + char *cpuid; + int isa; + + cpuid = perf_header__read_feature(session, HEADER_CPUID); + + if (!cpuid) { + pr_err("read HEADER_CPUID failed.\n"); + return -ENOTSUP; + } + + if (strstr(cpuid, "Intel")) + isa = 1; + else if (strstr(cpuid, "AMD")) + isa = 0; + else { + pr_err("CPU %s is not supported.\n", cpuid); + isa = -ENOTSUP; + } + + free(cpuid); + return isa; +} + +static const char *file_name; + +static int read_events(void) +{ + struct perf_session *kvm_session; + int ret; + + kvm_session = perf_session__new(file_name, O_RDONLY, 0, false, &eops); + if (!kvm_session) { + pr_err("Initializing perf session failed\n"); + return -EINVAL; + } + + if (!perf_session__has_traces(kvm_session, "kvm record")) + return -EINVAL; + + /* + * Do not use 'isa' recorded in kvm_exit tracepoint since it is not + * traced in the old kernel. + */ + ret = get_cpu_isa(kvm_session); + + if (ret < 0) + return ret; + + cpu_isa = ret; + + return perf_session__process_events(kvm_session, &eops); +} + +static bool verify_vcpu(int vcpu) +{ + if (vcpu != -1 && vcpu < 0) { + pr_err("Invalid vcpu:%d.\n", vcpu); + return false; + } + + return true; +} + +static int kvm_events_report_vcpu(int vcpu) +{ + int ret = -EINVAL; + + if (!verify_vcpu(vcpu)) + goto exit; + + if (!select_key()) + goto exit; + + if (!register_kvm_events_ops()) + goto exit; + + init_kvm_event_record(); + setup_pager(); + + ret = read_events(); + if (ret) + goto exit; + + sort_result(vcpu); + print_result(vcpu); +exit: + return ret; +} + +static const char * const record_args[] = { + "record", + "-R", + "-f", + "-m", "1024", + "-c", "1", + "-e", "kvm:kvm_entry", + "-e", "kvm:kvm_exit", + "-e", "kvm:kvm_mmio", + "-e", "kvm:kvm_pio", +}; + +#define STRDUP_FAIL_EXIT(s) \ + ({ char *_p; \ + _p = strdup(s); \ + if (!_p) \ + return -ENOMEM; \ + _p; \ + }) + +static int kvm_events_record(int argc, const char **argv) +{ + unsigned int rec_argc, i, j; + const char **rec_argv; + + rec_argc = ARRAY_SIZE(record_args) + argc + 2; + rec_argv = calloc(rec_argc + 1, sizeof(char *)); + + if (rec_argv == NULL) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(record_args); i++) + rec_argv[i] = STRDUP_FAIL_EXIT(record_args[i]); + + rec_argv[i++] = STRDUP_FAIL_EXIT("-o"); + rec_argv[i++] = STRDUP_FAIL_EXIT(file_name); + + for (j = 1; j < (unsigned int)argc; j++, i++) + rec_argv[i] = argv[j]; + + return cmd_record(i, rec_argv, NULL); +} + +static const char * const kvm_events_report_usage[] = { + "perf kvm stat report [<options>]", + NULL +}; + +static const struct option kvm_events_report_options[] = { + OPT_STRING(0, "event", &report_event, "report event", + "event for reporting: vmexit, mmio, ioport"), + OPT_INTEGER(0, "vcpu", &trace_vcpu, + "vcpu id to report"), + OPT_STRING('k', "key", &sort_key, "sort-key", + "key for sorting: sample(sort by samples number)" + " time (sort by avg time)"), + OPT_END() +}; + +static int kvm_events_report(int argc, const char **argv) +{ + symbol__init(); + + if (argc) { + argc = parse_options(argc, argv, + kvm_events_report_options, + kvm_events_report_usage, 0); + if (argc) + usage_with_options(kvm_events_report_usage, + kvm_events_report_options); + } + + return kvm_events_report_vcpu(trace_vcpu); +} + +static void print_kvm_stat_usage(void) +{ + printf("Usage: perf kvm stat <command>\n\n"); + + printf("# Available commands:\n"); + printf("\trecord: record kvm events\n"); + printf("\treport: report statistical data of kvm events\n"); + + printf("\nOtherwise, it is the alias of 'perf stat':\n"); +} + +static int kvm_cmd_stat(int argc, const char **argv) +{ + if (argc == 1) { + print_kvm_stat_usage(); + goto perf_stat; + } + + if (!strncmp(argv[1], "rec", 3)) + return kvm_events_record(argc - 1, argv + 1); + + if (!strncmp(argv[1], "rep", 3)) + return kvm_events_report(argc - 1 , argv + 1); + +perf_stat: + return cmd_stat(argc, argv, NULL); +} + static char name_buffer[256]; static const char * const kvm_usage[] = { - "perf kvm [<options>] {top|record|report|diff|buildid-list}", + "perf kvm [<options>] {top|record|report|diff|buildid-list|stat}", NULL }; @@ -135,6 +967,8 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused) return cmd_top(argc, argv, NULL); else if (!strncmp(argv[0], "buildid-list", 12)) return __cmd_buildid_list(argc, argv); + else if (!strncmp(argv[0], "stat", 4)) + return kvm_cmd_stat(argc, argv); else usage_with_options(kvm_usage, kvm_options); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index acbf633..ad72b28 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1673,6 +1673,11 @@ static int process_build_id(struct perf_file_section *section, return 0; } +static char *read_cpuid(struct perf_header *ph, int fd) +{ + return do_read_string(fd, ph); +} + static struct perf_evsel * perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) { @@ -1726,6 +1731,7 @@ process_event_desc(struct perf_file_section *section __maybe_unused, struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); + char *(*read)(struct perf_header *h, int fd); int (*process)(struct perf_file_section *section, struct perf_header *h, int feat, int fd, void *data); const char *name; @@ -1740,6 +1746,9 @@ struct feature_ops { #define FEAT_OPF(n, func) \ [n] = { .name = #n, .write = write_##func, .print = print_##func, \ .full_only = true } +#define FEAT_OPA_R(n, func) \ + [n] = { .name = #n, .write = write_##func, .print = print_##func, \ + .read = read_##func } /* feature_ops not implemented: */ #define print_tracing_data NULL @@ -1754,7 +1763,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPA(HEADER_ARCH, arch), FEAT_OPA(HEADER_NRCPUS, nrcpus), FEAT_OPA(HEADER_CPUDESC, cpudesc), - FEAT_OPA(HEADER_CPUID, cpuid), + FEAT_OPA_R(HEADER_CPUID, cpuid), FEAT_OPA(HEADER_TOTAL_MEM, total_mem), FEAT_OPP(HEADER_EVENT_DESC, event_desc), FEAT_OPA(HEADER_CMDLINE, cmdline), @@ -1809,6 +1818,54 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) return 0; } +struct header_read_data { + int feat; + char *result; +}; + +static int perf_file_section__read_feature(struct perf_file_section *section, + struct perf_header *ph, + int feat, int fd, void *data) +{ + struct header_read_data *hd = data; + + if (feat != hd->feat) + return 0; + + if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { + pr_debug("Failed to lseek to %" PRIu64 " offset for feature " + "%d, continuing...\n", section->offset, feat); + return 0; + } + + if (feat >= HEADER_LAST_FEATURE) { + pr_warning("unknown feature %d\n", feat); + return 0; + } + + if (!feat_ops[feat].read) { + pr_warning("read is not supported for feature %d\n", feat); + return 0; + } + + hd->result = feat_ops[feat].read(ph, fd); + return 0; +} + +char *perf_header__read_feature(struct perf_session *session, int feat) +{ + struct perf_header *header = &session->header; + struct header_read_data hd; + int fd = session->fd; + + hd.feat = feat; + hd.result = NULL; + + perf_header__process_sections(header, fd, &hd, + perf_file_section__read_feature); + return hd.result; +} + static int do_write_feat(int fd, struct perf_header *h, int type, struct perf_file_section **p, struct perf_evlist *evlist) diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 209dad4..58de08b 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -94,6 +94,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, int feat, int fd, void *data)); int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); +char *perf_header__read_feature(struct perf_session *session, int feat); int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, const char *name, bool is_kallsyms, bool is_vdso); diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 70c2c13..f66610b 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -16,6 +16,8 @@ struct thread { bool comm_set; char *comm; int comm_len; + + void *priv; }; struct machine; ^ permalink raw reply related [flat|nested] 14+ messages in thread
end of thread, other threads:[~2012-09-27 4:29 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-09-17 8:31 [PATCH v8 0/3] KVM: perf: kvm events analysis tool Dong Hao 2012-09-17 8:31 ` [PATCH v8 1/3] KVM: x86: export svm/vmx exit code and vector code to userspace Dong Hao 2012-09-17 14:58 ` Arnaldo Carvalho de Melo 2012-09-20 12:51 ` Marcelo Tosatti 2012-09-27 4:26 ` [tip:perf/core] KVM: x86: Export svm/ vmx " tip-bot for Xiao Guangrong 2012-09-17 8:31 ` [PATCH v8 2/3] perf: move stat related code to util/stat.c Dong Hao 2012-09-18 14:01 ` David Ahern 2012-09-18 19:18 ` David Ahern 2012-09-19 1:53 ` Xiao Guangrong 2012-09-19 4:00 ` David Ahern 2012-09-19 15:18 ` [tip:perf/core] perf stat: Move stats " tip-bot for Xiao Guangrong 2012-09-17 8:31 ` [PATCH v8 3/3] KVM: perf: kvm events analysis tool Dong Hao 2012-09-20 13:34 ` David Ahern 2012-09-27 4:27 ` [tip:perf/core] perf kvm: Events " tip-bot for Xiao Guangrong
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.