Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: Add trace markers

Trace markers allow userspace to trace execution of a virtual machine
in order to monitor its performance.

Signed-off-by: Feng (Eric) Liu <eric.e.liu@intel.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>

authored by

Feng (Eric) Liu and committed by
Avi Kivity
2714d1d3 53371b50

+147 -2
+34 -1
arch/x86/kvm/vmx.c
··· 1843 1843 { 1844 1844 struct vcpu_vmx *vmx = to_vmx(vcpu); 1845 1845 1846 + KVMTRACE_1D(INJ_VIRQ, vcpu, (u32)irq, handler); 1847 + 1846 1848 if (vcpu->arch.rmode.active) { 1847 1849 vmx->rmode.irq.pending = true; 1848 1850 vmx->rmode.irq.vector = irq; ··· 1995 1993 error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE); 1996 1994 if (is_page_fault(intr_info)) { 1997 1995 cr2 = vmcs_readl(EXIT_QUALIFICATION); 1996 + KVMTRACE_3D(PAGE_FAULT, vcpu, error_code, (u32)cr2, 1997 + (u32)((u64)cr2 >> 32), handler); 1998 1998 return kvm_mmu_page_fault(vcpu, cr2, error_code); 1999 1999 } 2000 2000 ··· 2025 2021 struct kvm_run *kvm_run) 2026 2022 { 2027 2023 ++vcpu->stat.irq_exits; 2024 + KVMTRACE_1D(INTR, vcpu, vmcs_read32(VM_EXIT_INTR_INFO), handler); 2028 2025 return 1; 2029 2026 } 2030 2027 ··· 2083 2078 reg = (exit_qualification >> 8) & 15; 2084 2079 switch ((exit_qualification >> 4) & 3) { 2085 2080 case 0: /* mov to cr */ 2081 + KVMTRACE_3D(CR_WRITE, vcpu, (u32)cr, (u32)vcpu->arch.regs[reg], 2082 + (u32)((u64)vcpu->arch.regs[reg] >> 32), handler); 2086 2083 switch (cr) { 2087 2084 case 0: 2088 2085 vcpu_load_rsp_rip(vcpu); ··· 2117 2110 vcpu->arch.cr0 &= ~X86_CR0_TS; 2118 2111 vmcs_writel(CR0_READ_SHADOW, vcpu->arch.cr0); 2119 2112 vmx_fpu_activate(vcpu); 2113 + KVMTRACE_0D(CLTS, vcpu, handler); 2120 2114 skip_emulated_instruction(vcpu); 2121 2115 return 1; 2122 2116 case 1: /*mov from cr*/ ··· 2126 2118 vcpu_load_rsp_rip(vcpu); 2127 2119 vcpu->arch.regs[reg] = vcpu->arch.cr3; 2128 2120 vcpu_put_rsp_rip(vcpu); 2121 + KVMTRACE_3D(CR_READ, vcpu, (u32)cr, 2122 + (u32)vcpu->arch.regs[reg], 2123 + (u32)((u64)vcpu->arch.regs[reg] >> 32), 2124 + handler); 2129 2125 skip_emulated_instruction(vcpu); 2130 2126 return 1; 2131 2127 case 8: 2132 2128 vcpu_load_rsp_rip(vcpu); 2133 2129 vcpu->arch.regs[reg] = kvm_get_cr8(vcpu); 2134 2130 vcpu_put_rsp_rip(vcpu); 2131 + KVMTRACE_2D(CR_READ, vcpu, (u32)cr, 2132 + (u32)vcpu->arch.regs[reg], handler); 2135 2133 skip_emulated_instruction(vcpu); 2136 2134 return 1; 2137 2135 } ··· 2183 2169 val = 0; 2184 2170 } 2185 2171 vcpu->arch.regs[reg] = val; 2172 + KVMTRACE_2D(DR_READ, vcpu, (u32)dr, (u32)val, handler); 2186 2173 } else { 2187 2174 /* mov to dr */ 2188 2175 } ··· 2208 2193 return 1; 2209 2194 } 2210 2195 2196 + KVMTRACE_3D(MSR_READ, vcpu, ecx, (u32)data, (u32)(data >> 32), 2197 + handler); 2198 + 2211 2199 /* FIXME: handling of bits 32:63 of rax, rdx */ 2212 2200 vcpu->arch.regs[VCPU_REGS_RAX] = data & -1u; 2213 2201 vcpu->arch.regs[VCPU_REGS_RDX] = (data >> 32) & -1u; ··· 2223 2205 u32 ecx = vcpu->arch.regs[VCPU_REGS_RCX]; 2224 2206 u64 data = (vcpu->arch.regs[VCPU_REGS_RAX] & -1u) 2225 2207 | ((u64)(vcpu->arch.regs[VCPU_REGS_RDX] & -1u) << 32); 2208 + 2209 + KVMTRACE_3D(MSR_WRITE, vcpu, ecx, (u32)data, (u32)(data >> 32), 2210 + handler); 2226 2211 2227 2212 if (vmx_set_msr(vcpu, ecx, data) != 0) { 2228 2213 kvm_inject_gp(vcpu, 0); ··· 2251 2230 cpu_based_vm_exec_control = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); 2252 2231 cpu_based_vm_exec_control &= ~CPU_BASED_VIRTUAL_INTR_PENDING; 2253 2232 vmcs_write32(CPU_BASED_VM_EXEC_CONTROL, cpu_based_vm_exec_control); 2233 + 2234 + KVMTRACE_0D(PEND_INTR, vcpu, handler); 2235 + 2254 2236 /* 2255 2237 * If the user space waits to inject interrupts, exit as soon as 2256 2238 * possible ··· 2295 2271 2296 2272 exit_qualification = vmcs_read64(EXIT_QUALIFICATION); 2297 2273 offset = exit_qualification & 0xffful; 2274 + 2275 + KVMTRACE_1D(APIC_ACCESS, vcpu, (u32)offset, handler); 2298 2276 2299 2277 er = emulate_instruction(vcpu, kvm_run, 0, 0, 0); 2300 2278 ··· 2360 2334 u32 exit_reason = vmcs_read32(VM_EXIT_REASON); 2361 2335 struct vcpu_vmx *vmx = to_vmx(vcpu); 2362 2336 u32 vectoring_info = vmx->idt_vectoring_info; 2337 + 2338 + KVMTRACE_3D(VMEXIT, vcpu, exit_reason, (u32)vmcs_readl(GUEST_RIP), 2339 + (u32)((u64)vmcs_readl(GUEST_RIP) >> 32), entryexit); 2363 2340 2364 2341 if (unlikely(vmx->fail)) { 2365 2342 kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY; ··· 2444 2415 enable_irq_window(vcpu); 2445 2416 return; 2446 2417 } 2418 + 2419 + KVMTRACE_1D(REDELIVER_EVT, vcpu, idtv_info_field, handler); 2447 2420 2448 2421 vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field); 2449 2422 vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, ··· 2632 2601 intr_info = vmcs_read32(VM_EXIT_INTR_INFO); 2633 2602 2634 2603 /* We need to handle NMIs before interrupts are enabled */ 2635 - if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) /* nmi */ 2604 + if ((intr_info & INTR_INFO_INTR_TYPE_MASK) == 0x200) { /* nmi */ 2605 + KVMTRACE_0D(NMI, vcpu, handler); 2636 2606 asm("int $2"); 2607 + } 2637 2608 } 2638 2609 2639 2610 static void vmx_free_vmcs(struct kvm_vcpu *vcpu)
+26
arch/x86/kvm/x86.c
··· 303 303 void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw) 304 304 { 305 305 kvm_set_cr0(vcpu, (vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)); 306 + KVMTRACE_1D(LMSW, vcpu, 307 + (u32)((vcpu->arch.cr0 & ~0x0ful) | (msw & 0x0f)), 308 + handler); 306 309 } 307 310 EXPORT_SYMBOL_GPL(kvm_lmsw); 308 311 ··· 2272 2269 vcpu->arch.pio.guest_page_offset = 0; 2273 2270 vcpu->arch.pio.rep = 0; 2274 2271 2272 + if (vcpu->run->io.direction == KVM_EXIT_IO_IN) 2273 + KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size, 2274 + handler); 2275 + else 2276 + KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size, 2277 + handler); 2278 + 2275 2279 kvm_x86_ops->cache_regs(vcpu); 2276 2280 memcpy(vcpu->arch.pio_data, &vcpu->arch.regs[VCPU_REGS_RAX], 4); 2277 2281 kvm_x86_ops->decache_regs(vcpu); ··· 2316 2306 vcpu->arch.pio.down = down; 2317 2307 vcpu->arch.pio.guest_page_offset = offset_in_page(address); 2318 2308 vcpu->arch.pio.rep = rep; 2309 + 2310 + if (vcpu->run->io.direction == KVM_EXIT_IO_IN) 2311 + KVMTRACE_2D(IO_READ, vcpu, vcpu->run->io.port, (u32)size, 2312 + handler); 2313 + else 2314 + KVMTRACE_2D(IO_WRITE, vcpu, vcpu->run->io.port, (u32)size, 2315 + handler); 2319 2316 2320 2317 if (!count) { 2321 2318 kvm_x86_ops->skip_emulated_instruction(vcpu); ··· 2431 2414 int kvm_emulate_halt(struct kvm_vcpu *vcpu) 2432 2415 { 2433 2416 ++vcpu->stat.halt_exits; 2417 + KVMTRACE_0D(HLT, vcpu, handler); 2434 2418 if (irqchip_in_kernel(vcpu->kvm)) { 2435 2419 vcpu->arch.mp_state = VCPU_MP_STATE_HALTED; 2436 2420 up_read(&vcpu->kvm->slots_lock); ··· 2468 2450 a1 = vcpu->arch.regs[VCPU_REGS_RCX]; 2469 2451 a2 = vcpu->arch.regs[VCPU_REGS_RDX]; 2470 2452 a3 = vcpu->arch.regs[VCPU_REGS_RSI]; 2453 + 2454 + KVMTRACE_1D(VMMCALL, vcpu, (u32)nr, handler); 2471 2455 2472 2456 if (!is_long_mode(vcpu)) { 2473 2457 nr &= 0xFFFFFFFF; ··· 2659 2639 } 2660 2640 kvm_x86_ops->decache_regs(vcpu); 2661 2641 kvm_x86_ops->skip_emulated_instruction(vcpu); 2642 + KVMTRACE_5D(CPUID, vcpu, function, 2643 + (u32)vcpu->arch.regs[VCPU_REGS_RAX], 2644 + (u32)vcpu->arch.regs[VCPU_REGS_RBX], 2645 + (u32)vcpu->arch.regs[VCPU_REGS_RCX], 2646 + (u32)vcpu->arch.regs[VCPU_REGS_RDX], handler); 2662 2647 } 2663 2648 EXPORT_SYMBOL_GPL(kvm_emulate_cpuid); 2664 2649 ··· 2819 2794 if (test_and_clear_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests)) 2820 2795 kvm_x86_ops->tlb_flush(vcpu); 2821 2796 2797 + KVMTRACE_0D(VMENTRY, vcpu, entryexit); 2822 2798 kvm_x86_ops->run(vcpu, kvm_run); 2823 2799 2824 2800 vcpu->guest_mode = 0;
+20
include/asm-x86/kvm.h
··· 209 209 struct kvm_pit_channel_state channels[3]; 210 210 }; 211 211 212 + #define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02) 213 + #define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03) 214 + #define KVM_TRC_PEND_INTR (KVM_TRC_HANDLER + 0x04) 215 + #define KVM_TRC_IO_READ (KVM_TRC_HANDLER + 0x05) 216 + #define KVM_TRC_IO_WRITE (KVM_TRC_HANDLER + 0x06) 217 + #define KVM_TRC_CR_READ (KVM_TRC_HANDLER + 0x07) 218 + #define KVM_TRC_CR_WRITE (KVM_TRC_HANDLER + 0x08) 219 + #define KVM_TRC_DR_READ (KVM_TRC_HANDLER + 0x09) 220 + #define KVM_TRC_DR_WRITE (KVM_TRC_HANDLER + 0x0A) 221 + #define KVM_TRC_MSR_READ (KVM_TRC_HANDLER + 0x0B) 222 + #define KVM_TRC_MSR_WRITE (KVM_TRC_HANDLER + 0x0C) 223 + #define KVM_TRC_CPUID (KVM_TRC_HANDLER + 0x0D) 224 + #define KVM_TRC_INTR (KVM_TRC_HANDLER + 0x0E) 225 + #define KVM_TRC_NMI (KVM_TRC_HANDLER + 0x0F) 226 + #define KVM_TRC_VMMCALL (KVM_TRC_HANDLER + 0x10) 227 + #define KVM_TRC_HLT (KVM_TRC_HANDLER + 0x11) 228 + #define KVM_TRC_CLTS (KVM_TRC_HANDLER + 0x12) 229 + #define KVM_TRC_LMSW (KVM_TRC_HANDLER + 0x13) 230 + #define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14) 231 + 212 232 #endif
+19
include/asm-x86/kvm_host.h
··· 667 667 TASK_SWITCH_GATE = 3, 668 668 }; 669 669 670 + #define KVMTRACE_5D(evt, vcpu, d1, d2, d3, d4, d5, name) \ 671 + trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ 672 + vcpu, 5, d1, d2, d3, d4, d5) 673 + #define KVMTRACE_4D(evt, vcpu, d1, d2, d3, d4, name) \ 674 + trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ 675 + vcpu, 4, d1, d2, d3, d4, 0) 676 + #define KVMTRACE_3D(evt, vcpu, d1, d2, d3, name) \ 677 + trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ 678 + vcpu, 3, d1, d2, d3, 0, 0) 679 + #define KVMTRACE_2D(evt, vcpu, d1, d2, name) \ 680 + trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ 681 + vcpu, 2, d1, d2, 0, 0, 0) 682 + #define KVMTRACE_1D(evt, vcpu, d1, name) \ 683 + trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ 684 + vcpu, 1, d1, 0, 0, 0, 0) 685 + #define KVMTRACE_0D(evt, vcpu, name) \ 686 + trace_mark(kvm_trace_##name, "%u %p %u %u %u %u %u %u", KVM_TRC_##evt, \ 687 + vcpu, 0, 0, 0, 0, 0, 0) 688 + 670 689 #endif
+48 -1
include/linux/kvm.h
··· 14 14 15 15 #define KVM_API_VERSION 12 16 16 17 + /* for KVM_TRACE_ENABLE */ 18 + struct kvm_user_trace_setup { 19 + __u32 buf_size; /* sub_buffer size of each per-cpu */ 20 + __u32 buf_nr; /* the number of sub_buffers of each per-cpu */ 21 + }; 22 + 17 23 /* for KVM_CREATE_MEMORY_REGION */ 18 24 struct kvm_memory_region { 19 25 __u32 slot; ··· 248 242 __u64 parm64; 249 243 }; 250 244 245 + #define KVM_TRC_SHIFT 16 246 + /* 247 + * kvm trace categories 248 + */ 249 + #define KVM_TRC_ENTRYEXIT (1 << KVM_TRC_SHIFT) 250 + #define KVM_TRC_HANDLER (1 << (KVM_TRC_SHIFT + 1)) /* only 12 bits */ 251 + 252 + /* 253 + * kvm trace action 254 + */ 255 + #define KVM_TRC_VMENTRY (KVM_TRC_ENTRYEXIT + 0x01) 256 + #define KVM_TRC_VMEXIT (KVM_TRC_ENTRYEXIT + 0x02) 257 + #define KVM_TRC_PAGE_FAULT (KVM_TRC_HANDLER + 0x01) 258 + 259 + #define KVM_TRC_HEAD_SIZE 12 260 + #define KVM_TRC_CYCLE_SIZE 8 261 + #define KVM_TRC_EXTRA_MAX 7 262 + 263 + /* This structure represents a single trace buffer record. */ 264 + struct kvm_trace_rec { 265 + __u32 event:28; 266 + __u32 extra_u32:3; 267 + __u32 cycle_in:1; 268 + __u32 pid; 269 + __u32 vcpu_id; 270 + union { 271 + struct { 272 + __u32 cycle_lo, cycle_hi; 273 + __u32 extra_u32[KVM_TRC_EXTRA_MAX]; 274 + } cycle; 275 + struct { 276 + __u32 extra_u32[KVM_TRC_EXTRA_MAX]; 277 + } nocycle; 278 + } u; 279 + }; 280 + 251 281 #define KVMIO 0xAE 252 282 253 283 /* ··· 304 262 */ 305 263 #define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */ 306 264 #define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2) 307 - 265 + /* 266 + * ioctls for kvm trace 267 + */ 268 + #define KVM_TRACE_ENABLE _IOW(KVMIO, 0x06, struct kvm_user_trace_setup) 269 + #define KVM_TRACE_PAUSE _IO(KVMIO, 0x07) 270 + #define KVM_TRACE_DISABLE _IO(KVMIO, 0x08) 308 271 /* 309 272 * Extension capability list. 310 273 */