diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-10-29 08:17:56 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-10-29 08:17:56 -0400 |
commit | 66a565c203bc31b76969711fbd92da11bee2f129 (patch) | |
tree | 1d5a60b14b9f808b3c0cece5761002ad32f0e274 /tools/perf | |
parent | 6fc774ef4ceca99c35dd3fb230dab618f78c8d6f (diff) | |
parent | 4edf30e39e6cff32390eaff6a1508969b3cd967b (diff) |
Merge tag 'perf-ebpf-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull basic perf/ebpf integration:
"Please see the changeset comments, but this is the very basic integration of
perf with libbpf that, given a .o file built for the 'bpf' target with clang,
will get it validated and loaded into the kernel via the sys_bpf syscall, which
can be seen using 'perf trace' to trace the whole thing looking just for the
bpf and perf_event_open syscalls:
# perf trace -e bpf,perf_event_open perf record -g --event /tmp/foo.o -a
362.779 ( 0.129 ms): perf/22408 bpf(cmd: 5, uattr: 0x7ffd4edb6db0, size: 48 ) = 3
384.192 ( 0.016 ms): perf/22408 perf_event_open(attr_uptr: 0x7ffd4edbace0, pid: -1, cpu: 3, group_fd: -1, flags: FD_CLOEXEC) = 5
384.247 ( 0.038 ms): perf/22408 perf_event_open(attr_uptr: 0x37aedd8, pid: -1, group_fd: -1, flags: FD_CLOEXEC) = 5
384.261 ( 0.007 ms): perf/22408 perf_event_open(attr_uptr: 0x37aedd8, pid: -1, group_fd: -1, flags: FD_CLOEXEC) = 5
387.680 ( 3.413 ms): perf/22408 perf_event_open(attr_uptr: 0x3222f08, pid: -1, group_fd: -1, flags: FD_CLOEXEC) = 5
387.688 ( 0.005 ms): perf/22408 perf_event_open(attr_uptr: 0x3222f08, pid: -1, cpu: 1, group_fd: -1, flags: FD_CLOEXEC) = 6
387.693 ( 0.004 ms): perf/22408 perf_event_open(attr_uptr: 0x3222f08, pid: -1, cpu: 2, group_fd: -1, flags: FD_CLOEXEC) = 7
387.698 ( 0.003 ms): perf/22408 perf_event_open(attr_uptr: 0x3222f08, pid: -1, cpu: 3, group_fd: -1, flags: FD_CLOEXEC) = 8
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.221 MB perf.data (2 samples) ]
# perf script
bash 18389 [002] 83446.412607: perf_bpf_probe:fork: (ffffffff8109be30)
29be31 _do_fork (/lib/modules/4.3.0-rc6+/build/vmlinux)
96d662 tracesys_phase2 (/lib/modules/4.3.0-rc6+/build/vmlinux)
bd56c __libc_fork (/usr/lib64/libc-2.17.so)
413b2 make_child (/usr/bin/bash)
bash 18389 [002] 83447.227255: perf_bpf_probe:fork: (ffffffff8109be30)
29be31 _do_fork (/lib/modules/4.3.0-rc6+/build/vmlinux)
96d662 tracesys_phase2 (/lib/modules/4.3.0-rc6+/build/vmlinux)
bd56c __libc_fork (/usr/lib64/libc-2.17.so)
413b2 make_child (/usr/bin/bash)
# perf evlist -v
perf_bpf_probe:fork: type: 2, size: 112, config: 0x6cf, { sample_period, sample_freq }: 1, sample_type: IP|TID|TIME|CALLCHAIN|CPU|PERIOD|RAW, disabled: 1, inherit: 1, mmap: 1, comm: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1
#
More work is about to be reviewed, tested and merged that will allow the whole
process of going from a .c file to an .o file via clang, etc to be done
automagically. (Wang Nan)"
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/MANIFEST | 3 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 21 | ||||
-rw-r--r-- | tools/perf/config/Makefile | 19 | ||||
-rw-r--r-- | tools/perf/perf.c | 2 | ||||
-rw-r--r-- | tools/perf/tests/make | 4 | ||||
-rw-r--r-- | tools/perf/util/Build | 1 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.c | 339 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.h | 84 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 118 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 8 | ||||
-rw-r--r-- | tools/perf/util/parse-events.l | 3 | ||||
-rw-r--r-- | tools/perf/util/parse-events.y | 18 |
12 files changed, 615 insertions, 5 deletions
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 9e6bdf5b2df6..39c38cb45b00 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -17,6 +17,7 @@ tools/build | |||
17 | tools/arch/x86/include/asm/atomic.h | 17 | tools/arch/x86/include/asm/atomic.h |
18 | tools/arch/x86/include/asm/rmwcc.h | 18 | tools/arch/x86/include/asm/rmwcc.h |
19 | tools/lib/traceevent | 19 | tools/lib/traceevent |
20 | tools/lib/bpf | ||
20 | tools/lib/api | 21 | tools/lib/api |
21 | tools/lib/bpf | 22 | tools/lib/bpf |
22 | tools/lib/hweight.c | 23 | tools/lib/hweight.c |
@@ -69,6 +70,8 @@ arch/*/lib/memset*.S | |||
69 | include/linux/poison.h | 70 | include/linux/poison.h |
70 | include/linux/hw_breakpoint.h | 71 | include/linux/hw_breakpoint.h |
71 | include/uapi/linux/perf_event.h | 72 | include/uapi/linux/perf_event.h |
73 | include/uapi/linux/bpf.h | ||
74 | include/uapi/linux/bpf_common.h | ||
72 | include/uapi/linux/const.h | 75 | include/uapi/linux/const.h |
73 | include/uapi/linux/swab.h | 76 | include/uapi/linux/swab.h |
74 | include/uapi/linux/hw_breakpoint.h | 77 | include/uapi/linux/hw_breakpoint.h |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 56517d304772..1e2e2d1d26b7 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -75,6 +75,8 @@ include config/utilities.mak | |||
75 | # Define NO_LZMA if you do not want to support compressed (xz) kernel modules | 75 | # Define NO_LZMA if you do not want to support compressed (xz) kernel modules |
76 | # | 76 | # |
77 | # Define NO_AUXTRACE if you do not want AUX area tracing support | 77 | # Define NO_AUXTRACE if you do not want AUX area tracing support |
78 | # | ||
79 | # Define NO_LIBBPF if you do not want BPF support | ||
78 | 80 | ||
79 | # As per kernel Makefile, avoid funny character set dependencies | 81 | # As per kernel Makefile, avoid funny character set dependencies |
80 | unexport LC_ALL | 82 | unexport LC_ALL |
@@ -145,6 +147,7 @@ AWK = awk | |||
145 | 147 | ||
146 | LIB_DIR = $(srctree)/tools/lib/api/ | 148 | LIB_DIR = $(srctree)/tools/lib/api/ |
147 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ | 149 | TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ |
150 | BPF_DIR = $(srctree)/tools/lib/bpf/ | ||
148 | 151 | ||
149 | # include config/Makefile by default and rule out | 152 | # include config/Makefile by default and rule out |
150 | # non-config cases | 153 | # non-config cases |
@@ -180,6 +183,7 @@ strip-libs = $(filter-out -l%,$(1)) | |||
180 | 183 | ||
181 | ifneq ($(OUTPUT),) | 184 | ifneq ($(OUTPUT),) |
182 | TE_PATH=$(OUTPUT) | 185 | TE_PATH=$(OUTPUT) |
186 | BPF_PATH=$(OUTPUT) | ||
183 | ifneq ($(subdir),) | 187 | ifneq ($(subdir),) |
184 | LIB_PATH=$(OUTPUT)/../lib/api/ | 188 | LIB_PATH=$(OUTPUT)/../lib/api/ |
185 | else | 189 | else |
@@ -188,6 +192,7 @@ endif | |||
188 | else | 192 | else |
189 | TE_PATH=$(TRACE_EVENT_DIR) | 193 | TE_PATH=$(TRACE_EVENT_DIR) |
190 | LIB_PATH=$(LIB_DIR) | 194 | LIB_PATH=$(LIB_DIR) |
195 | BPF_PATH=$(BPF_DIR) | ||
191 | endif | 196 | endif |
192 | 197 | ||
193 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a | 198 | LIBTRACEEVENT = $(TE_PATH)libtraceevent.a |
@@ -199,6 +204,8 @@ LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYN | |||
199 | LIBAPI = $(LIB_PATH)libapi.a | 204 | LIBAPI = $(LIB_PATH)libapi.a |
200 | export LIBAPI | 205 | export LIBAPI |
201 | 206 | ||
207 | LIBBPF = $(BPF_PATH)libbpf.a | ||
208 | |||
202 | # python extension build directories | 209 | # python extension build directories |
203 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ | 210 | PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ |
204 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ | 211 | PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ |
@@ -251,6 +258,9 @@ export PERL_PATH | |||
251 | LIB_FILE=$(OUTPUT)libperf.a | 258 | LIB_FILE=$(OUTPUT)libperf.a |
252 | 259 | ||
253 | PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) | 260 | PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) |
261 | ifndef NO_LIBBPF | ||
262 | PERFLIBS += $(LIBBPF) | ||
263 | endif | ||
254 | 264 | ||
255 | # We choose to avoid "if .. else if .. else .. endif endif" | 265 | # We choose to avoid "if .. else if .. else .. endif endif" |
256 | # because maintaining the nesting to match is a pain. If | 266 | # because maintaining the nesting to match is a pain. If |
@@ -420,6 +430,13 @@ $(LIBAPI)-clean: | |||
420 | $(call QUIET_CLEAN, libapi) | 430 | $(call QUIET_CLEAN, libapi) |
421 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null | 431 | $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null |
422 | 432 | ||
433 | $(LIBBPF): FORCE | ||
434 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a | ||
435 | |||
436 | $(LIBBPF)-clean: | ||
437 | $(call QUIET_CLEAN, libbpf) | ||
438 | $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null | ||
439 | |||
423 | help: | 440 | help: |
424 | @echo 'Perf make targets:' | 441 | @echo 'Perf make targets:' |
425 | @echo ' doc - make *all* documentation (see below)' | 442 | @echo ' doc - make *all* documentation (see below)' |
@@ -459,7 +476,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html | |||
459 | $(DOC_TARGETS): | 476 | $(DOC_TARGETS): |
460 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) | 477 | $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) |
461 | 478 | ||
462 | TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include | 479 | TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include ../lib/bpf |
463 | TAG_FILES= ../../include/uapi/linux/perf_event.h | 480 | TAG_FILES= ../../include/uapi/linux/perf_event.h |
464 | 481 | ||
465 | TAGS: | 482 | TAGS: |
@@ -567,7 +584,7 @@ config-clean: | |||
567 | $(call QUIET_CLEAN, config) | 584 | $(call QUIET_CLEAN, config) |
568 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null | 585 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null |
569 | 586 | ||
570 | clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean | 587 | clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean config-clean |
571 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) | 588 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) |
572 | $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | 589 | $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete |
573 | $(Q)$(RM) $(OUTPUT).config-detected | 590 | $(Q)$(RM) $(OUTPUT).config-detected |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index ab09adaabc9c..de89ec574361 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -106,6 +106,7 @@ ifdef LIBBABELTRACE | |||
106 | FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf | 106 | FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf |
107 | endif | 107 | endif |
108 | 108 | ||
109 | FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi | ||
109 | # include ARCH specific config | 110 | # include ARCH specific config |
110 | -include $(src-perf)/arch/$(ARCH)/Makefile | 111 | -include $(src-perf)/arch/$(ARCH)/Makefile |
111 | 112 | ||
@@ -237,6 +238,7 @@ ifdef NO_LIBELF | |||
237 | NO_DEMANGLE := 1 | 238 | NO_DEMANGLE := 1 |
238 | NO_LIBUNWIND := 1 | 239 | NO_LIBUNWIND := 1 |
239 | NO_LIBDW_DWARF_UNWIND := 1 | 240 | NO_LIBDW_DWARF_UNWIND := 1 |
241 | NO_LIBBPF := 1 | ||
240 | else | 242 | else |
241 | ifeq ($(feature-libelf), 0) | 243 | ifeq ($(feature-libelf), 0) |
242 | ifeq ($(feature-glibc), 1) | 244 | ifeq ($(feature-glibc), 1) |
@@ -246,13 +248,14 @@ else | |||
246 | LIBC_SUPPORT := 1 | 248 | LIBC_SUPPORT := 1 |
247 | endif | 249 | endif |
248 | ifeq ($(LIBC_SUPPORT),1) | 250 | ifeq ($(LIBC_SUPPORT),1) |
249 | msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev); | 251 | msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install elfutils-libelf-devel/libelf-dev); |
250 | 252 | ||
251 | NO_LIBELF := 1 | 253 | NO_LIBELF := 1 |
252 | NO_DWARF := 1 | 254 | NO_DWARF := 1 |
253 | NO_DEMANGLE := 1 | 255 | NO_DEMANGLE := 1 |
254 | NO_LIBUNWIND := 1 | 256 | NO_LIBUNWIND := 1 |
255 | NO_LIBDW_DWARF_UNWIND := 1 | 257 | NO_LIBDW_DWARF_UNWIND := 1 |
258 | NO_LIBBPF := 1 | ||
256 | else | 259 | else |
257 | ifneq ($(filter s% -static%,$(LDFLAGS),),) | 260 | ifneq ($(filter s% -static%,$(LDFLAGS),),) |
258 | msg := $(error No static glibc found, please install glibc-static); | 261 | msg := $(error No static glibc found, please install glibc-static); |
@@ -309,6 +312,13 @@ ifndef NO_LIBELF | |||
309 | $(call detected,CONFIG_DWARF) | 312 | $(call detected,CONFIG_DWARF) |
310 | endif # PERF_HAVE_DWARF_REGS | 313 | endif # PERF_HAVE_DWARF_REGS |
311 | endif # NO_DWARF | 314 | endif # NO_DWARF |
315 | |||
316 | ifndef NO_LIBBPF | ||
317 | ifeq ($(feature-bpf), 1) | ||
318 | CFLAGS += -DHAVE_LIBBPF_SUPPORT | ||
319 | $(call detected,CONFIG_LIBBPF) | ||
320 | endif | ||
321 | endif # NO_LIBBPF | ||
312 | endif # NO_LIBELF | 322 | endif # NO_LIBELF |
313 | 323 | ||
314 | ifeq ($(ARCH),powerpc) | 324 | ifeq ($(ARCH),powerpc) |
@@ -324,6 +334,13 @@ ifndef NO_LIBUNWIND | |||
324 | endif | 334 | endif |
325 | endif | 335 | endif |
326 | 336 | ||
337 | ifndef NO_LIBBPF | ||
338 | ifneq ($(feature-bpf), 1) | ||
339 | msg := $(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.) | ||
340 | NO_LIBBPF := 1 | ||
341 | endif | ||
342 | endif | ||
343 | |||
327 | dwarf-post-unwind := 1 | 344 | dwarf-post-unwind := 1 |
328 | dwarf-post-unwind-text := BUG | 345 | dwarf-post-unwind-text := BUG |
329 | 346 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 543713422d14..3d4c7c09adea 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "util/run-command.h" | 15 | #include "util/run-command.h" |
16 | #include "util/parse-events.h" | 16 | #include "util/parse-events.h" |
17 | #include "util/parse-options.h" | 17 | #include "util/parse-options.h" |
18 | #include "util/bpf-loader.h" | ||
18 | #include "util/debug.h" | 19 | #include "util/debug.h" |
19 | #include <api/fs/tracing_path.h> | 20 | #include <api/fs/tracing_path.h> |
20 | #include <pthread.h> | 21 | #include <pthread.h> |
@@ -385,6 +386,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
385 | status = p->fn(argc, argv, prefix); | 386 | status = p->fn(argc, argv, prefix); |
386 | exit_browser(status); | 387 | exit_browser(status); |
387 | perf_env__exit(&perf_env); | 388 | perf_env__exit(&perf_env); |
389 | bpf__clear(); | ||
388 | 390 | ||
389 | if (status) | 391 | if (status) |
390 | return status & 0xff; | 392 | return status & 0xff; |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index ba31c4bd441d..2cbd0c6901e3 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -44,6 +44,7 @@ make_no_libnuma := NO_LIBNUMA=1 | |||
44 | make_no_libaudit := NO_LIBAUDIT=1 | 44 | make_no_libaudit := NO_LIBAUDIT=1 |
45 | make_no_libbionic := NO_LIBBIONIC=1 | 45 | make_no_libbionic := NO_LIBBIONIC=1 |
46 | make_no_auxtrace := NO_AUXTRACE=1 | 46 | make_no_auxtrace := NO_AUXTRACE=1 |
47 | make_no_libbpf := NO_LIBBPF=1 | ||
47 | make_tags := tags | 48 | make_tags := tags |
48 | make_cscope := cscope | 49 | make_cscope := cscope |
49 | make_help := help | 50 | make_help := help |
@@ -66,7 +67,7 @@ make_static := LDFLAGS=-static | |||
66 | make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 | 67 | make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 |
67 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 | 68 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 |
68 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 | 69 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 |
69 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 | 70 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 |
70 | 71 | ||
71 | # $(run) contains all available tests | 72 | # $(run) contains all available tests |
72 | run := make_pure | 73 | run := make_pure |
@@ -94,6 +95,7 @@ run += make_no_libnuma | |||
94 | run += make_no_libaudit | 95 | run += make_no_libaudit |
95 | run += make_no_libbionic | 96 | run += make_no_libbionic |
96 | run += make_no_auxtrace | 97 | run += make_no_auxtrace |
98 | run += make_no_libbpf | ||
97 | run += make_help | 99 | run += make_help |
98 | run += make_doc | 100 | run += make_doc |
99 | run += make_perf_o | 101 | run += make_perf_o |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 9217119c4108..591b3fe3ed49 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-bts.o | |||
87 | libperf-y += parse-branch-options.o | 87 | libperf-y += parse-branch-options.o |
88 | libperf-y += parse-regs-options.o | 88 | libperf-y += parse-regs-options.o |
89 | 89 | ||
90 | libperf-$(CONFIG_LIBBPF) += bpf-loader.o | ||
90 | libperf-$(CONFIG_LIBELF) += symbol-elf.o | 91 | libperf-$(CONFIG_LIBELF) += symbol-elf.o |
91 | libperf-$(CONFIG_LIBELF) += probe-file.o | 92 | libperf-$(CONFIG_LIBELF) += probe-file.o |
92 | libperf-$(CONFIG_LIBELF) += probe-event.o | 93 | libperf-$(CONFIG_LIBELF) += probe-event.o |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c new file mode 100644 index 000000000000..aa784a498c48 --- /dev/null +++ b/tools/perf/util/bpf-loader.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * bpf-loader.c | ||
3 | * | ||
4 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | ||
5 | * Copyright (C) 2015 Huawei Inc. | ||
6 | */ | ||
7 | |||
8 | #include <bpf/libbpf.h> | ||
9 | #include <linux/err.h> | ||
10 | #include "perf.h" | ||
11 | #include "debug.h" | ||
12 | #include "bpf-loader.h" | ||
13 | #include "probe-event.h" | ||
14 | #include "probe-finder.h" // for MAX_PROBES | ||
15 | |||
16 | #define DEFINE_PRINT_FN(name, level) \ | ||
17 | static int libbpf_##name(const char *fmt, ...) \ | ||
18 | { \ | ||
19 | va_list args; \ | ||
20 | int ret; \ | ||
21 | \ | ||
22 | va_start(args, fmt); \ | ||
23 | ret = veprintf(level, verbose, pr_fmt(fmt), args);\ | ||
24 | va_end(args); \ | ||
25 | return ret; \ | ||
26 | } | ||
27 | |||
28 | DEFINE_PRINT_FN(warning, 0) | ||
29 | DEFINE_PRINT_FN(info, 0) | ||
30 | DEFINE_PRINT_FN(debug, 1) | ||
31 | |||
32 | struct bpf_prog_priv { | ||
33 | struct perf_probe_event pev; | ||
34 | }; | ||
35 | |||
36 | struct bpf_object *bpf__prepare_load(const char *filename) | ||
37 | { | ||
38 | struct bpf_object *obj; | ||
39 | static bool libbpf_initialized; | ||
40 | |||
41 | if (!libbpf_initialized) { | ||
42 | libbpf_set_print(libbpf_warning, | ||
43 | libbpf_info, | ||
44 | libbpf_debug); | ||
45 | libbpf_initialized = true; | ||
46 | } | ||
47 | |||
48 | obj = bpf_object__open(filename); | ||
49 | if (!obj) { | ||
50 | pr_debug("bpf: failed to load %s\n", filename); | ||
51 | return ERR_PTR(-EINVAL); | ||
52 | } | ||
53 | |||
54 | return obj; | ||
55 | } | ||
56 | |||
57 | void bpf__clear(void) | ||
58 | { | ||
59 | struct bpf_object *obj, *tmp; | ||
60 | |||
61 | bpf_object__for_each_safe(obj, tmp) { | ||
62 | bpf__unprobe(obj); | ||
63 | bpf_object__close(obj); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | static void | ||
68 | bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, | ||
69 | void *_priv) | ||
70 | { | ||
71 | struct bpf_prog_priv *priv = _priv; | ||
72 | |||
73 | cleanup_perf_probe_events(&priv->pev, 1); | ||
74 | free(priv); | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | config_bpf_program(struct bpf_program *prog) | ||
79 | { | ||
80 | struct perf_probe_event *pev = NULL; | ||
81 | struct bpf_prog_priv *priv = NULL; | ||
82 | const char *config_str; | ||
83 | int err; | ||
84 | |||
85 | config_str = bpf_program__title(prog, false); | ||
86 | if (!config_str) { | ||
87 | pr_debug("bpf: unable to get title for program\n"); | ||
88 | return -EINVAL; | ||
89 | } | ||
90 | |||
91 | priv = calloc(sizeof(*priv), 1); | ||
92 | if (!priv) { | ||
93 | pr_debug("bpf: failed to alloc priv\n"); | ||
94 | return -ENOMEM; | ||
95 | } | ||
96 | pev = &priv->pev; | ||
97 | |||
98 | pr_debug("bpf: config program '%s'\n", config_str); | ||
99 | err = parse_perf_probe_command(config_str, pev); | ||
100 | if (err < 0) { | ||
101 | pr_debug("bpf: '%s' is not a valid config string\n", | ||
102 | config_str); | ||
103 | err = -EINVAL; | ||
104 | goto errout; | ||
105 | } | ||
106 | |||
107 | if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { | ||
108 | pr_debug("bpf: '%s': group for event is set and not '%s'.\n", | ||
109 | config_str, PERF_BPF_PROBE_GROUP); | ||
110 | err = -EINVAL; | ||
111 | goto errout; | ||
112 | } else if (!pev->group) | ||
113 | pev->group = strdup(PERF_BPF_PROBE_GROUP); | ||
114 | |||
115 | if (!pev->group) { | ||
116 | pr_debug("bpf: strdup failed\n"); | ||
117 | err = -ENOMEM; | ||
118 | goto errout; | ||
119 | } | ||
120 | |||
121 | if (!pev->event) { | ||
122 | pr_debug("bpf: '%s': event name is missing\n", | ||
123 | config_str); | ||
124 | err = -EINVAL; | ||
125 | goto errout; | ||
126 | } | ||
127 | pr_debug("bpf: config '%s' is ok\n", config_str); | ||
128 | |||
129 | err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear); | ||
130 | if (err) { | ||
131 | pr_debug("Failed to set priv for program '%s'\n", config_str); | ||
132 | goto errout; | ||
133 | } | ||
134 | |||
135 | return 0; | ||
136 | |||
137 | errout: | ||
138 | if (pev) | ||
139 | clear_perf_probe_event(pev); | ||
140 | free(priv); | ||
141 | return err; | ||
142 | } | ||
143 | |||
144 | static int bpf__prepare_probe(void) | ||
145 | { | ||
146 | static int err = 0; | ||
147 | static bool initialized = false; | ||
148 | |||
149 | /* | ||
150 | * Make err static, so if init failed the first, bpf__prepare_probe() | ||
151 | * fails each time without calling init_probe_symbol_maps multiple | ||
152 | * times. | ||
153 | */ | ||
154 | if (initialized) | ||
155 | return err; | ||
156 | |||
157 | initialized = true; | ||
158 | err = init_probe_symbol_maps(false); | ||
159 | if (err < 0) | ||
160 | pr_debug("Failed to init_probe_symbol_maps\n"); | ||
161 | probe_conf.max_probes = MAX_PROBES; | ||
162 | return err; | ||
163 | } | ||
164 | |||
165 | int bpf__probe(struct bpf_object *obj) | ||
166 | { | ||
167 | int err = 0; | ||
168 | struct bpf_program *prog; | ||
169 | struct bpf_prog_priv *priv; | ||
170 | struct perf_probe_event *pev; | ||
171 | |||
172 | err = bpf__prepare_probe(); | ||
173 | if (err) { | ||
174 | pr_debug("bpf__prepare_probe failed\n"); | ||
175 | return err; | ||
176 | } | ||
177 | |||
178 | bpf_object__for_each_program(prog, obj) { | ||
179 | err = config_bpf_program(prog); | ||
180 | if (err) | ||
181 | goto out; | ||
182 | |||
183 | err = bpf_program__get_private(prog, (void **)&priv); | ||
184 | if (err || !priv) | ||
185 | goto out; | ||
186 | pev = &priv->pev; | ||
187 | |||
188 | err = convert_perf_probe_events(pev, 1); | ||
189 | if (err < 0) { | ||
190 | pr_debug("bpf_probe: failed to convert perf probe events"); | ||
191 | goto out; | ||
192 | } | ||
193 | |||
194 | err = apply_perf_probe_events(pev, 1); | ||
195 | if (err < 0) { | ||
196 | pr_debug("bpf_probe: failed to apply perf probe events"); | ||
197 | goto out; | ||
198 | } | ||
199 | } | ||
200 | out: | ||
201 | return err < 0 ? err : 0; | ||
202 | } | ||
203 | |||
204 | #define EVENTS_WRITE_BUFSIZE 4096 | ||
205 | int bpf__unprobe(struct bpf_object *obj) | ||
206 | { | ||
207 | int err, ret = 0; | ||
208 | struct bpf_program *prog; | ||
209 | struct bpf_prog_priv *priv; | ||
210 | |||
211 | bpf_object__for_each_program(prog, obj) { | ||
212 | int i; | ||
213 | |||
214 | err = bpf_program__get_private(prog, (void **)&priv); | ||
215 | if (err || !priv) | ||
216 | continue; | ||
217 | |||
218 | for (i = 0; i < priv->pev.ntevs; i++) { | ||
219 | struct probe_trace_event *tev = &priv->pev.tevs[i]; | ||
220 | char name_buf[EVENTS_WRITE_BUFSIZE]; | ||
221 | struct strfilter *delfilter; | ||
222 | |||
223 | snprintf(name_buf, EVENTS_WRITE_BUFSIZE, | ||
224 | "%s:%s", tev->group, tev->event); | ||
225 | name_buf[EVENTS_WRITE_BUFSIZE - 1] = '\0'; | ||
226 | |||
227 | delfilter = strfilter__new(name_buf, NULL); | ||
228 | if (!delfilter) { | ||
229 | pr_debug("Failed to create filter for unprobing\n"); | ||
230 | ret = -ENOMEM; | ||
231 | continue; | ||
232 | } | ||
233 | |||
234 | err = del_perf_probe_events(delfilter); | ||
235 | strfilter__delete(delfilter); | ||
236 | if (err) { | ||
237 | pr_debug("Failed to delete %s\n", name_buf); | ||
238 | ret = err; | ||
239 | continue; | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | int bpf__load(struct bpf_object *obj) | ||
247 | { | ||
248 | int err; | ||
249 | |||
250 | err = bpf_object__load(obj); | ||
251 | if (err) { | ||
252 | pr_debug("bpf: load objects failed\n"); | ||
253 | return err; | ||
254 | } | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | int bpf__foreach_tev(struct bpf_object *obj, | ||
259 | bpf_prog_iter_callback_t func, | ||
260 | void *arg) | ||
261 | { | ||
262 | struct bpf_program *prog; | ||
263 | int err; | ||
264 | |||
265 | bpf_object__for_each_program(prog, obj) { | ||
266 | struct probe_trace_event *tev; | ||
267 | struct perf_probe_event *pev; | ||
268 | struct bpf_prog_priv *priv; | ||
269 | int i, fd; | ||
270 | |||
271 | err = bpf_program__get_private(prog, | ||
272 | (void **)&priv); | ||
273 | if (err || !priv) { | ||
274 | pr_debug("bpf: failed to get private field\n"); | ||
275 | return -EINVAL; | ||
276 | } | ||
277 | |||
278 | pev = &priv->pev; | ||
279 | for (i = 0; i < pev->ntevs; i++) { | ||
280 | tev = &pev->tevs[i]; | ||
281 | |||
282 | fd = bpf_program__fd(prog); | ||
283 | if (fd < 0) { | ||
284 | pr_debug("bpf: failed to get file descriptor\n"); | ||
285 | return fd; | ||
286 | } | ||
287 | |||
288 | err = (*func)(tev, fd, arg); | ||
289 | if (err) { | ||
290 | pr_debug("bpf: call back failed, stop iterate\n"); | ||
291 | return err; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | #define bpf__strerror_head(err, buf, size) \ | ||
299 | char sbuf[STRERR_BUFSIZE], *emsg;\ | ||
300 | if (!size)\ | ||
301 | return 0;\ | ||
302 | if (err < 0)\ | ||
303 | err = -err;\ | ||
304 | emsg = strerror_r(err, sbuf, sizeof(sbuf));\ | ||
305 | switch (err) {\ | ||
306 | default:\ | ||
307 | scnprintf(buf, size, "%s", emsg);\ | ||
308 | break; | ||
309 | |||
310 | #define bpf__strerror_entry(val, fmt...)\ | ||
311 | case val: {\ | ||
312 | scnprintf(buf, size, fmt);\ | ||
313 | break;\ | ||
314 | } | ||
315 | |||
316 | #define bpf__strerror_end(buf, size)\ | ||
317 | }\ | ||
318 | buf[size - 1] = '\0'; | ||
319 | |||
320 | int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, | ||
321 | int err, char *buf, size_t size) | ||
322 | { | ||
323 | bpf__strerror_head(err, buf, size); | ||
324 | bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); | ||
325 | bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n"); | ||
326 | bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n"); | ||
327 | bpf__strerror_end(buf, size); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | int bpf__strerror_load(struct bpf_object *obj __maybe_unused, | ||
332 | int err, char *buf, size_t size) | ||
333 | { | ||
334 | bpf__strerror_head(err, buf, size); | ||
335 | bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?", | ||
336 | emsg) | ||
337 | bpf__strerror_end(buf, size); | ||
338 | return 0; | ||
339 | } | ||
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h new file mode 100644 index 000000000000..a8f25ee06fc5 --- /dev/null +++ b/tools/perf/util/bpf-loader.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com> | ||
3 | * Copyright (C) 2015, Huawei Inc. | ||
4 | */ | ||
5 | #ifndef __BPF_LOADER_H | ||
6 | #define __BPF_LOADER_H | ||
7 | |||
8 | #include <linux/compiler.h> | ||
9 | #include <linux/err.h> | ||
10 | #include <string.h> | ||
11 | #include "probe-event.h" | ||
12 | #include "debug.h" | ||
13 | |||
14 | struct bpf_object; | ||
15 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" | ||
16 | |||
17 | typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, | ||
18 | int fd, void *arg); | ||
19 | |||
20 | #ifdef HAVE_LIBBPF_SUPPORT | ||
21 | struct bpf_object *bpf__prepare_load(const char *filename); | ||
22 | |||
23 | void bpf__clear(void); | ||
24 | |||
25 | int bpf__probe(struct bpf_object *obj); | ||
26 | int bpf__unprobe(struct bpf_object *obj); | ||
27 | int bpf__strerror_probe(struct bpf_object *obj, int err, | ||
28 | char *buf, size_t size); | ||
29 | |||
30 | int bpf__load(struct bpf_object *obj); | ||
31 | int bpf__strerror_load(struct bpf_object *obj, int err, | ||
32 | char *buf, size_t size); | ||
33 | int bpf__foreach_tev(struct bpf_object *obj, | ||
34 | bpf_prog_iter_callback_t func, void *arg); | ||
35 | #else | ||
36 | static inline struct bpf_object * | ||
37 | bpf__prepare_load(const char *filename __maybe_unused) | ||
38 | { | ||
39 | pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); | ||
40 | return ERR_PTR(-ENOTSUP); | ||
41 | } | ||
42 | |||
43 | static inline void bpf__clear(void) { } | ||
44 | |||
45 | static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} | ||
46 | static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;} | ||
47 | static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; } | ||
48 | |||
49 | static inline int | ||
50 | bpf__foreach_tev(struct bpf_object *obj __maybe_unused, | ||
51 | bpf_prog_iter_callback_t func __maybe_unused, | ||
52 | void *arg __maybe_unused) | ||
53 | { | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static inline int | ||
58 | __bpf_strerror(char *buf, size_t size) | ||
59 | { | ||
60 | if (!size) | ||
61 | return 0; | ||
62 | strncpy(buf, | ||
63 | "ERROR: eBPF object loading is disabled during compiling.\n", | ||
64 | size); | ||
65 | buf[size - 1] = '\0'; | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline int | ||
70 | bpf__strerror_probe(struct bpf_object *obj __maybe_unused, | ||
71 | int err __maybe_unused, | ||
72 | char *buf, size_t size) | ||
73 | { | ||
74 | return __bpf_strerror(buf, size); | ||
75 | } | ||
76 | |||
77 | static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused, | ||
78 | int err __maybe_unused, | ||
79 | char *buf, size_t size) | ||
80 | { | ||
81 | return __bpf_strerror(buf, size); | ||
82 | } | ||
83 | #endif | ||
84 | #endif | ||
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 72abcf254ccb..d97b03710331 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "symbol.h" | 11 | #include "symbol.h" |
12 | #include "cache.h" | 12 | #include "cache.h" |
13 | #include "header.h" | 13 | #include "header.h" |
14 | #include "bpf-loader.h" | ||
14 | #include "debug.h" | 15 | #include "debug.h" |
15 | #include <api/fs/tracing_path.h> | 16 | #include <api/fs/tracing_path.h> |
16 | #include "parse-events-bison.h" | 17 | #include "parse-events-bison.h" |
@@ -529,6 +530,123 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, | |||
529 | return ret; | 530 | return ret; |
530 | } | 531 | } |
531 | 532 | ||
533 | struct __add_bpf_event_param { | ||
534 | struct parse_events_evlist *data; | ||
535 | struct list_head *list; | ||
536 | }; | ||
537 | |||
538 | static int add_bpf_event(struct probe_trace_event *tev, int fd, | ||
539 | void *_param) | ||
540 | { | ||
541 | LIST_HEAD(new_evsels); | ||
542 | struct __add_bpf_event_param *param = _param; | ||
543 | struct parse_events_evlist *evlist = param->data; | ||
544 | struct list_head *list = param->list; | ||
545 | int err; | ||
546 | |||
547 | pr_debug("add bpf event %s:%s and attach bpf program %d\n", | ||
548 | tev->group, tev->event, fd); | ||
549 | |||
550 | err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, | ||
551 | tev->event, evlist->error, NULL); | ||
552 | if (err) { | ||
553 | struct perf_evsel *evsel, *tmp; | ||
554 | |||
555 | pr_debug("Failed to add BPF event %s:%s\n", | ||
556 | tev->group, tev->event); | ||
557 | list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { | ||
558 | list_del(&evsel->node); | ||
559 | perf_evsel__delete(evsel); | ||
560 | } | ||
561 | return err; | ||
562 | } | ||
563 | pr_debug("adding %s:%s\n", tev->group, tev->event); | ||
564 | |||
565 | list_splice(&new_evsels, list); | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | int parse_events_load_bpf_obj(struct parse_events_evlist *data, | ||
570 | struct list_head *list, | ||
571 | struct bpf_object *obj) | ||
572 | { | ||
573 | int err; | ||
574 | char errbuf[BUFSIZ]; | ||
575 | struct __add_bpf_event_param param = {data, list}; | ||
576 | static bool registered_unprobe_atexit = false; | ||
577 | |||
578 | if (IS_ERR(obj) || !obj) { | ||
579 | snprintf(errbuf, sizeof(errbuf), | ||
580 | "Internal error: load bpf obj with NULL"); | ||
581 | err = -EINVAL; | ||
582 | goto errout; | ||
583 | } | ||
584 | |||
585 | /* | ||
586 | * Register atexit handler before calling bpf__probe() so | ||
587 | * bpf__probe() don't need to unprobe probe points its already | ||
588 | * created when failure. | ||
589 | */ | ||
590 | if (!registered_unprobe_atexit) { | ||
591 | atexit(bpf__clear); | ||
592 | registered_unprobe_atexit = true; | ||
593 | } | ||
594 | |||
595 | err = bpf__probe(obj); | ||
596 | if (err) { | ||
597 | bpf__strerror_probe(obj, err, errbuf, sizeof(errbuf)); | ||
598 | goto errout; | ||
599 | } | ||
600 | |||
601 | err = bpf__load(obj); | ||
602 | if (err) { | ||
603 | bpf__strerror_load(obj, err, errbuf, sizeof(errbuf)); | ||
604 | goto errout; | ||
605 | } | ||
606 | |||
607 | err = bpf__foreach_tev(obj, add_bpf_event, ¶m); | ||
608 | if (err) { | ||
609 | snprintf(errbuf, sizeof(errbuf), | ||
610 | "Attach events in BPF object failed"); | ||
611 | goto errout; | ||
612 | } | ||
613 | |||
614 | return 0; | ||
615 | errout: | ||
616 | data->error->help = strdup("(add -v to see detail)"); | ||
617 | data->error->str = strdup(errbuf); | ||
618 | return err; | ||
619 | } | ||
620 | |||
621 | int parse_events_load_bpf(struct parse_events_evlist *data, | ||
622 | struct list_head *list, | ||
623 | char *bpf_file_name) | ||
624 | { | ||
625 | struct bpf_object *obj; | ||
626 | |||
627 | obj = bpf__prepare_load(bpf_file_name); | ||
628 | if (IS_ERR(obj) || !obj) { | ||
629 | char errbuf[BUFSIZ]; | ||
630 | int err; | ||
631 | |||
632 | err = obj ? PTR_ERR(obj) : -EINVAL; | ||
633 | |||
634 | if (err == -ENOTSUP) | ||
635 | snprintf(errbuf, sizeof(errbuf), | ||
636 | "BPF support is not compiled"); | ||
637 | else | ||
638 | snprintf(errbuf, sizeof(errbuf), | ||
639 | "BPF object file '%s' is invalid", | ||
640 | bpf_file_name); | ||
641 | |||
642 | data->error->help = strdup("(add -v to see detail)"); | ||
643 | data->error->str = strdup(errbuf); | ||
644 | return err; | ||
645 | } | ||
646 | |||
647 | return parse_events_load_bpf_obj(data, list, obj); | ||
648 | } | ||
649 | |||
532 | static int | 650 | static int |
533 | parse_breakpoint_type(const char *type, struct perf_event_attr *attr) | 651 | parse_breakpoint_type(const char *type, struct perf_event_attr *attr) |
534 | { | 652 | { |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 13c9063513eb..765018a17448 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -123,6 +123,14 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, | |||
123 | char *sys, char *event, | 123 | char *sys, char *event, |
124 | struct parse_events_error *error, | 124 | struct parse_events_error *error, |
125 | struct list_head *head_config); | 125 | struct list_head *head_config); |
126 | int parse_events_load_bpf(struct parse_events_evlist *data, | ||
127 | struct list_head *list, | ||
128 | char *bpf_file_name); | ||
129 | /* Provide this function for perf test */ | ||
130 | struct bpf_object; | ||
131 | int parse_events_load_bpf_obj(struct parse_events_evlist *data, | ||
132 | struct list_head *list, | ||
133 | struct bpf_object *obj); | ||
126 | int parse_events_add_numeric(struct parse_events_evlist *data, | 134 | int parse_events_add_numeric(struct parse_events_evlist *data, |
127 | struct list_head *list, | 135 | struct list_head *list, |
128 | u32 type, u64 config, | 136 | u32 type, u64 config, |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 8d0de5b2991d..cf330ebf812c 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -115,6 +115,7 @@ do { \ | |||
115 | group [^,{}/]*[{][^}]*[}][^,{}/]* | 115 | group [^,{}/]*[{][^}]*[}][^,{}/]* |
116 | event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* | 116 | event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* |
117 | event [^,{}/]+ | 117 | event [^,{}/]+ |
118 | bpf_object .*\.(o|bpf) | ||
118 | 119 | ||
119 | num_dec [0-9]+ | 120 | num_dec [0-9]+ |
120 | num_hex 0x[a-fA-F0-9]+ | 121 | num_hex 0x[a-fA-F0-9]+ |
@@ -159,6 +160,7 @@ modifier_bp [rwx]{1,3} | |||
159 | } | 160 | } |
160 | 161 | ||
161 | {event_pmu} | | 162 | {event_pmu} | |
163 | {bpf_object} | | ||
162 | {event} { | 164 | {event} { |
163 | BEGIN(INITIAL); | 165 | BEGIN(INITIAL); |
164 | REWIND(1); | 166 | REWIND(1); |
@@ -266,6 +268,7 @@ r{num_raw_hex} { return raw(yyscanner); } | |||
266 | {num_hex} { return value(yyscanner, 16); } | 268 | {num_hex} { return value(yyscanner, 16); } |
267 | 269 | ||
268 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } | 270 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } |
271 | {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } | ||
269 | {name} { return pmu_str_check(yyscanner); } | 272 | {name} { return pmu_str_check(yyscanner); } |
270 | "/" { BEGIN(config); return '/'; } | 273 | "/" { BEGIN(config); return '/'; } |
271 | - { return '-'; } | 274 | - { return '-'; } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index ae6af269f9c9..497f19b20f0b 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -42,6 +42,7 @@ static inc_group_count(struct list_head *list, | |||
42 | %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM | 42 | %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM |
43 | %token PE_EVENT_NAME | 43 | %token PE_EVENT_NAME |
44 | %token PE_NAME | 44 | %token PE_NAME |
45 | %token PE_BPF_OBJECT | ||
45 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP | 46 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP |
46 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT | 47 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT |
47 | %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP | 48 | %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP |
@@ -53,6 +54,7 @@ static inc_group_count(struct list_head *list, | |||
53 | %type <num> PE_RAW | 54 | %type <num> PE_RAW |
54 | %type <num> PE_TERM | 55 | %type <num> PE_TERM |
55 | %type <str> PE_NAME | 56 | %type <str> PE_NAME |
57 | %type <str> PE_BPF_OBJECT | ||
56 | %type <str> PE_NAME_CACHE_TYPE | 58 | %type <str> PE_NAME_CACHE_TYPE |
57 | %type <str> PE_NAME_CACHE_OP_RESULT | 59 | %type <str> PE_NAME_CACHE_OP_RESULT |
58 | %type <str> PE_MODIFIER_EVENT | 60 | %type <str> PE_MODIFIER_EVENT |
@@ -70,6 +72,7 @@ static inc_group_count(struct list_head *list, | |||
70 | %type <tracepoint_name> tracepoint_name | 72 | %type <tracepoint_name> tracepoint_name |
71 | %type <head> event_legacy_numeric | 73 | %type <head> event_legacy_numeric |
72 | %type <head> event_legacy_raw | 74 | %type <head> event_legacy_raw |
75 | %type <head> event_bpf_file | ||
73 | %type <head> event_def | 76 | %type <head> event_def |
74 | %type <head> event_mod | 77 | %type <head> event_mod |
75 | %type <head> event_name | 78 | %type <head> event_name |
@@ -203,7 +206,8 @@ event_def: event_pmu | | |||
203 | event_legacy_mem | | 206 | event_legacy_mem | |
204 | event_legacy_tracepoint sep_dc | | 207 | event_legacy_tracepoint sep_dc | |
205 | event_legacy_numeric sep_dc | | 208 | event_legacy_numeric sep_dc | |
206 | event_legacy_raw sep_dc | 209 | event_legacy_raw sep_dc | |
210 | event_bpf_file | ||
207 | 211 | ||
208 | event_pmu: | 212 | event_pmu: |
209 | PE_NAME '/' event_config '/' | 213 | PE_NAME '/' event_config '/' |
@@ -449,6 +453,18 @@ PE_RAW | |||
449 | $$ = list; | 453 | $$ = list; |
450 | } | 454 | } |
451 | 455 | ||
456 | event_bpf_file: | ||
457 | PE_BPF_OBJECT | ||
458 | { | ||
459 | struct parse_events_evlist *data = _data; | ||
460 | struct parse_events_error *error = data->error; | ||
461 | struct list_head *list; | ||
462 | |||
463 | ALLOC_LIST(list); | ||
464 | ABORT_ON(parse_events_load_bpf(data, list, $1)); | ||
465 | $$ = list; | ||
466 | } | ||
467 | |||
452 | start_terms: event_config | 468 | start_terms: event_config |
453 | { | 469 | { |
454 | struct parse_events_terms *data = _data; | 470 | struct parse_events_terms *data = _data; |