diff options
| -rw-r--r-- | arch/x86/include/asm/perf_event.h | 15 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/perf_event.c | 31 | ||||
| -rw-r--r-- | include/linux/perf_event.h | 21 | ||||
| -rw-r--r-- | kernel/perf_event.c | 23 |
4 files changed, 77 insertions, 13 deletions
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index f6d43dbfd8e7..254883d0c7e0 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h | |||
| @@ -135,17 +135,10 @@ extern void perf_events_lapic_init(void); | |||
| 135 | */ | 135 | */ |
| 136 | #define PERF_EFLAGS_EXACT (1UL << 3) | 136 | #define PERF_EFLAGS_EXACT (1UL << 3) |
| 137 | 137 | ||
| 138 | #define perf_misc_flags(regs) \ | 138 | struct pt_regs; |
| 139 | ({ int misc = 0; \ | 139 | extern unsigned long perf_instruction_pointer(struct pt_regs *regs); |
| 140 | if (user_mode(regs)) \ | 140 | extern unsigned long perf_misc_flags(struct pt_regs *regs); |
| 141 | misc |= PERF_RECORD_MISC_USER; \ | 141 | #define perf_misc_flags(regs) perf_misc_flags(regs) |
| 142 | else \ | ||
| 143 | misc |= PERF_RECORD_MISC_KERNEL; \ | ||
| 144 | if (regs->flags & PERF_EFLAGS_EXACT) \ | ||
| 145 | misc |= PERF_RECORD_MISC_EXACT; \ | ||
| 146 | misc; }) | ||
| 147 | |||
| 148 | #define perf_instruction_pointer(regs) ((regs)->ip) | ||
| 149 | 142 | ||
| 150 | #else | 143 | #else |
| 151 | static inline void init_hw_perf_events(void) { } | 144 | static inline void init_hw_perf_events(void) { } |
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 626154a9f535..2ea78abf69d9 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c | |||
| @@ -1720,6 +1720,11 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) | |||
| 1720 | { | 1720 | { |
| 1721 | struct perf_callchain_entry *entry; | 1721 | struct perf_callchain_entry *entry; |
| 1722 | 1722 | ||
| 1723 | if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { | ||
| 1724 | /* TODO: We don't support guest os callchain now */ | ||
| 1725 | return NULL; | ||
| 1726 | } | ||
| 1727 | |||
| 1723 | if (in_nmi()) | 1728 | if (in_nmi()) |
| 1724 | entry = &__get_cpu_var(pmc_nmi_entry); | 1729 | entry = &__get_cpu_var(pmc_nmi_entry); |
| 1725 | else | 1730 | else |
| @@ -1743,3 +1748,29 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski | |||
| 1743 | regs->cs = __KERNEL_CS; | 1748 | regs->cs = __KERNEL_CS; |
| 1744 | local_save_flags(regs->flags); | 1749 | local_save_flags(regs->flags); |
| 1745 | } | 1750 | } |
| 1751 | |||
| 1752 | unsigned long perf_instruction_pointer(struct pt_regs *regs) | ||
| 1753 | { | ||
| 1754 | unsigned long ip; | ||
| 1755 | if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) | ||
| 1756 | ip = perf_guest_cbs->get_guest_ip(); | ||
| 1757 | else | ||
| 1758 | ip = instruction_pointer(regs); | ||
| 1759 | return ip; | ||
| 1760 | } | ||
| 1761 | |||
| 1762 | unsigned long perf_misc_flags(struct pt_regs *regs) | ||
| 1763 | { | ||
| 1764 | int misc = 0; | ||
| 1765 | if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { | ||
| 1766 | misc |= perf_guest_cbs->is_user_mode() ? | ||
| 1767 | PERF_RECORD_MISC_GUEST_USER : | ||
| 1768 | PERF_RECORD_MISC_GUEST_KERNEL; | ||
| 1769 | } else | ||
| 1770 | misc |= user_mode(regs) ? PERF_RECORD_MISC_USER : | ||
| 1771 | PERF_RECORD_MISC_KERNEL; | ||
| 1772 | if (regs->flags & PERF_EFLAGS_EXACT) | ||
| 1773 | misc |= PERF_RECORD_MISC_EXACT; | ||
| 1774 | |||
| 1775 | return misc; | ||
| 1776 | } | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index bf896d0b2e9c..24de5f181a41 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -288,11 +288,13 @@ struct perf_event_mmap_page { | |||
| 288 | __u64 data_tail; /* user-space written tail */ | 288 | __u64 data_tail; /* user-space written tail */ |
| 289 | }; | 289 | }; |
| 290 | 290 | ||
| 291 | #define PERF_RECORD_MISC_CPUMODE_MASK (3 << 0) | 291 | #define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0) |
| 292 | #define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) | 292 | #define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) |
| 293 | #define PERF_RECORD_MISC_KERNEL (1 << 0) | 293 | #define PERF_RECORD_MISC_KERNEL (1 << 0) |
| 294 | #define PERF_RECORD_MISC_USER (2 << 0) | 294 | #define PERF_RECORD_MISC_USER (2 << 0) |
| 295 | #define PERF_RECORD_MISC_HYPERVISOR (3 << 0) | 295 | #define PERF_RECORD_MISC_HYPERVISOR (3 << 0) |
| 296 | #define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0) | ||
| 297 | #define PERF_RECORD_MISC_GUEST_USER (5 << 0) | ||
| 296 | 298 | ||
| 297 | #define PERF_RECORD_MISC_EXACT (1 << 14) | 299 | #define PERF_RECORD_MISC_EXACT (1 << 14) |
| 298 | /* | 300 | /* |
| @@ -446,6 +448,12 @@ enum perf_callchain_context { | |||
| 446 | # include <asm/perf_event.h> | 448 | # include <asm/perf_event.h> |
| 447 | #endif | 449 | #endif |
| 448 | 450 | ||
| 451 | struct perf_guest_info_callbacks { | ||
| 452 | int (*is_in_guest) (void); | ||
| 453 | int (*is_user_mode) (void); | ||
| 454 | unsigned long (*get_guest_ip) (void); | ||
| 455 | }; | ||
| 456 | |||
| 449 | #ifdef CONFIG_HAVE_HW_BREAKPOINT | 457 | #ifdef CONFIG_HAVE_HW_BREAKPOINT |
| 450 | #include <asm/hw_breakpoint.h> | 458 | #include <asm/hw_breakpoint.h> |
| 451 | #endif | 459 | #endif |
| @@ -932,6 +940,12 @@ static inline void perf_event_mmap(struct vm_area_struct *vma) | |||
| 932 | __perf_event_mmap(vma); | 940 | __perf_event_mmap(vma); |
| 933 | } | 941 | } |
| 934 | 942 | ||
| 943 | extern struct perf_guest_info_callbacks *perf_guest_cbs; | ||
| 944 | extern int perf_register_guest_info_callbacks( | ||
| 945 | struct perf_guest_info_callbacks *); | ||
| 946 | extern int perf_unregister_guest_info_callbacks( | ||
| 947 | struct perf_guest_info_callbacks *); | ||
| 948 | |||
| 935 | extern void perf_event_comm(struct task_struct *tsk); | 949 | extern void perf_event_comm(struct task_struct *tsk); |
| 936 | extern void perf_event_fork(struct task_struct *tsk); | 950 | extern void perf_event_fork(struct task_struct *tsk); |
| 937 | 951 | ||
| @@ -1001,6 +1015,11 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, | |||
| 1001 | static inline void | 1015 | static inline void |
| 1002 | perf_bp_event(struct perf_event *event, void *data) { } | 1016 | perf_bp_event(struct perf_event *event, void *data) { } |
| 1003 | 1017 | ||
| 1018 | static inline int perf_register_guest_info_callbacks | ||
| 1019 | (struct perf_guest_info_callbacks *) {return 0; } | ||
| 1020 | static inline int perf_unregister_guest_info_callbacks | ||
| 1021 | (struct perf_guest_info_callbacks *) {return 0; } | ||
| 1022 | |||
| 1004 | static inline void perf_event_mmap(struct vm_area_struct *vma) { } | 1023 | static inline void perf_event_mmap(struct vm_area_struct *vma) { } |
| 1005 | static inline void perf_event_comm(struct task_struct *tsk) { } | 1024 | static inline void perf_event_comm(struct task_struct *tsk) { } |
| 1006 | static inline void perf_event_fork(struct task_struct *tsk) { } | 1025 | static inline void perf_event_fork(struct task_struct *tsk) { } |
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 07b7a435bf03..9dbe8cdaf145 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -2798,6 +2798,27 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski | |||
| 2798 | 2798 | ||
| 2799 | 2799 | ||
| 2800 | /* | 2800 | /* |
| 2801 | * We assume there is only KVM supporting the callbacks. | ||
| 2802 | * Later on, we might change it to a list if there is | ||
| 2803 | * another virtualization implementation supporting the callbacks. | ||
| 2804 | */ | ||
| 2805 | struct perf_guest_info_callbacks *perf_guest_cbs; | ||
| 2806 | |||
| 2807 | int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) | ||
| 2808 | { | ||
| 2809 | perf_guest_cbs = cbs; | ||
| 2810 | return 0; | ||
| 2811 | } | ||
| 2812 | EXPORT_SYMBOL_GPL(perf_register_guest_info_callbacks); | ||
| 2813 | |||
| 2814 | int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) | ||
| 2815 | { | ||
| 2816 | perf_guest_cbs = NULL; | ||
| 2817 | return 0; | ||
| 2818 | } | ||
| 2819 | EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks); | ||
| 2820 | |||
| 2821 | /* | ||
| 2801 | * Output | 2822 | * Output |
| 2802 | */ | 2823 | */ |
| 2803 | static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail, | 2824 | static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail, |
| @@ -3749,7 +3770,7 @@ void __perf_event_mmap(struct vm_area_struct *vma) | |||
| 3749 | .event_id = { | 3770 | .event_id = { |
| 3750 | .header = { | 3771 | .header = { |
| 3751 | .type = PERF_RECORD_MMAP, | 3772 | .type = PERF_RECORD_MMAP, |
| 3752 | .misc = 0, | 3773 | .misc = PERF_RECORD_MISC_USER, |
| 3753 | /* .size */ | 3774 | /* .size */ |
| 3754 | }, | 3775 | }, |
| 3755 | /* .pid */ | 3776 | /* .pid */ |
