Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 39447b3

Browse files
Zhang, Yanminavikivity
authored andcommitted
perf: Enhance perf to allow for guest statistic collection from host
Below patch introduces perf_guest_info_callbacks and related register/unregister functions. Add more PERF_RECORD_MISC_XXX bits meaning guest kernel and guest user space. Signed-off-by: Zhang Yanmin <[email protected]> Signed-off-by: Avi Kivity <[email protected]>
1 parent b5a80b7 commit 39447b3

File tree

4 files changed

+77
-13
lines changed

4 files changed

+77
-13
lines changed

arch/x86/include/asm/perf_event.h

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,10 @@ extern void perf_events_lapic_init(void);
135135
*/
136136
#define PERF_EFLAGS_EXACT (1UL << 3)
137137

138-
#define perf_misc_flags(regs) \
139-
({ int misc = 0; \
140-
if (user_mode(regs)) \
141-
misc |= PERF_RECORD_MISC_USER; \
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)
138+
struct pt_regs;
139+
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
140+
extern unsigned long perf_misc_flags(struct pt_regs *regs);
141+
#define perf_misc_flags(regs) perf_misc_flags(regs)
149142

150143
#else
151144
static inline void init_hw_perf_events(void) { }

arch/x86/kernel/cpu/perf_event.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1720,6 +1720,11 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
17201720
{
17211721
struct perf_callchain_entry *entry;
17221722

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+
17231728
if (in_nmi())
17241729
entry = &__get_cpu_var(pmc_nmi_entry);
17251730
else
@@ -1743,3 +1748,29 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski
17431748
regs->cs = __KERNEL_CS;
17441749
local_save_flags(regs->flags);
17451750
}
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+
}

include/linux/perf_event.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,13 @@ struct perf_event_mmap_page {
288288
__u64 data_tail; /* user-space written tail */
289289
};
290290

291-
#define PERF_RECORD_MISC_CPUMODE_MASK (3 << 0)
291+
#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0)
292292
#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0)
293293
#define PERF_RECORD_MISC_KERNEL (1 << 0)
294294
#define PERF_RECORD_MISC_USER (2 << 0)
295295
#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)
296298

297299
#define PERF_RECORD_MISC_EXACT (1 << 14)
298300
/*
@@ -446,6 +448,12 @@ enum perf_callchain_context {
446448
# include <asm/perf_event.h>
447449
#endif
448450

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+
449457
#ifdef CONFIG_HAVE_HW_BREAKPOINT
450458
#include <asm/hw_breakpoint.h>
451459
#endif
@@ -932,6 +940,12 @@ static inline void perf_event_mmap(struct vm_area_struct *vma)
932940
__perf_event_mmap(vma);
933941
}
934942

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+
935949
extern void perf_event_comm(struct task_struct *tsk);
936950
extern void perf_event_fork(struct task_struct *tsk);
937951

@@ -1001,6 +1015,11 @@ perf_sw_event(u32 event_id, u64 nr, int nmi,
10011015
static inline void
10021016
perf_bp_event(struct perf_event *event, void *data) { }
10031017

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+
10041023
static inline void perf_event_mmap(struct vm_area_struct *vma) { }
10051024
static inline void perf_event_comm(struct task_struct *tsk) { }
10061025
static inline void perf_event_fork(struct task_struct *tsk) { }

kernel/perf_event.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2797,6 +2797,27 @@ void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip, int ski
27972797
}
27982798

27992799

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+
28002821
/*
28012822
* Output
28022823
*/
@@ -3749,7 +3770,7 @@ void __perf_event_mmap(struct vm_area_struct *vma)
37493770
.event_id = {
37503771
.header = {
37513772
.type = PERF_RECORD_MMAP,
3752-
.misc = 0,
3773+
.misc = PERF_RECORD_MISC_USER,
37533774
/* .size */
37543775
},
37553776
/* .pid */

0 commit comments

Comments
 (0)