From patchwork Wed Mar 3 09:27:12 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yanmin Zhang X-Patchwork-Id: 83305 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o239PLBk003626 for ; Wed, 3 Mar 2010 09:25:22 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755172Ab0CCJZT (ORCPT ); Wed, 3 Mar 2010 04:25:19 -0500 Received: from mga09.intel.com ([134.134.136.24]:57674 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754359Ab0CCJZO (ORCPT ); Wed, 3 Mar 2010 04:25:14 -0500 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga102.jf.intel.com with ESMTP; 03 Mar 2010 01:23:19 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.49,573,1262592000"; d="scan'208";a="600855548" Received: from unknown (HELO [10.239.13.147]) ([10.239.13.147]) by orsmga001.jf.intel.com with ESMTP; 03 Mar 2010 01:24:51 -0800 Subject: Re: KVM PMU virtualization From: "Zhang, Yanmin" To: Ingo Molnar Cc: Joerg Roedel , Jes Sorensen , KVM General , Peter Zijlstra , Avi Kivity , Zachary Amsden , Gleb Natapov , ming.m.lin@intel.com In-Reply-To: <1267587152.1726.171.camel@localhost> References: <4B86917C.4070102@redhat.com> <20100225173423.GB4246@8bytes.org> <1267152917.1726.82.camel@localhost> <20100226085105.GC4246@8bytes.org> <20100226091732.GI15885@elte.hu> <1267513746.1726.104.camel@localhost> <20100302093629.GB8591@elte.hu> <1267587152.1726.171.camel@localhost> Date: Wed, 03 Mar 2010 17:27:12 +0800 Message-Id: <1267608432.1726.182.camel@localhost> Mime-Version: 1.0 X-Mailer: Evolution 2.28.0 (2.28.0-2.fc12) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 03 Mar 2010 09:25:22 +0000 (UTC) diff -Nraup linux-2.6.33/arch/x86/include/asm/ptrace.h linux-2.6.33_perfkvm/arch/x86/include/asm/ptrace.h --- linux-2.6.33/arch/x86/include/asm/ptrace.h 2010-02-25 02:52:17.000000000 +0800 +++ linux-2.6.33_perfkvm/arch/x86/include/asm/ptrace.h 2010-03-03 14:57:03.792070616 +0800 @@ -167,6 +167,15 @@ static inline int user_mode(struct pt_re #endif } +static inline int user_mode_cs(u16 cs) +{ +#ifdef CONFIG_X86_32 + return (cs & SEGMENT_RPL_MASK) == USER_RPL; +#else + return !!(cs & 3); +#endif +} + static inline int user_mode_vm(struct pt_regs *regs) { #ifdef CONFIG_X86_32 diff -Nraup linux-2.6.33/arch/x86/kvm/vmx.c linux-2.6.33_perfkvm/arch/x86/kvm/vmx.c --- linux-2.6.33/arch/x86/kvm/vmx.c 2010-02-25 02:52:17.000000000 +0800 +++ linux-2.6.33_perfkvm/arch/x86/kvm/vmx.c 2010-03-03 15:06:01.660057862 +0800 @@ -26,6 +26,7 @@ #include #include #include +#include #include "kvm_cache_regs.h" #include "x86.h" @@ -3553,8 +3554,14 @@ static void vmx_complete_interrupts(stru /* We need to handle NMIs before interrupts are enabled */ if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR && - (exit_intr_info & INTR_INFO_VALID_MASK)) + (exit_intr_info & INTR_INFO_VALID_MASK)) { + u64 rip = vmcs_readl(GUEST_RIP); + int user_mode; + user_mode = user_mode_cs(vmcs_read16(GUEST_CS_SELECTOR)); + perf_save_virt_ip(user_mode, rip); asm("int $2"); + perf_reset_virt_ip(); + } idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK; diff -Nraup linux-2.6.33/include/linux/perf_event.h linux-2.6.33_perfkvm/include/linux/perf_event.h --- linux-2.6.33/include/linux/perf_event.h 2010-02-25 02:52:17.000000000 +0800 +++ linux-2.6.33_perfkvm/include/linux/perf_event.h 2010-03-03 15:22:05.325064001 +0800 @@ -287,11 +287,13 @@ struct perf_event_mmap_page { __u64 data_tail; /* user-space written tail */ }; -#define PERF_RECORD_MISC_CPUMODE_MASK (3 << 0) -#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) +#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0) +#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) #define PERF_RECORD_MISC_KERNEL (1 << 0) #define PERF_RECORD_MISC_USER (2 << 0) #define PERF_RECORD_MISC_HYPERVISOR (3 << 0) +#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0) +#define PERF_RECORD_MISC_GUEST_USER (5 << 0) struct perf_event_header { __u32 type; @@ -841,6 +843,37 @@ static inline void perf_event_mmap(struc __perf_event_mmap(vma); } +struct perf_virt_ip_info { + int user_mode; + u64 ip; +}; + +DECLARE_PER_CPU(struct perf_virt_ip_info, perf_virt_ip); +extern void perf_save_virt_ip(int user_mode, u64 ip); +extern void perf_reset_virt_ip(void); + +static inline u64 perf_instruction_pointer(struct pt_regs *regs) +{ + u64 ip; + ip = percpu_read(perf_virt_ip.ip); + if (!ip) + ip = instruction_pointer(regs); + else + perf_reset_virt_ip(); + return ip; +} + +static inline unsigned int perf_misc_flags(struct pt_regs *regs) +{ + if (percpu_read(perf_virt_ip.ip)) { + return percpu_read(perf_virt_ip.user_mode) ? + PERF_RECORD_MISC_GUEST_USER : + PERF_RECORD_MISC_GUEST_KERNEL; + } else + return user_mode(regs) ? PERF_RECORD_MISC_USER : + PERF_RECORD_MISC_KERNEL; +} + extern void perf_event_comm(struct task_struct *tsk); extern void perf_event_fork(struct task_struct *tsk); @@ -855,12 +888,6 @@ extern void perf_tp_event(int event_id, void *record, int entry_size); extern void perf_bp_event(struct perf_event *event, void *data); -#ifndef perf_misc_flags -#define perf_misc_flags(regs) (user_mode(regs) ? PERF_RECORD_MISC_USER : \ - PERF_RECORD_MISC_KERNEL) -#define perf_instruction_pointer(regs) instruction_pointer(regs) -#endif - extern int perf_output_begin(struct perf_output_handle *handle, struct perf_event *event, unsigned int size, int nmi, int sample); @@ -895,6 +922,10 @@ perf_sw_event(u32 event_id, u64 nr, int static inline void perf_bp_event(struct perf_event *event, void *data) { } +static inline void perf_save_virt_ip(int user_mode, u64 ip) { } +static inline void perf_reset_virt_ip(void) { } +#define perf_instruction_pointer(event, regs) instruction_pointer(regs) + static inline void perf_event_mmap(struct vm_area_struct *vma) { } static inline void perf_event_comm(struct task_struct *tsk) { } static inline void perf_event_fork(struct task_struct *tsk) { } diff -Nraup linux-2.6.33/kernel/perf_event.c linux-2.6.33_perfkvm/kernel/perf_event.c --- linux-2.6.33/kernel/perf_event.c 2010-02-25 02:52:17.000000000 +0800 +++ linux-2.6.33_perfkvm/kernel/perf_event.c 2010-03-03 15:16:25.521592849 +0800 @@ -3077,6 +3077,26 @@ void perf_output_sample(struct perf_outp } } +DEFINE_PER_CPU(struct perf_virt_ip_info, perf_virt_ip) = {0,0}; +EXPORT_PER_CPU_SYMBOL(perf_virt_ip); + +void perf_save_virt_ip(int user_mode, u64 ip) +{ + if (!atomic_read(&nr_events)) + return; + percpu_write(perf_virt_ip.user_mode, ip); + percpu_write(perf_virt_ip.ip, ip); +} +EXPORT_SYMBOL_GPL(perf_save_virt_ip); + +void perf_reset_virt_ip(void) +{ + if (!percpu_read(perf_virt_ip.ip)) + return; + percpu_write(perf_virt_ip.ip, 0); +} +EXPORT_SYMBOL_GPL(perf_reset_virt_ip); + void perf_prepare_sample(struct perf_event_header *header, struct perf_sample_data *data, struct perf_event *event,