aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorSong Liu <songliubraving@fb.com>2019-01-17 11:15:15 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2019-01-21 15:00:57 -0500
commit6ee52e2a3fe4ea35520720736e6791df1fb67106 (patch)
treebe662847ba4bee4b26c755a19b1f257bf59e0370 /kernel/events
parentd764ac6464915523e68e220b6aa4c3c2eb8e3f94 (diff)
perf, bpf: Introduce PERF_RECORD_BPF_EVENT
For better performance analysis of BPF programs, this patch introduces PERF_RECORD_BPF_EVENT, a new perf_event_type that exposes BPF program load/unload information to user space. Each BPF program may contain up to BPF_MAX_SUBPROGS (256) sub programs. The following example shows kernel symbols for a BPF program with 7 sub programs: ffffffffa0257cf9 t bpf_prog_b07ccb89267cf242_F ffffffffa02592e1 t bpf_prog_2dcecc18072623fc_F ffffffffa025b0e9 t bpf_prog_bb7a405ebaec5d5c_F ffffffffa025dd2c t bpf_prog_a7540d4a39ec1fc7_F ffffffffa025fcca t bpf_prog_05762d4ade0e3737_F ffffffffa026108f t bpf_prog_db4bd11e35df90d4_F ffffffffa0263f00 t bpf_prog_89d64e4abf0f0126_F ffffffffa0257cf9 t bpf_prog_ae31629322c4b018__dummy_tracepoi When a bpf program is loaded, PERF_RECORD_KSYMBOL is generated for each of these sub programs. Therefore, PERF_RECORD_BPF_EVENT is not needed for simple profiling. For annotation, user space need to listen to PERF_RECORD_BPF_EVENT and gather more information about these (sub) programs via sys_bpf. Signed-off-by: Song Liu <songliubraving@fb.com> Reviewed-by: Arnaldo Carvalho de Melo <acme@redhat.com> Acked-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Peter Zijlstra (Intel) <peterz@infradeaed.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: Peter Zijlstra <peterz@infradead.org> Cc: kernel-team@fb.com Cc: netdev@vger.kernel.org Link: http://lkml.kernel.org/r/20190117161521.1341602-4-songliubraving@fb.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'kernel/events')
-rw-r--r--kernel/events/core.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c
index e04ab5f325cf..236bb8ddb7bc 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -386,6 +386,7 @@ static atomic_t nr_task_events __read_mostly;
386static atomic_t nr_freq_events __read_mostly; 386static atomic_t nr_freq_events __read_mostly;
387static atomic_t nr_switch_events __read_mostly; 387static atomic_t nr_switch_events __read_mostly;
388static atomic_t nr_ksymbol_events __read_mostly; 388static atomic_t nr_ksymbol_events __read_mostly;
389static atomic_t nr_bpf_events __read_mostly;
389 390
390static LIST_HEAD(pmus); 391static LIST_HEAD(pmus);
391static DEFINE_MUTEX(pmus_lock); 392static DEFINE_MUTEX(pmus_lock);
@@ -4308,6 +4309,8 @@ static void unaccount_event(struct perf_event *event)
4308 dec = true; 4309 dec = true;
4309 if (event->attr.ksymbol) 4310 if (event->attr.ksymbol)
4310 atomic_dec(&nr_ksymbol_events); 4311 atomic_dec(&nr_ksymbol_events);
4312 if (event->attr.bpf_event)
4313 atomic_dec(&nr_bpf_events);
4311 4314
4312 if (dec) { 4315 if (dec) {
4313 if (!atomic_add_unless(&perf_sched_count, -1, 1)) 4316 if (!atomic_add_unless(&perf_sched_count, -1, 1))
@@ -7747,6 +7750,116 @@ err:
7747 WARN_ONCE(1, "%s: Invalid KSYMBOL type 0x%x\n", __func__, ksym_type); 7750 WARN_ONCE(1, "%s: Invalid KSYMBOL type 0x%x\n", __func__, ksym_type);
7748} 7751}
7749 7752
7753/*
7754 * bpf program load/unload tracking
7755 */
7756
7757struct perf_bpf_event {
7758 struct bpf_prog *prog;
7759 struct {
7760 struct perf_event_header header;
7761 u16 type;
7762 u16 flags;
7763 u32 id;
7764 u8 tag[BPF_TAG_SIZE];
7765 } event_id;
7766};
7767
7768static int perf_event_bpf_match(struct perf_event *event)
7769{
7770 return event->attr.bpf_event;
7771}
7772
7773static void perf_event_bpf_output(struct perf_event *event, void *data)
7774{
7775 struct perf_bpf_event *bpf_event = data;
7776 struct perf_output_handle handle;
7777 struct perf_sample_data sample;
7778 int ret;
7779
7780 if (!perf_event_bpf_match(event))
7781 return;
7782
7783 perf_event_header__init_id(&bpf_event->event_id.header,
7784 &sample, event);
7785 ret = perf_output_begin(&handle, event,
7786 bpf_event->event_id.header.size);
7787 if (ret)
7788 return;
7789
7790 perf_output_put(&handle, bpf_event->event_id);
7791 perf_event__output_id_sample(event, &handle, &sample);
7792
7793 perf_output_end(&handle);
7794}
7795
7796static void perf_event_bpf_emit_ksymbols(struct bpf_prog *prog,
7797 enum perf_bpf_event_type type)
7798{
7799 bool unregister = type == PERF_BPF_EVENT_PROG_UNLOAD;
7800 char sym[KSYM_NAME_LEN];
7801 int i;
7802
7803 if (prog->aux->func_cnt == 0) {
7804 bpf_get_prog_name(prog, sym);
7805 perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_BPF,
7806 (u64)(unsigned long)prog->bpf_func,
7807 prog->jited_len, unregister, sym);
7808 } else {
7809 for (i = 0; i < prog->aux->func_cnt; i++) {
7810 struct bpf_prog *subprog = prog->aux->func[i];
7811
7812 bpf_get_prog_name(subprog, sym);
7813 perf_event_ksymbol(
7814 PERF_RECORD_KSYMBOL_TYPE_BPF,
7815 (u64)(unsigned long)subprog->bpf_func,
7816 subprog->jited_len, unregister, sym);
7817 }
7818 }
7819}
7820
7821void perf_event_bpf_event(struct bpf_prog *prog,
7822 enum perf_bpf_event_type type,
7823 u16 flags)
7824{
7825 struct perf_bpf_event bpf_event;
7826
7827 if (type <= PERF_BPF_EVENT_UNKNOWN ||
7828 type >= PERF_BPF_EVENT_MAX)
7829 return;
7830
7831 switch (type) {
7832 case PERF_BPF_EVENT_PROG_LOAD:
7833 case PERF_BPF_EVENT_PROG_UNLOAD:
7834 if (atomic_read(&nr_ksymbol_events))
7835 perf_event_bpf_emit_ksymbols(prog, type);
7836 break;
7837 default:
7838 break;
7839 }
7840
7841 if (!atomic_read(&nr_bpf_events))
7842 return;
7843
7844 bpf_event = (struct perf_bpf_event){
7845 .prog = prog,
7846 .event_id = {
7847 .header = {
7848 .type = PERF_RECORD_BPF_EVENT,
7849 .size = sizeof(bpf_event.event_id),
7850 },
7851 .type = type,
7852 .flags = flags,
7853 .id = prog->aux->id,
7854 },
7855 };
7856
7857 BUILD_BUG_ON(BPF_TAG_SIZE % sizeof(u64));
7858
7859 memcpy(bpf_event.event_id.tag, prog->tag, BPF_TAG_SIZE);
7860 perf_iterate_sb(perf_event_bpf_output, &bpf_event, NULL);
7861}
7862
7750void perf_event_itrace_started(struct perf_event *event) 7863void perf_event_itrace_started(struct perf_event *event)
7751{ 7864{
7752 event->attach_state |= PERF_ATTACH_ITRACE; 7865 event->attach_state |= PERF_ATTACH_ITRACE;
@@ -10008,6 +10121,8 @@ static void account_event(struct perf_event *event)
10008 inc = true; 10121 inc = true;
10009 if (event->attr.ksymbol) 10122 if (event->attr.ksymbol)
10010 atomic_inc(&nr_ksymbol_events); 10123 atomic_inc(&nr_ksymbol_events);
10124 if (event->attr.bpf_event)
10125 atomic_inc(&nr_bpf_events);
10011 10126
10012 if (inc) { 10127 if (inc) {
10013 /* 10128 /*