perf/core improvements and fixes
Subsystems (3)
Arnaldo Carvalho de Melo
maintainerHi Ingo,
Please consider pulling, this was based on tip/perf/urgent and I did a
test merge of tip/perf/core with tip/perf/urgent and then with this branch, haven't noticed problems,
Best regards,
- Arnaldo
The following changes since commit e15bf88a44d1fcb685754b2868b1cd28927af3aa:
Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent (2015-11-18 06:56:48 +0100)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo
for you to fetch changes up to 2c6caff2b26fde8f3f87183f8c97f2cebfdbcb98:
perf ui/gtk: Support folded callchains (2015-11-19 13:19:26 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:
User visible:
- Allows BPF scriptlets specify arguments to be fetched using
DWARF info, using a prologue generated at compile/build time (He Kuang, Wang Nan)
- Allow attaching BPF scriptlets to module symbols (Wang Nan)
- Allow attaching BPF scriptlets to userspace code using uprobe (Wang Nan)
- BPF programs now can specify 'perf probe' tunables via its section name, separating key=val values using semicolons (Wang Nan)
Testing some of these new BPF features:
Use case: get callchains when receiving SSL packets, filter then in the
kernel, at arbitrary place.
# cat ssl.bpf.c #define SEC(NAME) __attribute__((section(NAME), used))
struct pt_regs;
SEC("func=__inet_lookup_established hnum")
int func(struct pt_regs *ctx, int err, unsigned short port)
{
return err == 0 && port == 443;
} char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
#
# perf record -a -g -e ssl.bpf.c ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.787 MB perf.data (3 samples) ] # perf script | head -30 swapper 0 [000] 58783.268118: perf_bpf_probe:func: (ffffffff816a0f60) hnum=0x1bb 8a0f61 __inet_lookup_established (/lib/modules/4.3.0+/build/vmlinux) 896def ip_rcv_finish (/lib/modules/4.3.0+/build/vmlinux) 8976c2 ip_rcv (/lib/modules/4.3.0+/build/vmlinux) 855eba __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux) 8572a8 process_backlog (/lib/modules/4.3.0+/build/vmlinux) 856b11 net_rx_action (/lib/modules/4.3.0+/build/vmlinux) 2a284b __do_softirq (/lib/modules/4.3.0+/build/vmlinux) 2a2ba3 irq_exit (/lib/modules/4.3.0+/build/vmlinux) 96b7a4 do_IRQ (/lib/modules/4.3.0+/build/vmlinux) 969807 ret_from_intr (/lib/modules/4.3.0+/build/vmlinux) 2dede5 cpu_startup_entry (/lib/modules/4.3.0+/build/vmlinux) 95d5bc rest_init (/lib/modules/4.3.0+/build/vmlinux) 1163ffa start_kernel ([kernel.vmlinux].init.text) 11634d7 x86_64_start_reservations ([kernel.vmlinux].init.text) 1163623 x86_64_start_kernel ([kernel.vmlinux].init.text)
qemu-system-x86 9178 [003] 58785.792417: perf_bpf_probe:func: (ffffffff816a0f60) hnum=0x1bb
8a0f61 __inet_lookup_established (/lib/modules/4.3.0+/build/vmlinux) 896def ip_rcv_finish (/lib/modules/4.3.0+/build/vmlinux) 8976c2 ip_rcv (/lib/modules/4.3.0+/build/vmlinux) 855eba __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux) 856660 netif_receive_skb_internal (/lib/modules/4.3.0+/build/vmlinux) 8566ec netif_receive_skb_sk (/lib/modules/4.3.0+/build/vmlinux) 430a br_handle_frame_finish ([bridge]) 48bc br_handle_frame ([bridge]) 855f44 __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux)
#
Use 'perf probe' various options to list functions, see what variables can be collected at any given point, experiment first collecting without a filter, then filter, use it together with 'perf trace', 'perf top', with or without callchains, if it explodes, please tell us!
- Introduce a new callchain mode: "folded", that will list per line representations of all callchains for a give histogram entry, facilitating 'perf report' output processing by other tools, such as Brendan Gregg's flamegraph tools (Namhyung Kim)
E.g:
# perf report | grep -v ^# | head
18.37% 0.00% swapper [kernel.kallsyms] [k] cpu_startup_entry
|
---cpu_startup_entry
|
|--12.07%--start_secondary
|
--6.30%--rest_init
start_kernel
x86_64_start_reservations
x86_64_start_kernel
#Becomes, in "folded" mode:
# perf report -g folded | grep -v ^# | head -5
18.37% 0.00% swapper [kernel.kallsyms] [k] cpu_startup_entry
12.07% cpu_startup_entry;start_secondary
6.30% cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel
16.90% 0.00% swapper [kernel.kallsyms] [k] call_cpuidle
11.23% call_cpuidle;cpu_startup_entry;start_secondary
5.67% call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel
16.90% 0.00% swapper [kernel.kallsyms] [k] cpuidle_enter
11.23% cpuidle_enter;call_cpuidle;cpu_startup_entry;start_secondary
5.67% cpuidle_enter;call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel
15.12% 0.00% swapper [kernel.kallsyms] [k] cpuidle_enter_state
#The user can also select one of "count", "period" or "percent" as the first column.
Infrastructure:
- Fix multiple leaks found with valgrind and a refcount debugger (Masami Hiramatsu)
- Add further 'perf test' entries for BPF and LLVM (Wang Nan)
- Improve 'perf test' to suport subtests, so that the series of tests performed in the LLVM and BPF main tests appear in the default 'perf test' output (Wang Nan)
- Move memdup() from tools/perf to tools/lib/string.c (Arnaldo Carvalho de Melo)
- Adopt strtobool() from the kernel into tools/lib/ (Wang Nan)
- Fix selftests_install tools/ Makefile rule (Kevin Hilman)
----------------------------------------------------------------
Arnaldo Carvalho de Melo (3):
perf test: Fix build of BPF and LLVM on older glibc libraries
tools: Adopt memdup() from tools/perf, moving it to tools/lib/string.c perf tests: Pass the subtest index to each test routine
He Kuang (1):
perf bpf: Add prologue for BPF programs for fetching arguments
Kevin Hilman (1):
tools: Fix selftests_install Makefile rule
Masami Hiramatsu (9):
perf probe: Fix to free temporal Dwarf_Frame
perf machine: Fix machine__findnew_module_map to put registered map perf machine: Fix machine__destroy_kernel_maps to drop vmlinux_maps references perf machine: Fix to destroy kernel maps when machine exits
perf tools: Make perf_exec_path() always return malloc'd string perf tools: Fix to put new map after inserting to map_groups in dso__load_sym perf tools: Fix __dsos__addnew to put dso after adding it to the list perf tools: Fix machine__create_kernel_maps to put kernel dso refcount perf machine: Fix machine__findnew_module_map to put dso
Namhyung Kim (9):
perf report: Support folded callchain mode on --stdio perf callchain: Abstract callchain print function
perf callchain: Add count fields to struct callchain_node perf report: Add callchain value option
perf hists browser: Factor out hist_browser__show_callchain_list() perf hists browser: Support flat callchains
perf hists browser: Support folded callchains
perf ui/gtk: Support flat callchains
perf ui/gtk: Support folded callchains
Wang Nan (14):
tools: Clone the kernel's strtobool function
bpf tools: Load a program with different instances using preprocessor perf bpf: Add BPF_PROLOGUE config options for further patches perf bpf: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on perf bpf: Allow BPF program attach to uprobe events
perf bpf: Allow attaching BPF programs to modules symbols perf bpf: Allow BPF program config probing options
perf bpf: Generate prologue for BPF programs
perf test: Test the BPF prologue adding infrastructure
perf test: Fix 'perf test BPF' when it fails to find a suitable vmlinux perf bpf: Use same BPF program if arguments are identical perf test: Print result for each LLVM subtest
perf test: Print result for each BPF subtest
perf test: Mute test cases error messages if verbose == 0
tools/Makefile | 2 +- tools/include/linux/string.h | 11 + tools/lib/bpf/libbpf.c | 146 ++++++++- tools/lib/bpf/libbpf.h | 64 ++++ tools/lib/string.c | 62 ++++ tools/perf/Documentation/perf-report.txt | 14 +- tools/perf/MANIFEST | 2 + tools/perf/arch/x86/include/arch-tests.h | 8 +- tools/perf/arch/x86/tests/insn-x86.c | 2 +- tools/perf/arch/x86/tests/intel-cqm.c | 2 +- tools/perf/arch/x86/tests/perf-time-to-tsc.c | 2 +- tools/perf/arch/x86/tests/rdpmc.c | 2 +- tools/perf/arch/x86/util/Build | 1 + tools/perf/builtin-report.c | 4 +- tools/perf/config/Makefile | 12 + tools/perf/tests/.gitignore | 1 + tools/perf/tests/Build | 9 +- tools/perf/tests/attr.c | 2 +- tools/perf/tests/bp_signal.c | 2 +- tools/perf/tests/bp_signal_overflow.c | 2 +- tools/perf/tests/bpf-script-test-prologue.c | 35 +++ tools/perf/tests/bpf.c | 93 ++++-- tools/perf/tests/builtin-test.c | 112 ++++++- tools/perf/tests/code-reading.c | 2 +- tools/perf/tests/dso-data.c | 6 +- tools/perf/tests/dwarf-unwind.c | 2 +- tools/perf/tests/evsel-roundtrip-name.c | 2 +- tools/perf/tests/evsel-tp-sched.c | 2 +- tools/perf/tests/fdarray.c | 4 +- tools/perf/tests/hists_cumulate.c | 2 +- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_link.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/kmod-path.c | 2 +- tools/perf/tests/llvm.c | 75 +++-- tools/perf/tests/llvm.h | 2 + tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/tests/openat-syscall-all-cpus.c | 2 +- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/tests/openat-syscall.c | 2 +- tools/perf/tests/parse-events.c | 2 +- tools/perf/tests/parse-no-sample-id-all.c | 2 +- tools/perf/tests/perf-record.c | 2 +- tools/perf/tests/pmu.c | 2 +- tools/perf/tests/python-use.c | 3 +- tools/perf/tests/sample-parsing.c | 2 +- tools/perf/tests/sw-clock.c | 2 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/tests/task-exit.c | 2 +- tools/perf/tests/tests.h | 89 +++--- tools/perf/tests/thread-map.c | 2 +- tools/perf/tests/thread-mg-share.c | 2 +- tools/perf/tests/topology.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 2 +- tools/perf/ui/browsers/hists.c | 315 +++++++++++++++++-- tools/perf/ui/gtk/hists.c | 148 ++++++++- tools/perf/ui/stdio/hist.c | 94 +++++- tools/perf/util/Build | 7 + tools/perf/util/bpf-loader.c | 434 ++++++++++++++++++++++++- tools/perf/util/bpf-loader.h | 4 + tools/perf/util/bpf-prologue.c | 455 +++++++++++++++++++++++++++ tools/perf/util/bpf-prologue.h | 34 ++ tools/perf/util/callchain.c | 135 +++++++- tools/perf/util/callchain.h | 28 +- tools/perf/util/dso.c | 2 + tools/perf/util/exec_cmd.c | 21 +- tools/perf/util/exec_cmd.h | 5 +- tools/perf/util/help.c | 6 +- tools/perf/util/include/linux/string.h | 3 - tools/perf/util/machine.c | 17 +- tools/perf/util/probe-event.c | 7 +- tools/perf/util/probe-finder.c | 9 +- tools/perf/util/string.c | 16 - tools/perf/util/symbol-elf.c | 2 + tools/perf/util/util.c | 3 +- 77 files changed, 2286 insertions(+), 282 deletions(-) create mode 100644 tools/include/linux/string.h create mode 100644 tools/lib/string.c create mode 100644 tools/perf/tests/bpf-script-test-prologue.c create mode 100644 tools/perf/util/bpf-prologue.c create mode 100644 tools/perf/util/bpf-prologue.h delete mode 100644 tools/perf/util/include/linux/string.h
Arnaldo Carvalho de Melo
maintainerPATCH 1/37 perf test: Fix build of BPF and LLVM on older glibc libraries
From: Arnaldo Carvalho de Melo <[email protected]>
$ rpm -q glibc glibc-2.12-1.166.el6_7.1.x86_64
<SNIP>
CC /tmp/build/perf/tests/llvm.o
cc1: warnings being treated as errors
tests/llvm.c: In function ‘test_llvm__fetch_bpf_obj’:
tests/llvm.c:53: error: declaration of ‘index’ shadows a global declaration /usr/include/string.h:489: error: shadowed declaration is here
<SNIP>
CC /tmp/build/perf/tests/bpf.o
cc1: warnings being treated as errors
tests/bpf.c: In function ‘__test__bpf’:
tests/bpf.c:149: error: declaration of ‘index’ shadows a global declaration /usr/include/string.h:489: error: shadowed declaration is here
<SNIP>
--- tools/perf/tests/bpf.c | 14 +++++++------- tools/perf/tests/llvm.c | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-)
tools/perf/tests/bpf.c +7 -7
@@ -146,7 +146,7 @@ prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)return obj; } -static int __test__bpf (int index) +static int __test__bpf (int idx) {int ret;void *obj_buf;
@@ -154,27 +154,27 @@ static int __test__bpf(int index)struct bpf_object *obj; ret =test_llvm__fetch_bpf_obj (&obj_buf, &obj_buf_sz, - bpf_testcase_table[index].prog_id, + bpf_testcase_table[idx].prog_id, true);if (ret !=TEST_OK || !obj_buf || !obj_buf_sz) {pr_debug ("Unable to get BPF object, %s\n" , - bpf_testcase_table[index].msg_compile_fail); -if (index ==0 ) + bpf_testcase_table[idx].msg_compile_fail); +if (idx ==0 )return TEST_SKIP ;else return TEST_FAIL ; } obj =prepare_bpf (obj_buf, obj_buf_sz, - bpf_testcase_table[index].name); + bpf_testcase_table[idx].name);if (!obj) { ret =TEST_FAIL ; goto out; } ret =do_test (obj, - bpf_testcase_table[index].target_func, - bpf_testcase_table[index].expect_result); + bpf_testcase_table[idx].target_func, + bpf_testcase_table[idx].expect_result); out:bpf__clear ();return ret;
tools/perf/tests/llvm.c +4 -4
@@ -50,7 +50,7 @@ static struct {int test_llvm__fetch_bpf_obj (void **p_obj_buf,size_t *p_obj_buf_sz, -enum test_llvm__testcase index, +enum test_llvm__testcase idx,bool force) {const char *source;
@@ -59,11 +59,11 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf,char *tmpl_new =NULL , *clang_opt_new =NULL ;int err, old_verbose, ret =TEST_FAIL ; -if (index >= __LLVM_TESTCASE_MAX) +if (idx >= __LLVM_TESTCASE_MAX)return TEST_FAIL ; - source = bpf_source_table[index].source; - desc = bpf_source_table[index].desc; + source = bpf_source_table[idx].source; + desc = bpf_source_table[idx].desc;perf_config (perf_config_cb,NULL );
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 2/37 tools: Fix selftests_install Makefile rule
In reply to Arnaldo Carvalho de MeloFrom: Kevin Hilman <[email protected]>
Fix copy/paste error in selftests_install rule which was copy-pasted from the clean rule but not properly changed.
--- tools/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/Makefile +1 -1
@@ -96,7 +96,7 @@ cgroup_install firewire_install hv_install lguest_install perf_install usb_insta $(call descend,$(@:_install=),install) selftests_install: - $(call descend,testing/$(@:_clean=),install) + $(call descend,testing/$(@:_install=),install) turbostat_install x86_energy_perf_policy_install: $(call descend,power/x86/$(@:_install=),install)
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 3/37 tools: Adopt memdup() from tools/perf, moving it to tools/lib/string.c
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
That will contain more string functions with counterparts, sometimes verbatim copies, in the kernel.
--- tools/include/linux/string.h | 9 +++++++++ tools/lib/string.c | 19 +++++++++++++++++++ tools/perf/MANIFEST | 2 ++ tools/perf/util/Build | 6 ++++++ tools/perf/util/include/linux/string.h | 3 --- tools/perf/util/string.c | 16 ---------------- 6 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 tools/include/linux/string.h create mode 100644 tools/lib/string.c delete mode 100644 tools/perf/util/include/linux/string.h
tools/include/linux/string.h new file +9 -0
@@ -0,0 +1,9 @@ +#ifndef _TOOLS_LINUX_STRING_H_ +#define _TOOLS_LINUX_STRING_H_ + + +#include <linux/types.h> /* for size_t */ + +void *memdup (const void *src,size_t len); + +#endif /* _LINUX_STRING_H_ */
tools/lib/string.c new file +19 -0
@@ -0,0 +1,19 @@ +#include <stdlib.h> +#include <string.h> +#include <linux/string.h> + +/** +* memdup - duplicate region of memory +* +* @src: memory region to duplicate +* @len: memory region length +*/ +void *memdup (const void *src,size_t len) +{ +void *p =malloc (len); + +if (p) +memcpy (p, src, len); + +return p; +}
tools/perf/MANIFEST +2 -0
@@ -22,6 +22,7 @@ tools/lib/api tools/lib/bpf tools/lib/hweight.c tools/lib/rbtree.c +tools/lib/string.c tools/lib/symbol/kallsyms.c tools/lib/symbol/kallsyms.h tools/lib/util/find_next_bit.c
@@ -50,6 +51,7 @@ tools/include/linux/log2.h tools/include/linux/poison.h tools/include/linux/rbtree.h tools/include/linux/rbtree_augmented.h +tools/include/linux/string.h tools/include/linux/types.h tools/include/linux/err.h include/asm-generic/bitops/arch_hweight.h
tools/perf/util/Build +6 -0
@@ -21,6 +21,7 @@ libperf-y += parse-events.o libperf-y += perf_regs.o libperf-y += path.o libperf-y += rbtree.o +libperf-y += libstring.o libperf-y += bitmap.o libperf-y += hweight.o libperf-y += run-command.o
@@ -138,6 +139,7 @@ $(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c CFLAGS_find_next_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" +CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" CFLAGS_parse-events.o += -Wno-redundant-decls
@@ -153,6 +155,10 @@ $(OUTPUT)util/rbtree.o: ../lib/rbtree.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) +$(OUTPUT)util/libstring.o: ../lib/string.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) + $(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c)
tools/perf/util/include/linux/string.h deleted +0 -3
@@ -1,3 +0,0 @@ -#include <string.h> - -void *memdup (const void *src,size_t len);
tools/perf/util/string.c +0 -16
@@ -342,22 +342,6 @@ char *rtrim(char *s)return s; } -/** -* memdup - duplicate region of memory -* @src: memory region to duplicate -* @len: memory region length -*/ -void *memdup (const void *src,size_t len) -{ -void *p; - - p =malloc (len); -if (p) -memcpy (p, src, len); - -return p; -} -char *asprintf_expr_inout_ints (const char *var,bool in,size_t nints,int *ints) {/*
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 4/37 tools: Clone the kernel's strtobool function
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
Copying it to tools/lib/string.c, the counterpart to the kernel's lib/string.c.
This is preparation for enhancing BPF program configuration, which will allow config string like 'inlines=yes'.
--- tools/include/linux/string.h | 2 ++ tools/lib/string.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
tools/include/linux/string.h +2 -0
@@ -6,4 +6,6 @@void *memdup (const void *src,size_t len); +int strtobool (const char *s,bool *res); +#endif /* _LINUX_STRING_H_ */
tools/lib/string.c +43 -0
51 lines not on this page · raw message
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 5/37 bpf tools: Load a program with different instances using preprocessor
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
This patch is a preparation for BPF prologue support which allows generating a series of BPF bytecode for fetching kernel data before calling program code. With the newly introduced multiple instances support, perf is able to create different prologues for different kprobe points.
Before this patch, a bpf_program can be loaded into kernel only once, and get the only resulting fd. What this patch does is to allow creating and loading different variants of one bpf_program, then fetching their fds.
Here we describe the basic idea in this patch. The detailed description of the newly introduced APIs can be found in comments in the patch body.
The key of this patch is the new mechanism in bpf_program__load(). Instead of loading BPF program into kernel directly, it calls a 'pre-processor' to generate program instances which would be finally loaded into the kernel based on the original code. To enable the generation of multiple instances, libbpf passes an index to the pre-processor so it know which instance is being loaded.
Pre-processor should be called from libbpf's user (perf) using bpf_program__set_prep(). The number of instances and the relationship between indices and the target instance should be clear when calling bpf_program__set_prep().
To retrieve a fd for a specific instance of a program, bpf_program__nth_fd() is introduced. It returns the resulting fd according to index.
--- tools/lib/bpf/libbpf.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++--- tools/lib/bpf/libbpf.h | 64 ++++++++++++++++++++++ 2 files changed, 201 insertions(+), 9 deletions(-)
tools/lib/bpf/libbpf.c +137 -9
@@ -152,7 +152,11 @@ struct bpf_program { } *reloc_desc;int nr_reloc; -int fd; +struct { +int nr; +int *fds; + } instances; +bpf_program_prep_t preprocessor;struct bpf_object *obj;void *priv;
@@ -206,10 +210,25 @@ struct bpf_object {static void bpf_program__unload (struct bpf_program *prog) { +int i; +if (!prog)return ; -zclose (prog->fd); +/* +* If the object is opened but the program was never loaded, +* it is possible that prog->instances.nr == -1. +*/ +if (prog->instances.nr >0 ) { +for (i =0 ; i < prog->instances.nr; i++) +zclose (prog->instances.fds[i]); + }else if (prog->instances.nr !=-1 ) { +pr_warning ("Internal error: instances.nr is %d\n" , + prog->instances.nr); + } + + prog->instances.nr =-1 ; +zfree (&prog->instances.fds); }static void bpf_program__exit (struct bpf_program *prog)
@@ -260,7 +279,8 @@ bpf_program__init(void *data, size_t size, char *name, int idx,memcpy (prog->insns, data, prog->insns_cnt *sizeof (struct bpf_insn )); prog->idx = idx; - prog->fd =-1 ; + prog->instances.fds =NULL ; + prog->instances.nr =-1 ;return 0 ; errout:
@@ -860,13 +880,73 @@ static int bpf_program__load(struct bpf_program *prog, char *license, u32 kern_version) { - int err, fd; + int err = 0, fd, i; - err =load_program (prog->insns, prog->insns_cnt, - license, kern_version, &fd); -if (!err) - prog->fd = fd; +if (prog->instances.nr <0 || !prog->instances.fds) { +if (prog->preprocessor) { +pr_warning ("Internal error: can't load program '%s'\n" , + prog->section_name); +return -LIBBPF_ERRNO__INTERNAL ; + } + prog->instances.fds =malloc (sizeof (int )); +if (!prog->instances.fds) { +pr_warning ("Not enough memory for BPF fds\n" ); +return -ENOMEM ; + } + prog->instances.nr =1 ; + prog->instances.fds[0 ] =-1 ; + } + +if (!prog->preprocessor) { +if (prog->instances.nr !=1 ) { +pr_warning ("Program '%s' is inconsistent: nr(%d) != 1\n" , + prog->section_name, prog->instances.nr); + } + err =load_program (prog->insns, prog->insns_cnt, + license, kern_version, &fd); +if (!err) + prog->instances.fds[0 ] = fd; + goto out; + } + +for (i =0 ; i < prog->instances.nr; i++) { +struct bpf_prog_prep_result result; +bpf_program_prep_t preprocessor = prog->preprocessor; + +bzero (&result,sizeof (result)); + err =preprocessor (prog, i, prog->insns, + prog->insns_cnt, &result); +if (err) { +pr_warning ("Preprocessing the %dth instance of program '%s' failed\n" , + i, prog->section_name); + goto out; + } + +if (!result.new_insn_ptr || !result.new_insn_cnt) { +pr_debug ("Skip loading the %dth instance of program '%s'\n" , + i, prog->section_name); + prog->instances.fds[i] =-1 ; +if (result.pfd) + *result.pfd =-1 ; +continue ; + } + + err =load_program (result.new_insn_ptr, + result.new_insn_cnt, + license, kern_version, &fd); + +if (err) { +pr_warning ("Loading the %dth instance of program '%s' failed\n" , + i, prog->section_name); + goto out; + } + +if (result.pfd) + *result.pfd = fd; + prog->instances.fds[i] = fd; + } +out:if (err)pr_warning ("failed to load program '%s'\n" , prog->section_name);
@@ -1121,5 +1201,53 @@ const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)int bpf_program__fd (struct bpf_program *prog) { -return prog->fd; +return bpf_program__nth_fd (prog,0 ); +} + +int bpf_program__set_prep (struct bpf_program *prog,int nr_instances, +bpf_program_prep_t prep) +{ +int *instances_fds; + +if (nr_instances <=0 || !prep) +return -EINVAL ; + +if (prog->instances.nr >0 || prog->instances.fds) { +pr_warning ("Can't set pre-processor after loading\n" ); +return -EINVAL ; + } + + instances_fds =malloc (sizeof (int ) * nr_instances); +if (!instances_fds) { +pr_warning ("alloc memory failed for fds\n" ); +return -ENOMEM ; + } + +/* fill all fd with -1 */ +memset (instances_fds,-1 ,sizeof (int ) * nr_instances); + + prog->instances.nr = nr_instances; + prog->instances.fds = instances_fds; + prog->preprocessor = prep; +return 0 ; +} + +int bpf_program__nth_fd (struct bpf_program *prog,int n) +{ +int fd; + +if (n >= prog->instances.nr || n <0 ) { +pr_warning ("Can't get the %dth fd from program %s: only %d instances\n" , + n, prog->section_name, prog->instances.nr); +return -EINVAL ; + } + + fd = prog->instances.fds[n]; +if (fd <0 ) { +pr_warning ("%dth instance of program '%s' is invalid\n" , + n, prog->section_name); +return -ENOENT ; + } + +return fd; }
tools/lib/bpf/libbpf.h +64 -0
70 lines not on this page · raw message
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 6/37 perf bpf: Add BPF_PROLOGUE config options for further patches
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
If both LIBBPF and DWARF are detected, it is possible to create prologue for eBPF programs to help them access kernel data. HAVE_BPF_PROLOGUE and CONFIG_BPF_PROLOGUE are added as flags for this feature.
PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET is introduced in commit 63ab024a5b6f295ca17a293ad81b7c728f49a89a ("perf tools:regs_query_register_offset() infrastructure"), which indicates that an architecture supports converting name of a register to its offset in 'struct pt_regs'. Without this support, BPF_PROLOGUE should be turned off.
--- tools/perf/config/Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
tools/perf/config/Makefile +12 -0
@@ -318,6 +318,18 @@ ifndef NO_LIBELF CFLAGS += -DHAVE_LIBBPF_SUPPORT $(call detected,CONFIG_LIBBPF) endif + + ifndef NO_DWARF + ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET + CFLAGS += -DHAVE_BPF_PROLOGUE + $(call detected,CONFIG_BPF_PROLOGUE) + else + msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset()); + endif + else + msg := $(warning DWARF support is off, BPF prologue is disabled); + endif + endif # NO_LIBBPF endif # NO_LIBELF
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 7/37 perf bpf: Compile dwarf-regs.c if CONFIG_BPF_PROLOGUE is on
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
regs_query_register_offset() in dwarf-regs.c is required by BPF prologue. This patch compiles it if CONFIG_BPF_PROLOGUE is on to avoid build failure when CONFIG_BPF_PROLOGUE is on but CONFIG_DWARF is not set.
--- tools/perf/arch/x86/util/Build | 1 + 1 file changed, 1 insertion(+)
tools/perf/arch/x86/util/Build +1 -0
@@ -5,6 +5,7 @@ libperf-y += kvm-stat.o libperf-y += perf_regs.o libperf-$(CONFIG_DWARF) += dwarf-regs.o +libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 8/37 perf bpf: Allow BPF program attach to uprobe events
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
This patch adds a new syntax to the BPF object section name to support probing at uprobe event. Now we can use BPF program like this:
SEC(
"exec=/lib64/libc.so.6;"
"libcwrite=__write"
)
int libcwrite(void *ctx)
{
return 1;
}Where, in section name of a program, before the main config string, we can use 'key=value' style options. Now the only option key is "exec", for uprobes.
--- tools/perf/util/bpf-loader.c | 120 ++++++++++++++++++++++++++++++++++++++++--- tools/perf/util/bpf-loader.h | 1 + 2 files changed, 115 insertions(+), 6 deletions(-)
tools/perf/util/bpf-loader.c +114 -6
@@ -110,6 +110,113 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, }static int +config__exec (const char *value,struct perf_probe_event *pev) +{ + pev->uprobes = true; + pev->target =strdup (value); +if (!pev->target) +return -ENOMEM ; +return 0 ; +} + +static struct { +const char *key; +const char *usage; +const char *desc; +int (*func)(const char *,struct perf_probe_event *); +} bpf_config_terms[] = { + { + .key ="exec" , + .usage ="exec=<full path of file>" , + .desc ="Set uprobe target" , + .func = config__exec, + }, +}; + +static int +do_config (const char *key,const char *value, +struct perf_probe_event *pev) +{ +unsigned int i; + +pr_debug ("config bpf program: %s=%s\n" , key, value); +for (i =0 ; i <ARRAY_SIZE (bpf_config_terms); i++) +if (strcmp (key, bpf_config_terms[i].key) ==0 ) +return bpf_config_terms[i].func (value, pev); + +pr_debug ("BPF: ERROR: invalid config option in object: %s=%s\n" , + key, value); + +pr_debug ("\nHint: Currently valid options are:\n" ); +for (i =0 ; i <ARRAY_SIZE (bpf_config_terms); i++) +pr_debug ("\t%s:\t%s\n" , bpf_config_terms[i].usage, + bpf_config_terms[i].desc); +pr_debug ("\n" ); + +return -BPF_LOADER_ERRNO__CONFIG_TERM ; +} + +static const char * +parse_config_kvpair (const char *config_str,struct perf_probe_event *pev) +{ +char *text =strdup (config_str); +char *sep, *line; +const char *main_str =NULL ; +int err =0 ; + +if (!text) { +pr_debug ("No enough memory: dup config_str failed\n" ); +return ERR_PTR (-ENOMEM ); + } + + line = text; +while ((sep =strchr (line,';' ))) { +char *equ; + + *sep ='\0' ; + equ =strchr (line,'=' ); +if (!equ) { +pr_warning ("WARNING: invalid config in BPF object: %s\n" , + line); +pr_warning ("\tShould be 'key=value'.\n" ); + goto nextline; + } + *equ ='\0' ; + + err =do_config (line, equ +1 , pev); +if (err) +break ; +nextline: + line = sep +1 ; + } + +if (!err) + main_str = config_str + (line - text); +free (text); + +return err ?ERR_PTR (err) : main_str; +} + +static int +parse_config (const char *config_str,struct perf_probe_event *pev) +{ +int err; +const char *main_str =parse_config_kvpair (config_str, pev); + +if (IS_ERR (main_str)) +return PTR_ERR (main_str); + + err =parse_perf_probe_command (main_str, pev); +if (err <0 ) { +pr_debug ("bpf: '%s' is not a valid config string\n" , + config_str); +/* parse failed, don't need clear pev. */ +return -BPF_LOADER_ERRNO__CONFIG ; + } +return 0 ; +} + +static int config_bpf_program (struct bpf_program *prog) {struct perf_probe_event *pev =NULL ;
@@ -131,13 +238,9 @@ config_bpf_program(struct bpf_program *prog) pev = &priv->pev;pr_debug ("bpf: config program '%s'\n" , config_str); - err =parse_perf_probe_command (config_str, pev); -if (err <0 ) { -pr_debug ("bpf: '%s' is not a valid config string\n" , - config_str); - err = -BPF_LOADER_ERRNO__CONFIG ; + err =parse_config (config_str, pev); +if (err) goto errout; - }if (pev->group &&strcmp (pev->group,PERF_BPF_PROBE_GROUP )) { pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
@@ -340,6 +443,7 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = { [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string", [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", + [ERRCODE_OFFSET(CONFIG_TERM)] = "Invalid config term in config string", }; static int
@@ -420,6 +524,10 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, int err, char *buf, size_t size) {bpf__strerror_head (err ,buf ,size ); +case BPF_LOADER_ERRNO__CONFIG_TERM : { +scnprintf (buf, size,"%s (add -v to see detail)" , emsg); +break ; + }bpf__strerror_entry (EEXIST ,"Probe point exist. Try use 'perf probe -d \"*\"'" );bpf__strerror_entry (EACCES ,"You need to be root" );bpf__strerror_entry (EPERM ,"You need to be root, and /proc/sys/kernel/kptr_restrict should be 0" );
tools/perf/util/bpf-loader.h +1 -0
@@ -20,6 +20,7 @@ enum bpf_loader_errno {BPF_LOADER_ERRNO__EVENTNAME ,/* Event name is missing */ BPF_LOADER_ERRNO__INTERNAL ,/* BPF loader internal error */ BPF_LOADER_ERRNO__COMPILE ,/* Error when compiling BPF scriptlet */ +BPF_LOADER_ERRNO__CONFIG_TERM ,/* Invalid config term in config term */ __BPF_LOADER_ERRNO__END, };
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 9/37 perf bpf: Allow attaching BPF programs to modules symbols
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
By extending the syntax of BPF object section names, this patch allows users to attach BPF programs to symbols in modules. For example:
SEC("module=i915;"
"parse_cmds=i915_parse_cmds")
int parse_cmds(void *ctx)
{
return 1;
}The implementation is very simple: like what 'perf probe' does, for module, fill 'uprobe' field in 'struct perf_probe_event'. Other parts will be done automatically.
--- tools/perf/util/bpf-loader.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
tools/perf/util/bpf-loader.c +16 -0
@@ -119,6 +119,16 @@ config__exec(const char *value, struct perf_probe_event *pev)return 0 ; } +static int +config__module (const char *value,struct perf_probe_event *pev) +{ + pev->uprobes = false; + pev->target =strdup (value); +if (!pev->target) +return -ENOMEM ; +return 0 ; +} + static struct { const char *key; const char *usage;
@@ -131,6 +141,12 @@ static struct { .desc = "Set uprobe target", .func = config__exec, }, + { + .key = "module", + .usage = "module=<module name> ", + .desc = "Set kprobe module", + .func = config__module, + } }; static int
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 10/37 perf bpf: Allow BPF program config probing options
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
By extending the syntax of BPF object section names, this patch allows users to config probing options like what they can do in 'perf probe'.
The error message in 'perf probe' is also updated.
Test result:
For following BPF file test_probe_glob.c:
# cat test_probe_glob.c
__attribute__((section("inlines=no;func=SyS_dup?"), used)) int func(void *ctx)
{
return 1;}
char _license[] __attribute__((section("license"), used)) = "GPL"; int _version __attribute__((section("version"), used)) = 0x40300; #
# ./perf record -e ./test_probe_glob.c ls / ... [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.013 MB perf.data ] # ./perf evlist perf_bpf_probe:func_1 perf_bpf_probe:func
After changing "inlines=no" to "inlines=yes":
# ./perf record -e ./test_probe_glob.c ls / ... [ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.013 MB perf.data ] # ./perf evlist perf_bpf_probe:func_3 perf_bpf_probe:func_2 perf_bpf_probe:func_1 perf_bpf_probe:func
Then test 'force':
Use following program:
# cat test_probe_force.c
__attribute__((section("func=sys_write"), used)) int funca(void *ctx)
{
return 1;}
__attribute__((section("force=yes;func=sys_write"), used))
int funcb(void *ctx)
{
return 1;
}
char _license[] __attribute__((section("license"), used)) = "GPL";
int _version __attribute__((section("version"), used)) = 0x40300;
# # perf record -e ./test_probe_force.c usleep 1
Error: event "func" already exists.
Hint: Remove existing event by 'perf probe -d'
or force duplicates by 'perf probe -f'
or set 'force=yes' in BPF source.
event syntax error: './test_probe_force.c'
\___ Probe point exist. Try 'perf probe -d "*"' and set 'force=yes' (add -v to see detail)
...
Then replace 'force=no' to 'force=yes':
# vim test_probe_force.c # perf record -e ./test_probe_force.c usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.017 MB perf.data ] # perf evlist perf_bpf_probe:func_1 perf_bpf_probe:func #
--- tools/perf/util/bpf-loader.c | 53 +++++++++++++++++++++++++++++++++++++++++-- tools/perf/util/probe-event.c | 7 ++++-- 2 files changed, 56 insertions(+), 4 deletions(-)
tools/perf/util/bpf-loader.c +51 -2
@@ -7,6 +7,7 @@#include <bpf/libbpf.h> #include <linux/err.h> +#include <linux/string.h> #include "perf.h" #include "debug.h" #include "bpf-loader.h"
@@ -129,6 +130,38 @@ config__module(const char *value, struct perf_probe_event *pev)return 0 ; } +static int +config__bool (const char *value, +bool *pbool,bool invert) +{ +int err; +bool bool_value; + +if (!pbool) +return -EINVAL ; + + err =strtobool (value, &bool_value); +if (err) +return err; + + *pbool = invert ? !bool_value : bool_value; +return 0 ; +} + +static int +config__inlines (const char *value, +struct perf_probe_event *pev__maybe_unused ) +{ +return config__bool (value, &probe_conf.no_inlines, true); +} + +static int +config__force (const char *value, +struct perf_probe_event *pev__maybe_unused ) +{ +return config__bool (value, &probe_conf.force_add, false); +} + static struct { const char *key; const char *usage;
@@ -146,7 +179,19 @@ static struct { .usage = "module=<module name> ", .desc = "Set kprobe module", .func = config__module, - } + }, + { + .key = "inlines", + .usage = "inlines=[yes|no] ", + .desc = "Probe at inline symbol", + .func = config__inlines, + }, + { + .key = "force", + .usage = "force=[yes|no] ", + .desc = "Forcibly add events with existing name", + .func = config__force, + }, }; static int
@@ -240,6 +285,10 @@ config_bpf_program(struct bpf_program *prog)const char *config_str;int err; +/* Initialize per-program probing setting */ + probe_conf.no_inlines = false; + probe_conf.force_add = false; + config_str =bpf_program__title (prog, false);if (IS_ERR (config_str)) {pr_debug ("bpf: unable to get title for program\n" );
@@ -544,7 +593,7 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,scnprintf (buf, size,"%s (add -v to see detail)" , emsg);break ; } -bpf__strerror_entry (EEXIST ,"Probe point exist. Try use 'perf probe -d \"*\"'" ); +bpf__strerror_entry (EEXIST ,"Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'" );bpf__strerror_entry (EACCES ,"You need to be root" );bpf__strerror_entry (EPERM ,"You need to be root, and /proc/sys/kernel/kptr_restrict should be 0" );bpf__strerror_entry (ENOENT ,"You need to check probing points in BPF file" );
tools/perf/util/probe-event.c +5 -2
@@ -2326,8 +2326,11 @@ static int get_new_event_name(char *buf, size_t len, const char *base, goto out;if (!allow_suffix) { -pr_warning ("Error: event \"%s\" already exists. " -"(Use -f to force duplicates.)\n" , buf); +pr_warning ("Error: event \"%s\" already exists.\n" +" Hint: Remove existing event by 'perf probe -d'\n" +" or force duplicates by 'perf probe -f'\n" +" or set 'force=yes' in BPF source.\n" , + buf); ret = -EEXIST ; goto out; }
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 11/37 perf bpf: Add prologue for BPF programs for fetching arguments
In reply to Arnaldo Carvalho de MeloFrom: He Kuang <[email protected]>
This patch generates a prologue for a BPF program which fetches arguments for it. With this patch, the program can have arguments as follow:
SEC("lock_page=__lock_page page->flags")
int lock_page(struct pt_regs *ctx, int err, unsigned long flags) {
return 1;
}
This patch passes at most 3 arguments from r3, r4 and r5. r1 is still the ctx pointer. r2 is used to indicate if dereferencing was done successfully.
This patch uses r6 to hold ctx (struct pt_regs) and r7 to hold stack pointer for result. Result of each arguments first store on stack:
low address
BPF_REG_FP - 24 ARG3 BPF_REG_FP - 16 ARG2 BPF_REG_FP - 8 ARG1
BPF_REG_FP
high address
Then loaded into r3, r4 and r5.
The output prologue for offn(...off2(off1(reg)))) should be:
r6 <- r1 // save ctx into a callee saved register
r7 <- fp
r7 <- r7 - stack_offset // pointer to result slot
/* load r3 with the offset in pt_regs of 'reg' */
(r7) <- r3 // make slot valid
r3 <- r3 + off1 // prepare to read unsafe pointer
r2 <- 8
r1 <- r7 // result put onto stack
call probe_read // read unsafe pointer
jnei r0, 0, err // error checking
r3 <- (r7) // read result
r3 <- r3 + off2 // prepare to read unsafe pointer
r2 <- 8
r1 <- r7
call probe_read
jnei r0, 0, err
...
/* load r2, r3, r4 from stack */
goto success
err:
r2 <- 1
/* load r3, r4, r5 with 0 */
goto usercode
success:
r2 <- 0
usercode:
r1 <- r6 // restore ctx
// original user codeIf all of arguments reside in register (dereferencing is not required), gen_prologue_fastpath() will be used to create fast prologue:
r3 <- (r1 + offset of reg1)
r4 <- (r1 + offset of reg2)
r5 <- (r1 + offset of reg3)
r2 <- 0P.S.
eBPF calling convention is defined as:
* r0 - return value from in-kernel function, and exit value
for eBPF program
* r1 - r5 - arguments from eBPF program to in-kernel function
* r6 - r9 - callee saved registers that in-kernel function will
preserve
* r10 - read-only frame pointer to access stack
Committer note:
At least testing if it builds and loads:
# cat test_probe_arg.c struct pt_regs;
__attribute__((section("lock_page=__lock_page page->flags"), used))
int func(struct pt_regs *ctx, int err, unsigned long flags)
{
return 1;
} char _license[] __attribute__((section("license"), used)) = "GPL"; int _version __attribute__((section("version"), used)) = 0x40300;
# perf record -e ./test_probe_arg.c usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.016 MB perf.data ] # perf evlist perf_bpf_probe:lock_page #
--- tools/perf/util/Build | 1 + tools/perf/util/bpf-loader.c | 3 + tools/perf/util/bpf-loader.h | 3 + tools/perf/util/bpf-prologue.c | 455 +++++++++++++++++++++++++++++++++++++++++ tools/perf/util/bpf-prologue.h | 34 +++ 5 files changed, 496 insertions(+) create mode 100644 tools/perf/util/bpf-prologue.c create mode 100644 tools/perf/util/bpf-prologue.h
tools/perf/util/Build +1 -0
@@ -89,6 +89,7 @@ libperf-y += parse-branch-options.o libperf-y += parse-regs-options.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o +libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += probe-file.o libperf-$(CONFIG_LIBELF) += probe-event.o
tools/perf/util/bpf-loader.c +3 -0
@@ -509,6 +509,9 @@ static const char *bpf_loader_strerror_table[NR_ERRNO] = { [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error", [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet", [ERRCODE_OFFSET(CONFIG_TERM)] = "Invalid config term in config string", + [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue", + [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program", + [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue", }; static int
tools/perf/util/bpf-loader.h +3 -0
@@ -21,6 +21,9 @@ enum bpf_loader_errno {BPF_LOADER_ERRNO__INTERNAL ,/* BPF loader internal error */ BPF_LOADER_ERRNO__COMPILE ,/* Error when compiling BPF scriptlet */ BPF_LOADER_ERRNO__CONFIG_TERM ,/* Invalid config term in config term */ +BPF_LOADER_ERRNO__PROLOGUE ,/* Failed to generate prologue */ +BPF_LOADER_ERRNO__PROLOGUE2BIG ,/* Prologue too big for program */ +BPF_LOADER_ERRNO__PROLOGUEOOB ,/* Offset out of bound for prologue */ __BPF_LOADER_ERRNO__END, };
tools/perf/util/bpf-prologue.c new file +455 -0
455 lines not on this page · raw message
tools/perf/util/bpf-prologue.h new file +34 -0
@@ -0,0 +1,34 @@ +/* +* Copyright (C) 2015, He Kuang <[email protected]> +* Copyright (C) 2015, Huawei Inc. +*/ +#ifndef __BPF_PROLOGUE_H +#define __BPF_PROLOGUE_H + +#include <linux/compiler.h> +#include <linux/filter.h> +#include "probe-event.h" + +#define BPF_PROLOGUE_MAX_ARGS 3 +#define BPF_PROLOGUE_START_ARG_REG BPF_REG_3 +#define BPF_PROLOGUE_FETCH_RESULT_REG BPF_REG_2 + +#ifdef HAVE_BPF_PROLOGUE +int bpf__gen_prologue (struct probe_trace_arg *args,int nargs, +struct bpf_insn *new_prog,size_t *new_cnt, +size_t cnt_space); +#else +static inline int +bpf__gen_prologue (struct probe_trace_arg *args__maybe_unused , +int nargs__maybe_unused , +struct bpf_insn *new_prog__maybe_unused , +size_t *new_cnt, +size_t cnt_space__maybe_unused ) +{ +if (!new_cnt) +return -EINVAL ; + *new_cnt =0 ; +return -ENOTSUP ; +} +#endif +#endif /* __BPF_PROLOGUE_H */
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 12/37 perf bpf: Generate prologue for BPF programs
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
This patch generates a prologue for each 'struct probe_trace_event' for fetching arguments for BPF programs.
After bpf__probe(), iterate over each program to check whether prologues are required. If none of the 'struct perf_probe_event' programs will attach to have at least one argument, simply skip preprocessor hooking. For those who a prologue is required, call bpf__gen_prologue() and paste the original instruction after the prologue.
--- tools/perf/util/bpf-loader.c | 120 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-)
tools/perf/util/bpf-loader.c +119 -1
@@ -5,12 +5,15 @@* Copyright (C) 2015 Huawei Inc. */ +#include <linux/bpf.h> #include <bpf/libbpf.h> #include <linux/err.h> #include <linux/string.h> #include "perf.h" #include "debug.h" #include "bpf-loader.h" +#include "bpf-prologue.h" +#include "llvm-utils.h" #include "probe-event.h" #include "probe-finder.h" // for MAX_PROBES #include "llvm-utils.h"
@@ -33,6 +36,8 @@ DEFINE_PRINT_FN(debug, 1)struct bpf_prog_priv {struct perf_probe_event pev; +bool need_prologue; +struct bpf_insn *insns_buf; };static bool libbpf_initialized;
@@ -107,6 +112,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,struct bpf_prog_priv *priv = _priv;cleanup_perf_probe_events (&priv->pev,1 ); +zfree (&priv->insns_buf);free (priv); }
@@ -365,6 +371,102 @@ static int bpf__prepare_probe(void)return err; } +static int +preproc_gen_prologue (struct bpf_program *prog,int n, +struct bpf_insn *orig_insns,int orig_insns_cnt, +struct bpf_prog_prep_result *res) +{ +struct probe_trace_event *tev; +struct perf_probe_event *pev; +struct bpf_prog_priv *priv; +struct bpf_insn *buf; +size_t prologue_cnt =0 ; +int err; + + err =bpf_program__get_private (prog, (void **)&priv); +if (err || !priv) + goto errout; + + pev = &priv->pev; + +if (n <0 || n >= pev->ntevs) + goto errout; + + tev = &pev->tevs[n]; + + buf = priv->insns_buf; + err =bpf__gen_prologue (tev->args, tev->nargs, + buf, &prologue_cnt, +BPF_MAXINSNS - orig_insns_cnt); +if (err) { +const char *title; + + title =bpf_program__title (prog, false); +if (!title) + title ="[unknown]" ; + +pr_debug ("Failed to generate prologue for program %s\n" , + title); +return err; + } + +memcpy (&buf[prologue_cnt], orig_insns, +sizeof (struct bpf_insn ) * orig_insns_cnt); + + res->new_insn_ptr = buf; + res->new_insn_cnt = prologue_cnt + orig_insns_cnt; + res->pfd =NULL ; +return 0 ; + +errout: +pr_debug ("Internal error in preproc_gen_prologue\n" ); +return -BPF_LOADER_ERRNO__PROLOGUE ; +} + +static int hook_load_preprocessor (struct bpf_program *prog) +{ +struct perf_probe_event *pev; +struct bpf_prog_priv *priv; +bool need_prologue = false; +int err, i; + + err =bpf_program__get_private (prog, (void **)&priv); +if (err || !priv) { +pr_debug ("Internal error when hook preprocessor\n" ); +return -BPF_LOADER_ERRNO__INTERNAL ; + } + + pev = &priv->pev; +for (i =0 ; i < pev->ntevs; i++) { +struct probe_trace_event *tev = &pev->tevs[i]; + +if (tev->nargs >0 ) { + need_prologue = true; +break ; + } + } + +/* +* Since all tevs don't have argument, we don't need generate +* prologue. +*/ +if (!need_prologue) { + priv->need_prologue = false; +return 0 ; + } + + priv->need_prologue = true; + priv->insns_buf =malloc (sizeof (struct bpf_insn ) *BPF_MAXINSNS ); +if (!priv->insns_buf) { +pr_debug ("No enough memory: alloc insns_buf failed\n" ); +return -ENOMEM ; + } + + err =bpf_program__set_prep (prog, pev->ntevs, + preproc_gen_prologue); +return err; +} +int bpf__probe (struct bpf_object *obj) {int err =0 ;
@@ -399,6 +501,18 @@ int bpf__probe(struct bpf_object *obj)pr_debug ("bpf_probe: failed to apply perf probe events" ); goto out; } + +/* +* After probing, let's consider prologue, which +* adds program fetcher to BPF programs. +* +* hook_load_preprocessorr() hooks pre-processor +* to bpf_program, let it generate prologue +* dynamically during loading. +*/ + err =hook_load_preprocessor (prog); +if (err) + goto out; } out:return err <0 ? err :0 ;
@@ -482,7 +596,11 @@ int bpf__foreach_tev(struct bpf_object *obj,for (i =0 ; i < pev->ntevs; i++) { tev = &pev->tevs[i]; - fd =bpf_program__fd (prog); +if (priv->need_prologue) + fd =bpf_program__nth_fd (prog, i); +else + fd =bpf_program__fd (prog); +if (fd <0 ) {pr_debug ("bpf: failed to get file descriptor\n" );return fd;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 13/37 perf test: Test the BPF prologue adding infrastructure
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
This patch introduces a new BPF script to test the BPF prologue adding routines. The new script probes at null_lseek, which is the function pointer used when we try to lseek on '/dev/null'.
The null_lseek function is chosen because it is used by function pointers, so we don't need to consider inlining and LTO.
By extracting file->f_mode, bpf-script-test-prologue.c should know whether the file is writable or readonly. According to llseek_loop() and bpf-script-test-prologue.c, one fourth of total lseeks should be collected.
Committer note:
Testing it:
# perf test -v BPF <SNIP> Kernel build dir is set to /lib/modules/4.3.0+/build set env: KBUILD_DIR=/lib/modules/4.3.0+/build unset env: KBUILD_OPTS include option is set to -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h set env: NR_CPUS=4 set env: LINUX_VERSION_CODE=0x40300 set env: CLANG_EXEC=/usr/libexec/icecc/bin/clang set env: CLANG_OPTIONS=-xc set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.9.2/include -I/home/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/git/linux/include -Iinclude -I/home/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/git/linux/include/uapi -Iinclude/generated/uapi -include /home/git/linux/include/linux/kconfig.h set env: WORKING_DIR=/lib/modules/4.3.0+/build set env: CLANG_SOURCE=- llvm compiling command template: echo '/* * bpf-script-test-prologue.c * Test BPF prologue */ #ifndef LINUX_VERSION_CODE # error Need LINUX_VERSION_CODE # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' #endif #define SEC(NAME) __attribute__((section(NAME), used))
#include <uapi/linux/fs.h> #define FMODE_READ 0x1 #define FMODE_WRITE 0x2
static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void *) 6;
SEC("func=null_lseek file->f_mode offset orig")
int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
unsigned long offset, unsigned long orig)
{
if (err)
return 0;
if (f_mode & FMODE_WRITE)
return 0;
if (offset & 1)
return 0;
if (orig == SEEK_CUR)
return 0;
return 1;}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
' | $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o -
libbpf: loading object '[bpf_prologue_test]' from buffer
libbpf: section .strtab, size 135, link 0, flags 0, type=3
libbpf: section .text, size 0, link 0, flags 6, type=1
libbpf: section .data, size 0, link 0, flags 3, type=1
libbpf: section .bss, size 0, link 0, flags 3, type=8
libbpf: section func=null_lseek file->f_mode offset orig, size 112, link 0, flags 6, type=1
libbpf: found program func=null_lseek file->f_mode offset orig
libbpf: section license, size 4, link 0, flags 3, type=1
libbpf: license of [bpf_prologue_test] is GPL
libbpf: section version, size 4, link 0, flags 3, type=1
libbpf: kernel version of [bpf_prologue_test] is 40300
libbpf: section .symtab, size 168, link 1, flags 0, type=2
bpf: config program 'func=null_lseek file->f_mode offset orig'
symbol:null_lseek file:(null) line:0 offset:0 return:0 lazy:(null)
parsing arg: file->f_mode into file, f_mode(1)
parsing arg: offset into offset
parsing arg: orig into orig
bpf: config 'func=null_lseek file->f_mode offset orig' is ok
Looking at the vmlinux_path (7 entries long)
Using /lib/modules/4.3.0+/build/vmlinux for symbols
Open Debuginfo file: /lib/modules/4.3.0+/build/vmlinux
Try to find probe point from debuginfo.
Matched function: null_lseek
Probe point found: null_lseek+0
Searching 'file' variable in context.
Converting variable file into trace event.
converting f_mode in file
f_mode type is unsigned int.
Searching 'offset' variable in context.
Converting variable offset into trace event.
offset type is long long int.
Searching 'orig' variable in context.
Converting variable orig into trace event.
orig type is int.
Found 1 probe_trace_events.
Opening /sys/kernel/debug/tracing//kprobe_events write=1
Writing event: p:perf_bpf_probe/func _text+4840528 f_mode=+68(%di):u32 offset=%si:s64 orig=%dx:s32
libbpf: don't need create maps for [bpf_prologue_test]
prologue: pass validation
prologue: slow path
prologue: fetch arg 0, base reg is %di
prologue: arg 0: offset 68
prologue: fetch arg 1, base reg is %si
prologue: fetch arg 2, base reg is %dx
add bpf event perf_bpf_probe:func and attach bpf program 3
adding perf_bpf_probe:func
adding perf_bpf_probe:func to 0x51672c0
mmap size 1052672B
Opening /sys/kernel/debug/tracing//kprobe_events write=1
Opening /sys/kernel/debug/tracing//uprobe_events write=1
Parsing probe_events: p:perf_bpf_probe/func _text+4840528 f_mode=+68(%di):u32 offset=%si:s64 orig=%dx:s32
Group:perf_bpf_probe Event:func probe:p
Writing event: -:perf_bpf_probe/func
test child finished with 0
---- end ----
Test BPF filter: Ok
#
--- tools/perf/tests/.gitignore | 1 + tools/perf/tests/Build | 9 +++++++- tools/perf/tests/bpf-script-test-prologue.c | 35 +++++++++++++++++++++++++++++ tools/perf/tests/bpf.c | 34 ++++++++++++++++++++++++++++ tools/perf/tests/llvm.c | 4 ++++ tools/perf/tests/llvm.h | 2 ++ 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tools/perf/tests/bpf-script-test-prologue.c
tools/perf/tests/.gitignore +1 -0
@@ -1,2 +1,3 @@ llvm-src-base.c llvm-src-kbuild.c +llvm-src-prologue.c
tools/perf/tests/Build +8 -1
@@ -31,7 +31,7 @@ perf-y += sample-parsing.o perf-y += parse-no-sample-id-all.o perf-y += kmod-path.o perf-y += thread-map.o -perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o +perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o perf-y += bpf.o perf-y += topology.o
@@ -49,6 +49,13 @@ $(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ $(Q)echo ';' >> $@ +$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c + $(call rule_mkdir) + $(Q)echo '#include <tests/llvm.h>' > $@ + $(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@ + $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ + $(Q)echo ';' >> $@ + ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o endif
tools/perf/tests/bpf-script-test-prologue.c new file +35 -0
@@ -0,0 +1,35 @@ +/* +* bpf-script-test-prologue.c +* Test BPF prologue +*/ +#ifndef LINUX_VERSION_CODE +# error Need LINUX_VERSION_CODE +# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' +#endif +#define SEC (NAME ) __attribute__((section(NAME), used)) + +#include <uapi/linux/fs.h> + +#define FMODE_READ 0x1 +#define FMODE_WRITE 0x2 + +static void (*bpf_trace_printk)(const char *fmt,int fmt_size, ...) = + (void *)6 ; + +SEC("func=null_lseek file->f_mode offset orig") +int bpf_func__null_lseek (void *ctx,int err,unsigned long f_mode, +unsigned long offset,unsigned long orig) +{ +if (err) +return 0 ; +if (f_mode &FMODE_WRITE ) +return 0 ; +if (offset &1 ) +return 0 ; +if (orig ==SEEK_CUR ) +return 0 ; +return 1 ; +} + +char _license[] SEC("license") = "GPL"; +int _version SEC("version") = LINUX_VERSION_CODE;
tools/perf/tests/bpf.c +34 -0
@@ -19,6 +19,29 @@ static int epoll_pwait_loop(void)return 0 ; } +#ifdef HAVE_BPF_PROLOGUE + +static int llseek_loop (void ) +{ +int fds[2 ], i; + + fds[0 ] =open ("/dev/null" ,O_RDONLY ); + fds[1 ] =open ("/dev/null" ,O_RDWR ); + +if (fds[0 ] <0 || fds[1 ] <0 ) +return -1 ; + +for (i =0 ; i <NR_ITERS ; i++) { +lseek (fds[i %2 ], i, (i /2 ) %2 ?SEEK_CUR :SEEK_SET ); +lseek (fds[(i +1 ) %2 ], i, (i /2 ) %2 ?SEEK_CUR :SEEK_SET ); + } +close (fds[0 ]); +close (fds[1 ]); +return 0 ; +} + +#endif + static struct { enum test_llvm__testcase prog_id; const char *desc;
@@ -37,6 +60,17 @@ static struct { &epoll_pwait_loop, (NR_ITERS + 1) / 2, }, +#ifdef HAVE_BPF_PROLOGUE + { + LLVM_TESTCASE_BPF_PROLOGUE, + "Test BPF prologue generation", + "[bpf_prologue_test]", + "fix kbuild first", + "check your vmlinux setting?", + &llseek_loop, + (NR_ITERS + 1) / 4, + }, +#endif }; static int do_test(struct bpf_object *obj, int (*func)(void),
tools/perf/tests/llvm.c +4 -0
@@ -44,6 +44,10 @@ static struct { .source = test_llvm__bpf_test_kbuild_prog, .desc = "Test kbuild searching", }, + [LLVM_TESTCASE_BPF_PROLOGUE] = { + .source = test_llvm__bpf_test_prologue_prog, + .desc = "Test BPF prologue generation", + }, };
tools/perf/tests/llvm.h +2 -0
@@ -6,10 +6,12 @@extern const char test_llvm__bpf_base_prog[];extern const char test_llvm__bpf_test_kbuild_prog[]; +extern const char test_llvm__bpf_test_prologue_prog[];enum test_llvm__testcase {LLVM_TESTCASE_BASE ,LLVM_TESTCASE_KBUILD , +LLVM_TESTCASE_BPF_PROLOGUE , __LLVM_TESTCASE_MAX, };
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 14/37 perf test: Fix 'perf test BPF' when it fails to find a suitable vmlinux
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
Two bugs in 'perf test BPF' are found when testing BPF prologue without vmlinux:
# mv /lib/modules/4.3.0-rc4+/build/vmlinux{,.bak}
# ./perf test BPF
37: Test BPF filter :Failed to find the path for kernel: No such file or directory
OkTest BPF should fail in this case.
After this patch:
# ./perf test BPF
37: Test BPF filter :Failed to find the path for kernel: No such file or directory
FAILED!
# mv /lib/modules/4.3.0-rc4+/build/vmlinux{.bak,}
# ./perf test BPF
37: Test BPF filter : Ok--- tools/perf/tests/bpf.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
tools/perf/tests/bpf.c +4 -3
@@ -102,8 +102,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), err =parse_events_load_bpf_obj (&parse_evlist, &parse_evlist.list, obj);if (err ||list_empty (&parse_evlist.list)) {pr_debug ("Failed to add events selected by BPF\n" ); -if (!err) -return TEST_FAIL ; +return TEST_FAIL ; }snprintf (pid,sizeof (pid),"%d" ,getpid ());
@@ -157,8 +156,10 @@ static int do_test(struct bpf_object *obj, int (*func)(void), } } -if (count != expect) +if (count != expect) {pr_debug ("BPF filter result incorrect\n" ); + goto out_delete_evlist; + } ret =TEST_OK ;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 15/37 perf bpf: Use same BPF program if arguments are identical
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
This patch allows creating only one BPF program for different 'probe_trace_event'(tev) entries generated by one 'perf_probe_event'(pev) if their prologues are identical.
This is done by comparing the argument list of different tev instances, and the maps type of prologue and tev using a mapping array. This patch utilizes qsort to sort the tevs. After sorting, tevs with identical argument lists will be grouped together.
Test result:
Sample BPF program:
#define SEC(NAME) __attribute__((section(NAME), used))
SEC("inlines=no;"
"func=SyS_dup? oldfd")
int func(void *ctx)
{
return 1;
}It would probe at SyS_dup2 and SyS_dup3, obtaining oldfd as its argument.
The following cmdline shows a BPF program being loaded into the kernel by perf:
# perf record -e ./test_bpf_arg.c sleep 4 & sleep 1 && ls /proc/$!/fd/ -l | grep bpf-prog
Before this patch:
# perf record -e ./test_bpf_arg.c sleep 4 & sleep 1 && ls /proc/$!/fd/ -l | grep bpf-prog [1] 24858 lrwx------ 1 root root 64 Nov 14 04:09 3 -> anon_inode:bpf-prog lrwx------ 1 root root 64 Nov 14 04:09 4 -> anon_inode:bpf-prog ...
After this patch:
# perf record -e ./test_bpf_arg.c sleep 4 & sleep 1 && ls /proc/$!/fd/ -l | grep bpf-prog [1] 25699 lrwx------ 1 root root 64 Nov 14 04:10 3 -> anon_inode:bpf-prog ...
--- tools/perf/util/bpf-loader.c | 138 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 7 deletions(-)
tools/perf/util/bpf-loader.c +131 -7
@@ -38,6 +38,8 @@ struct bpf_prog_priv {struct perf_probe_event pev;bool need_prologue;struct bpf_insn *insns_buf; +int nr_types; +int *type_mapping; };static bool libbpf_initialized;
@@ -113,6 +115,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,cleanup_perf_probe_events (&priv->pev,1 );zfree (&priv->insns_buf); +zfree (&priv->type_mapping);free (priv); }
@@ -381,7 +384,7 @@ preproc_gen_prologue(struct bpf_program *prog, int n,struct bpf_prog_priv *priv;struct bpf_insn *buf;size_t prologue_cnt =0 ; -int err; +int i, err; err =bpf_program__get_private (prog, (void **)&priv);if (err || !priv)
@@ -389,10 +392,21 @@ preproc_gen_prologue(struct bpf_program *prog, int n, pev = &priv->pev; -if (n <0 || n >= pev->ntevs) +if (n <0 || n >= priv->nr_types) goto errout; - tev = &pev->tevs[n]; +/* Find a tev belongs to that type */ +for (i =0 ; i < pev->ntevs; i++) { +if (priv->type_mapping[i] == n) +break ; + } + +if (i >= pev->ntevs) { +pr_debug ("Internal error: prologue type %d not found\n" , n); +return -BPF_LOADER_ERRNO__PROLOGUE ; + } + + tev = &pev->tevs[i]; buf = priv->insns_buf; err = bpf__gen_prologue(tev->args, tev->nargs,
@@ -423,6 +437,101 @@ errout:return -BPF_LOADER_ERRNO__PROLOGUE ; } +/* +* compare_tev_args is reflexive, transitive and antisymmetric. +* I can proof it but this margin is too narrow to contain. +*/ +static int compare_tev_args (const void *ptev1,const void *ptev2) +{ +int i, ret; +const struct probe_trace_event *tev1 = + *(const struct probe_trace_event **)ptev1; +const struct probe_trace_event *tev2 = + *(const struct probe_trace_event **)ptev2; + + ret = tev2->nargs - tev1->nargs; +if (ret) +return ret; + +for (i =0 ; i < tev1->nargs; i++) { +struct probe_trace_arg *arg1, *arg2; +struct probe_trace_arg_ref *ref1, *ref2; + + arg1 = &tev1->args[i]; + arg2 = &tev2->args[i]; + + ret =strcmp (arg1->value, arg2->value); +if (ret) +return ret; + + ref1 = arg1->ref; + ref2 = arg2->ref; + +while (ref1 && ref2) { + ret = ref2->offset - ref1->offset; +if (ret) +return ret; + + ref1 = ref1->next; + ref2 = ref2->next; + } + +if (ref1 || ref2) +return ref2 ?1 :-1 ; + } + +return 0 ; +} + +/* +* Assign a type number to each tevs in a pev. +* mapping is an array with same slots as tevs in that pev. +* nr_types will be set to number of types. +*/ +static int map_prologue (struct perf_probe_event *pev,int *mapping, +int *nr_types) +{ +int i, type =0 ; +struct probe_trace_event **ptevs; + +size_t array_sz =sizeof (*ptevs) * pev->ntevs; + + ptevs =malloc (array_sz); +if (!ptevs) { +pr_debug ("No ehough memory: alloc ptevs failed\n" ); +return -ENOMEM ; + } + +pr_debug ("In map_prologue, ntevs=%d\n" , pev->ntevs); +for (i =0 ; i < pev->ntevs; i++) + ptevs[i] = &pev->tevs[i]; + +qsort (ptevs, pev->ntevs,sizeof (*ptevs), + compare_tev_args); + +for (i =0 ; i < pev->ntevs; i++) { +int n; + + n = ptevs[i] - pev->tevs; +if (i ==0 ) { + mapping[n] = type; +pr_debug ("mapping[%d]=%d\n" , n, type); +continue ; + } + +if (compare_tev_args (ptevs + i, ptevs + i -1 ) ==0 ) + mapping[n] = type; +else + mapping[n] = ++type; + +pr_debug ("mapping[%d]=%d\n" , n, mapping[n]); + } +free (ptevs); + *nr_types = type +1 ; + +return 0 ; +} +static int hook_load_preprocessor (struct bpf_program *prog) {struct perf_probe_event *pev;
@@ -462,7 +571,19 @@ static int hook_load_preprocessor(struct bpf_program *prog)return -ENOMEM ; } - err =bpf_program__set_prep (prog, pev->ntevs, + priv->type_mapping =malloc (sizeof (int ) * pev->ntevs); +if (!priv->type_mapping) { +pr_debug ("No enough memory: alloc type_mapping failed\n" ); +return -ENOMEM ; + } +memset (priv->type_mapping,-1 , +sizeof (int ) * pev->ntevs); + + err =map_prologue (pev, priv->type_mapping, &priv->nr_types); +if (err) +return err; + + err =bpf_program__set_prep (prog, priv->nr_types, preproc_gen_prologue);return err; }
@@ -596,10 +717,13 @@ int bpf__foreach_tev(struct bpf_object *obj,for (i =0 ; i < pev->ntevs; i++) { tev = &pev->tevs[i]; -if (priv->need_prologue) - fd =bpf_program__nth_fd (prog, i); -else +if (priv->need_prologue) { +int type = priv->type_mapping[i]; + + fd =bpf_program__nth_fd (prog, type); + }else { fd =bpf_program__fd (prog); + }if (fd <0 ) {pr_debug ("bpf: failed to get file descriptor\n" );
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 16/37 perf tests: Pass the subtest index to each test routine
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Some tests have sub-tests we want to run, so allow passing this.
Wang tried to avoid having to touch all tests, but then, having the test.func in an anonymous union makes the build fail on older compilers, like the one in RHEL6, where:
test a = {
.func = foo,
};
fails.
To fix it leave the func pointer in the main structure and pass the subtest index to all tests, end result function is the same, but we have just one function pointer, not two, with and without the subtest index as an argument.
--- tools/perf/arch/x86/include/arch-tests.h | 8 +-- tools/perf/arch/x86/tests/insn-x86.c | 2 +- tools/perf/arch/x86/tests/intel-cqm.c | 2 +- tools/perf/arch/x86/tests/perf-time-to-tsc.c | 2 +- tools/perf/arch/x86/tests/rdpmc.c | 2 +- tools/perf/tests/attr.c | 2 +- tools/perf/tests/bp_signal.c | 2 +- tools/perf/tests/bp_signal_overflow.c | 2 +- tools/perf/tests/bpf.c | 2 +- tools/perf/tests/builtin-test.c | 6 +-- tools/perf/tests/code-reading.c | 2 +- tools/perf/tests/dso-data.c | 6 +-- tools/perf/tests/dwarf-unwind.c | 2 +- tools/perf/tests/evsel-roundtrip-name.c | 2 +- tools/perf/tests/evsel-tp-sched.c | 2 +- tools/perf/tests/fdarray.c | 4 +- tools/perf/tests/hists_cumulate.c | 2 +- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_link.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/kmod-path.c | 2 +- tools/perf/tests/llvm.c | 2 +- tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/tests/openat-syscall-all-cpus.c | 2 +- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/tests/openat-syscall.c | 2 +- tools/perf/tests/parse-events.c | 2 +- tools/perf/tests/parse-no-sample-id-all.c | 2 +- tools/perf/tests/perf-record.c | 2 +- tools/perf/tests/pmu.c | 2 +- tools/perf/tests/python-use.c | 3 +- tools/perf/tests/sample-parsing.c | 2 +- tools/perf/tests/sw-clock.c | 2 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/tests/task-exit.c | 2 +- tools/perf/tests/tests.h | 78 ++++++++++++++-------------- tools/perf/tests/thread-map.c | 2 +- tools/perf/tests/thread-mg-share.c | 2 +- tools/perf/tests/topology.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 2 +- 42 files changed, 89 insertions(+), 88 deletions(-)
tools/perf/arch/x86/include/arch-tests.h +4 -4
@@ -2,10 +2,10 @@#define ARCH_TESTS_H /* Tests */ -int test__rdpmc (void ); -int test__perf_time_to_tsc (void ); -int test__insn_x86 (void ); -int test__intel_cqm_count_nmi_context (void ); +int test__rdpmc (int subtest); +int test__perf_time_to_tsc (int subtest); +int test__insn_x86 (int subtest); +int test__intel_cqm_count_nmi_context (int subtest);#ifdef HAVE_DWARF_UNWIND_SUPPORT struct thread ;
tools/perf/arch/x86/tests/insn-x86.c +1 -1
@@ -171,7 +171,7 @@ static int test_data_set(struct test_data *dat_set, int x86_64)* verbose (-v) option to see all the instructions and whether or not they * decoded successfuly. */ -int test__insn_x86 (void ) +int test__insn_x86 (int subtest__maybe_unused ) {int ret =0 ;
tools/perf/arch/x86/tests/intel-cqm.c +1 -1
@@ -33,7 +33,7 @@ static pid_t spawn(void)* the last read counter value to avoid triggering a WARN_ON_ONCE() in * smp_call_function_many() caused by sending IPIs from NMI context. */ -int test__intel_cqm_count_nmi_context (void ) +int test__intel_cqm_count_nmi_context (int subtest__maybe_unused ) {struct perf_evlist *evlist =NULL ;struct perf_evsel *evsel =NULL ;
tools/perf/arch/x86/tests/perf-time-to-tsc.c +1 -1
@@ -35,7 +35,7 @@* %0 is returned, otherwise %-1 is returned. If TSC conversion is not * supported then then the test passes but " (not supported)" is printed. */ -int test__perf_time_to_tsc (void ) +int test__perf_time_to_tsc (int subtest__maybe_unused ) {struct record_opts opts = { .mmap_pages =UINT_MAX ,
tools/perf/arch/x86/tests/rdpmc.c +1 -1
@@ -149,7 +149,7 @@ out_close:return 0 ; } -int test__rdpmc (void ) +int test__rdpmc (int subtest__maybe_unused ) {int status =0 ;int wret =0 ;
tools/perf/tests/attr.c +1 -1
@@ -153,7 +153,7 @@ static int run_dir(const char *d, const char *perf)return system (cmd); } -int test__attr (void ) +int test__attr (int subtest__maybe_unused ) {struct stat st;char path_perf[PATH_MAX ];
tools/perf/tests/bp_signal.c +1 -1
@@ -111,7 +111,7 @@ static long long bp_count(int fd)return count; } -int test__bp_signal (void ) +int test__bp_signal (int subtest__maybe_unused ) {struct sigaction sa;long long count1, count2;
tools/perf/tests/bp_signal_overflow.c +1 -1
@@ -58,7 +58,7 @@ static long long bp_count(int fd)#define EXECUTIONS 10000#define THRESHOLD 100 -int test__bp_signal_overflow (void ) +int test__bp_signal_overflow (int subtest__maybe_unused ) {struct perf_event_attr pe;struct sigaction sa;
tools/perf/tests/bpf.c +1 -1
@@ -215,7 +215,7 @@ out:return ret; } -int test__bpf (void ) +int test__bpf (int subtest__maybe_unused ) {unsigned int i;int err;
tools/perf/tests/builtin-test.c +3 -3
@@ -203,7 +203,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const charreturn false; } -static int run_test (struct test *test) +static int run_test (struct test *test,int subtest) {int status, err =-1 , child =fork ();char sbuf[STRERR_BUFSIZE ];
@@ -216,7 +216,7 @@ static int run_test(struct test *test)if (!child) {pr_debug ("test child forked, pid %d\n" ,getpid ()); - err = test->func (); + err = test->func (subtest);exit (err); }
@@ -265,7 +265,7 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) }pr_debug ("\n--- start ---\n" ); - err =run_test (t); + err =run_test (t, i);pr_debug ("---- end ----\n%s:" , t->desc);switch (err) {
tools/perf/tests/code-reading.c +1 -1
@@ -601,7 +601,7 @@ out_err:return err; } -int test__code_reading (void ) +int test__code_reading (int subtest__maybe_unused ) {int ret;
tools/perf/tests/dso-data.c +3 -3
@@ -110,7 +110,7 @@ static int dso__data_fd(struct dso *dso, struct machine *machine)return fd; } -int test__dso_data (void ) +int test__dso_data (int subtest__maybe_unused ) {struct machine machine;struct dso *dso;
@@ -245,7 +245,7 @@ static int set_fd_limit(int n)return setrlimit (RLIMIT_NOFILE , &rlim); } -int test__dso_data_cache (void ) +int test__dso_data_cache (int subtest__maybe_unused ) {struct machine machine;long nr_end, nr =open_files_cnt ();
@@ -302,7 +302,7 @@ int test__dso_data_cache(void)return 0 ; } -int test__dso_data_reopen (void ) +int test__dso_data_reopen (int subtest__maybe_unused ) {struct machine machine;long nr_end, nr =open_files_cnt ();
tools/perf/tests/dwarf-unwind.c +1 -1
@@ -142,7 +142,7 @@ static int krava_1(struct thread *thread)return krava_2 (thread); } -int test__dwarf_unwind (void ) +int test__dwarf_unwind (int subtest__maybe_unused ) {struct machines machines;struct machine *machine;
tools/perf/tests/evsel-roundtrip-name.c +1 -1
@@ -95,7 +95,7 @@ out_delete_evlist:#define perf_evsel__name_array_test (names) \ __perf_evsel__name_array_test(names, ARRAY_SIZE(names)) -int test__perf_evsel__roundtrip_name_test (void ) +int test__perf_evsel__roundtrip_name_test (int subtest__maybe_unused ) {int err =0 , ret =0 ;
tools/perf/tests/evsel-tp-sched.c +1 -1
@@ -32,7 +32,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,return ret; } -int test__perf_evsel__tp_sched_test (void ) +int test__perf_evsel__tp_sched_test (int subtest__maybe_unused ) {struct perf_evsel *evsel =perf_evsel__newtp ("sched" ,"sched_switch" );int ret =0 ;
tools/perf/tests/fdarray.c +2 -2
@@ -25,7 +25,7 @@ static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILEreturn printed +fdarray__fprintf (fda, fp); } -int test__fdarray__filter (void ) +int test__fdarray__filter (int subtest__maybe_unused ) {int nr_fds, expected_fd[2 ], fd, err =TEST_FAIL ;struct fdarray *fda =fdarray__new (5 ,5 );
@@ -103,7 +103,7 @@ out:return err; } -int test__fdarray__add (void ) +int test__fdarray__add (int subtest__maybe_unused ) {int err =TEST_FAIL ;struct fdarray *fda =fdarray__new (2 ,2 );
tools/perf/tests/hists_cumulate.c +1 -1
@@ -686,7 +686,7 @@ out:return err; } -int test__hists_cumulate (void ) +int test__hists_cumulate (int subtest__maybe_unused ) {int err =TEST_FAIL ;struct machines machines;
tools/perf/tests/hists_filter.c +1 -1
@@ -104,7 +104,7 @@ out:return TEST_FAIL ; } -int test__hists_filter (void ) +int test__hists_filter (int subtest__maybe_unused ) {int err =TEST_FAIL ;struct machines machines;
tools/perf/tests/hists_link.c +1 -1
@@ -274,7 +274,7 @@ static int validate_link(struct hists *leader, struct hists *other)return __validate_link (leader,0 ) ||__validate_link (other,1 ); } -int test__hists_link (void ) +int test__hists_link (int subtest__maybe_unused ) {int err =-1 ;struct hists *hists, *first_hists;
tools/perf/tests/hists_output.c +1 -1
@@ -576,7 +576,7 @@ out:return err; } -int test__hists_output (void ) +int test__hists_output (int subtest__maybe_unused ) {int err =TEST_FAIL ;struct machines machines;
tools/perf/tests/keep-tracking.c +1 -1
@@ -49,7 +49,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)* when an event is disabled but a dummy software event is not disabled. If the * test passes %0 is returned, otherwise %-1 is returned. */ -int test__keep_tracking (void ) +int test__keep_tracking (int subtest__maybe_unused ) {struct record_opts opts = { .mmap_pages =UINT_MAX ,
tools/perf/tests/kmod-path.c +1 -1
@@ -49,7 +49,7 @@ static int test_is_kernel_module(const char *path, int cpumode, bool expect)#define M (path, c, e) \ TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e)) -int test__kmod_path__parse (void ) +int test__kmod_path__parse (int subtest__maybe_unused ) {/* path alloc_name alloc_ext kmod comp name ext */ T ("/xxxx/xxxx/x-x.ko" , true , true , true, false,"[x_x]" ,NULL );
tools/perf/tests/llvm.c +1 -1
@@ -131,7 +131,7 @@ out:return ret; } -int test__llvm (void ) +int test__llvm (int subtest__maybe_unused ) {enum test_llvm__testcase i;
tools/perf/tests/mmap-basic.c +1 -1
@@ -16,7 +16,7 @@* Then it checks if the number of syscalls reported as perf events by * the kernel corresponds to the number of syscalls made. */ -int test__basic_mmap (void ) +int test__basic_mmap (int subtest__maybe_unused ) {int err =-1 ;union perf_event *event;
tools/perf/tests/mmap-thread-lookup.c +1 -1
@@ -221,7 +221,7 @@ static int mmap_events(synth_cb synth)* * by using all thread objects. */ -int test__mmap_thread_lookup (void ) +int test__mmap_thread_lookup (int subtest__maybe_unused ) {/* perf_event__synthesize_threads synthesize */ TEST_ASSERT_VAL("failed with sythesizing all",
tools/perf/tests/openat-syscall-all-cpus.c +1 -1
@@ -7,7 +7,7 @@#include "debug.h" #include "stat.h" -int test__openat_syscall_event_on_all_cpus (void ) +int test__openat_syscall_event_on_all_cpus (int subtest__maybe_unused ) {int err =-1 , fd, cpu;struct cpu_map *cpus;
tools/perf/tests/openat-syscall-tp-fields.c +1 -1
@@ -6,7 +6,7 @@#include "tests.h" #include "debug.h" -int test__syscall_openat_tp_fields (void ) +int test__syscall_openat_tp_fields (int subtest__maybe_unused ) {struct record_opts opts = { .target = {
tools/perf/tests/openat-syscall.c +1 -1
@@ -5,7 +5,7 @@#include "debug.h" #include "tests.h" -int test__openat_syscall_event (void ) +int test__openat_syscall_event (int subtest__maybe_unused ) {int err =-1 , fd;struct perf_evsel *evsel;
tools/perf/tests/parse-events.c +1 -1
@@ -1765,7 +1765,7 @@ static void debug_warn(const char *warn, va_list params)fprintf (stderr," Warning: %s\n" , msg); } -int test__parse_events (void ) +int test__parse_events (int subtest__maybe_unused ) {int ret1, ret2 =0 ;
tools/perf/tests/parse-no-sample-id-all.c +1 -1
@@ -67,7 +67,7 @@ struct test_attr_event {* * Return: %0 on success, %-1 if the test fails. */ -int test__parse_no_sample_id_all (void ) +int test__parse_no_sample_id_all (int subtest__maybe_unused ) {int err;
tools/perf/tests/perf-record.c +1 -1
@@ -32,7 +32,7 @@ realloc:return cpu; } -int test__PERF_RECORD (void ) +int test__PERF_RECORD (int subtest__maybe_unused ) {struct record_opts opts = { .target = {
tools/perf/tests/pmu.c +1 -1
@@ -133,7 +133,7 @@ static struct list_head *test_terms_list(void)return &terms; } -int test__pmu (void ) +int test__pmu (int subtest__maybe_unused ) {char *format =test_format_dir_get ();LIST_HEAD (formats);
tools/perf/tests/python-use.c +2 -1
@@ -4,11 +4,12 @@#include <stdio.h> #include <stdlib.h> +#include <linux/compiler.h> #include "tests.h" extern int verbose; -int test__python_use (void ) +int test__python_use (int subtest__maybe_unused ) {char *cmd;int ret;
tools/perf/tests/sample-parsing.c +1 -1
@@ -290,7 +290,7 @@ out_free:* checks sample format bits separately and together. If the test passes %0 is * returned, otherwise %-1 is returned. */ -int test__sample_parsing (void ) +int test__sample_parsing (int subtest__maybe_unused ) {const u64 rf[] = {4 ,5 ,6 ,7 ,12 ,13 ,14 ,15 };u64 sample_type;
tools/perf/tests/sw-clock.c +1 -1
@@ -122,7 +122,7 @@ out_delete_evlist:return err; } -int test__sw_clock_freq (void ) +int test__sw_clock_freq (int subtest__maybe_unused ) {int ret;
tools/perf/tests/switch-tracking.c +1 -1
@@ -305,7 +305,7 @@ out_free_nodes:* evsel->system_wide and evsel->tracking flags (respectively) with other events * sometimes enabled or disabled. */ -int test__switch_tracking (void ) +int test__switch_tracking (int subtest__maybe_unused ) {const char *sched_switch ="sched:sched_switch" ;struct switch_tracking switch_tracking = { .tids =NULL , };
tools/perf/tests/task-exit.c +1 -1
@@ -31,7 +31,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused,* if the number of exit event reported by the kernel is 1 or not * in order to check the kernel returns correct number of event. */ -int test__task_exit (void ) +int test__task_exit (int subtest__maybe_unused ) {int err =-1 ;union perf_event *event;
tools/perf/tests/tests.h +39 -39
87 lines not on this page · raw message
tools/perf/tests/thread-map.c +1 -1
@@ -4,7 +4,7 @@#include "thread_map.h" #include "debug.h" -int test__thread_map (void ) +int test__thread_map (int subtest__maybe_unused ) {struct thread_map *map;
tools/perf/tests/thread-mg-share.c +1 -1
@@ -4,7 +4,7 @@#include "map.h" #include "debug.h" -int test__thread_mg_share (void ) +int test__thread_mg_share (int subtest__maybe_unused ) {struct machines machines;struct machine *machine;
tools/perf/tests/topology.c +1 -1
@@ -84,7 +84,7 @@ static int check_cpu_topology(char *path, struct cpu_map *map)return 0 ; } -int test_session_topology (void ) +int test_session_topology (int subtest__maybe_unused ) {char path[PATH_MAX ];struct cpu_map *map;
tools/perf/tests/vmlinux-kallsyms.c +1 -1
@@ -18,7 +18,7 @@ static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,#define UM (x) kallsyms_map->unmap_ip(kallsyms_map, (x)) -int test__vmlinux_matches_kallsyms (void ) +int test__vmlinux_matches_kallsyms (int subtest__maybe_unused ) {int err =-1 ;struct rb_node *nd;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 17/37 perf test: Print result for each LLVM subtest
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
Currently 'perf test llvm' and 'perf test BPF' have multiple sub-tests, but the result is provided in only one line:
# perf test LLVM 35: Test LLVM searching and compiling : Ok
This patch introduces sub-tests support, allowing 'perf test' to report result for each sub-tests:
# perf test LLVM 35: Test LLVM searching and compiling : 35.1: Basic BPF llvm compiling test : Ok 35.2: Test kbuild searching : Ok 35.3: Compile source for BPF prologue generation test : Ok
When a failure happens:
# cat ~/.perfconfig
[llvm]
clang-path = "/bin/false"
# perf test LLVM
35: Test LLVM searching and compiling :
35.1: Basic BPF llvm compiling test : FAILED!
35.2: Test kbuild searching : Skip
35.3: Compile source for BPF prologue generation test : SkipAnd:
# rm ~/.perfconfig # ./perf test LLVM 35: Test LLVM searching and compiling : 35.1: Basic BPF llvm compiling test : Skip 35.2: Test kbuild searching : Skip 35.3: Compile source for BPF prologue generation test : Skip
Skip by user:
# ./perf test -s 1,`seq -s , 3 42` 1: vmlinux symtab matches kallsyms : Skip (user override) 2: detect openat syscall event : Ok ... 35: Test LLVM searching and compiling : Skip (user override) ...
--- tools/perf/tests/builtin-test.c | 91 ++++++++++++++++++++++++++++++++++------- tools/perf/tests/llvm.c | 65 ++++++++++++++--------------- tools/perf/tests/tests.h | 9 ++++ 3 files changed, 115 insertions(+), 50 deletions(-)
tools/perf/tests/builtin-test.c +76 -15
@@ -160,6 +160,11 @@ static struct test generic_tests[] = { { .desc = "Test LLVM searching and compiling", .func = test__llvm, + .subtest = { + .skip_if_fail = true, + .get_nr = test__llvm_subtest_get_nr, + .get_desc = test__llvm_subtest_get_desc, + }, }, { .desc = "Test topology in session",
@@ -237,6 +242,40 @@ static int run_test(struct test *test, int subtest)for (j =0 ; j <ARRAY_SIZE (tests); j++) \for (t = &tests[j][0 ]; t->func; t++) +static int test_and_print(struct test *t, bool force_skip, int subtest) +{ +int err; + +if (!force_skip) { +pr_debug ("\n--- start ---\n" ); + err =run_test (t, subtest); +pr_debug ("---- end ----\n" ); + }else { +pr_debug ("\n--- force skipped ---\n" ); + err =TEST_SKIP ; + } + +if (!t->subtest.get_nr) +pr_debug ("%s:" , t->desc); +else +pr_debug ("%s subtest %d:" , t->desc, subtest); + +switch (err) { +case TEST_OK : +pr_info (" Ok\n" ); +break ; +case TEST_SKIP : +color_fprintf (stderr,PERF_COLOR_YELLOW ," Skip\n" ); +break ; +case TEST_FAIL : +default : +color_fprintf (stderr,PERF_COLOR_RED ," FAILED!\n" ); +break ; + } + +return err; +} +static int __cmd_test (int argc,const char *argv[],struct intlist *skiplist) {struct test *t;
@@ -264,21 +303,43 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)continue ; } -pr_debug ("\n--- start ---\n" ); - err =run_test (t, i); -pr_debug ("---- end ----\n%s:" , t->desc); - -switch (err) { -case TEST_OK : -pr_info (" Ok\n" ); -break ; -case TEST_SKIP : -color_fprintf (stderr,PERF_COLOR_YELLOW ," Skip\n" ); -break ; -case TEST_FAIL : -default : -color_fprintf (stderr,PERF_COLOR_RED ," FAILED!\n" ); -break ; +if (!t->subtest.get_nr) { +test_and_print (t, false,-1 ); + }else { +int subn = t->subtest.get_nr (); +/* +* minus 2 to align with normal testcases. +* For subtest we print additional '.x' in number. +* for example: +* +* 35: Test LLVM searching and compiling : +* 35.1: Basic BPF llvm compiling test : Ok +*/ +int subw = width >2 ? width -2 : width; +bool skip = false; +int subi; + +if (subn <=0 ) { +color_fprintf (stderr,PERF_COLOR_YELLOW , +" Skip (not compiled in)\n" ); +continue ; + } +pr_info ("\n" ); + +for (subi =0 ; subi < subn; subi++) { +int len =strlen (t->subtest.get_desc (subi)); + +if (subw < len) + subw = len; + } + +for (subi =0 ; subi < subn; subi++) { +pr_info ("%2d.%1d: %-*s:" , i, subi +1 , subw, + t->subtest.get_desc (subi)); + err =test_and_print (t, skip, subi); +if (err !=TEST_OK && t->subtest.skip_if_fail) + skip = true; + } } }
tools/perf/tests/llvm.c +30 -35
81 lines not on this page · raw message
tools/perf/tests/tests.h +9 -0
@@ -1,6 +1,8 @@#ifndef TESTS_H #define TESTS_H +#include <stdbool.h> +#define TEST_ASSERT_VAL (text, cond) \ do { \ if (!(cond)) { \
@@ -27,6 +29,11 @@ enum {struct test {const char *desc;int (*func)(int subtest); +struct { +bool skip_if_fail; +int (*get_nr)(void ); +const char *(*get_desc)(int subtest); + } subtest; };/* Tests */
@@ -66,6 +73,8 @@ int test__fdarray__add(int subtest);int test__kmod_path__parse (int subtest);int test__thread_map (int subtest);int test__llvm (int subtest); +const char *test__llvm_subtest_get_desc (int subtest); +int test__llvm_subtest_get_nr (void );int test__bpf (int subtest);int test_session_topology (int subtest);
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 18/37 perf test: Print result for each BPF subtest
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
This patch prints each sub-tests results for BPF testcases.
Before:
# ./perf test BPF 37: Test BPF filter : Ok
After:
# ./perf test BPF 37: Test BPF filter : 37.1: Test basic BPF filtering : Ok 37.2: Test BPF prologue generation : Ok
When a failure happens:
# cat ~/.perfconfig
[llvm]
clang-path = "/bin/false"
# ./perf test BPF
37: Test BPF filter :
37.1: Test basic BPF filtering : Skip
37.2: Test BPF prologue generation : Skip--- tools/perf/tests/bpf.c | 38 ++++++++++++++++++++++++++++---------- tools/perf/tests/builtin-test.c | 5 +++++ tools/perf/tests/tests.h | 2 ++ 3 files changed, 35 insertions(+), 10 deletions(-)
tools/perf/tests/bpf.c +28 -10
@@ -215,28 +215,46 @@ out:return ret; } -int test__bpf (int subtest__maybe_unused ) +int test__bpf_subtest_get_nr (void ) +{ +return (int )ARRAY_SIZE (bpf_testcase_table); +} + +const char *test__bpf_subtest_get_desc (int i) +{ +if (i <0 || i >= (int )ARRAY_SIZE (bpf_testcase_table)) +return NULL ; +return bpf_testcase_table[i].desc; +} + +int test__bpf (int i) { -unsigned int i;int err; +if (i <0 || i >= (int )ARRAY_SIZE (bpf_testcase_table)) +return TEST_FAIL ; +if (geteuid () !=0 ) {pr_debug ("Only root can run BPF test\n" );return TEST_SKIP ; } -for (i =0 ; i <ARRAY_SIZE (bpf_testcase_table); i++) { - err =__test__bpf (i); + err =__test__bpf (i); +return err; +} -if (err !=TEST_OK ) -return err; - } +#else +int test__bpf_subtest_get_nr (void ) +{ +return 0 ; +} -return TEST_OK ; +const char *test__bpf_subtest_get_desc (int i__maybe_unused ) +{ +return NULL ; } -#else -int test__bpf (void ) +int test__bpf (int i__maybe_unused ) {pr_debug ("Skip BPF test because BPF support is not compiled\n" );return TEST_SKIP ;
tools/perf/tests/builtin-test.c +5 -0
@@ -173,6 +173,11 @@ static struct test generic_tests[] = { { .desc = "Test BPF filter", .func = test__bpf, + .subtest = { + .skip_if_fail = true, + .get_nr = test__bpf_subtest_get_nr, + .get_desc = test__bpf_subtest_get_desc, + }, }, { .func = NULL,
tools/perf/tests/tests.h +2 -0
@@ -76,6 +76,8 @@ int test__llvm(int subtest);const char *test__llvm_subtest_get_desc (int subtest);int test__llvm_subtest_get_nr (void );int test__bpf (int subtest); +const char *test__bpf_subtest_get_desc (int subtest); +int test__bpf_subtest_get_nr (void );int test_session_topology (int subtest);#if defined(__arm__) || defined(__aarch64__)
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 19/37 perf test: Mute test cases error messages if verbose == 0
In reply to Arnaldo Carvalho de MeloFrom: Wang Nan <[email protected]>
Sometimes error messages in breaks the pretty output of 'perf test'. For example:
# mv /lib/modules/4.3.0-rc4+/build/vmlinux{,.bak}
# perf test LLVM BPF
35: Test LLVM searching and compiling :
35.1: Basic BPF llvm compiling test : Ok
35.2: Test kbuild searching : Ok
35.3: Compile source for BPF prologue generation test : Ok
37: Test BPF filter :
37.1: Test basic BPF filtering : Ok
37.2: Test BPF prologue generation :Failed to find the path for kernel: No such file or directory FAILED!This patch mute test cases thoroughly by redirect their stdout and stderr to /dev/null when verbose == 0. After applying this patch:
# ./perf test LLVM BPF 35: Test LLVM searching and compiling : 35.1: Basic BPF llvm compiling test : Ok 35.2: Test kbuild searching : Ok 35.3: Compile source for BPF prologue generation test : Ok 37: Test BPF filter : 37.1: Test basic BPF filtering : Ok 37.2: Test BPF prologue generation : FAILED!
# ./perf test -v LLVM BPF 35: Test LLVM searching and compiling : 35.1: Basic BPF llvm compiling test : --- start --- test child forked, pid 13183 Kernel build dir is set to /lib/modules/4.3.0-rc4+/build set env: KBUILD_DIR=/lib/modules/4.3.0-rc4+/build ... bpf: config 'func=null_lseek file->f_mode offset orig' is ok Looking at the vmlinux_path (7 entries long) Failed to find the path for kernel: No such file or directory bpf_probe: failed to convert perf probe eventsFailed to add events selected by BPF test child finished with -1 ---- end ---- Test BPF filter subtest 1: FAILED!
--- tools/perf/tests/builtin-test.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
tools/perf/tests/builtin-test.c +12 -0
@@ -226,6 +226,18 @@ static int run_test(struct test *test, int subtest)if (!child) {pr_debug ("test child forked, pid %d\n" ,getpid ()); +if (!verbose) { +int nullfd =open ("/dev/null" ,O_WRONLY ); +if (nullfd >=0 ) { +close (STDERR_FILENO ); +close (STDOUT_FILENO ); + +dup2 (nullfd,STDOUT_FILENO ); +dup2 (STDOUT_FILENO ,STDERR_FILENO ); +close (nullfd); + } + } + err = test->func (subtest);exit (err); }
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 20/37 perf probe: Fix to free temporal Dwarf_Frame
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Since dwarf_cfi_addrframe returns malloc'd Dwarf_Frame object, it has to be freed after it is used.
--- tools/perf/util/probe-finder.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
tools/perf/util/probe-finder.c +6 -3
@@ -683,21 +683,24 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) ret =dwarf_getlocation_addr (&fb_attr, pf->addr, &pf->fb_ops, &nops,1 );if (ret <=0 || nops ==0 ) { pf->fb_ops =NULL ; + ret =0 ;#if _ELFUTILS_PREREQ (0 ,142 ) } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && pf->cfi !=NULL ) { -Dwarf_Frame *frame; +Dwarf_Frame *frame =NULL ;if (dwarf_cfi_addrframe (pf->cfi, pf->addr, &frame) !=0 ||dwarf_frame_cfa (frame, &pf->fb_ops, &nops) !=0 ) {pr_warning ("Failed to get call frame on 0x%jx\n" , (uintmax_t )pf->addr); -return -ENOENT ; + ret = -ENOENT ; } +free (frame);#endif }/* Call finder's callback handler */ - ret = pf->callback (sc_die, pf); +if (ret >=0 ) + ret = pf->callback (sc_die, pf);/* *pf->fb_ops will be cached in libdw. Don't free it. */ pf->fb_ops =NULL ;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 21/37 perf machine: Fix machine__findnew_module_map to put registered map
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix machine object to drop the reference to the map object after it inserted it into machine->kmaps.
refcnt debugger shows what happened:
----
==== [2] ====
Unreclaimed map: 0x346f750
Refcount +1 => 1 at
./perf(map__new2+0xb5) [0x4bdea5]
./perf() [0x4b8aaf]
./perf(modules__parse+0xfc) [0x4a9cbc]
./perf() [0x4b83c0]
./perf(machine__create_kernel_maps+0x148) [0x4bb208]
./perf(machine__new_host+0xfa) [0x4bb3fa]
./perf(init_probe_symbol_maps+0x93) [0x5062b3]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f5373899af5]
./perf() [0x4220a9]
Refcount +1 => 2 at
./perf(maps__insert+0x9a) [0x4bfd4a]
./perf() [0x4b8acb]
./perf(modules__parse+0xfc) [0x4a9cbc]
./perf() [0x4b83c0]
./perf(machine__create_kernel_maps+0x148) [0x4bb208]
./perf(machine__new_host+0xfa) [0x4bb3fa]
./perf(init_probe_symbol_maps+0x93) [0x5062b3]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f5373899af5]
./perf() [0x4220a9]
Refcount -1 => 1 at
./perf(map_groups__exit+0x94) [0x4bea54]
./perf(machine__delete+0x3d) [0x4b91ed]
./perf(exit_probe_symbol_maps+0x28) [0x506358]
./perf() [0x45628a]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f5373899af5]
./perf() [0x4220a9]----
This pattern clearly shows that the refcnt of the map is acquired twice by map__new2 and maps__insert but released onlu once at map_groups__exit, when we purge its maps rbtree.
Since maps__insert already reference counted the map, we have to drop the constructor (map__new2) reference count right after inserting it.
These happened in machine__findnew_module_map, as below.
----
# eu-addr2line -e ./perf -f 0x4b8aaf machine__findnew_module_map inlined at util/machine.c:1046 in machine__create_module util/machine.c:582 # eu-addr2line -e ./perf -f 0x4b8acb map_groups__insert inlined at util/machine.c:585 in machine__create_module util/map.h:208 ----
(note that both are at util/machine.c:58X which is
machine__findnew_module_map)
--- tools/perf/util/machine.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/util/machine.c +2 -0
@@ -585,6 +585,8 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,map_groups__insert (&machine->kmaps, map); +/* Put the map here because map_groups__insert alread got it */ +map__put (map); out:free (m.name);return map;
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 22/37 perf machine: Fix machine__destroy_kernel_maps to drop vmlinux_maps references
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix machine__destroy_kernel_maps() to drop vmlinux_maps references before filling it with NULL.
Refcnt debugger shows
==== [1] ====
Unreclaimed map: 0x36b1070
Refcount +1 => 1 at
./perf(map__new2+0xb5) [0x4bdec5]
./perf(machine__create_kernel_maps+0x72) [0x4bb152]
./perf(machine__new_host+0xfa) [0x4bb41a]
./perf(init_probe_symbol_maps+0x93) [0x5062d3]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f1fc9fc4af5]
./perf() [0x4220a9]
Refcount +1 => 2 at
./perf(maps__insert+0x9a) [0x4bfd6a]
./perf(machine__create_kernel_maps+0xc3) [0x4bb1a3]
./perf(machine__new_host+0xfa) [0x4bb41a]
./perf(init_probe_symbol_maps+0x93) [0x5062d3]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f1fc9fc4af5]
./perf() [0x4220a9]
Refcount -1 => 1 at
./perf(map_groups__exit+0x94) [0x4bea74]
./perf(machine__delete+0x3d) [0x4b91fd]
./perf(exit_probe_symbol_maps+0x28) [0x506378]
./perf() [0x45628a]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f1fc9fc4af5]
./perf() [0x4220a9]map__new2() returns map with refcnt = 1, and also map_groups__insert gets it again in__machine__create_kernel_maps().
machine__destroy_kernel_maps() calls map_groups__remove() to decrement the refcnt, but before decrement it again (corresponding to map__new2), it makes vmlinux_maps[type] = NULL. And this may cause a refcnt leak.
--- tools/perf/util/machine.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/machine.c +1 -0
@@ -790,6 +790,7 @@ void machine__destroy_kernel_maps(struct machine *machine) kmap->ref_reloc_sym =NULL ; } +map__put (machine->vmlinux_maps[type]); machine->vmlinux_maps[type] =NULL ; } }
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 23/37 perf machine: Fix to destroy kernel maps when machine exits
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Actually machine__exit forgot to call machine__destroy_kernel_maps.
This fixes some memory leaks on map as below.
Without this fix.
----
./perf probe vfs_read
Added new event:
probe:vfs_read (on vfs_read)
You can now use it in all perf tools, such as:
perf record -e probe:vfs_read -aR sleep 1
REFCNT: BUG: Unreclaimed objects found.
REFCNT: Total 4 objects are not reclaimed.
To see all backtraces, rerun with -v option
----
With this fix.
----
./perf probe vfs_read
Added new event:
probe:vfs_read (on vfs_read)
You can now use it in all perf tools, such as:
perf record -e probe:vfs_read -aR sleep 1
REFCNT: BUG: Unreclaimed objects found.
REFCNT: Total 2 objects are not reclaimed.
To see all backtraces, rerun with -v option
----
--- tools/perf/util/machine.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/util/machine.c +1 -0
@@ -122,6 +122,7 @@ void machine__delete_threads(struct machine *machine)void machine__exit (struct machine *machine) { +machine__destroy_kernel_maps (machine);map_groups__exit (&machine->kmaps);dsos__exit (&machine->dsos);machine__exit_vdso (machine);
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 24/37 perf tools: Make perf_exec_path() always return malloc'd string
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Since system_path() returns malloc'd string if given path is not an absolute path, perf_exec_path() sometimes returns a static string and sometimes returns a malloc'd string depending on the environment variables or command options.
This may cause a memory leak because the caller can not unconditionally free the returned string.
This fixes perf_exec_path() and system_path() to always return a malloc'd string, so the caller can always free it.
--- tools/perf/util/exec_cmd.c | 21 +++++++++++---------- tools/perf/util/exec_cmd.h | 5 +++-- tools/perf/util/help.c | 6 ++++-- 3 files changed, 18 insertions(+), 14 deletions(-)
tools/perf/util/exec_cmd.c +11 -10
@@ -9,17 +9,17 @@static const char *argv_exec_path;static const char *argv0_path; -const char *system_path (const char *path) +char *system_path (const char *path) {static const char *prefix =PREFIX ;struct strbuf d =STRBUF_INIT ;if (is_absolute_path (path)) -return path; +return strdup (path);strbuf_addf (&d,"%s/%s" , prefix, path); path =strbuf_detach (&d,NULL ); -return path; +return (char *)path; }const char *perf_extract_argv0_path (const char *argv0)
@@ -52,17 +52,16 @@ void perf_set_argv_exec_path(const char *exec_path)/* Returns the highest-priority, location to look for perf programs. */ -const char *perf_exec_path (void ) +char *perf_exec_path (void ) { -const char *env; +char *env;if (argv_exec_path) -return argv_exec_path; +return strdup (argv_exec_path); env =getenv (EXEC_PATH_ENVIRONMENT ); -if (env && *env) { -return env; - } +if (env && *env) +return strdup (env);return system_path (PERF_EXEC_PATH ); }
@@ -83,9 +82,11 @@ void setup_path(void) {const char *old_path =getenv ("PATH" );struct strbuf new_path =STRBUF_INIT ; +char *tmp =perf_exec_path (); -add_path (&new_path,perf_exec_path ()); +add_path (&new_path, tmp);add_path (&new_path, argv0_path); +free (tmp);if (old_path)strbuf_addstr (&new_path, old_path);
tools/perf/util/exec_cmd.h +3 -2
@@ -3,10 +3,11 @@extern void perf_set_argv_exec_path (const char *exec_path);extern const char *perf_extract_argv0_path (const char *path); -extern const char *perf_exec_path (void );extern void setup_path (void );extern int execv_perf_cmd (const char **argv);/* NULL terminated */ extern int execl_perf_cmd (const char *cmd, ...); -extern const char *system_path (const char *path); +/* perf_exec_path and system_path return malloc'd string, caller must free it */ +extern char *perf_exec_path (void ); +extern char *system_path (const char *path);#endif /* __PERF_EXEC_CMD_H */
tools/perf/util/help.c +4 -2
@@ -159,7 +159,7 @@ void load_command_list(const char *prefix, struct cmdnames *other_cmds) {const char *env_path =getenv ("PATH" ); -const char *exec_path =perf_exec_path (); +char *exec_path =perf_exec_path ();if (exec_path) {list_commands_in_dir (main_cmds, exec_path, prefix);
@@ -187,6 +187,7 @@ void load_command_list(const char *prefix, sizeof(*other_cmds->names), cmdname_compare);uniq (other_cmds); } +free (exec_path);exclude_cmds (other_cmds, main_cmds); }
@@ -203,13 +204,14 @@ void list_commands(const char *title, struct cmdnames *main_cmds, longest = other_cmds->names[i]->len;if (main_cmds->cnt) { -const char *exec_path =perf_exec_path (); +char *exec_path =perf_exec_path ();printf ("available %s in '%s'\n" , title, exec_path);printf ("----------------" );mput_char ('-' ,strlen (title) +strlen (exec_path));putchar ('\n' );pretty_print_string_list (main_cmds, longest);putchar ('\n' ); +free (exec_path); }if (other_cmds->cnt) {
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 25/37 perf tools: Fix to put new map after inserting to map_groups in dso__load_sym
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix dso__load_sym to put the map object which is already insterted to kmaps.
Refcnt debugger shows
==== [0] ====
Unreclaimed map: 0x39113e0
Refcount +1 => 1 at
./perf(map__new2+0xb5) [0x4be155]
./perf(dso__load_sym+0xee1) [0x503461]
./perf(dso__load_vmlinux+0xbf) [0x4aa6df]
./perf(dso__load_vmlinux_path+0x8c) [0x4aa83c]
./perf() [0x50528a]
./perf(convert_perf_probe_events+0xd79) [0x50ac29]
./perf() [0x45600f]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f152368baf5]
./perf() [0x4220a9]
Refcount +1 => 2 at
./perf(maps__insert+0x9a) [0x4bfffa]
./perf(dso__load_sym+0xf89) [0x503509]
./perf(dso__load_vmlinux+0xbf) [0x4aa6df]
./perf(dso__load_vmlinux_path+0x8c) [0x4aa83c]
./perf() [0x50528a]
./perf(convert_perf_probe_events+0xd79) [0x50ac29]
./perf() [0x45600f]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f152368baf5]
./perf() [0x4220a9]
Refcount -1 => 1 at
./perf(map_groups__exit+0x94) [0x4bed04]
./perf(machine__delete+0xb0) [0x4b9300]
./perf(exit_probe_symbol_maps+0x28) [0x506608]
./perf() [0x45628a]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f152368baf5]
./perf() [0x4220a9]This means that the dso__load_sym calls map__new2 and maps_insert, both of them bump the map refcount, but map_groups__exit will drop just one reference.
Fix it by dropping the refcount after inserting it into kmaps.
--- tools/perf/util/symbol-elf.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/util/symbol-elf.c +2 -0
@@ -1042,6 +1042,8 @@ int dso__load_sym(struct dso *dso, struct map *map, } curr_dso->symtab_type = dso->symtab_type;map_groups__insert (kmaps, curr_map); +/* kmaps already got it */ +map__put (curr_map);dsos__add (&map->groups->machine->dsos, curr_dso);dso__set_loaded (curr_dso, map->type); }else
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 26/37 perf tools: Fix __dsos__addnew to put dso after adding it to the list
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
__dsos__addnew should drop the constructor reference to dso after adding it to the list, because __dsos__add() will get a reference that will be kept while it is in the list.
This fixes DSO leaks when entries are removed to the list and the refcount never gets to zero.
Refcnt debugger shows:
==== [0] ====
Unreclaimed dso: 0x2fccab0
Refcount +1 => 1 at
./perf(dso__new+0x1ff) [0x4a62df]
./perf(__dsos__addnew+0x29) [0x4a6e19]
./perf(dsos__findnew+0xd1) [0x4a7281]
./perf(machine__findnew_kernel+0x27) [0x4a5e17]
./perf() [0x4b8df2]
./perf(machine__create_kernel_maps+0x28) [0x4bb528]
./perf(machine__new_host+0xfa) [0x4bb84a]
./perf(init_probe_symbol_maps+0x93) [0x506713]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f46df132af5]
./perf() [0x4220a9]
Refcount +1 => 2 at
./perf(__dsos__addnew+0xfb) [0x4a6eeb]
./perf(dsos__findnew+0xd1) [0x4a7281]
./perf(machine__findnew_kernel+0x27) [0x4a5e17]
./perf() [0x4b8df2]
./perf(machine__create_kernel_maps+0x28) [0x4bb528]
./perf(machine__new_host+0xfa) [0x4bb84a]
./perf(init_probe_symbol_maps+0x93) [0x506713]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f46df132af5]
./perf() [0x4220a9]
Refcount +1 => 3 at
./perf(dsos__findnew+0x7e) [0x4a722e]
./perf(machine__findnew_kernel+0x27) [0x4a5e17]
./perf() [0x4b8df2]
./perf(machine__create_kernel_maps+0x28) [0x4bb528]
./perf(machine__new_host+0xfa) [0x4bb84a]
./perf(init_probe_symbol_maps+0x93) [0x506713]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f46df132af5]
./perf() [0x4220a9][snip]
--- tools/perf/util/dso.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/util/dso.c +2 -0
@@ -1243,6 +1243,8 @@ struct dso *__dsos__addnew(struct dsos *dsos, const char *name)if (dso !=NULL ) {__dsos__add (dsos, dso);dso__set_basename (dso); +/* Put dso here because __dsos_add already got it */ +dso__put (dso); }return dso; }
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 27/37 perf tools: Fix machine__create_kernel_maps to put kernel dso refcount
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix machine__create_kernel_maps() to put kernel dso because the dso has been gotten via __machine__create_kernel_maps().
Refcnt debugger shows:
==== [0] ====
Unreclaimed dso: 0x3036ab0
Refcount +1 => 1 at
./perf(dso__new+0x1ff) [0x4a62df]
./perf(__dsos__addnew+0x29) [0x4a6e19]
./perf(dsos__findnew+0xd1) [0x4a7181]
./perf(machine__findnew_kernel+0x27) [0x4a5e17]
./perf() [0x4b8cf2]
./perf(machine__create_kernel_maps+0x28) [0x4bb428]
./perf(machine__new_host+0xfa) [0x4bb74a]
./perf(init_probe_symbol_maps+0x93) [0x506613]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7ffa6809eaf5]
./perf() [0x4220a9]
[snip]
Refcount +1 => 2 at
./perf(dsos__findnew+0x7e) [0x4a712e]
./perf(machine__findnew_kernel+0x27) [0x4a5e17]
./perf() [0x4b8cf2]
./perf(machine__create_kernel_maps+0x28) [0x4bb428]
./perf(machine__new_host+0xfa) [0x4bb74a]
./perf(init_probe_symbol_maps+0x93) [0x506613]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7ffa6809eaf5]
./perf() [0x4220a9]
[snip]
Refcount -1 => 1 at
./perf(dso__put+0x2f) [0x4a664f]
./perf(machine__delete+0xfe) [0x4b93ee]
./perf(exit_probe_symbol_maps+0x28) [0x5066b8]
./perf() [0x45628a]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7ffa6809eaf5]
./perf() [0x4220a9]Actually, dsos__findnew gets the dso before returning it, so the dso user (in this case machine__create_kernel_maps) has to put the dso after used.
--- tools/perf/util/machine.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
tools/perf/util/machine.c +6 -3
@@ -1088,11 +1088,14 @@ int machine__create_kernel_maps(struct machine *machine)struct dso *kernel =machine__get_kernel (machine);const char *name;u64 addr =machine__get_running_kernel_start (machine, &name); -if (!addr) +int ret; + +if (!addr || kernel ==NULL )return -1 ; -if (kernel ==NULL || -__machine__create_kernel_maps (machine, kernel) <0 ) + ret =__machine__create_kernel_maps (machine, kernel); +dso__put (kernel); +if (ret <0 )return -1 ;if (symbol_conf.use_modules &&machine__create_modules (machine) <0 ) {
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 28/37 perf machine: Fix machine__findnew_module_map to put dso
In reply to Arnaldo Carvalho de MeloFrom: Masami Hiramatsu <[email protected]>
Fix machine__findnew_module_map to drop the reference to the dso because it is already referenced by both machine__findnew_module_dso() and map__new2().
Refcnt debugger shows:
==== [1] ====
Unreclaimed dso: 0x1ffd980
Refcount +1 => 1 at
./perf(dso__new+0x1ff) [0x4a62df]
./perf(__dsos__addnew+0x29) [0x4a6e19]
./perf() [0x4b8b91]
./perf(modules__parse+0xfc) [0x4a9d5c]
./perf() [0x4b8460]
./perf(machine__create_kernel_maps+0x150) [0x4bb550]
./perf(machine__new_host+0xfa) [0x4bb75a]
./perf(init_probe_symbol_maps+0x93) [0x506623]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f1345a8eaf5]
./perf() [0x4220a9]This map_groups__insert(0x4b8b91) already gets a reference to the new dso:
----
eu-addr2line -e ./perf -f 0x4b8b91 map_groups__insert inlined at util/machine.c:586 in machine__create_module
util/map.h:207
----
So this dso refcnt will be released when map_groups gets released.
[snip]
Refcount +1 => 2 at
./perf(dso__get+0x34) [0x4a65f4]
./perf() [0x4b8b35]
./perf(modules__parse+0xfc) [0x4a9d5c]
./perf() [0x4b8460]
./perf(machine__create_kernel_maps+0x150) [0x4bb550]
./perf(machine__new_host+0xfa) [0x4bb75a]
./perf(init_probe_symbol_maps+0x93) [0x506623]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f1345a8eaf5]
./perf() [0x4220a9]Here, machine__findnew_module_dso(0x4b8b35) gets the dso (and stores it in a local variable):
----
# eu-addr2line -e ./perf -f 0x4b8b35 machine__findnew_module_dso inlined at util/machine.c:578 in machine__create_module util/machine.c:514 ----
Refcount +1 => 3 at
./perf(dso__get+0x34) [0x4a65f4]
./perf(map__new2+0x76) [0x4be1c6]
./perf() [0x4b8b4f]
./perf(modules__parse+0xfc) [0x4a9d5c]
./perf() [0x4b8460]
./perf(machine__create_kernel_maps+0x150) [0x4bb550]
./perf(machine__new_host+0xfa) [0x4bb75a]
./perf(init_probe_symbol_maps+0x93) [0x506623]
./perf() [0x455ffa]
./perf(cmd_probe+0x6c) [0x4566bc]
./perf() [0x47abc5]
./perf(main+0x610) [0x421f90]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f1345a8eaf5]
./perf() [0x4220a9]But also map__new2() gets the dso which will be put when the map is released.
So, we have to drop the constructor reference obtained in machine__findnew_module_dso().
--- tools/perf/util/machine.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/util/machine.c +3 -1
@@ -565,7 +565,7 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start, const char *filename) {struct map *map =NULL ; -struct dso *dso; +struct dso *dso =NULL ;struct kmod_path m;if (kmod_path__parse_name (&m, filename))
@@ -589,6 +589,8 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,/* Put the map here because map_groups__insert alread got it */ map__put (map); out: +/* put the dso here, corresponding to machine__findnew_module_dso */ +dso__put (dso);free (m.name);return map; }
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 29/37 perf report: Support folded callchain mode on --stdio
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Add new call chain option (-g) 'folded' to print callchains in a line. The callchains are separated by semicolons, and preceded by (absolute) percent values and a space.
For example, the following 20 lines can be printed in 3 lines with the folded output mode:
$ perf report -g flat --no-children | grep -v ^# | head -20
60.48% swapper [kernel.vmlinux] [k] intel_idle
54.60%
intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
cpu_startup_entry
start_secondary 5.88%
intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
cpu_startup_entry
rest_init
start_kernel
x86_64_start_reservations
x86_64_start_kernel $ perf report -g folded --no-children | grep -v ^# | head -3
60.48% swapper [kernel.vmlinux] [k] intel_idle
54.60% intel_idle;cpuidle_enter_state;cpuidle_enter;call_cpuidle;cpu_startup_entry;start_secondary
5.88% intel_idle;cpuidle_enter_state;cpuidle_enter;call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernelThis mode is supported only for --stdio now and intended to be used by some scripts like in FlameGraphs[1]. Support for other UI might be added later.
[1] http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html
--- tools/perf/Documentation/perf-report.txt | 1 + tools/perf/ui/stdio/hist.c | 55 ++++++++++++++++++++++++++++++++ tools/perf/util/callchain.c | 6 ++++ tools/perf/util/callchain.h | 5 +-- 4 files changed, 65 insertions(+), 2 deletions(-)
tools/perf/Documentation/perf-report.txt +1 -0
@@ -181,6 +181,7 @@ OPTIONS - graph: use a graph tree, displaying absolute overhead rates. (default) - fractal: like graph, but displays relative rates. Each branch of the tree is considered as a new profiled object. + - folded: call chains are displayed in a line, separated by semicolons - none: disable call chain display. threshold is a percentage value which specifies a minimum percent to be
tools/perf/ui/stdio/hist.c +55 -0
67 lines not on this page · raw message
tools/perf/util/callchain.c +6 -0
@@ -44,6 +44,10 @@ static int parse_callchain_mode(const char *value) callchain_param.mode =CHAIN_GRAPH_REL ;return 0 ; } +if (!strncmp (value,"folded" ,strlen (value))) { + callchain_param.mode =CHAIN_FOLDED ; +return 0 ; + }return -1 ; }
@@ -218,6 +222,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,switch (mode) {case CHAIN_FLAT : +case CHAIN_FOLDED :if (rnode->hit < chain->hit) p = &(*p)->rb_left;else
@@ -338,6 +343,7 @@ int callchain_register_param(struct callchain_param *param) param->sort = sort_chain_graph_rel;break ;case CHAIN_FLAT : +case CHAIN_FOLDED : param->sort = sort_chain_flat;break ;case CHAIN_NONE :
tools/perf/util/callchain.h +3 -2
@@ -24,7 +24,7 @@#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP#define CALLCHAIN_REPORT_HELP \ - HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|none)\n" \ + HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|folded|none)\n" \ HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \ HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \ HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \
@@ -43,7 +43,8 @@ enum chain_mode {CHAIN_NONE ,CHAIN_FLAT ,CHAIN_GRAPH_ABS , -CHAIN_GRAPH_REL +CHAIN_GRAPH_REL , + CHAIN_FOLDED, }; enum chain_order {
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 30/37 perf callchain: Abstract callchain print function
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
This is a preparation to support for printing other type of callchain value like count or period.
--- tools/perf/ui/browsers/hists.c | 8 +++++--- tools/perf/ui/gtk/hists.c | 8 ++------ tools/perf/ui/stdio/hist.c | 35 +++++++++++++++++------------------ tools/perf/util/callchain.c | 29 +++++++++++++++++++++++++++++ tools/perf/util/callchain.h | 4 ++++ 5 files changed, 57 insertions(+), 27 deletions(-)
tools/perf/ui/browsers/hists.c +5 -3
@@ -592,7 +592,6 @@ static int hist_browser__show_callchain(struct hist_browser *browser,while (node) { struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);struct rb_node *next =rb_next (node); -u64 cumul =callchain_cumul_hits (child);struct callchain_list *chain;char folded_sign =' ' ;int first = true;
@@ -619,9 +618,12 @@ static int hist_browser__show_callchain(struct hist_browser *browser, browser->show_dso);if (was_first && need_percent) { -double percent = cumul *100.0 / total; +char buf[64 ]; -if (asprintf (&alloc_str,"%2.2f%% %s" , percent, str) <0 ) +callchain_node__scnprintf_value (child, buf,sizeof (buf), + total); + +if (asprintf (&alloc_str,"%s %s" , buf, str) <0 ) str ="Not enough memory!" ;else str = alloc_str;
tools/perf/ui/gtk/hists.c +2 -6
@@ -100,14 +100,10 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,struct callchain_list *chain;GtkTreeIter iter, new_parent;bool need_new_parent; -double percent; -u64 hits, child_total; +u64 child_total; node = rb_entry(nd, struct callchain_node, rb_node); - hits =callchain_cumul_hits (node); - percent =100.0 * hits / total; - new_parent = *parent; need_new_parent = !has_single_node && (node->val_nr >1 );
@@ -116,7 +112,7 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,gtk_tree_store_append (store, &iter, &new_parent); -scnprintf (buf,sizeof (buf),"%5.2f%%" , percent); +callchain_node__scnprintf_value (node, buf,sizeof (buf), total);gtk_tree_store_set (store, &iter,0 , buf,-1 );callchain_list__sym_name (chain, buf,sizeof (buf), false);
tools/perf/ui/stdio/hist.c +17 -18
@@ -34,10 +34,10 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,return ret; } -static size_t ipchain__fprintf_graph (FILE *fp,struct callchain_list *chain, +static size_t ipchain__fprintf_graph (FILE *fp,struct callchain_node *node, +struct callchain_list *chain,int depth,int depth_mask,int period, -u64 total_samples,u64 hits, -int left_margin) +u64 total_samples,int left_margin) {int i;size_t ret =0 ;
@@ -50,10 +50,9 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,else ret +=fprintf (fp," " );if (!period && i == depth -1 ) { -double percent; - - percent = hits *100.0 / total_samples; - ret +=percent_color_fprintf (fp,"--%2.2f%%-- " , percent); + ret +=fprintf (fp,"--" ); + ret +=callchain_node__fprintf_value (node, fp, total_samples); + ret +=fprintf (fp,"--" ); }else ret +=fprintf (fp,"%s" ," " ); }
@@ -120,10 +119,9 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, left_margin); i =0 ;list_for_each_entry (chain, &child->val, list) { - ret +=ipchain__fprintf_graph (fp, chain, depth, + ret +=ipchain__fprintf_graph (fp, child, chain, depth, new_depth_mask, i++, total_samples, - cumul, left_margin); }
@@ -143,14 +141,17 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,if (callchain_param.mode ==CHAIN_GRAPH_REL && remaining && remaining != total_samples) { +struct callchain_node rem_node = { + .hit = remaining, + };if (!rem_sq_bracket)return ret; new_depth_mask &= ~(1 << (depth -1 )); - ret +=ipchain__fprintf_graph (fp, &rem_hits, depth, + ret +=ipchain__fprintf_graph (fp, &rem_node, &rem_hits, depth, new_depth_mask,0 , total_samples, - remaining, left_margin); + left_margin); }return ret;
@@ -243,12 +244,11 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,struct rb_node *rb_node =rb_first (tree);while (rb_node) { -double percent; - chain = rb_entry(rb_node, struct callchain_node, rb_node); - percent = chain->hit *100.0 / total_samples; - ret =percent_color_fprintf (fp," %6.2f%%\n" , percent); + ret +=fprintf (fp," " ); + ret +=callchain_node__fprintf_value (chain, fp, total_samples); + ret +=fprintf (fp,"\n" ); ret +=__callchain__fprintf_flat (fp, chain, total_samples); ret +=fprintf (fp,"\n" );if (++entries_printed == callchain_param.print_limit)
@@ -295,12 +295,11 @@ static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,struct rb_node *rb_node =rb_first (tree);while (rb_node) { -double percent; chain = rb_entry(rb_node, struct callchain_node, rb_node); - percent = chain->hit *100.0 / total_samples; - ret +=fprintf (fp,"%.2f%% " , percent); + ret +=callchain_node__fprintf_value (chain, fp, total_samples); + ret +=fprintf (fp," " ); ret +=__callchain__fprintf_folded (fp, chain); ret +=fprintf (fp,"\n" );if (++entries_printed == callchain_param.print_limit)
tools/perf/util/callchain.c +29 -0
@@ -805,6 +805,35 @@ char *callchain_list__sym_name(struct callchain_list *cl,return bf; } +char *callchain_node__scnprintf_value (struct callchain_node *node, +char *bf,size_t bfsize,u64 total) +{ +double percent =0.0 ; +u64 period =callchain_cumul_hits (node); + +if (callchain_param.mode ==CHAIN_FOLDED ) + period = node->hit; +if (total) + percent = period *100.0 / total; + +scnprintf (bf, bfsize,"%.2f%%" , percent); +return bf; +} + +int callchain_node__fprintf_value (struct callchain_node *node, +FILE *fp,u64 total) +{ +double percent =0.0 ; +u64 period =callchain_cumul_hits (node); + +if (callchain_param.mode ==CHAIN_FOLDED ) + period = node->hit; +if (total) + percent = period *100.0 / total; + +return percent_color_fprintf (fp,"%.2f%%" , percent); +} +static void free_callchain_node (struct callchain_node *node) {struct callchain_list *list, *tmp;
tools/perf/util/callchain.h +4 -0
@@ -230,6 +230,10 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,char *callchain_list__sym_name (struct callchain_list *cl,char *bf,size_t bfsize,bool show_dso); +char *callchain_node__scnprintf_value (struct callchain_node *node, +char *bf,size_t bfsize,u64 total); +int callchain_node__fprintf_value (struct callchain_node *node, +FILE *fp,u64 total);void free_callchain (struct callchain_root *root);
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 31/37 perf callchain: Add count fields to struct callchain_node
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
It's to track the count of occurrences of the callchains.
--- tools/perf/util/callchain.c | 10 ++++++++++ tools/perf/util/callchain.h | 7 +++++++ 2 files changed, 17 insertions(+)
tools/perf/util/callchain.c +10 -0
@@ -437,6 +437,8 @@ add_child(struct callchain_node *parent, new->children_hit =0 ; new->hit = period; + new->children_count =0 ; + new->count =1 ;return new; }
@@ -484,6 +486,9 @@ split_add_child(struct callchain_node *parent, parent->children_hit =callchain_cumul_hits (new); new->val_nr = parent->val_nr - idx_local; parent->val_nr = idx_local; + new->count = parent->count; + new->children_count = parent->children_count; + parent->children_count =callchain_cumul_counts (new);/* create a new child for the new branch if any */ if (idx_total < cursor->nr) {
@@ -494,6 +499,8 @@ split_add_child(struct callchain_node *parent, parent->hit =0 ; parent->children_hit += period; + parent->count =0 ; + parent->children_count +=1 ; node =callchain_cursor_current (cursor); new =add_child (parent, cursor, period);
@@ -516,6 +523,7 @@ split_add_child(struct callchain_node *parent,rb_insert_color (&new->rb_node_in, &parent->rb_root_in); }else { parent->hit = period; + parent->count =1 ; } }
@@ -562,6 +570,7 @@ append_chain_children(struct callchain_node *root, inc_children_hit: root->children_hit += period; + root->children_count++; } static int
@@ -614,6 +623,7 @@ append_chain(struct callchain_node *root,/* we match 100% of the path, increment the hit */ if (matches == root->val_nr && cursor->pos == cursor->nr) { root->hit += period; + root->count++;return 0 ; }
tools/perf/util/callchain.h +7 -0
@@ -60,6 +60,8 @@ struct callchain_node {struct rb_root rb_root_in;/* input tree of children */ struct rb_root rb_root;/* sorted output tree of children */ unsigned int val_nr; +unsigned int count; +unsigned int children_count;u64 hit;u64 children_hit; };
@@ -145,6 +147,11 @@ static inline u64 callchain_cumul_hits(struct callchain_node *node)return node->hit + node->children_hit; } +static inline unsigned callchain_cumul_counts (struct callchain_node *node) +{ +return node->count + node->children_count; +} +int callchain_register_param (struct callchain_param *param); int callchain_append(struct callchain_root *root, struct callchain_cursor *cursor,
Signature · 1 line
2.1.0
Re: [PATCH 31/37] perf callchain: Add count fields to struct callchain_node
Namhyung,
Quoted 3 lines · Arnaldo Carvalho de Melo
From: Namhyung Kim <[email protected]>
It's to track the count of occurrences of the callchains.
Please explain why you do something like this in the changelog, even just a single line to tell which feature is going to use this and why.
No need to resend just for that, it's just for future patches.
Thanks.
Namhyung Kim
maintainerRe: [PATCH 31/37] perf callchain: Add count fields to struct callchain_node
Hi Frederic,
Quoted 11 lines · Frederic Weisbecker
Namhyung,
Quoted 3 lines · Arnaldo Carvalho de Melo
From: Namhyung Kim <[email protected]>
It's to track the count of occurrences of the callchains.
Please explain why you do something like this in the changelog, even just a single line to tell which feature is going to use this and why.
No need to resend just for that, it's just for future patches.
OK, I'll keep in mind that.
This patch is a preparation for supporting different callchain value output style. Instead of current percent output, it could have period or count with this change.
Thanks,
Namhyung
Arnaldo Carvalho de Melo
maintainerPATCH 32/37 perf report: Add callchain value option
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
Now -g/--call-graph option supports how to display callchain values. Possible values are 'percent', 'period' and 'count'. The percent is same as before and it's the default behavior. The period displays the raw period value rather than the percentage. The count displays the number of occurrences.
$ perf report --no-children --stdio -g percent
...
39.93% swapper [kernel.vmlinux] [k] intel_idel
|
---intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
cpu_startup_entry
|
|--28.63%-- start_secondary
|
--11.30%-- rest_init $ perf report --no-children --show-total-period --stdio -g period
...
39.93% 13018705 swapper [kernel.vmlinux] [k] intel_idel
|
---intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
cpu_startup_entry
|
|--9334403-- start_secondary
|
--3684302-- rest_init $ perf report --no-children --show-nr-samples --stdio -g count
...
39.93% 80 swapper [kernel.vmlinux] [k] intel_idel
|
---intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
cpu_startup_entry
|
|--57-- start_secondary
|
--23-- rest_init--- tools/perf/Documentation/perf-report.txt | 13 ++++--- tools/perf/builtin-report.c | 4 +-- tools/perf/ui/stdio/hist.c | 10 +++++- tools/perf/util/callchain.c | 62 +++++++++++++++++++++++++++----- tools/perf/util/callchain.h | 10 +++++- tools/perf/util/util.c | 3 +- 6 files changed, 84 insertions(+), 18 deletions(-)
tools/perf/Documentation/perf-report.txt +9 -4
@@ -170,11 +170,11 @@ OPTIONS Dump raw trace in ASCII. -g:: ---call-graph=<print_type,threshold[,print_limit],order,sort_key,branch>:: +--call-graph=<print_type,threshold[,print_limit],order,sort_key[,branch],value>:: Display call chains using type, min percent threshold, print limit, - call order, sort key and branch. Note that ordering of parameters is not - fixed so any parement can be given in an arbitraty order. One exception - is the print_limit which should be preceded by threshold. + call order, sort key, optional branch and value. Note that ordering of + parameters is not fixed so any parement can be given in an arbitraty order. + One exception is the print_limit which should be preceded by threshold. print_type can be either: - flat: single column, linear exposure of call chains.
@@ -205,6 +205,11 @@ OPTIONS - branch: include last branch information in callgraph when available. Usually more convenient to use --branch-history for this. + value can be: + - percent: diplay overhead percent (default) + - period: display event period + - count: display event count + --children:: Accumulate callchain of children to parent entry so that then can show up in the output. The output will have a new "Children" column
tools/perf/builtin-report.c +2 -2
@@ -625,7 +625,7 @@ parse_percent_limit(const struct option *opt, const char *str,return 0 ; } -#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function" +#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"const char report_callchain_help[] ="Display call graph (stack chain/backtrace):\n\n" CALLCHAIN_REPORT_HELP
@@ -708,7 +708,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)OPT_BOOLEAN ('x' ,"exclude-other" , &symbol_conf.exclude_other,"Only display entries with parent-match" ),OPT_CALLBACK_DEFAULT ('g' ,"call-graph" , &report, -"print_type,threshold[,print_limit],order,sort_key[,branch]" , +"print_type,threshold[,print_limit],order,sort_key[,branch],value" , report_callchain_help, &report_parse_callchain_opt, callchain_default_opt), OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
tools/perf/ui/stdio/hist.c +9 -1
@@ -81,13 +81,14 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, int depth_mask, int left_margin) {struct rb_node *node, *next; -struct callchain_node *child; +struct callchain_node *child =NULL ;struct callchain_list *chain;int new_depth_mask = depth_mask;u64 remaining;size_t ret =0 ;int i;uint entries_printed =0 ; +int cumul_count =0 ; remaining = total_samples;
@@ -99,6 +100,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, child = rb_entry(node, struct callchain_node, rb_node); cumul =callchain_cumul_hits (child); remaining -= cumul; + cumul_count +=callchain_cumul_counts (child);/* * The depth mask manages the output of pipes that show
@@ -148,6 +150,12 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,if (!rem_sq_bracket)return ret; +if (callchain_param.value ==CCVAL_COUNT && child && child->parent) { + rem_node.count = child->parent->children_count - cumul_count; +if (rem_node.count <=0 ) +return ret; + } + new_depth_mask &= ~(1 << (depth -1 )); ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth, new_depth_mask, 0, total_samples,
tools/perf/util/callchain.c +53 -9
92 lines not on this page · raw message
tools/perf/util/callchain.h +9 -1
@@ -29,7 +29,8 @@HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \HELP_PAD "sort_key:\tcall graph sort key (function|address)\n" \ -HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" +HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" \ +HELP_PAD "value:\t\tcall graph value (percent|period|count)\n" enum perf_call_graph_mode { CALLCHAIN_NONE,
@@ -81,6 +82,12 @@ enum chain_key {CCKEY_ADDRESS }; +enum chain_value { +CCVAL_PERCENT , +CCVAL_PERIOD , +CCVAL_COUNT , +}; +struct callchain_param {bool enabled;enum perf_call_graph_mode record_mode;
@@ -93,6 +100,7 @@ struct callchain_param {bool order_set;enum chain_key key;bool branch_callstack; +enum chain_value value; };extern struct callchain_param callchain_param;
tools/perf/util/util.c +2 -1
@@ -21,7 +21,8 @@ struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_ABS, .min_percent = 0.5, .order = ORDER_CALLEE, - .key = CCKEY_FUNCTION + .key = CCKEY_FUNCTION, + .value = CCVAL_PERCENT, };/*
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 33/37 perf hists browser: Factor out hist_browser__show_callchain_list()
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
This function is to print a single callchain list entry. As this function will be used by other function, factor out to a separate function.
--- tools/perf/ui/browsers/hists.c | 72 ++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 27 deletions(-)
tools/perf/ui/browsers/hists.c +45 -27
@@ -574,6 +574,44 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u#define LEVEL_OFFSET_STEP 3 +static int hist_browser__show_callchain_list (struct hist_browser *browser, +struct callchain_node *node, +struct callchain_list *chain, +unsigned short row,u64 total, +bool need_percent,int offset, +print_callchain_entry_fn print, +struct callchain_print_arg *arg) +{ +char bf[1024 ], *alloc_str; +const char *str; + +if (arg->row_offset !=0 ) { + arg->row_offset--; +return 0 ; + } + + alloc_str =NULL ; + str =callchain_list__sym_name (chain, bf,sizeof (bf), + browser->show_dso); + +if (need_percent) { +char buf[64 ]; + +callchain_node__scnprintf_value (node, buf,sizeof (buf), + total); + +if (asprintf (&alloc_str,"%s %s" , buf, str) <0 ) + str ="Not enough memory!" ; +else + str = alloc_str; + } + +free (alloc_str); +return 1 ; +} + static int hist_browser__show_callchain(struct hist_browser *browser, struct rb_root *root, int level, unsigned short row, u64 total,
@@ -598,8 +636,6 @@ static int hist_browser__show_callchain(struct hist_browser *browser,int extra_offset =0 ;list_for_each_entry (chain, &child->val, list) { -char bf[1024 ], *alloc_str; -const char *str;bool was_first = first;if (first)
@@ -608,34 +644,16 @@ static int hist_browser__show_callchain(struct hist_browser *browser, extra_offset =LEVEL_OFFSET_STEP ; folded_sign =callchain_list__folded (chain); -if (arg->row_offset !=0 ) { - arg->row_offset--; - goto do_next; - } - alloc_str =NULL ; - str =callchain_list__sym_name (chain, bf,sizeof (bf), - browser->show_dso); + row +=hist_browser__show_callchain_list (browser, child, + chain, row, total, + was_first && need_percent, + offset + extra_offset, + print, arg); -if (was_first && need_percent) { -char buf[64 ]; - -callchain_node__scnprintf_value (child, buf,sizeof (buf), - total); - -if (asprintf (&alloc_str,"%s %s" , buf, str) <0 ) - str ="Not enough memory!" ; -else - str = alloc_str; - } - -free (alloc_str); - -if (is_output_full (browser, ++row)) +if (is_output_full (browser, row)) goto out; -do_next: +if (folded_sign =='+' )break ; }
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 34/37 perf hists browser: Support flat callchains
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The flat callchain mode is to print all chains in a single, simple hierarchy so make it easy to see.
Currently perf report --tui doesn't show flat callchains properly. With flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes. To do that, add parent_val list to struct callchain_node and show them along with the (normal) val list.
For example, consider following callchains with '-g graph'.
$ perf report -g graph
- 39.93% swapper [kernel.vmlinux] [k] intel_idle
intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
- cpu_startup_entry
28.63% start_secondary
- 11.30% rest_init
start_kernel
x86_64_start_reservations
x86_64_start_kernelBefore:
$ perf report -g flat
- 39.93% swapper [kernel.vmlinux] [k] intel_idle
28.63% start_secondary
- 11.30% rest_init
start_kernel
x86_64_start_reservations
x86_64_start_kernelAfter:
$ perf report -g flat
- 39.93% swapper [kernel.vmlinux] [k] intel_idle
- 28.63% intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
cpu_startup_entry
start_secondary
- 11.30% intel_idle
cpuidle_enter_state
cpuidle_enter
call_cpuidle
cpu_startup_entry
start_kernel
x86_64_start_reservations
x86_64_start_kernel--- tools/perf/ui/browsers/hists.c | 122 ++++++++++++++++++++++++++++++++++++++++- tools/perf/util/callchain.c | 44 +++++++++++++++ tools/perf/util/callchain.h | 2 + 3 files changed, 166 insertions(+), 2 deletions(-)
tools/perf/ui/browsers/hists.c +120 -2
@@ -178,12 +178,44 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)return n; } +static int callchain_node__count_flat_rows (struct callchain_node *node) +{ +struct callchain_list *chain; +char folded_sign =0 ; +int n =0 ; + +list_for_each_entry (chain, &node->parent_val, list) { +if (!folded_sign) { +/* only check first chain list entry */ + folded_sign =callchain_list__folded (chain); +if (folded_sign =='+' ) +return 1 ; + } + n++; + } + +list_for_each_entry (chain, &node->val, list) { +if (!folded_sign) { +/* node->parent_val list might be empty */ + folded_sign =callchain_list__folded (chain); +if (folded_sign =='+' ) +return 1 ; + } + n++; + } + +return n; +} +static int callchain_node__count_rows (struct callchain_node *node) {struct callchain_list *chain;bool unfolded = false;int n =0 ; +if (callchain_param.mode ==CHAIN_FLAT ) +return callchain_node__count_flat_rows (node); +list_for_each_entry (chain, &node->val, list) { ++n; unfolded = chain->unfolded;
@@ -263,7 +295,7 @@ static void callchain_node__init_have_children(struct callchain_node *node, chain = list_entry(node->val.next, struct callchain_list, list); chain->has_children = has_sibling; -if (!list_empty (&node->val)) { +if (node->val.next != node->val.prev) { chain = list_entry(node->val.prev, struct callchain_list, list); chain->has_children = !RB_EMPTY_ROOT (&node->rb_root); }
@@ -279,6 +311,8 @@ static void callchain__init_have_children(struct rb_root *root)for (nd =rb_first (root); nd; nd =rb_next (nd)) { struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);callchain_node__init_have_children (node, has_sibling); +if (callchain_param.mode ==CHAIN_FLAT ) +callchain_node__make_parent_list (node); } }
@@ -612,6 +646,83 @@ static int hist_browser__show_callchain_list(struct hist_browser *browser,return 1 ; } +static int hist_browser__show_callchain_flat (struct hist_browser *browser, +struct rb_root *root, +unsigned short row,u64 total, +print_callchain_entry_fn print, +struct callchain_print_arg *arg, +check_output_full_fn is_output_full) +{ +struct rb_node *node; +int first_row = row, offset =LEVEL_OFFSET_STEP ; +bool need_percent; + + node =rb_first (root); + need_percent = node &&rb_next (node); + +while (node) { + struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); +struct rb_node *next =rb_next (node); +struct callchain_list *chain; +char folded_sign =' ' ; +int first = true; +int extra_offset =0 ; + +list_for_each_entry (chain, &child->parent_val, list) { +bool was_first = first; + +if (first) + first = false; +else if (need_percent) + extra_offset =LEVEL_OFFSET_STEP ; + + folded_sign =callchain_list__folded (chain); + + row +=hist_browser__show_callchain_list (browser, child, + chain, row, total, + was_first && need_percent, + offset + extra_offset, + print, arg); + +if (is_output_full (browser, row)) + goto out; + +if (folded_sign =='+' ) + goto next; + } + +list_for_each_entry (chain, &child->val, list) { +bool was_first = first; + +if (first) + first = false; +else if (need_percent) + extra_offset =LEVEL_OFFSET_STEP ; + + folded_sign =callchain_list__folded (chain); + + row +=hist_browser__show_callchain_list (browser, child, + chain, row, total, + was_first && need_percent, + offset + extra_offset, + print, arg); + +if (is_output_full (browser, row)) + goto out; + +if (folded_sign =='+' ) +break ; + } + +next: +if (is_output_full (browser, row)) +break ; + node = next; + } +out: +return row - first_row; +} + static int hist_browser__show_callchain(struct hist_browser *browser, struct rb_root *root, int level, unsigned short row, u64 total,
@@ -864,10 +975,17 @@ static int hist_browser__show_entry(struct hist_browser *browser, total = entry->stat.period; } - printed +=hist_browser__show_callchain (browser, +if (callchain_param.mode ==CHAIN_FLAT ) { + printed +=hist_browser__show_callchain_flat (browser, + &entry->sorted_chain, row, total, + hist_browser__show_callchain_entry, &arg, + hist_browser__check_output_full); + }else { + printed +=hist_browser__show_callchain (browser, &entry->sorted_chain,1 , row, total, hist_browser__show_callchain_entry, &arg, hist_browser__check_output_full); + }if (arg.is_current_entry) browser->he_selection = entry;
tools/perf/util/callchain.c +44 -0
59 lines not on this page · raw message
tools/perf/util/callchain.h +2 -0
@@ -56,6 +56,7 @@ enum chain_order {struct callchain_node {struct callchain_node *parent;struct list_head val; +struct list_head parent_val;struct rb_node rb_node_in;/* to insert nodes in an rbtree */ struct rb_node rb_node;/* to sort nodes in an output tree */ struct rb_root rb_root_in;/* input tree of children */
@@ -251,5 +252,6 @@ int callchain_node__fprintf_value(struct callchain_node *node, FILE *fp, u64 total);void free_callchain (struct callchain_root *root); +int callchain_node__make_parent_list (struct callchain_node *node);#endif /* __PERF_CALLCHAIN_H */
Signature · 1 line
2.1.0
Re: [PATCH 34/37] perf hists browser: Support flat callchains
Quoted 64 lines · Arnaldo Carvalho de Melo
From: Namhyung Kim <[email protected]>
The flat callchain mode is to print all chains in a single, simple hierarchy so make it easy to see.
Currently perf report --tui doesn't show flat callchains properly. With flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes. To do that, add
parent_vallist to structcallchain_nodeand show them along with the (normal) val list.For example, consider following callchains with '-g graph'.
$ perf report -g graph - 39.93% swapper [kernel.vmlinux] [k] intel_idle intel_idle cpuidle_enter_state cpuidle_enter call_cpuidle - cpu_startup_entry 28.63% start_secondary - 11.30% rest_init start_kernel x86_64_start_reservations x86_64_start_kernelBefore:
$ perf report -g flat - 39.93% swapper [kernel.vmlinux] [k] intel_idle 28.63% start_secondary - 11.30% rest_init start_kernel x86_64_start_reservations x86_64_start_kernelAfter:
$ perf report -g flat - 39.93% swapper [kernel.vmlinux] [k] intel_idle - 28.63% intel_idle cpuidle_enter_state cpuidle_enter call_cpuidle cpu_startup_entry start_secondary - 11.30% intel_idle cpuidle_enter_state cpuidle_enter call_cpuidle cpu_startup_entry start_kernel x86_64_start_reservations x86_64_start_kernelSigned-off-by Namhyung Kim <[email protected]>Tested-by Brendan Gregg <[email protected]>Cc Andi Kleen <[email protected]>Cc David Ahern <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Jiri Olsa <[email protected]>Cc Kan Liang <[email protected]>Cc Peter Zijlstra <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>---
[...]
Quoted 17 lines
tools/perf/util/callchain.c +17
-0+int callchain_node__make_parent_list (struct callchain_node *node) +{ +struct callchain_node *parent = node->parent; +struct callchain_list *chain, *new; +LIST_HEAD (head); + +while (parent) { +list_for_each_entry_reverse (chain, &parent->val, list) { + new =malloc (sizeof (*new)); +if (new ==NULL ) + goto out; + *new = *chain; + new->has_children = false; +list_add_tail (&new->list, &head); + } + parent = parent->parent; + }
tools/perf/util/callchain.c void free_callchain(struct callchain_root *root) · line 953
Quoted 10 lines
tools/perf/util/callchain.c +10
-0+ +list_for_each_entry_safe_reverse (chain, new, &head, list) +list_move_tail (&chain->list, &node->parent_val); + +if (!list_empty (&node->parent_val)) { + chain = list_first_entry(&node->parent_val, struct callchain_list, list); + chain->has_children =rb_prev (&node->rb_node) ||rb_next (&node->rb_node); + + chain = list_first_entry(&node->val, struct callchain_list, list); + chain->has_children = false;
I'm a bit puzzled with this, can't we rewind through the parents on printing or adding to the flat rbtree instead of having this parent_val field?
Thanks.
Namhyung Kim
maintainerRe: [PATCH 34/37] perf hists browser: Support flat callchains
Quoted 90 lines · Frederic Weisbecker
Quoted 64 lines · Arnaldo Carvalho de Melo
From: Namhyung Kim <[email protected]>
The flat callchain mode is to print all chains in a single, simple hierarchy so make it easy to see.
Currently perf report --tui doesn't show flat callchains properly. With flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes. To do that, add
parent_vallist to structcallchain_nodeand show them along with the (normal) val list.For example, consider following callchains with '-g graph'.
$ perf report -g graph - 39.93% swapper [kernel.vmlinux] [k] intel_idle intel_idle cpuidle_enter_state cpuidle_enter call_cpuidle - cpu_startup_entry 28.63% start_secondary - 11.30% rest_init start_kernel x86_64_start_reservations x86_64_start_kernelBefore:
$ perf report -g flat - 39.93% swapper [kernel.vmlinux] [k] intel_idle 28.63% start_secondary - 11.30% rest_init start_kernel x86_64_start_reservations x86_64_start_kernelAfter:
$ perf report -g flat - 39.93% swapper [kernel.vmlinux] [k] intel_idle - 28.63% intel_idle cpuidle_enter_state cpuidle_enter call_cpuidle cpu_startup_entry start_secondary - 11.30% intel_idle cpuidle_enter_state cpuidle_enter call_cpuidle cpu_startup_entry start_kernel x86_64_start_reservations x86_64_start_kernelSigned-off-by Namhyung Kim <[email protected]>Tested-by Brendan Gregg <[email protected]>Cc Andi Kleen <[email protected]>Cc David Ahern <[email protected]>Cc Frederic Weisbecker <[email protected]>Cc Jiri Olsa <[email protected]>Cc Kan Liang <[email protected]>Cc Peter Zijlstra <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>---
[...]
Quoted 22 lines
tools/perf/util/callchain.c +22
-0+int callchain_node__make_parent_list (struct callchain_node *node) +{ +struct callchain_node *parent = node->parent; +struct callchain_list *chain, *new; +LIST_HEAD (head); + +while (parent) { +list_for_each_entry_reverse (chain, &parent->val, list) { + new =malloc (sizeof (*new)); +if (new ==NULL ) + goto out; + *new = *chain; + new->has_children = false; +list_add_tail (&new->list, &head); + } + parent = parent->parent; + } + +list_for_each_entry_safe_reverse (chain, new, &head, list) +list_move_tail (&chain->list, &node->parent_val); + +if (!list_empty (&node->parent_val)) {
Quoted 8 lines
tools/perf/util/callchain.c void free_callchain(struct callchain_root *root) · line 953
Quoted 5 lines
tools/perf/util/callchain.c +5
-0+ chain = list_first_entry(&node->parent_val, struct callchain_list, list); + chain->has_children =rb_prev (&node->rb_node) ||rb_next (&node->rb_node); + + chain = list_first_entry(&node->val, struct callchain_list, list); + chain->has_children = false;I'm a bit puzzled with this, can't we rewind through the parents on printing or adding to the flat rbtree instead of having this
parent_valfield?
Yes, this code is to simplify things on parent nodes. Maybe we could go up to parents and print the callchain list there as you said.
However, problem I think is how to handle 'has_children' information on parents. That info controls folding status of each callchain. As the info is in the struct callchain_list and flat or folded callchain mode require the info should be in the top-most entry, I cannot share entries in parent nodes.
Thus I simply copied callchain lists in parents to leaf nodes. Yes, it will consume some memory but can simplify the code.
Thank you for your review anyway!
Namhyung
Re: [PATCH 34/37] perf hists browser: Support flat callchains
Em Tue, Nov 24, 2015 at 02:27:08PM +0900, Namhyung Kim escreveu:
Quoted 39 lines · Frederic Weisbecker
Quoted 26 lines · Arnaldo Carvalho de Melo
Quoted 1 line
From: Namhyung Kim <[email protected]>
[...]
Quoted 22 lines
tools/perf/util/callchain.c +22
-0+int callchain_node__make_parent_list (struct callchain_node *node) +{ +struct callchain_node *parent = node->parent; +struct callchain_list *chain, *new; +LIST_HEAD (head); + +while (parent) { +list_for_each_entry_reverse (chain, &parent->val, list) { + new =malloc (sizeof (*new)); +if (new ==NULL ) + goto out; + *new = *chain; + new->has_children = false; +list_add_tail (&new->list, &head); + } + parent = parent->parent; + } + +list_for_each_entry_safe_reverse (chain, new, &head, list) +list_move_tail (&chain->list, &node->parent_val); + +if (!list_empty (&node->parent_val)) {Quoted 8 lines
tools/perf/util/callchain.c void free_callchain(struct callchain_root *root) · line 953
Quoted 5 lines
tools/perf/util/callchain.c +5
-0+ chain = list_first_entry(&node->parent_val, struct callchain_list, list); + chain->has_children =rb_prev (&node->rb_node) ||rb_next (&node->rb_node); + + chain = list_first_entry(&node->val, struct callchain_list, list); + chain->has_children = false;I'm a bit puzzled with this, can't we rewind through the parents on printing or adding to the flat rbtree instead of having this
parent_valfield?Yes, this code is to simplify things on parent nodes. Maybe we could go up to parents and print the callchain list there as you said.
Quoted 8 lines
However, problem I think is how to handle '
has_children' information on parents. That info controls folding status of each callchain. As the info is in the structcallchain_listand flat or folded callchain mode require the info should be in the top-most entry, I cannot share entries in parent nodes.Thus I simply copied callchain lists in parents to leaf nodes. Yes, it will consume some memory but can simplify the code.
I haven't done any measuring, but I'm noticing that 'perf top -g' is showing more warnings about not being able to process events fast enough and so ends up losing events, I tried with --max-stack 16 and it helped, this is just a heads up.
Perhaps my workstation workloads are gettning deeper callchains over time, but perhaps this is the cost of processing callchains that is increasing, I need to stop and try to quantify this.
We really need to look at reducing the overhead of processing callchains.
- Arnaldo
Namhyung Kim
maintainerRe: [PATCH 34/37] perf hists browser: Support flat callchains
Hi Arnaldo,
Quoted 46 lines · Arnaldo Carvalho de Melo
Em Tue, Nov 24, 2015 at 02:27:08PM +0900, Namhyung Kim escreveu:
Quoted 45 lines · Frederic Weisbecker
Quoted 26 lines · Arnaldo Carvalho de Melo
Quoted 1 line
From: Namhyung Kim <[email protected]>
[...]
Quoted 22 lines
tools/perf/util/callchain.c +22
-0+int callchain_node__make_parent_list (struct callchain_node *node) +{ +struct callchain_node *parent = node->parent; +struct callchain_list *chain, *new; +LIST_HEAD (head); + +while (parent) { +list_for_each_entry_reverse (chain, &parent->val, list) { + new =malloc (sizeof (*new)); +if (new ==NULL ) + goto out; + *new = *chain; + new->has_children = false; +list_add_tail (&new->list, &head); + } + parent = parent->parent; + } + +list_for_each_entry_safe_reverse (chain, new, &head, list) +list_move_tail (&chain->list, &node->parent_val); + +if (!list_empty (&node->parent_val)) {Quoted 8 lines
tools/perf/util/callchain.c void free_callchain(struct callchain_root *root) · line 953
Quoted 5 lines
tools/perf/util/callchain.c +5
-0+ chain = list_first_entry(&node->parent_val, struct callchain_list, list); + chain->has_children =rb_prev (&node->rb_node) ||rb_next (&node->rb_node); + + chain = list_first_entry(&node->val, struct callchain_list, list); + chain->has_children = false;I'm a bit puzzled with this, can't we rewind through the parents on printing or adding to the flat rbtree instead of having this
parent_valfield?Yes, this code is to simplify things on parent nodes. Maybe we could go up to parents and print the callchain list there as you said.
However, problem I think is how to handle '
has_children' information on parents. That info controls folding status of each callchain. As the info is in the structcallchain_listand flat or folded callchain mode require the info should be in the top-most entry, I cannot share entries in parent nodes.
Quoted 7 lines
Quoted 2 lines
Thus I simply copied callchain lists in parents to leaf nodes. Yes, it will consume some memory but can simplify the code.
I haven't done any measuring, but I'm noticing that 'perf top -g' is showing more warnings about not being able to process events fast enough and so ends up losing events, I tried with --max-stack 16 and it helped, this is just a heads up.
OK, but it seems that it's not related to this patch since this patch only affects flat or folded callchain mode.
Quoted 7 lines
Perhaps my workstation workloads are gettning deeper callchains over time, but perhaps this is the cost of processing callchains that is increasing, I need to stop and try to quantify this.
We really need to look at reducing the overhead of processing callchains.
Right, but with my multi-thread work, I realized that perf is getting heavier recently. I guess it's mostly due to the atomic refcount work. I need to get back to the multi-thread work..
Anyway I made a initial multi-thread support for perf top too. I think I posted it to the list, but I cannot find the link. You can take a look at it on 'perf/top-threaded-v1' branch in my tree.
git.kernel.org/pub/scm/linux/kernel/git/namhyung/linux-perf.git
Thanks,
Namhyung
Re: [PATCH 34/37] perf hists browser: Support flat callchains
Em Wed, Nov 25, 2015 at 10:26:08AM +0900, Namhyung Kim escreveu:
Quoted 9 lines · Arnaldo Carvalho de Melo
Quoted 8 lines
Em Tue, Nov 24, 2015 at 02:27:08PM +0900, Namhyung Kim escreveu:
Quoted 6 lines · Frederic Weisbecker
Quoted 3 lines · Arnaldo Carvalho de Melo
Quoted 1 line
From: Namhyung Kim <[email protected]>
[...]
Thus I simply copied callchain lists in parents to leaf nodes. Yes, it will consume some memory but can simplify the code.
Quoted 7 lines
Quoted 4 lines
I haven't done any measuring, but I'm noticing that 'perf top -g' is showing more warnings about not being able to process events fast enough and so ends up losing events, I tried with --max-stack 16 and it helped, this is just a heads up.
OK, but it seems that it's not related to this patch since this patch only affects flat or folded callchain mode.
Well, doesn't this patch makes some of the involved data structures larger, thus putting more pressure on the L1 cache, etc? It may well be related, but we need to measure.
Quoted 10 lines
Quoted 6 lines
Perhaps my workstation workloads are gettning deeper callchains over time, but perhaps this is the cost of processing callchains that is increasing, I need to stop and try to quantify this.
We really need to look at reducing the overhead of processing callchains.
Right, but with my multi-thread work, I realized that perf is getting heavier recently. I guess it's mostly due to the atomic refcount work. I need to get back to the multi-thread work..
We really need to measure this ;-)
- Arnaldo
Re: [PATCH 34/37] perf hists browser: Support flat callchains
Em Tue, Nov 24, 2015 at 10:34:18PM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 26 lines
Em Wed, Nov 25, 2015 at 10:26:08AM +0900, Namhyung Kim escreveu:
Quoted 9 lines · Arnaldo Carvalho de Melo
Quoted 8 lines
Em Tue, Nov 24, 2015 at 02:27:08PM +0900, Namhyung Kim escreveu:
Quoted 6 lines · Frederic Weisbecker
Quoted 3 lines · Arnaldo Carvalho de Melo
Quoted 1 line
From: Namhyung Kim <[email protected]>
[...]
Thus I simply copied callchain lists in parents to leaf nodes. Yes, it will consume some memory but can simplify the code.
Quoted 7 lines
Quoted 4 lines
I haven't done any measuring, but I'm noticing that 'perf top -g' is showing more warnings about not being able to process events fast enough and so ends up losing events, I tried with --max-stack 16 and it helped, this is just a heads up.
OK, but it seems that it's not related to this patch since this patch only affects flat or folded callchain mode.
Well, doesn't this patch makes some of the involved data structures larger, thus putting more pressure on the L1 cache, etc? It may well be related, but we need to measure.
Quoted 4 lines
Quoted 4 lines
Perhaps my workstation workloads are gettning deeper callchains over time, but perhaps this is the cost of processing callchains that is increasing, I need to stop and try to quantify this.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
We really need to look at reducing the overhead of processing callchains.
Right, but with my multi-thread work, I realized that perf is getting heavier recently. I guess it's mostly due to the atomic refcount work. I need to get back to the multi-thread work..
We really need to measure this ;-)
So, something strange, if I use:
[acme@zoo linux]$ cat ~/bin/allmod
rm -rf ../build/allmodconfig/ ; mkdir ../build/allmodconfig/ ; make O=../build/allmodconfig/ allmodconfig ; make -j32 O=../build/allmodconfig [acme@zoo linux]$
To generate background load, I don't see that much this:
+ 8.55% 8.49% libc-2┌─Warning!──────────────────────────────────────────────┐ ▒ + 7.08% 6.98% perf │Events are being lost, check IO/CPU overload! │ ▒ + 6.84% 0.04% perf │ │ ▒ + 6.01% 0.09% perf │You may want to run 'perf' using a RT scheduler policy:│ ▒ + 5.26% 0.13% [kerne│ │t▒ + 4.96% 1.50% perf │ perf top -r 80 │ ▒ + 4.76% 3.58% perf │ │ ▒ + 4.69% 0.05% perf │Or reduce the sampling frequency. │ ▒
Its with a low loadavg:
[acme@zoo linux]$ cat /proc/loadavg
0.75 0.79 0.64 3/549 21259
That it pops up :-\
If I take a snapshot with 'P'
# head -40 perf.hist.0
+ 21.43% 21.09% libc-2.20.so [.] _int_malloc
+ 19.49% 0.00% perf [.] cmd_top
+ 19.46% 0.02% perf [.] perf_top__mmap_read_idx
+ 19.03% 0.06% perf [.] hist_entry_iter__add
+ 16.46% 1.85% perf [.] iter_add_next_cumulative_entry
+ 12.09% 11.98% libc-2.20.so [.] free
+ 10.68% 10.61% libc-2.20.so [.] __libc_calloc
+ 9.61% 0.09% perf [.] hists__decay_entries
+ 8.92% 8.85% libc-2.20.so [.] malloc_consolidate
+ 8.17% 6.33% perf [.] free_callchain_node
+ 7.94% 0.09% perf [.] hist_entry__delete
+ 6.22% 0.03% perf [.] callchain_append
+ 6.20% 6.11% perf [.] append_chain_children
+ 5.44% 1.50% perf [.] __hists__add_entry
+ 4.34% 0.14% [kernel] [k] entry_SYSCALL_64_fastpath
+ 3.69% 3.67% perf [.] sort__dso_cmp
+ 3.12% 0.20% perf [.] hists__output_resort
+ 2.88% 0.00% [unknown] [.] 0x6d86258d4c544155
+ 2.88% 0.00% libc-2.20.so [.] __libc_start_main
+ 2.88% 0.00% perf [.] main
+ 2.88% 0.00% perf [.] run_builtin
+ 2.66% 0.00% libpthread-2.20.so [.] start_thread
+ 2.66% 0.00% perf [.] display_thread_tui
+ 2.66% 0.00% perf [.] perf_evlist__tui_browse_hists
+ 2.66% 0.00% perf [.] perf_evsel__hists_browse
+ 2.49% 0.07% [kernel] [k] sys_futex
+ 2.42% 0.06% [kernel] [k] do_futex
2.24% 0.00% perf [.] perf_top__sort_new_samples
+ 1.92% 0.51% perf [.] hists__collapse_resort
+ 1.87% 1.86% perf [.] hpp__sort_overhead_acc
+ 1.69% 0.09% libc-2.20.so [.] __lll_unlock_wake_private
+ 1.45% 1.44% perf [.] hpp__nop_cmp
1.45% 1.43% perf [.] rb_erase
+ 1.44% 1.42% perf [.] __sort__hpp_cmp
1.31% 0.16% libc-2.20.so [.] __lll_lock_wait_private
1.18% 0.19% [kernel] [k] futex_wake
+ 1.13% 1.13% perf [.] sort__sym_cmp
1.11% 0.02% [kernel] [k] schedule
1.09% 0.22% [kernel] [k] __schedule
0.99% 0.08% [kernel] [k] futex_waitSo its quite a lot of mallocs, i.e. just do a 'perf top -g' and wait a bit, malloc goes on bubbling up to the top, about the same time it starts showing that popup screen telling that we're losing events.
If I use --no-children, to see if there is a difference, using either --call-graph caller or callee, it doesn't get more than about 1%.
Ok, now I tried with "perf top --call-graph caller" i.e. with --children, and looked at the _int_malloc callchains I get really long, bogus callchains, see below. That explains why I don't lose events when I use --max-stack.
I'll have to stop now, and I put the full perf.hist.1 at
http://vger.kernel.org/~acme/perf/perf.hist.1.xz
- Arnaldo
[root@zoo ~]# head -60 perf.hist.1
- 17.92% 17.10% libc-2.20.so [.] _int_malloc
+ 112.80% _int_malloc
11.14% 0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068Namhyung Kim
maintainerRe: [PATCH 34/37] perf hists browser: Support flat callchains
Hi Arnaldo,
Quoted 174 lines · Arnaldo Carvalho de Melo
Em Tue, Nov 24, 2015 at 10:34:18PM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 26 lines
Em Wed, Nov 25, 2015 at 10:26:08AM +0900, Namhyung Kim escreveu:
Quoted 9 lines · Arnaldo Carvalho de Melo
Quoted 8 lines
Em Tue, Nov 24, 2015 at 02:27:08PM +0900, Namhyung Kim escreveu:
Quoted 6 lines · Frederic Weisbecker
Quoted 3 lines · Arnaldo Carvalho de Melo
Quoted 1 line
From: Namhyung Kim <[email protected]>
[...]
Thus I simply copied callchain lists in parents to leaf nodes. Yes, it will consume some memory but can simplify the code.
Quoted 7 lines
Quoted 4 lines
I haven't done any measuring, but I'm noticing that 'perf top -g' is showing more warnings about not being able to process events fast enough and so ends up losing events, I tried with --max-stack 16 and it helped, this is just a heads up.
OK, but it seems that it's not related to this patch since this patch only affects flat or folded callchain mode.
Well, doesn't this patch makes some of the involved data structures larger, thus putting more pressure on the L1 cache, etc? It may well be related, but we need to measure.
Quoted 4 lines
Quoted 4 lines
Perhaps my workstation workloads are gettning deeper callchains over time, but perhaps this is the cost of processing callchains that is increasing, I need to stop and try to quantify this.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
We really need to look at reducing the overhead of processing callchains.
Right, but with my multi-thread work, I realized that perf is getting heavier recently. I guess it's mostly due to the atomic refcount work. I need to get back to the multi-thread work..
We really need to measure this ;-)
So, something strange, if I use:
[acme@zoo linux]$ cat ~/bin/allmod
rm -rf ../build/allmodconfig/ ; mkdir ../build/allmodconfig/ ; make O=../build/allmodconfig/ allmodconfig ; make -j32 O=../build/allmodconfig [acme@zoo linux]$To generate background load, I don't see that much this:
(quoted diff) +8
-0+ 8.55% 8.49% libc-2┌─Warning!──────────────────────────────────────────────┐ ▒ + 7.08% 6.98% perf │Events are being lost, check IO/CPU overload! │ ▒ + 6.84% 0.04% perf │ │ ▒ + 6.01% 0.09% perf │You may want to run 'perf' using a RT scheduler policy:│ ▒ + 5.26% 0.13% [kerne│ │t▒ + 4.96% 1.50% perf │ perf top -r 80 │ ▒ + 4.76% 3.58% perf │ │ ▒ + 4.69% 0.05% perf │Or reduce the sampling frequency. │ ▒Its with a low loadavg:
[acme@zoo linux]$ cat
/proc/loadavg
0.75 0.79 0.64 3/549 21259That it pops up :-\
If I take a snapshot with 'P'
# head -40 perf.hist.0(quoted diff) +33
-0+ 21.43% 21.09% libc-2.20.so [.] _int_malloc + 19.49% 0.00% perf [.] cmd_top + 19.46% 0.02% perf [.] perf_top__mmap_read_idx + 19.03% 0.06% perf [.] hist_entry_iter__add + 16.46% 1.85% perf [.] iter_add_next_cumulative_entry + 12.09% 11.98% libc-2.20.so [.] free + 10.68% 10.61% libc-2.20.so [.] __libc_calloc + 9.61% 0.09% perf [.] hists__decay_entries + 8.92% 8.85% libc-2.20.so [.] malloc_consolidate + 8.17% 6.33% perf [.] free_callchain_node + 7.94% 0.09% perf [.] hist_entry__delete + 6.22% 0.03% perf [.] callchain_append + 6.20% 6.11% perf [.] append_chain_children + 5.44% 1.50% perf [.] __hists__add_entry + 4.34% 0.14% [kernel] [k] entry_SYSCALL_64_fastpath + 3.69% 3.67% perf [.] sort__dso_cmp + 3.12% 0.20% perf [.] hists__output_resort + 2.88% 0.00% [unknown] [.] 0x6d86258d4c544155 + 2.88% 0.00% libc-2.20.so [.] __libc_start_main + 2.88% 0.00% perf [.] main + 2.88% 0.00% perf [.] run_builtin + 2.66% 0.00% libpthread-2.20.so [.] start_thread + 2.66% 0.00% perf [.] display_thread_tui + 2.66% 0.00% perf [.] perf_evlist__tui_browse_hists + 2.66% 0.00% perf [.] perf_evsel__hists_browse + 2.49% 0.07% [kernel] [k] sys_futex + 2.42% 0.06% [kernel] [k] do_futex 2.24% 0.00% perf [.] perf_top__sort_new_samples + 1.92% 0.51% perf [.] hists__collapse_resort + 1.87% 1.86% perf [.] hpp__sort_overhead_acc + 1.69% 0.09% libc-2.20.so [.] __lll_unlock_wake_private + 1.45% 1.44% perf [.] hpp__nop_cmp 1.45% 1.43% perf [.] rb_erase + 1.44% 1.42% perf [.] __sort__hpp_cmp 1.31% 0.16% libc-2.20.so [.] __lll_lock_wait_private 1.18% 0.19% [kernel] [k] futex_wake + 1.13% 1.13% perf [.] sort__sym_cmp 1.11% 0.02% [kernel] [k] schedule 1.09% 0.22% [kernel] [k] __schedule 0.99% 0.08% [kernel] [k] futex_waitSo its quite a lot of mallocs, i.e. just do a 'perf top -g' and wait a bit, malloc goes on bubbling up to the top, about the same time it starts showing that popup screen telling that we're losing events.
If I use --no-children, to see if there is a difference, using either --call-graph caller or callee, it doesn't get more than about 1%.
Ok, now I tried with "perf top --call-graph caller" i.e. with --children, and looked at the
_int_malloccallchains I get really long, bogus callchains, see below. That explains why I don't lose events when I use --max-stack.I'll have to stop now, and I put the full perf.hist.1 at
http://vger.kernel.org/~acme/perf/perf.hist.1.xz- Arnaldo
[root@zoo ~]# head -60 perf.hist.1
- 17.92% 17.10% libc-2.20.so [.]_int_malloc
+ 112.80%_int_malloc11.14% 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068 0x41bf5118 0x41bf5068
Quoted 8 lines
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068
0x41bf5118
0x41bf5068Hmm.. we should cut off the loop in the broken callchains. And it'd be good to apply --hide-unresolved to callchains as well. I'll take a look at it.
Thanks,
Namhyung
Arnaldo Carvalho de Melo
maintainerPATCH 35/37 perf hists browser: Support folded callchains
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The folded callchain mode prints all chains in a single line.
Currently perf report --tui doesn't support folded callchains. Like flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes. To do that, add flat_val list to struct callchain_node and show them along with the (normal) val list.
For example, folded callchain looks like below:
$ perf report -g folded --tui
Samples: 234 of event 'cycles:pp', Event count (approx.): 32605268
Overhead Command Shared Object Symbol
- 39.93% swapper [kernel.vmlinux] [k] intel_idle
+ 28.63% intel_idle; cpuidle_enter_state; cpuidle_enter; ...
+ 11.30% intel_idle; cpuidle_enter_state; cpuidle_enter; ...--- tools/perf/ui/browsers/hists.c | 125 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +124 -1
@@ -207,6 +207,11 @@ static int callchain_node__count_flat_rows(struct callchain_node *node)return n; } +static int callchain_node__count_folded_rows (struct callchain_node *node__maybe_unused ) +{ +return 1 ; +} +static int callchain_node__count_rows (struct callchain_node *node) {struct callchain_list *chain;
@@ -215,6 +220,8 @@ static int callchain_node__count_rows(struct callchain_node *node)if (callchain_param.mode ==CHAIN_FLAT )return callchain_node__count_flat_rows (node); +else if (callchain_param.mode ==CHAIN_FOLDED ) +return callchain_node__count_folded_rows (node);list_for_each_entry (chain, &node->val, list) { ++n;
@@ -311,7 +318,8 @@ static void callchain__init_have_children(struct rb_root *root)for (nd =rb_first (root); nd; nd =rb_next (nd)) { struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);callchain_node__init_have_children (node, has_sibling); -if (callchain_param.mode ==CHAIN_FLAT ) +if (callchain_param.mode ==CHAIN_FLAT || + callchain_param.mode ==CHAIN_FOLDED )callchain_node__make_parent_list (node); } }
@@ -723,6 +731,116 @@ out:return row - first_row; } +static char *hist_browser__folded_callchain_str (struct hist_browser *browser, +struct callchain_list *chain, +char *value_str,char *old_str) +{ +char bf[1024 ]; +const char *str; +char *new; + + str =callchain_list__sym_name (chain, bf,sizeof (bf), + browser->show_dso); +if (old_str) { +if (asprintf (&new,"%s%s%s" , old_str, + symbol_conf.field_sep ?:";" , str) <0 ) + new =NULL ; + }else { +if (value_str) { +if (asprintf (&new,"%s %s" , value_str, str) <0 ) + new =NULL ; + }else { +if (asprintf (&new,"%s" , str) <0 ) + new =NULL ; + } + } +return new; +} + +static int hist_browser__show_callchain_folded (struct hist_browser *browser, +struct rb_root *root, +unsigned short row,u64 total, +print_callchain_entry_fn print, +struct callchain_print_arg *arg, +check_output_full_fn is_output_full) +{ +struct rb_node *node; +int first_row = row, offset =LEVEL_OFFSET_STEP ; +bool need_percent; + + node =rb_first (root); + need_percent = node &&rb_next (node); + +while (node) { + struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); +struct rb_node *next =rb_next (node); +struct callchain_list *chain, *first_chain =NULL ; +int first = true; +char *value_str =NULL , *value_str_alloc =NULL ; +char *chain_str =NULL , *chain_str_alloc =NULL ; + +if (arg->row_offset !=0 ) { + arg->row_offset--; + goto next; + } + +if (need_percent) { +char buf[64 ]; + +callchain_node__scnprintf_value (child, buf,sizeof (buf), total); +if (asprintf (&value_str,"%s" , buf) <0 ) { + value_str = (char *)"<...>" ; + goto do_print; + } + value_str_alloc = value_str; + } + +list_for_each_entry (chain, &child->parent_val, list) { + chain_str =hist_browser__folded_callchain_str (browser, + chain, value_str, chain_str); +if (first) { + first = false; + first_chain = chain; + } + +if (chain_str ==NULL ) { + chain_str = (char *)"Not enough memory!" ; + goto do_print; + } + + chain_str_alloc = chain_str; + } + +list_for_each_entry (chain, &child->val, list) { + chain_str =hist_browser__folded_callchain_str (browser, + chain, value_str, chain_str); +if (first) { + first = false; + first_chain = chain; + } + +if (chain_str ==NULL ) { + chain_str = (char *)"Not enough memory!" ; + goto do_print; + } + + chain_str_alloc = chain_str; + } + +do_print: +free (value_str_alloc); +free (chain_str_alloc); + +next: +if (is_output_full (browser, row)) +break ; + node = next; + } + +return row - first_row; +} + static int hist_browser__show_callchain(struct hist_browser *browser, struct rb_root *root, int level, unsigned short row, u64 total,
@@ -980,6 +1098,11 @@ static int hist_browser__show_entry(struct hist_browser *browser, &entry->sorted_chain, row, total, hist_browser__show_callchain_entry, &arg, hist_browser__check_output_full); + }else if (callchain_param.mode ==CHAIN_FOLDED ) { + printed +=hist_browser__show_callchain_folded (browser, + &entry->sorted_chain, row, total, + hist_browser__show_callchain_entry, &arg, + hist_browser__check_output_full); }else { printed += hist_browser__show_callchain(browser, &entry->sorted_chain, 1, row, total,
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 36/37 perf ui/gtk: Support flat callchains
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The flat callchain mode is to print all chains in a simple flat hierarchy so make it easy to see.
Currently perf report --gtk doesn't show flat callchains properly. With flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes. To do that, add parent_val list to struct callchain_node and show them along with the (normal) val list.
See the previous commit on TUI support for more information.
--- tools/perf/ui/gtk/hists.c | 80 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 4 deletions(-)
tools/perf/ui/gtk/hists.c +76 -4
@@ -89,8 +89,71 @@ void perf_gtk__init_hpp(void) perf_gtk__hpp_color_overhead_acc; } -static void perf_gtk__add_callchain (struct rb_root *root,GtkTreeStore *store, -GtkTreeIter *parent,int col,u64 total) +static void perf_gtk__add_callchain_flat (struct rb_root *root,GtkTreeStore *store, +GtkTreeIter *parent,int col,u64 total) +{ +struct rb_node *nd; +bool has_single_node = (rb_first (root) ==rb_last (root)); + +for (nd =rb_first (root); nd; nd =rb_next (nd)) { +struct callchain_node *node; +struct callchain_list *chain; +GtkTreeIter iter, new_parent; +bool need_new_parent; + + node = rb_entry(nd, struct callchain_node, rb_node); + + new_parent = *parent; + need_new_parent = !has_single_node; + +callchain_node__make_parent_list (node); + +list_for_each_entry (chain, &node->parent_val, list) { +char buf[128 ]; + +gtk_tree_store_append (store, &iter, &new_parent); + +callchain_node__scnprintf_value (node, buf,sizeof (buf), total); +gtk_tree_store_set (store, &iter,0 , buf,-1 ); + +callchain_list__sym_name (chain, buf,sizeof (buf), false); +gtk_tree_store_set (store, &iter, col, buf,-1 ); + +if (need_new_parent) { +/* +* Only show the top-most symbol in a callchain +* if it's not the only callchain. +*/ + new_parent = iter; + need_new_parent = false; + } + } + +list_for_each_entry (chain, &node->val, list) { +char buf[128 ]; + +gtk_tree_store_append (store, &iter, &new_parent); + +callchain_node__scnprintf_value (node, buf,sizeof (buf), total); +gtk_tree_store_set (store, &iter,0 , buf,-1 ); + +callchain_list__sym_name (chain, buf,sizeof (buf), false); +gtk_tree_store_set (store, &iter, col, buf,-1 ); + +if (need_new_parent) { +/* +* Only show the top-most symbol in a callchain +* if it's not the only callchain. +*/ + new_parent = iter; + need_new_parent = false; + } + } + } +} + +static void perf_gtk__add_callchain_graph (struct rb_root *root,GtkTreeStore *store, +GtkTreeIter *parent,int col,u64 total) {struct rb_node *nd;bool has_single_node = (rb_first (root) ==rb_last (root));
@@ -134,11 +197,20 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, child_total = total;/* Now 'iter' contains info of the last callchain_list */ -perf_gtk__add_callchain (&node->rb_root, store, &iter, col, - child_total); +perf_gtk__add_callchain_graph (&node->rb_root, store, &iter, col, + child_total); } } +static void perf_gtk__add_callchain (struct rb_root *root,GtkTreeStore *store, +GtkTreeIter *parent,int col,u64 total) +{ +if (callchain_param.mode ==CHAIN_FLAT ) +perf_gtk__add_callchain_flat (root, store, parent, col, total); +else +perf_gtk__add_callchain_graph (root, store, parent, col, total); +} +static void on_row_activated (GtkTreeView *view,GtkTreePath *path,GtkTreeViewColumn *col__maybe_unused ,gpointer user_data__maybe_unused )
Signature · 1 line
2.1.0
Arnaldo Carvalho de Melo
maintainerPATCH 37/37 perf ui/gtk: Support folded callchains
In reply to Arnaldo Carvalho de MeloFrom: Namhyung Kim <[email protected]>
The folded callchain mode is to print all chains in a single line. Currently perf report --gtk doesn't support folded callchains. Like flat callchains, only leaf nodes are added to the final rbtree so it should show entries in parent nodes.
--- tools/perf/ui/gtk/hists.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+)
tools/perf/ui/gtk/hists.c +62 -0
@@ -152,6 +152,66 @@ static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *sto } } +static void perf_gtk__add_callchain_folded (struct rb_root *root,GtkTreeStore *store, +GtkTreeIter *parent,int col,u64 total) +{ +struct rb_node *nd; + +for (nd =rb_first (root); nd; nd =rb_next (nd)) { +struct callchain_node *node; +struct callchain_list *chain; +GtkTreeIter iter; +char buf[64 ]; +char *str, *str_alloc =NULL ; +bool first = true; + + node = rb_entry(nd, struct callchain_node, rb_node); + +callchain_node__make_parent_list (node); + +list_for_each_entry (chain, &node->parent_val, list) { +char name[1024 ]; + +callchain_list__sym_name (chain, name,sizeof (name), false); + +if (asprintf (&str,"%s%s%s" , + first ?"" : str_alloc, + first ?"" : symbol_conf.field_sep ?:"; " , + name) <0 ) +return ; + + first = false; +free (str_alloc); + str_alloc = str; + } + +list_for_each_entry (chain, &node->val, list) { +char name[1024 ]; + +callchain_list__sym_name (chain, name,sizeof (name), false); + +if (asprintf (&str,"%s%s%s" , + first ?"" : str_alloc, + first ?"" : symbol_conf.field_sep ?:"; " , + name) <0 ) +return ; + + first = false; +free (str_alloc); + str_alloc = str; + } + +gtk_tree_store_append (store, &iter, parent); + +callchain_node__scnprintf_value (node, buf,sizeof (buf), total); +gtk_tree_store_set (store, &iter,0 , buf,-1 ); + +gtk_tree_store_set (store, &iter, col, str,-1 ); + +free (str_alloc); + } +} +static void perf_gtk__add_callchain_graph (struct rb_root *root,GtkTreeStore *store,GtkTreeIter *parent,int col,u64 total) {
@@ -207,6 +267,8 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store, {if (callchain_param.mode ==CHAIN_FLAT )perf_gtk__add_callchain_flat (root, store, parent, col, total); +else if (callchain_param.mode ==CHAIN_FOLDED ) +perf_gtk__add_callchain_folded (root, store, parent, col, total);else perf_gtk__add_callchain_graph (root, store, parent, col, total); }
Signature · 1 line
2.1.0
Hi Arnaldo,
I just have a question about the refcnt debugger patch. It seems that the debugger itself is dropped from this series, would you have a plan to merge it afterwards?
Since I'd like to change other refcnts with my refcnt API, and also to add some features, I'd like to decide I'd better update my local patches or wait for your work :)
Thanks!
Quoted 285 lines
From: Arnaldo Carvalho de Melo [mailto:[email protected]]
Hi Ingo,
Please consider pulling, this was based on tip/perf/urgent and I did a
test merge of tip/perf/core with tip/perf/urgent and then with this branch, haven't noticed problems,Best regards,
- Arnaldo
The following changes since commit
e15bf88a44d1fcb685754b2868b1cd28927af3aa:Merge tag 'perf-urgent-for-mingo' of
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linuxinto perf/urgent
(2015-11-18 06:56:48 +0100)are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingofor you to fetch changes up to
2c6caff2b26fde8f3f87183f8c97f2cebfdbcb98:perf ui/gtk: Support folded callchains (2015-11-19 13:19:26 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:User visible:
- Allows BPF scriptlets specify arguments to be fetched using
DWARF info, using a prologue generated at compile/build time (He Kuang, Wang Nan)- Allow attaching BPF scriptlets to module symbols (Wang Nan)
- Allow attaching BPF scriptlets to userspace code using uprobe (Wang Nan)
- BPF programs now can specify 'perf probe' tunables via its section name, separating key=val values using semicolons (Wang Nan)
Testing some of these new BPF features:
Use case: get callchains when receiving SSL packets, filter then in the
kernel, at arbitrary place.# cat ssl.bpf.c #define SEC(NAME) __attribute__((section(NAME), used))struct
pt_regs;
SEC("func=__inet_lookup_established hnum")
intfunc(struct pt_regs *ctx, int err, unsigned short port){ return err == 0 && port == 443;}
char _license[]
SEC("license")= "GPL";
int_versionSEC("version")=LINUX_VERSION_CODE;
## perf record -a -g -e ssl.bpf.c ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.787 MB perf.data (3 samples) ] # perf script | head -30 swapper 0 [000] 58783.268118: perf_bpf_probe:func: (ffffffff816a0f60) hnum=0x1bb 8a0f61 __inet_lookup_established (/lib/modules/4.3.0+/build/vmlinux) 896def ip_rcv_finish (/lib/modules/4.3.0+/build/vmlinux) 8976c2 ip_rcv (/lib/modules/4.3.0+/build/vmlinux) 855eba __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux) 8572a8 process_backlog (/lib/modules/4.3.0+/build/vmlinux) 856b11 net_rx_action (/lib/modules/4.3.0+/build/vmlinux) 2a284b __do_softirq (/lib/modules/4.3.0+/build/vmlinux) 2a2ba3 irq_exit (/lib/modules/4.3.0+/build/vmlinux) 96b7a4 do_IRQ (/lib/modules/4.3.0+/build/vmlinux) 969807 ret_from_intr (/lib/modules/4.3.0+/build/vmlinux) 2dede5 cpu_startup_entry (/lib/modules/4.3.0+/build/vmlinux) 95d5bc rest_init (/lib/modules/4.3.0+/build/vmlinux) 1163ffa start_kernel ([kernel.vmlinux].init.text) 11634d7 x86_64_start_reservations ([kernel.vmlinux].init.text) 1163623 x86_64_start_kernel ([kernel.vmlinux].init.text)qemu-system-x86 9178 [003] 58785.792417: perf_bpf_probe:func: (
ffffffff816a0f60) hnum=0x1bb8a0f61 __inet_lookup_established (/lib/modules/4.3.0+/build/vmlinux) 896def ip_rcv_finish (/lib/modules/4.3.0+/build/vmlinux) 8976c2 ip_rcv (/lib/modules/4.3.0+/build/vmlinux) 855eba __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux) 856660 netif_receive_skb_internal (/lib/modules/4.3.0+/build/vmlinux) 8566ec netif_receive_skb_sk (/lib/modules/4.3.0+/build/vmlinux) 430a br_handle_frame_finish ([bridge]) 48bc br_handle_frame ([bridge]) 855f44 __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux)#
Use 'perf probe' various options to list functions, see what variables can be collected at any given point, experiment first collecting without a filter, then filter, use it together with 'perf trace', 'perf top', with or without callchains, if it explodes, please tell us!
- Introduce a new callchain mode: "folded", that will list per line representations of all callchains for a give histogram entry, facilitating 'perf report' output processing by other tools, such as Brendan Gregg's flamegraph tools (Namhyung Kim)
E.g:
# perf report | grep -v ^# | head 18.37% 0.00% swapper [kernel.kallsyms] [k] cpu_startup_entry | ---cpu_startup_entry | |--12.07%--start_secondary | --6.30%--rest_init start_kernel x86_64_start_reservations x86_64_start_kernel #Becomes, in "folded" mode:
# perf report -g folded | grep -v ^# | head -5 18.37% 0.00% swapper [kernel.kallsyms] [k] cpu_startup_entry 12.07% cpu_startup_entry;start_secondary 6.30% cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel 16.90% 0.00% swapper [kernel.kallsyms] [k] call_cpuidle 11.23% call_cpuidle;cpu_startup_entry;start_secondary 5.67% call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel 16.90% 0.00% swapper [kernel.kallsyms] [k] cpuidle_enter 11.23% cpuidle_enter;call_cpuidle;cpu_startup_entry;start_secondary 5.67% cpuidle_enter;call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel 15.12% 0.00% swapper [kernel.kallsyms] [k] cpuidle_enter_state #The user can also select one of "count", "period" or "percent" as the first column.
Infrastructure:
- Fix multiple leaks found with valgrind and a refcount debugger (Masami Hiramatsu)
- Add further 'perf test' entries for BPF and LLVM (Wang Nan)
- Improve 'perf test' to suport subtests, so that the series of tests performed in the LLVM and BPF main tests appear in the default 'perf test' output (Wang Nan)
- Move
memdup()fromtools/perftotools/lib/string.c(Arnaldo Carvalho de Melo)- Adopt
strtobool()from the kernel intotools/lib/(Wang Nan)- Fix
selftests_installtools/Makefilerule (Kevin Hilman)Signed-off-by Arnaldo Carvalho de Melo <[email protected]>----------------------------------------------------------------
Arnaldo Carvalho de Melo (3):
perf test: Fix build of BPF and LLVM on older glibc libraries
tools: Adoptmemdup()fromtools/perf, moving it totools/lib/string.cperf tests: Pass the subtest index to each test routineHe Kuang (1):
perf bpf: Add prologue for BPF programs for fetching argumentsKevin Hilman (1):
tools: Fixselftests_installMakefileruleMasami Hiramatsu (9):
perf probe: Fix to free temporalDwarf_Frame
perf machine: Fixmachine__findnew_module_mapto put registered map perf machine: Fixmachine__destroy_kernel_mapsto dropvmlinux_mapsreferences perf machine: Fix to destroy kernel maps when machine exits
perf tools: Makeperf_exec_path()always return malloc'd string perf tools: Fix to put new map after inserting tomap_groupsindso__load_symperf tools: Fix__dsos__addnewto put dso after adding it to the list perf tools: Fixmachine__create_kernel_mapsto put kernel dso refcount perf machine: Fixmachine__findnew_module_mapto put dsoNamhyung Kim (9):
perf report: Support folded callchain mode on --stdio perf callchain: Abstract callchain print function
perf callchain: Add count fields to structcallchain_nodeperf report: Add callchain value option
perf hists browser: Factor outhist_browser__show_callchain_list()perf hists browser: Support flat callchains
perf hists browser: Support folded callchains
perf ui/gtk: Support flat callchains
perf ui/gtk: Support folded callchainsWang Nan (14):
tools: Clone the kernel's strtobool function
bpf tools: Load a program with different instances using preprocessor perf bpf: AddBPF_PROLOGUEconfig options for further patches perf bpf: Compiledwarf-regs.cifCONFIG_BPF_PROLOGUEis on perf bpf: Allow BPF program attach to uprobe events
perf bpf: Allow attaching BPF programs to modules symbols perf bpf: Allow BPF program config probing options
perf bpf: Generate prologue for BPF programs
perf test: Test the BPF prologue adding infrastructure
perf test: Fix 'perf test BPF' when it fails to find a suitable vmlinux perf bpf: Use same BPF program if arguments are identical perf test: Print result for each LLVM subtest
perf test: Print result for each BPF subtest
perf test: Mute test cases error messages if verbose == 0tools/Makefile | 2 +- tools/include/linux/string.h | 11 + tools/lib/bpf/libbpf.c | 146 ++++++++- tools/lib/bpf/libbpf.h | 64 ++++ tools/lib/string.c | 62 ++++ tools/perf/Documentation/perf-report.txt | 14 +- tools/perf/MANIFEST | 2 + tools/perf/arch/x86/include/arch-tests.h | 8 +- tools/perf/arch/x86/tests/insn-x86.c | 2 +- tools/perf/arch/x86/tests/intel-cqm.c | 2 +- tools/perf/arch/x86/tests/perf-time-to-tsc.c | 2 +- tools/perf/arch/x86/tests/rdpmc.c | 2 +- tools/perf/arch/x86/util/Build | 1 + tools/perf/builtin-report.c | 4 +- tools/perf/config/Makefile | 12 + tools/perf/tests/.gitignore | 1 + tools/perf/tests/Build | 9 +- tools/perf/tests/attr.c | 2 +- tools/perf/tests/bp_signal.c | 2 +- tools/perf/tests/bp_signal_overflow.c | 2 +- tools/perf/tests/bpf-script-test-prologue.c | 35 +++ tools/perf/tests/bpf.c | 93 ++++-- tools/perf/tests/builtin-test.c | 112 ++++++- tools/perf/tests/code-reading.c | 2 +- tools/perf/tests/dso-data.c | 6 +- tools/perf/tests/dwarf-unwind.c | 2 +- tools/perf/tests/evsel-roundtrip-name.c | 2 +- tools/perf/tests/evsel-tp-sched.c | 2 +- tools/perf/tests/fdarray.c | 4 +- tools/perf/tests/hists_cumulate.c | 2 +- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_link.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/kmod-path.c | 2 +- tools/perf/tests/llvm.c | 75 +++-- tools/perf/tests/llvm.h | 2 + tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/tests/openat-syscall-all-cpus.c | 2 +- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/tests/openat-syscall.c | 2 +- tools/perf/tests/parse-events.c | 2 +- tools/perf/tests/parse-no-sample-id-all.c | 2 +- tools/perf/tests/perf-record.c | 2 +- tools/perf/tests/pmu.c | 2 +- tools/perf/tests/python-use.c | 3 +- tools/perf/tests/sample-parsing.c | 2 +- tools/perf/tests/sw-clock.c | 2 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/tests/task-exit.c | 2 +- tools/perf/tests/tests.h | 89 +++--- tools/perf/tests/thread-map.c | 2 +- tools/perf/tests/thread-mg-share.c | 2 +- tools/perf/tests/topology.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 2 +- tools/perf/ui/browsers/hists.c | 315 +++++++++++++++++-- tools/perf/ui/gtk/hists.c | 148 ++++++++- tools/perf/ui/stdio/hist.c | 94 +++++- tools/perf/util/Build | 7 + tools/perf/util/bpf-loader.c | 434 ++++++++++++++++++++++++- tools/perf/util/bpf-loader.h | 4 + tools/perf/util/bpf-prologue.c | 455 +++++++++++++++++++++++++++ tools/perf/util/bpf-prologue.h | 34 ++ tools/perf/util/callchain.c | 135 +++++++- tools/perf/util/callchain.h | 28 +- tools/perf/util/dso.c | 2 + tools/perf/util/exec_cmd.c | 21 +- tools/perf/util/exec_cmd.h | 5 +- tools/perf/util/help.c | 6 +- tools/perf/util/include/linux/string.h | 3 - tools/perf/util/machine.c | 17 +- tools/perf/util/probe-event.c | 7 +- tools/perf/util/probe-finder.c | 9 +- tools/perf/util/string.c | 16 - tools/perf/util/symbol-elf.c | 2 + tools/perf/util/util.c | 3 +- 77 files changed, 2286 insertions(+), 282 deletions(-)
Quoted 6 lines
create mode 100644
tools/include/linux/string.hcreate mode 100644tools/lib/string.c
create mode 100644tools/perf/tests/bpf-script-test-prologue.ccreate mode 100644tools/perf/util/bpf-prologue.ccreate mode 100644tools/perf/util/bpf-prologue.hdelete mode 100644tools/perf/util/include/linux/string.h
���{.n�+�������+%�����ݶ��w��{.n�+����{��G�����{ay�ʇڙ�,j��f���h��������z_�(�階�ݢj"���m������G������?����&���~��iO��z��v�^�m����������?�I�
'Arnaldo Carvalho de Melo'
maintainerEm Fri, Nov 20, 2015 at 10:01:30AM +0000, 平松雅巳 / HIRAMATU,MASAMI escreveu:
Quoted 5 lines
Hi Arnaldo,
I just have a question about the refcnt debugger patch. It seems that the debugger itself is dropped from this series, would you have a plan to merge it afterwards?
I concentrated on the fixes, leaving the debugger itself to be reviewed later.
Quoted 3 lines
Since I'd like to change other refcnts with my refcnt API, and also to add some features, I'd like to decide I'd better update my local patches or wait for your work :)
You can continue using it as you did, and the fixes can continue to be applied before the debugger itself gets reviewed.
- Arnaldo
Quoted 12 lines
From: 'Arnaldo Carvalho de Melo' [mailto:[email protected]]
Em Fri, Nov 20, 2015 at 10:01:30AM +0000, 平松雅巳 / HIRAMATU,MASAMI escreveu:
Quoted 5 lines
Hi Arnaldo,
I just have a question about the refcnt debugger patch. It seems that the debugger itself is dropped from this series, would you have a plan to merge it afterwards?
I concentrated on the fixes, leaving the debugger itself to be reviewed later.
Quoted 6 lines
Quoted 3 lines
Since I'd like to change other refcnts with my refcnt API, and also to add some features, I'd like to decide I'd better update my local patches or wait for your work :)
You can continue using it as you did, and the fixes can continue to be applied before the debugger itself gets reviewed.
OK, so I'll continue to play on my series :)
Thank you!
Signature · 6 lines
Masami HIRAMATSU Linux Technology Research Center, System Productivity Research Dept. Center for Technology Innovation - Systems Engineering Hitachi, Ltd., Research & Development Group E-mail: [email protected] ���{.n�+�������+%�����ݶ��w��{.n�+����{��G�����{ay�ʇڙ�,j��f���h��������z_�(�階�ݢj"���m������G������?����&���~��iO��z��v�^�m����������?�I�
Quoted 279 lines · Arnaldo Carvalho de Melo
Hi Ingo,
Please consider pulling, this was based on tip/perf/urgent and I did a
test merge of tip/perf/core with tip/perf/urgent and then with this branch, haven't noticed problems,Best regards,
- Arnaldo
The following changes since commit
e15bf88a44d1fcb685754b2868b1cd28927af3aa:Merge tag 'perf-urgent-for-mingo' of
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linuxinto perf/urgent (2015-11-18 06:56:48 +0100)are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingofor you to fetch changes up to
2c6caff2b26fde8f3f87183f8c97f2cebfdbcb98:perf ui/gtk: Support folded callchains (2015-11-19 13:19:26 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:User visible:
- Allows BPF scriptlets specify arguments to be fetched using
DWARF info, using a prologue generated at compile/build time (He Kuang, Wang Nan)- Allow attaching BPF scriptlets to module symbols (Wang Nan)
- Allow attaching BPF scriptlets to userspace code using uprobe (Wang Nan)
- BPF programs now can specify 'perf probe' tunables via its section name, separating key=val values using semicolons (Wang Nan)
Testing some of these new BPF features:
Use case: get callchains when receiving SSL packets, filter then in the
kernel, at arbitrary place.# cat ssl.bpf.c #define SEC(NAME) __attribute__((section(NAME), used))struct
pt_regs;SEC("func=__inet_lookup_established hnum") int func(struct pt_regs *ctx, int err, unsigned short port) { return err == 0 && port == 443; }char _license[]
SEC("license")= "GPL";
int_versionSEC("version")=LINUX_VERSION_CODE;
## perf record -a -g -e ssl.bpf.c ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.787 MB perf.data (3 samples) ] # perf script | head -30 swapper 0 [000] 58783.268118: perf_bpf_probe:func: (ffffffff816a0f60) hnum=0x1bb 8a0f61 __inet_lookup_established (/lib/modules/4.3.0+/build/vmlinux) 896def ip_rcv_finish (/lib/modules/4.3.0+/build/vmlinux) 8976c2 ip_rcv (/lib/modules/4.3.0+/build/vmlinux) 855eba __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux) 8572a8 process_backlog (/lib/modules/4.3.0+/build/vmlinux) 856b11 net_rx_action (/lib/modules/4.3.0+/build/vmlinux) 2a284b __do_softirq (/lib/modules/4.3.0+/build/vmlinux) 2a2ba3 irq_exit (/lib/modules/4.3.0+/build/vmlinux) 96b7a4 do_IRQ (/lib/modules/4.3.0+/build/vmlinux) 969807 ret_from_intr (/lib/modules/4.3.0+/build/vmlinux) 2dede5 cpu_startup_entry (/lib/modules/4.3.0+/build/vmlinux) 95d5bc rest_init (/lib/modules/4.3.0+/build/vmlinux) 1163ffa start_kernel ([kernel.vmlinux].init.text) 11634d7 x86_64_start_reservations ([kernel.vmlinux].init.text) 1163623 x86_64_start_kernel ([kernel.vmlinux].init.text)qemu-system-x86 9178 [003] 58785.792417: perf_bpf_probe:func: (
ffffffff816a0f60) hnum=0x1bb8a0f61 __inet_lookup_established (/lib/modules/4.3.0+/build/vmlinux) 896def ip_rcv_finish (/lib/modules/4.3.0+/build/vmlinux) 8976c2 ip_rcv (/lib/modules/4.3.0+/build/vmlinux) 855eba __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux) 856660 netif_receive_skb_internal (/lib/modules/4.3.0+/build/vmlinux) 8566ec netif_receive_skb_sk (/lib/modules/4.3.0+/build/vmlinux) 430a br_handle_frame_finish ([bridge]) 48bc br_handle_frame ([bridge]) 855f44 __netif_receive_skb_core (/lib/modules/4.3.0+/build/vmlinux) 8565d8 __netif_receive_skb (/lib/modules/4.3.0+/build/vmlinux)#
Use 'perf probe' various options to list functions, see what variables can be collected at any given point, experiment first collecting without a filter, then filter, use it together with 'perf trace', 'perf top', with or without callchains, if it explodes, please tell us!
- Introduce a new callchain mode: "folded", that will list per line representations of all callchains for a give histogram entry, facilitating 'perf report' output processing by other tools, such as Brendan Gregg's flamegraph tools (Namhyung Kim)
E.g:
# perf report | grep -v ^# | head 18.37% 0.00% swapper [kernel.kallsyms] [k] cpu_startup_entry | ---cpu_startup_entry | |--12.07%--start_secondary | --6.30%--rest_init start_kernel x86_64_start_reservations x86_64_start_kernel #Becomes, in "folded" mode:
# perf report -g folded | grep -v ^# | head -5 18.37% 0.00% swapper [kernel.kallsyms] [k] cpu_startup_entry 12.07% cpu_startup_entry;start_secondary 6.30% cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel 16.90% 0.00% swapper [kernel.kallsyms] [k] call_cpuidle 11.23% call_cpuidle;cpu_startup_entry;start_secondary 5.67% call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel 16.90% 0.00% swapper [kernel.kallsyms] [k] cpuidle_enter 11.23% cpuidle_enter;call_cpuidle;cpu_startup_entry;start_secondary 5.67% cpuidle_enter;call_cpuidle;cpu_startup_entry;rest_init;start_kernel;x86_64_start_reservations;x86_64_start_kernel 15.12% 0.00% swapper [kernel.kallsyms] [k] cpuidle_enter_state #The user can also select one of "count", "period" or "percent" as the first column.
Infrastructure:
- Fix multiple leaks found with valgrind and a refcount debugger (Masami Hiramatsu)
- Add further 'perf test' entries for BPF and LLVM (Wang Nan)
- Improve 'perf test' to suport subtests, so that the series of tests performed in the LLVM and BPF main tests appear in the default 'perf test' output (Wang Nan)
- Move
memdup()fromtools/perftotools/lib/string.c(Arnaldo Carvalho de Melo)- Adopt
strtobool()from the kernel intotools/lib/(Wang Nan)- Fix
selftests_installtools/Makefilerule (Kevin Hilman)Signed-off-by Arnaldo Carvalho de Melo <[email protected]>----------------------------------------------------------------
Arnaldo Carvalho de Melo (3):
perf test: Fix build of BPF and LLVM on older glibc libraries
tools: Adoptmemdup()fromtools/perf, moving it totools/lib/string.cperf tests: Pass the subtest index to each test routineHe Kuang (1):
perf bpf: Add prologue for BPF programs for fetching argumentsKevin Hilman (1):
tools: Fixselftests_installMakefileruleMasami Hiramatsu (9):
perf probe: Fix to free temporalDwarf_Frame
perf machine: Fixmachine__findnew_module_mapto put registered map perf machine: Fixmachine__destroy_kernel_mapsto dropvmlinux_mapsreferences perf machine: Fix to destroy kernel maps when machine exits
perf tools: Makeperf_exec_path()always return malloc'd string perf tools: Fix to put new map after inserting tomap_groupsindso__load_symperf tools: Fix__dsos__addnewto put dso after adding it to the list perf tools: Fixmachine__create_kernel_mapsto put kernel dso refcount perf machine: Fixmachine__findnew_module_mapto put dsoNamhyung Kim (9):
perf report: Support folded callchain mode on --stdio perf callchain: Abstract callchain print function
perf callchain: Add count fields to structcallchain_nodeperf report: Add callchain value option
perf hists browser: Factor outhist_browser__show_callchain_list()perf hists browser: Support flat callchains
perf hists browser: Support folded callchains
perf ui/gtk: Support flat callchains
perf ui/gtk: Support folded callchainsWang Nan (14):
tools: Clone the kernel's strtobool function
bpf tools: Load a program with different instances using preprocessor perf bpf: AddBPF_PROLOGUEconfig options for further patches perf bpf: Compiledwarf-regs.cifCONFIG_BPF_PROLOGUEis on perf bpf: Allow BPF program attach to uprobe events
perf bpf: Allow attaching BPF programs to modules symbols perf bpf: Allow BPF program config probing options
perf bpf: Generate prologue for BPF programs
perf test: Test the BPF prologue adding infrastructure
perf test: Fix 'perf test BPF' when it fails to find a suitable vmlinux perf bpf: Use same BPF program if arguments are identical perf test: Print result for each LLVM subtest
perf test: Print result for each BPF subtest
perf test: Mute test cases error messages if verbose == 0tools/Makefile | 2 +- tools/include/linux/string.h | 11 + tools/lib/bpf/libbpf.c | 146 ++++++++- tools/lib/bpf/libbpf.h | 64 ++++ tools/lib/string.c | 62 ++++ tools/perf/Documentation/perf-report.txt | 14 +- tools/perf/MANIFEST | 2 + tools/perf/arch/x86/include/arch-tests.h | 8 +- tools/perf/arch/x86/tests/insn-x86.c | 2 +- tools/perf/arch/x86/tests/intel-cqm.c | 2 +- tools/perf/arch/x86/tests/perf-time-to-tsc.c | 2 +- tools/perf/arch/x86/tests/rdpmc.c | 2 +- tools/perf/arch/x86/util/Build | 1 + tools/perf/builtin-report.c | 4 +- tools/perf/config/Makefile | 12 + tools/perf/tests/.gitignore | 1 + tools/perf/tests/Build | 9 +- tools/perf/tests/attr.c | 2 +- tools/perf/tests/bp_signal.c | 2 +- tools/perf/tests/bp_signal_overflow.c | 2 +- tools/perf/tests/bpf-script-test-prologue.c | 35 +++ tools/perf/tests/bpf.c | 93 ++++-- tools/perf/tests/builtin-test.c | 112 ++++++- tools/perf/tests/code-reading.c | 2 +- tools/perf/tests/dso-data.c | 6 +- tools/perf/tests/dwarf-unwind.c | 2 +- tools/perf/tests/evsel-roundtrip-name.c | 2 +- tools/perf/tests/evsel-tp-sched.c | 2 +- tools/perf/tests/fdarray.c | 4 +- tools/perf/tests/hists_cumulate.c | 2 +- tools/perf/tests/hists_filter.c | 2 +- tools/perf/tests/hists_link.c | 2 +- tools/perf/tests/hists_output.c | 2 +- tools/perf/tests/keep-tracking.c | 2 +- tools/perf/tests/kmod-path.c | 2 +- tools/perf/tests/llvm.c | 75 +++-- tools/perf/tests/llvm.h | 2 + tools/perf/tests/mmap-basic.c | 2 +- tools/perf/tests/mmap-thread-lookup.c | 2 +- tools/perf/tests/openat-syscall-all-cpus.c | 2 +- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/tests/openat-syscall.c | 2 +- tools/perf/tests/parse-events.c | 2 +- tools/perf/tests/parse-no-sample-id-all.c | 2 +- tools/perf/tests/perf-record.c | 2 +- tools/perf/tests/pmu.c | 2 +- tools/perf/tests/python-use.c | 3 +- tools/perf/tests/sample-parsing.c | 2 +- tools/perf/tests/sw-clock.c | 2 +- tools/perf/tests/switch-tracking.c | 2 +- tools/perf/tests/task-exit.c | 2 +- tools/perf/tests/tests.h | 89 +++--- tools/perf/tests/thread-map.c | 2 +- tools/perf/tests/thread-mg-share.c | 2 +- tools/perf/tests/topology.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 2 +- tools/perf/ui/browsers/hists.c | 315 +++++++++++++++++-- tools/perf/ui/gtk/hists.c | 148 ++++++++- tools/perf/ui/stdio/hist.c | 94 +++++- tools/perf/util/Build | 7 + tools/perf/util/bpf-loader.c | 434 ++++++++++++++++++++++++- tools/perf/util/bpf-loader.h | 4 + tools/perf/util/bpf-prologue.c | 455 +++++++++++++++++++++++++++ tools/perf/util/bpf-prologue.h | 34 ++ tools/perf/util/callchain.c | 135 +++++++- tools/perf/util/callchain.h | 28 +- tools/perf/util/dso.c | 2 + tools/perf/util/exec_cmd.c | 21 +- tools/perf/util/exec_cmd.h | 5 +- tools/perf/util/help.c | 6 +- tools/perf/util/include/linux/string.h | 3 - tools/perf/util/machine.c | 17 +- tools/perf/util/probe-event.c | 7 +- tools/perf/util/probe-finder.c | 9 +- tools/perf/util/string.c | 16 - tools/perf/util/symbol-elf.c | 2 +
Quoted 8 lines
tools/perf/util/util.c | 3 +- 77 files changed, 2286 insertions(+), 282 deletions(-) create mode 100644 tools/include/linux/string.h create mode 100644 tools/lib/string.c create mode 100644 tools/perf/tests/bpf-script-test-prologue.c create mode 100644 tools/perf/util/bpf-prologue.c create mode 100644 tools/perf/util/bpf-prologue.h delete mode 100644 tools/perf/util/include/linux/string.h
Pulled into tip:perf/core, thanks a lot Arnaldo!
Ingo