Em Thu, Jan 10, 2019 at 06:40:37PM +0000, Song Liu escreveu: > > > > On Jan 10, 2019, at 10:24 AM, Arnaldo Carvalho de Melo <a...@kernel.org> > > wrote: > > > > Em Wed, Jan 09, 2019 at 11:21:05AM -0800, Song Liu escreveu: > >> For better performance analysis of dynamically JITed and loaded kernel > >> functions, such as BPF programs, this patch introduces > >> PERF_RECORD_KSYMBOL, a new perf_event_type that exposes kernel symbol > >> register/unregister information to user space. > >> > >> The following data structure is used for PERF_RECORD_KSYMBOL. > >> > >> /* > >> * struct { > >> * struct perf_event_header header; > >> * u64 addr; > >> * u32 len; > >> * u16 ksym_type; > >> * u16 flags; > >> * char name[]; > >> * struct sample_id sample_id; > >> * }; > >> */ > > > > So, I couldn't find where this gets used, the intention here is just to > > add the interfaces and afterwards is that you will wire this up? I would > > like to test the whole shebang to see it working. > > I guess you meant PERF_RECORD_BPF_EVENT not being used? > > PERF_RECORD_KSYMBOL is used by BPF in 3/7 and 5/7. I tested
Oops, I didn't look at 3/7, just read its cset summary line and as it says: Subject: [PATCH v6 perf, bpf-next 3/7] perf, bpf: introduce PERF_RECORD_BPF_EVENT I didn't thought it was related, perhaps break it down into one that states that it is wiring up PERF_RECORD_KSYMBOL, and at that point we could just test it, getting the notifications for new kallsyms related to BPF? > PERF_RECORD_BPF_EVENT with dump_trace. As we separate RECORD_KSYMBOL from > RECORD_BPF_EVENT, user space won't use BPF_EVENT until annotation support. Right, so why not just introduce PERF_RECORD_KSYMBOL, make it be used by tooling, etc, then move on to PERF_RECORD_BPF_EVENT? - Arnaldo > Thanks, > Song > > >> Signed-off-by: Song Liu <songliubrav...@fb.com> > >> --- > >> include/linux/perf_event.h | 13 +++++ > >> include/uapi/linux/perf_event.h | 26 ++++++++- > >> kernel/events/core.c | 98 ++++++++++++++++++++++++++++++++- > >> 3 files changed, 135 insertions(+), 2 deletions(-) > >> > >> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h > >> index 1d5c551a5add..6b5f08db5ef3 100644 > >> --- a/include/linux/perf_event.h > >> +++ b/include/linux/perf_event.h > >> @@ -1113,6 +1113,13 @@ static inline void perf_event_task_sched_out(struct > >> task_struct *prev, > >> } > >> > >> extern void perf_event_mmap(struct vm_area_struct *vma); > >> + > >> +/* callback function to generate ksymbol name */ > >> +typedef int (perf_ksymbol_get_name_f)(char *name, int name_len, void > >> *data); > >> +extern void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, > >> + bool unregister, > >> + perf_ksymbol_get_name_f get_name, void *data); > >> + > >> extern struct perf_guest_info_callbacks *perf_guest_cbs; > >> extern int perf_register_guest_info_callbacks(struct > >> perf_guest_info_callbacks *callbacks); > >> extern int perf_unregister_guest_info_callbacks(struct > >> perf_guest_info_callbacks *callbacks); > >> @@ -1333,6 +1340,12 @@ static inline int > >> perf_unregister_guest_info_callbacks > >> (struct perf_guest_info_callbacks *callbacks) > >> { return 0; } > >> > >> static inline void perf_event_mmap(struct vm_area_struct *vma) > >> { } > >> + > >> +typedef int (perf_ksymbol_get_name_f)(char *name, int name_len, void > >> *data); > >> +static inline void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, > >> + bool unregister, > >> + perf_ksymbol_get_name_f get_name, > >> + void *data) { } > >> static inline void perf_event_exec(void) { } > >> static inline void perf_event_comm(struct task_struct *tsk, bool exec) > >> { } > >> static inline void perf_event_namespaces(struct task_struct *tsk) { } > >> diff --git a/include/uapi/linux/perf_event.h > >> b/include/uapi/linux/perf_event.h > >> index 9de8780ac8d9..68c4da0227c5 100644 > >> --- a/include/uapi/linux/perf_event.h > >> +++ b/include/uapi/linux/perf_event.h > >> @@ -372,7 +372,8 @@ struct perf_event_attr { > >> context_switch : 1, /* context switch data */ > >> write_backward : 1, /* Write ring buffer from > >> end to beginning */ > >> namespaces : 1, /* include namespaces data > >> */ > >> - __reserved_1 : 35; > >> + ksymbol : 1, /* include ksymbol events > >> */ > >> + __reserved_1 : 34; > >> > >> union { > >> __u32 wakeup_events; /* wakeup every n events */ > >> @@ -965,9 +966,32 @@ enum perf_event_type { > >> */ > >> PERF_RECORD_NAMESPACES = 16, > >> > >> + /* > >> + * Record ksymbol register/unregister events: > >> + * > >> + * struct { > >> + * struct perf_event_header header; > >> + * u64 addr; > >> + * u32 len; > >> + * u16 ksym_type; > >> + * u16 flags; > >> + * char name[]; > >> + * struct sample_id sample_id; > >> + * }; > >> + */ > >> + PERF_RECORD_KSYMBOL = 17, > >> + > >> PERF_RECORD_MAX, /* non-ABI */ > >> }; > >> > >> +enum perf_record_ksymbol_type { > >> + PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0, > >> + PERF_RECORD_KSYMBOL_TYPE_BPF = 1, > >> + PERF_RECORD_KSYMBOL_TYPE_MAX /* non-ABI */ > >> +}; > >> + > >> +#define PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER (1 << 0) > >> + > >> #define PERF_MAX_STACK_DEPTH 127 > >> #define PERF_MAX_CONTEXTS_PER_STACK 8 > >> > >> diff --git a/kernel/events/core.c b/kernel/events/core.c > >> index 3cd13a30f732..ef27f2776999 100644 > >> --- a/kernel/events/core.c > >> +++ b/kernel/events/core.c > >> @@ -385,6 +385,7 @@ static atomic_t nr_namespaces_events __read_mostly; > >> static atomic_t nr_task_events __read_mostly; > >> static atomic_t nr_freq_events __read_mostly; > >> static atomic_t nr_switch_events __read_mostly; > >> +static atomic_t nr_ksymbol_events __read_mostly; > >> > >> static LIST_HEAD(pmus); > >> static DEFINE_MUTEX(pmus_lock); > >> @@ -4235,7 +4236,7 @@ static bool is_sb_event(struct perf_event *event) > >> > >> if (attr->mmap || attr->mmap_data || attr->mmap2 || > >> attr->comm || attr->comm_exec || > >> - attr->task || > >> + attr->task || attr->ksymbol || > >> attr->context_switch) > >> return true; > >> return false; > >> @@ -4305,6 +4306,8 @@ static void unaccount_event(struct perf_event *event) > >> dec = true; > >> if (has_branch_stack(event)) > >> dec = true; > >> + if (event->attr.ksymbol) > >> + atomic_dec(&nr_ksymbol_events); > >> > >> if (dec) { > >> if (!atomic_add_unless(&perf_sched_count, -1, 1)) > >> @@ -7650,6 +7653,97 @@ static void perf_log_throttle(struct perf_event > >> *event, int enable) > >> perf_output_end(&handle); > >> } > >> > >> +/* > >> + * ksymbol register/unregister tracking > >> + */ > >> + > >> +struct perf_ksymbol_event { > >> + const char *name; > >> + int name_len; > >> + struct { > >> + struct perf_event_header header; > >> + u64 addr; > >> + u32 len; > >> + u16 ksym_type; > >> + u16 flags; > >> + } event_id; > >> +}; > >> + > >> +static int perf_event_ksymbol_match(struct perf_event *event) > >> +{ > >> + return event->attr.ksymbol; > >> +} > >> + > >> +static void perf_event_ksymbol_output(struct perf_event *event, void > >> *data) > >> +{ > >> + struct perf_ksymbol_event *ksymbol_event = data; > >> + struct perf_output_handle handle; > >> + struct perf_sample_data sample; > >> + int ret; > >> + > >> + if (!perf_event_ksymbol_match(event)) > >> + return; > >> + > >> + perf_event_header__init_id(&ksymbol_event->event_id.header, > >> + &sample, event); > >> + ret = perf_output_begin(&handle, event, > >> + ksymbol_event->event_id.header.size); > >> + if (ret) > >> + return; > >> + > >> + perf_output_put(&handle, ksymbol_event->event_id); > >> + __output_copy(&handle, ksymbol_event->name, ksymbol_event->name_len); > >> + perf_event__output_id_sample(event, &handle, &sample); > >> + > >> + perf_output_end(&handle); > >> +} > >> + > >> +void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, bool unregister, > >> + perf_ksymbol_get_name_f get_name, void *data) > >> +{ > >> + struct perf_ksymbol_event ksymbol_event; > >> + char name[KSYM_NAME_LEN]; > >> + u16 flags = 0; > >> + int name_len; > >> + > >> + if (!atomic_read(&nr_ksymbol_events)) > >> + return; > >> + > >> + if (ksym_type >= PERF_RECORD_KSYMBOL_TYPE_MAX || > >> + ksym_type == PERF_RECORD_KSYMBOL_TYPE_UNKNOWN) > >> + goto err; > >> + > >> + get_name(name, KSYM_NAME_LEN, data); > >> + name_len = strlen(name) + 1; > >> + while (!IS_ALIGNED(name_len, sizeof(u64))) > >> + name[name_len++] = '\0'; > >> + BUILD_BUG_ON(KSYM_NAME_LEN % sizeof(u64)); > >> + > >> + if (unregister) > >> + flags |= PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER; > >> + > >> + ksymbol_event = (struct perf_ksymbol_event){ > >> + .name = name, > >> + .name_len = name_len, > >> + .event_id = { > >> + .header = { > >> + .type = PERF_RECORD_KSYMBOL, > >> + .size = sizeof(ksymbol_event.event_id) + > >> + name_len, > >> + }, > >> + .addr = addr, > >> + .len = len, > >> + .ksym_type = ksym_type, > >> + .flags = flags, > >> + }, > >> + }; > >> + > >> + perf_iterate_sb(perf_event_ksymbol_output, &ksymbol_event, NULL); > >> + return; > >> +err: > >> + WARN_ONCE(1, "%s: Invalid KSYMBOL type 0x%x\n", __func__, ksym_type); > >> +} > >> + > >> void perf_event_itrace_started(struct perf_event *event) > >> { > >> event->attach_state |= PERF_ATTACH_ITRACE; > >> @@ -9900,6 +9994,8 @@ static void account_event(struct perf_event *event) > >> inc = true; > >> if (is_cgroup_event(event)) > >> inc = true; > >> + if (event->attr.ksymbol) > >> + atomic_inc(&nr_ksymbol_events); > >> > >> if (inc) { > >> /* > >> -- > >> 2.17.1 > > > > -- > > > > - Arnaldo -- - Arnaldo