diff options
| author | Ingo Molnar <mingo@kernel.org> | 2016-04-27 11:02:24 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2016-04-27 11:02:24 -0400 |
| commit | a8944c5bf86dc6c153a71f2a386738c0d3f5ff9c (patch) | |
| tree | a251b1d510831dc071eadbbbe3e38a85fe643365 | |
| parent | 67d61296ffcc850bffdd4466430cb91e5328f39a (diff) | |
| parent | 4cb93446c587d56e2a54f4f83113daba2c0b6dee (diff) | |
Merge tag 'perf-core-for-mingo-20160427' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- perf trace --pf maj/min/all works with --call-graph: (Arnaldo Carvalho de Melo)
Tracing write syscalls and major page faults with callchains while starting
firefox, limiting the stack to 5 frames:
# perf trace -e write --pf maj --max-stack 5 firefox
589.549 ( 0.014 ms): firefox/15377 write(fd: 4, buf: 0x7fff80acc898, count: 151) = 151
[0xfaed] (/usr/lib64/libpthread-2.22.so)
fire_glxtest_process+0x5c (/usr/lib64/firefox/libxul.so)
InstallGdkErrorHandler+0x41 (/usr/lib64/firefox/libxul.so)
XREMain::XRE_mainInit+0x12c (/usr/lib64/firefox/libxul.so)
XREMain::XRE_main+0x1e4 (/usr/lib64/firefox/libxul.so)
760.704 ( 0.000 ms): firefox/15332 majfault [gtk_tree_view_accessible_get_type+0x0] => /usr/lib64/libgtk-3.so.0.1800.9@0xa0850 (x.)
gtk_tree_view_accessible_get_type+0x0 (/usr/lib64/libgtk-3.so.0.1800.9)
gtk_tree_view_class_intern_init+0x1a54 (/usr/lib64/libgtk-3.so.0.1800.9)
g_type_class_ref+0x6dd (/usr/lib64/libgobject-2.0.so.0.4600.2)
[0x115378] (/usr/lib64/libgnutls.so.30.6.3)
This automagically selects "--call-graph dwarf", use "--call-graph fp" on systems
where -fno-omit-frame-pointer was used to built the components of interest, to
incur in less overhead, or tune "--call-graph dwarf" appropriately, see 'perf record --help'.
- Allow /proc/sys/kernel/perf_event_max_stack, that defaults to the old hard coded value
of PERF_MAX_STACK_DEPTH (127), useful for huge callstacks for things like Groovy, Ruby, etc,
and also to reduce overhead by limiting it to a smaller value, upcoming work will allow
this to be done per-event (Arnaldo Carvalho de Melo)
- Make 'perf trace --min-stack' be honoured by --pf and --event (Arnaldo Carvalho de Melo)
- Make 'perf evlist -v' decode perf_event_attr->branch_sample_type (Arnaldo Carvalho de Melo)
# perf record --call lbr usleep 1
# perf evlist -v
cycles:ppp: ... sample_type: IP|TID|TIME|CALLCHAIN|PERIOD|BRANCH_STACK, ...
branch_sample_type: USER|CALL_STACK|NO_FLAGS|NO_CYCLES
#
- Clear dummy entry accumulated period, fixing such 'perf top/report' output
as: (Kan Liang)
4769.98% 0.01% 0.00% 0.01% tchain_edit [kernel] [k] update_fast_timekeeper
- System calls with pid_t arguments gets them augmented with the COMM event
more thoroughly:
# trace -e perf_event_open perf stat -e cycles -p 15608
6.876 ( 0.014 ms): perf_event_open(attr_uptr: 0x2ae20d8, pid: 15608 (hexchat), cpu: -1, group_fd: -1, flags: FD_CLOEXEC) = 3
6.882 ( 0.005 ms): perf_event_open(attr_uptr: 0x2ae20d8, pid: 15639 (gmain), cpu: -1, group_fd: -1, flags: FD_CLOEXEC) = 4
6.889 ( 0.005 ms): perf_event_open(attr_uptr: 0x2ae20d8, pid: 15640 (gdbus), cpu: -1, group_fd: -1, flags: FD_CLOEXEC) = 5
^^^^^^^^^^^^^^^^^^
^C
- Fix offline module name mismatch issue in 'perf probe' (Ravi Bangoria)
- Fix module probe issue if no dwarf support in (Ravi Bangoria)
Assorted fixes:
- Fix off-by-one in write_buildid() (Andrey Ryabinin)
- Fix segfault when printing callchains in 'perf script' (Chris Phlipot)
- Replace assignment with comparison on assert check in 'perf test' entry (Colin Ian King)
- Fix off-by-one comparison in intel-pt code (Colin Ian King)
- Close target file on error path in 'perf probe' (Masami Hiramatsu)
- Set default kprobe group name if not given in 'perf probe' (Masami Hiramatsu)
- Avoid partial perf_event_header reads (Wang Nan)
Infrastructure changes:
- Update x86's syscall_64.tbl copy, adding preadv2 & pwritev2 (Arnaldo Carvalho de Melo)
- Make the x86 clean quiet wrt syscall table removal (Jiri Olsa)
Cleanups:
- Simplify wrapper for LOCK_PI in 'perf bench futex' (Davidlohr Bueso)
- Remove duplicate const qualifier (Eric Engestrom)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
49 files changed, 475 insertions, 179 deletions
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 57653a44b128..260cde08e92e 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt | |||
| @@ -60,6 +60,7 @@ show up in /proc/sys/kernel: | |||
| 60 | - panic_on_warn | 60 | - panic_on_warn |
| 61 | - perf_cpu_time_max_percent | 61 | - perf_cpu_time_max_percent |
| 62 | - perf_event_paranoid | 62 | - perf_event_paranoid |
| 63 | - perf_event_max_stack | ||
| 63 | - pid_max | 64 | - pid_max |
| 64 | - powersave-nap [ PPC only ] | 65 | - powersave-nap [ PPC only ] |
| 65 | - printk | 66 | - printk |
| @@ -654,6 +655,19 @@ users (without CAP_SYS_ADMIN). The default value is 1. | |||
| 654 | 655 | ||
| 655 | ============================================================== | 656 | ============================================================== |
| 656 | 657 | ||
| 658 | perf_event_max_stack: | ||
| 659 | |||
| 660 | Controls maximum number of stack frames to copy for (attr.sample_type & | ||
| 661 | PERF_SAMPLE_CALLCHAIN) configured events, for instance, when using | ||
| 662 | 'perf record -g' or 'perf trace --call-graph fp'. | ||
| 663 | |||
| 664 | This can only be done when no events are in use that have callchains | ||
| 665 | enabled, otherwise writing to this file will return -EBUSY. | ||
| 666 | |||
| 667 | The default value is 127. | ||
| 668 | |||
| 669 | ============================================================== | ||
| 670 | |||
| 657 | pid_max: | 671 | pid_max: |
| 658 | 672 | ||
| 659 | PID allocation wrap value. When the kernel's next PID value | 673 | PID allocation wrap value. When the kernel's next PID value |
diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c index 4e02ae5950ff..27563befa8a2 100644 --- a/arch/arm/kernel/perf_callchain.c +++ b/arch/arm/kernel/perf_callchain.c | |||
| @@ -75,7 +75,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) | |||
| 75 | 75 | ||
| 76 | tail = (struct frame_tail __user *)regs->ARM_fp - 1; | 76 | tail = (struct frame_tail __user *)regs->ARM_fp - 1; |
| 77 | 77 | ||
| 78 | while ((entry->nr < PERF_MAX_STACK_DEPTH) && | 78 | while ((entry->nr < sysctl_perf_event_max_stack) && |
| 79 | tail && !((unsigned long)tail & 0x3)) | 79 | tail && !((unsigned long)tail & 0x3)) |
| 80 | tail = user_backtrace(tail, entry); | 80 | tail = user_backtrace(tail, entry); |
| 81 | } | 81 | } |
diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c index ff4665462a02..32c3c6e70119 100644 --- a/arch/arm64/kernel/perf_callchain.c +++ b/arch/arm64/kernel/perf_callchain.c | |||
| @@ -122,7 +122,7 @@ void perf_callchain_user(struct perf_callchain_entry *entry, | |||
| 122 | 122 | ||
| 123 | tail = (struct frame_tail __user *)regs->regs[29]; | 123 | tail = (struct frame_tail __user *)regs->regs[29]; |
| 124 | 124 | ||
| 125 | while (entry->nr < PERF_MAX_STACK_DEPTH && | 125 | while (entry->nr < sysctl_perf_event_max_stack && |
| 126 | tail && !((unsigned long)tail & 0xf)) | 126 | tail && !((unsigned long)tail & 0xf)) |
| 127 | tail = user_backtrace(tail, entry); | 127 | tail = user_backtrace(tail, entry); |
| 128 | } else { | 128 | } else { |
| @@ -132,7 +132,7 @@ void perf_callchain_user(struct perf_callchain_entry *entry, | |||
| 132 | 132 | ||
| 133 | tail = (struct compat_frame_tail __user *)regs->compat_fp - 1; | 133 | tail = (struct compat_frame_tail __user *)regs->compat_fp - 1; |
| 134 | 134 | ||
| 135 | while ((entry->nr < PERF_MAX_STACK_DEPTH) && | 135 | while ((entry->nr < sysctl_perf_event_max_stack) && |
| 136 | tail && !((unsigned long)tail & 0x3)) | 136 | tail && !((unsigned long)tail & 0x3)) |
| 137 | tail = compat_user_backtrace(tail, entry); | 137 | tail = compat_user_backtrace(tail, entry); |
| 138 | #endif | 138 | #endif |
diff --git a/arch/metag/kernel/perf_callchain.c b/arch/metag/kernel/perf_callchain.c index 315633461a94..252abc12a5a3 100644 --- a/arch/metag/kernel/perf_callchain.c +++ b/arch/metag/kernel/perf_callchain.c | |||
| @@ -65,7 +65,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) | |||
| 65 | 65 | ||
| 66 | --frame; | 66 | --frame; |
| 67 | 67 | ||
| 68 | while ((entry->nr < PERF_MAX_STACK_DEPTH) && frame) | 68 | while ((entry->nr < sysctl_perf_event_max_stack) && frame) |
| 69 | frame = user_backtrace(frame, entry); | 69 | frame = user_backtrace(frame, entry); |
| 70 | } | 70 | } |
| 71 | 71 | ||
diff --git a/arch/mips/kernel/perf_event.c b/arch/mips/kernel/perf_event.c index c1cf9c6c3f77..5021c546ad07 100644 --- a/arch/mips/kernel/perf_event.c +++ b/arch/mips/kernel/perf_event.c | |||
| @@ -35,7 +35,7 @@ static void save_raw_perf_callchain(struct perf_callchain_entry *entry, | |||
| 35 | addr = *sp++; | 35 | addr = *sp++; |
| 36 | if (__kernel_text_address(addr)) { | 36 | if (__kernel_text_address(addr)) { |
| 37 | perf_callchain_store(entry, addr); | 37 | perf_callchain_store(entry, addr); |
| 38 | if (entry->nr >= PERF_MAX_STACK_DEPTH) | 38 | if (entry->nr >= sysctl_perf_event_max_stack) |
| 39 | break; | 39 | break; |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
| @@ -59,7 +59,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, | |||
| 59 | } | 59 | } |
| 60 | do { | 60 | do { |
| 61 | perf_callchain_store(entry, pc); | 61 | perf_callchain_store(entry, pc); |
| 62 | if (entry->nr >= PERF_MAX_STACK_DEPTH) | 62 | if (entry->nr >= sysctl_perf_event_max_stack) |
| 63 | break; | 63 | break; |
| 64 | pc = unwind_stack(current, &sp, pc, &ra); | 64 | pc = unwind_stack(current, &sp, pc, &ra); |
| 65 | } while (pc); | 65 | } while (pc); |
diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c index e04a6752b399..22d9015c1acc 100644 --- a/arch/powerpc/perf/callchain.c +++ b/arch/powerpc/perf/callchain.c | |||
| @@ -247,7 +247,7 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, | |||
| 247 | sp = regs->gpr[1]; | 247 | sp = regs->gpr[1]; |
| 248 | perf_callchain_store(entry, next_ip); | 248 | perf_callchain_store(entry, next_ip); |
| 249 | 249 | ||
| 250 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 250 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 251 | fp = (unsigned long __user *) sp; | 251 | fp = (unsigned long __user *) sp; |
| 252 | if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp)) | 252 | if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp)) |
| 253 | return; | 253 | return; |
| @@ -453,7 +453,7 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, | |||
| 453 | sp = regs->gpr[1]; | 453 | sp = regs->gpr[1]; |
| 454 | perf_callchain_store(entry, next_ip); | 454 | perf_callchain_store(entry, next_ip); |
| 455 | 455 | ||
| 456 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 456 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 457 | fp = (unsigned int __user *) (unsigned long) sp; | 457 | fp = (unsigned int __user *) (unsigned long) sp; |
| 458 | if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp)) | 458 | if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp)) |
| 459 | return; | 459 | return; |
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 6596f66ce112..a4b8b5aed21c 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c | |||
| @@ -1756,7 +1756,7 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry, | |||
| 1756 | } | 1756 | } |
| 1757 | } | 1757 | } |
| 1758 | #endif | 1758 | #endif |
| 1759 | } while (entry->nr < PERF_MAX_STACK_DEPTH); | 1759 | } while (entry->nr < sysctl_perf_event_max_stack); |
| 1760 | } | 1760 | } |
| 1761 | 1761 | ||
| 1762 | static inline int | 1762 | static inline int |
| @@ -1790,7 +1790,7 @@ static void perf_callchain_user_64(struct perf_callchain_entry *entry, | |||
| 1790 | pc = sf.callers_pc; | 1790 | pc = sf.callers_pc; |
| 1791 | ufp = (unsigned long)sf.fp + STACK_BIAS; | 1791 | ufp = (unsigned long)sf.fp + STACK_BIAS; |
| 1792 | perf_callchain_store(entry, pc); | 1792 | perf_callchain_store(entry, pc); |
| 1793 | } while (entry->nr < PERF_MAX_STACK_DEPTH); | 1793 | } while (entry->nr < sysctl_perf_event_max_stack); |
| 1794 | } | 1794 | } |
| 1795 | 1795 | ||
| 1796 | static void perf_callchain_user_32(struct perf_callchain_entry *entry, | 1796 | static void perf_callchain_user_32(struct perf_callchain_entry *entry, |
| @@ -1822,7 +1822,7 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry, | |||
| 1822 | ufp = (unsigned long)sf.fp; | 1822 | ufp = (unsigned long)sf.fp; |
| 1823 | } | 1823 | } |
| 1824 | perf_callchain_store(entry, pc); | 1824 | perf_callchain_store(entry, pc); |
| 1825 | } while (entry->nr < PERF_MAX_STACK_DEPTH); | 1825 | } while (entry->nr < sysctl_perf_event_max_stack); |
| 1826 | } | 1826 | } |
| 1827 | 1827 | ||
| 1828 | void | 1828 | void |
diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 041e442a3e28..41d93d0e972b 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c | |||
| @@ -2277,7 +2277,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry) | |||
| 2277 | 2277 | ||
| 2278 | fp = compat_ptr(ss_base + regs->bp); | 2278 | fp = compat_ptr(ss_base + regs->bp); |
| 2279 | pagefault_disable(); | 2279 | pagefault_disable(); |
| 2280 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 2280 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 2281 | unsigned long bytes; | 2281 | unsigned long bytes; |
| 2282 | frame.next_frame = 0; | 2282 | frame.next_frame = 0; |
| 2283 | frame.return_address = 0; | 2283 | frame.return_address = 0; |
| @@ -2337,7 +2337,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs) | |||
| 2337 | return; | 2337 | return; |
| 2338 | 2338 | ||
| 2339 | pagefault_disable(); | 2339 | pagefault_disable(); |
| 2340 | while (entry->nr < PERF_MAX_STACK_DEPTH) { | 2340 | while (entry->nr < sysctl_perf_event_max_stack) { |
| 2341 | unsigned long bytes; | 2341 | unsigned long bytes; |
| 2342 | frame.next_frame = NULL; | 2342 | frame.next_frame = NULL; |
| 2343 | frame.return_address = 0; | 2343 | frame.return_address = 0; |
diff --git a/arch/xtensa/kernel/perf_event.c b/arch/xtensa/kernel/perf_event.c index 54f01188c29c..a6b00b3af429 100644 --- a/arch/xtensa/kernel/perf_event.c +++ b/arch/xtensa/kernel/perf_event.c | |||
| @@ -332,14 +332,14 @@ static int callchain_trace(struct stackframe *frame, void *data) | |||
| 332 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | 332 | void perf_callchain_kernel(struct perf_callchain_entry *entry, |
| 333 | struct pt_regs *regs) | 333 | struct pt_regs *regs) |
| 334 | { | 334 | { |
| 335 | xtensa_backtrace_kernel(regs, PERF_MAX_STACK_DEPTH, | 335 | xtensa_backtrace_kernel(regs, sysctl_perf_event_max_stack, |
| 336 | callchain_trace, NULL, entry); | 336 | callchain_trace, NULL, entry); |
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | void perf_callchain_user(struct perf_callchain_entry *entry, | 339 | void perf_callchain_user(struct perf_callchain_entry *entry, |
| 340 | struct pt_regs *regs) | 340 | struct pt_regs *regs) |
| 341 | { | 341 | { |
| 342 | xtensa_backtrace_user(regs, PERF_MAX_STACK_DEPTH, | 342 | xtensa_backtrace_user(regs, sysctl_perf_event_max_stack, |
| 343 | callchain_trace, entry); | 343 | callchain_trace, entry); |
| 344 | } | 344 | } |
| 345 | 345 | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 85749ae8cb5f..a090700cccca 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -58,7 +58,7 @@ struct perf_guest_info_callbacks { | |||
| 58 | 58 | ||
| 59 | struct perf_callchain_entry { | 59 | struct perf_callchain_entry { |
| 60 | __u64 nr; | 60 | __u64 nr; |
| 61 | __u64 ip[PERF_MAX_STACK_DEPTH]; | 61 | __u64 ip[0]; /* /proc/sys/kernel/perf_event_max_stack */ |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
| 64 | struct perf_raw_record { | 64 | struct perf_raw_record { |
| @@ -993,9 +993,11 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, | |||
| 993 | extern int get_callchain_buffers(void); | 993 | extern int get_callchain_buffers(void); |
| 994 | extern void put_callchain_buffers(void); | 994 | extern void put_callchain_buffers(void); |
| 995 | 995 | ||
| 996 | extern int sysctl_perf_event_max_stack; | ||
| 997 | |||
| 996 | static inline int perf_callchain_store(struct perf_callchain_entry *entry, u64 ip) | 998 | static inline int perf_callchain_store(struct perf_callchain_entry *entry, u64 ip) |
| 997 | { | 999 | { |
| 998 | if (entry->nr < PERF_MAX_STACK_DEPTH) { | 1000 | if (entry->nr < sysctl_perf_event_max_stack) { |
| 999 | entry->ip[entry->nr++] = ip; | 1001 | entry->ip[entry->nr++] = ip; |
| 1000 | return 0; | 1002 | return 0; |
| 1001 | } else { | 1003 | } else { |
| @@ -1017,6 +1019,8 @@ extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, | |||
| 1017 | void __user *buffer, size_t *lenp, | 1019 | void __user *buffer, size_t *lenp, |
| 1018 | loff_t *ppos); | 1020 | loff_t *ppos); |
| 1019 | 1021 | ||
| 1022 | int perf_event_max_stack_handler(struct ctl_table *table, int write, | ||
| 1023 | void __user *buffer, size_t *lenp, loff_t *ppos); | ||
| 1020 | 1024 | ||
| 1021 | static inline bool perf_paranoid_tracepoint_raw(void) | 1025 | static inline bool perf_paranoid_tracepoint_raw(void) |
| 1022 | { | 1026 | { |
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 499d9e933f8e..f5a19548be12 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c | |||
| @@ -66,7 +66,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) | |||
| 66 | /* check sanity of attributes */ | 66 | /* check sanity of attributes */ |
| 67 | if (attr->max_entries == 0 || attr->key_size != 4 || | 67 | if (attr->max_entries == 0 || attr->key_size != 4 || |
| 68 | value_size < 8 || value_size % 8 || | 68 | value_size < 8 || value_size % 8 || |
| 69 | value_size / 8 > PERF_MAX_STACK_DEPTH) | 69 | value_size / 8 > sysctl_perf_event_max_stack) |
| 70 | return ERR_PTR(-EINVAL); | 70 | return ERR_PTR(-EINVAL); |
| 71 | 71 | ||
| 72 | /* hash table size must be power of 2 */ | 72 | /* hash table size must be power of 2 */ |
| @@ -124,8 +124,8 @@ static u64 bpf_get_stackid(u64 r1, u64 r2, u64 flags, u64 r4, u64 r5) | |||
| 124 | struct perf_callchain_entry *trace; | 124 | struct perf_callchain_entry *trace; |
| 125 | struct stack_map_bucket *bucket, *new_bucket, *old_bucket; | 125 | struct stack_map_bucket *bucket, *new_bucket, *old_bucket; |
| 126 | u32 max_depth = map->value_size / 8; | 126 | u32 max_depth = map->value_size / 8; |
| 127 | /* stack_map_alloc() checks that max_depth <= PERF_MAX_STACK_DEPTH */ | 127 | /* stack_map_alloc() checks that max_depth <= sysctl_perf_event_max_stack */ |
| 128 | u32 init_nr = PERF_MAX_STACK_DEPTH - max_depth; | 128 | u32 init_nr = sysctl_perf_event_max_stack - max_depth; |
| 129 | u32 skip = flags & BPF_F_SKIP_FIELD_MASK; | 129 | u32 skip = flags & BPF_F_SKIP_FIELD_MASK; |
| 130 | u32 hash, id, trace_nr, trace_len; | 130 | u32 hash, id, trace_nr, trace_len; |
| 131 | bool user = flags & BPF_F_USER_STACK; | 131 | bool user = flags & BPF_F_USER_STACK; |
| @@ -143,7 +143,7 @@ static u64 bpf_get_stackid(u64 r1, u64 r2, u64 flags, u64 r4, u64 r5) | |||
| 143 | return -EFAULT; | 143 | return -EFAULT; |
| 144 | 144 | ||
| 145 | /* get_perf_callchain() guarantees that trace->nr >= init_nr | 145 | /* get_perf_callchain() guarantees that trace->nr >= init_nr |
| 146 | * and trace-nr <= PERF_MAX_STACK_DEPTH, so trace_nr <= max_depth | 146 | * and trace-nr <= sysctl_perf_event_max_stack, so trace_nr <= max_depth |
| 147 | */ | 147 | */ |
| 148 | trace_nr = trace->nr - init_nr; | 148 | trace_nr = trace->nr - init_nr; |
| 149 | 149 | ||
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index 343c22f5e867..b9325e7dcba1 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c | |||
| @@ -18,6 +18,14 @@ struct callchain_cpus_entries { | |||
| 18 | struct perf_callchain_entry *cpu_entries[0]; | 18 | struct perf_callchain_entry *cpu_entries[0]; |
| 19 | }; | 19 | }; |
| 20 | 20 | ||
| 21 | int sysctl_perf_event_max_stack __read_mostly = PERF_MAX_STACK_DEPTH; | ||
| 22 | |||
| 23 | static inline size_t perf_callchain_entry__sizeof(void) | ||
| 24 | { | ||
| 25 | return (sizeof(struct perf_callchain_entry) + | ||
| 26 | sizeof(__u64) * sysctl_perf_event_max_stack); | ||
| 27 | } | ||
| 28 | |||
| 21 | static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); | 29 | static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); |
| 22 | static atomic_t nr_callchain_events; | 30 | static atomic_t nr_callchain_events; |
| 23 | static DEFINE_MUTEX(callchain_mutex); | 31 | static DEFINE_MUTEX(callchain_mutex); |
| @@ -73,7 +81,7 @@ static int alloc_callchain_buffers(void) | |||
| 73 | if (!entries) | 81 | if (!entries) |
| 74 | return -ENOMEM; | 82 | return -ENOMEM; |
| 75 | 83 | ||
| 76 | size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS; | 84 | size = perf_callchain_entry__sizeof() * PERF_NR_CONTEXTS; |
| 77 | 85 | ||
| 78 | for_each_possible_cpu(cpu) { | 86 | for_each_possible_cpu(cpu) { |
| 79 | entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, | 87 | entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, |
| @@ -147,7 +155,8 @@ static struct perf_callchain_entry *get_callchain_entry(int *rctx) | |||
| 147 | 155 | ||
| 148 | cpu = smp_processor_id(); | 156 | cpu = smp_processor_id(); |
| 149 | 157 | ||
| 150 | return &entries->cpu_entries[cpu][*rctx]; | 158 | return (((void *)entries->cpu_entries[cpu]) + |
| 159 | (*rctx * perf_callchain_entry__sizeof())); | ||
| 151 | } | 160 | } |
| 152 | 161 | ||
| 153 | static void | 162 | static void |
| @@ -215,3 +224,25 @@ exit_put: | |||
| 215 | 224 | ||
| 216 | return entry; | 225 | return entry; |
| 217 | } | 226 | } |
| 227 | |||
| 228 | int perf_event_max_stack_handler(struct ctl_table *table, int write, | ||
| 229 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
| 230 | { | ||
| 231 | int new_value = sysctl_perf_event_max_stack, ret; | ||
| 232 | struct ctl_table new_table = *table; | ||
| 233 | |||
| 234 | new_table.data = &new_value; | ||
| 235 | ret = proc_dointvec_minmax(&new_table, write, buffer, lenp, ppos); | ||
| 236 | if (ret || !write) | ||
| 237 | return ret; | ||
| 238 | |||
| 239 | mutex_lock(&callchain_mutex); | ||
| 240 | if (atomic_read(&nr_callchain_events)) | ||
| 241 | ret = -EBUSY; | ||
| 242 | else | ||
| 243 | sysctl_perf_event_max_stack = new_value; | ||
| 244 | |||
| 245 | mutex_unlock(&callchain_mutex); | ||
| 246 | |||
| 247 | return ret; | ||
| 248 | } | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 725587f10667..c8b318663525 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -130,6 +130,9 @@ static int one_thousand = 1000; | |||
| 130 | #ifdef CONFIG_PRINTK | 130 | #ifdef CONFIG_PRINTK |
| 131 | static int ten_thousand = 10000; | 131 | static int ten_thousand = 10000; |
| 132 | #endif | 132 | #endif |
| 133 | #ifdef CONFIG_PERF_EVENTS | ||
| 134 | static int six_hundred_forty_kb = 640 * 1024; | ||
| 135 | #endif | ||
| 133 | 136 | ||
| 134 | /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ | 137 | /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ |
| 135 | static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; | 138 | static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; |
| @@ -1144,6 +1147,15 @@ static struct ctl_table kern_table[] = { | |||
| 1144 | .extra1 = &zero, | 1147 | .extra1 = &zero, |
| 1145 | .extra2 = &one_hundred, | 1148 | .extra2 = &one_hundred, |
| 1146 | }, | 1149 | }, |
| 1150 | { | ||
| 1151 | .procname = "perf_event_max_stack", | ||
| 1152 | .data = NULL, /* filled in by handler */ | ||
| 1153 | .maxlen = sizeof(sysctl_perf_event_max_stack), | ||
| 1154 | .mode = 0644, | ||
| 1155 | .proc_handler = perf_event_max_stack_handler, | ||
| 1156 | .extra1 = &zero, | ||
| 1157 | .extra2 = &six_hundred_forty_kb, | ||
| 1158 | }, | ||
| 1147 | #endif | 1159 | #endif |
| 1148 | #ifdef CONFIG_KMEMCHECK | 1160 | #ifdef CONFIG_KMEMCHECK |
| 1149 | { | 1161 | { |
diff --git a/tools/Makefile b/tools/Makefile index 60c7e6c8ff17..6bf68fe7dd29 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
| @@ -137,7 +137,8 @@ libsubcmd_clean: | |||
| 137 | $(call descend,lib/subcmd,clean) | 137 | $(call descend,lib/subcmd,clean) |
| 138 | 138 | ||
| 139 | perf_clean: | 139 | perf_clean: |
| 140 | $(call descend,$(@:_clean=),clean) | 140 | $(Q)mkdir -p $(PERF_O) . |
| 141 | $(Q)$(MAKE) --no-print-directory -C perf O=$(PERF_O) subdir= clean | ||
| 141 | 142 | ||
| 142 | selftests_clean: | 143 | selftests_clean: |
| 143 | $(call descend,testing/$(@:_clean=),clean) | 144 | $(call descend,testing/$(@:_clean=),clean) |
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index ef78c22ff44d..08556cf2c70d 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c | |||
| @@ -351,6 +351,19 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) | |||
| 351 | return err; | 351 | return err; |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | int procfs__read_str(const char *entry, char **buf, size_t *sizep) | ||
| 355 | { | ||
| 356 | char path[PATH_MAX]; | ||
| 357 | const char *procfs = procfs__mountpoint(); | ||
| 358 | |||
| 359 | if (!procfs) | ||
| 360 | return -1; | ||
| 361 | |||
| 362 | snprintf(path, sizeof(path), "%s/%s", procfs, entry); | ||
| 363 | |||
| 364 | return filename__read_str(path, buf, sizep); | ||
| 365 | } | ||
| 366 | |||
| 354 | int sysfs__read_ull(const char *entry, unsigned long long *value) | 367 | int sysfs__read_ull(const char *entry, unsigned long long *value) |
| 355 | { | 368 | { |
| 356 | char path[PATH_MAX]; | 369 | char path[PATH_MAX]; |
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 9f6598098dc5..16c9c2ed7c5b 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h | |||
| @@ -29,6 +29,8 @@ int filename__read_int(const char *filename, int *value); | |||
| 29 | int filename__read_ull(const char *filename, unsigned long long *value); | 29 | int filename__read_ull(const char *filename, unsigned long long *value); |
| 30 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | 30 | int filename__read_str(const char *filename, char **buf, size_t *sizep); |
| 31 | 31 | ||
| 32 | int procfs__read_str(const char *entry, char **buf, size_t *sizep); | ||
| 33 | |||
| 32 | int sysctl__read_int(const char *sysctl, int *value); | 34 | int sysctl__read_int(const char *sysctl, int *value); |
| 33 | int sysfs__read_int(const char *entry, int *value); | 35 | int sysfs__read_int(const char *entry, int *value); |
| 34 | int sysfs__read_ull(const char *entry, unsigned long long *value); | 36 | int sysfs__read_ull(const char *entry, unsigned long long *value); |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 496d42cdf02b..ebaf849e30ef 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
| @@ -248,7 +248,7 @@ OPTIONS | |||
| 248 | Note that when using the --itrace option the synthesized callchain size | 248 | Note that when using the --itrace option the synthesized callchain size |
| 249 | will override this value if the synthesized callchain size is bigger. | 249 | will override this value if the synthesized callchain size is bigger. |
| 250 | 250 | ||
| 251 | Default: 127 | 251 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
| 252 | 252 | ||
| 253 | -G:: | 253 | -G:: |
| 254 | --inverted:: | 254 | --inverted:: |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 4fc44c75263f..a856a1095893 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
| @@ -267,7 +267,7 @@ include::itrace.txt[] | |||
| 267 | Note that when using the --itrace option the synthesized callchain size | 267 | Note that when using the --itrace option the synthesized callchain size |
| 268 | will override this value if the synthesized callchain size is bigger. | 268 | will override this value if the synthesized callchain size is bigger. |
| 269 | 269 | ||
| 270 | Default: 127 | 270 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
| 271 | 271 | ||
| 272 | --ns:: | 272 | --ns:: |
| 273 | Use 9 decimal places when displaying time (i.e. show the nanoseconds) | 273 | Use 9 decimal places when displaying time (i.e. show the nanoseconds) |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 19f046f027cd..91d638df3a6b 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
| @@ -177,7 +177,7 @@ Default is to monitor all CPUS. | |||
| 177 | between information loss and faster processing especially for | 177 | between information loss and faster processing especially for |
| 178 | workloads that can have a very long callchain stack. | 178 | workloads that can have a very long callchain stack. |
| 179 | 179 | ||
| 180 | Default: 127 | 180 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
| 181 | 181 | ||
| 182 | --ignore-callees=<regex>:: | 182 | --ignore-callees=<regex>:: |
| 183 | Ignore callees of the function(s) matching the given regex. | 183 | Ignore callees of the function(s) matching the given regex. |
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index c075c002eaa4..6afe20121bc0 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
| @@ -143,7 +143,7 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
| 143 | Implies '--call-graph dwarf' when --call-graph not present on the | 143 | Implies '--call-graph dwarf' when --call-graph not present on the |
| 144 | command line, on systems where DWARF unwinding was built in. | 144 | command line, on systems where DWARF unwinding was built in. |
| 145 | 145 | ||
| 146 | Default: 127 | 146 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
| 147 | 147 | ||
| 148 | --min-stack:: | 148 | --min-stack:: |
| 149 | Set the stack depth limit when parsing the callchain, anything | 149 | Set the stack depth limit when parsing the callchain, anything |
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index a33729173b13..6c9211b18ec0 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile | |||
| @@ -24,6 +24,6 @@ $(header): $(sys)/syscall_64.tbl $(systbl) | |||
| 24 | $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ | 24 | $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ |
| 25 | 25 | ||
| 26 | clean:: | 26 | clean:: |
| 27 | rm -f $(header) | 27 | $(call QUIET_CLEAN, x86) $(RM) $(header) |
| 28 | 28 | ||
| 29 | archheaders: $(header) | 29 | archheaders: $(header) |
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index 2e5b565adacc..cac6d17ce5db 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | |||
| @@ -333,6 +333,8 @@ | |||
| 333 | 324 common membarrier sys_membarrier | 333 | 324 common membarrier sys_membarrier |
| 334 | 325 common mlock2 sys_mlock2 | 334 | 325 common mlock2 sys_mlock2 |
| 335 | 326 common copy_file_range sys_copy_file_range | 335 | 326 common copy_file_range sys_copy_file_range |
| 336 | 327 64 preadv2 sys_preadv2 | ||
| 337 | 328 64 pwritev2 sys_pwritev2 | ||
| 336 | 338 | ||
| 337 | # | 339 | # |
| 338 | # x32-specific system call numbers start at 512 to avoid cache impact | 340 | # x32-specific system call numbers start at 512 to avoid cache impact |
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index 6a18ce21f865..6952db65508a 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c | |||
| @@ -83,7 +83,7 @@ static void *workerfn(void *arg) | |||
| 83 | do { | 83 | do { |
| 84 | int ret; | 84 | int ret; |
| 85 | again: | 85 | again: |
| 86 | ret = futex_lock_pi(w->futex, NULL, 0, futex_flag); | 86 | ret = futex_lock_pi(w->futex, NULL, futex_flag); |
| 87 | 87 | ||
| 88 | if (ret) { /* handle lock acquisition */ | 88 | if (ret) { /* handle lock acquisition */ |
| 89 | if (!silent) | 89 | if (!silent) |
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h index d44de9f44281..b2e06d1190d0 100644 --- a/tools/perf/bench/futex.h +++ b/tools/perf/bench/futex.h | |||
| @@ -57,13 +57,11 @@ futex_wake(u_int32_t *uaddr, int nr_wake, int opflags) | |||
| 57 | 57 | ||
| 58 | /** | 58 | /** |
| 59 | * futex_lock_pi() - block on uaddr as a PI mutex | 59 | * futex_lock_pi() - block on uaddr as a PI mutex |
| 60 | * @detect: whether (1) or not (0) to perform deadlock detection | ||
| 61 | */ | 60 | */ |
| 62 | static inline int | 61 | static inline int |
| 63 | futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int detect, | 62 | futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int opflags) |
| 64 | int opflags) | ||
| 65 | { | 63 | { |
| 66 | return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags); | 64 | return futex(uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0, opflags); |
| 67 | } | 65 | } |
| 68 | 66 | ||
| 69 | /** | 67 | /** |
diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index a91aa85d80ff..2b54d0f2672a 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | 6 | * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include "debug.h" | ||
| 9 | #include "../perf.h" | 10 | #include "../perf.h" |
| 10 | #include "../util/util.h" | 11 | #include "../util/util.h" |
| 11 | #include <subcmd/parse-options.h> | 12 | #include <subcmd/parse-options.h> |
| @@ -63,14 +64,16 @@ static struct perf_event_attr cycle_attr = { | |||
| 63 | .config = PERF_COUNT_HW_CPU_CYCLES | 64 | .config = PERF_COUNT_HW_CPU_CYCLES |
| 64 | }; | 65 | }; |
| 65 | 66 | ||
| 66 | static void init_cycles(void) | 67 | static int init_cycles(void) |
| 67 | { | 68 | { |
| 68 | cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); | 69 | cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); |
| 69 | 70 | ||
| 70 | if (cycles_fd < 0 && errno == ENOSYS) | 71 | if (cycles_fd < 0 && errno == ENOSYS) { |
| 71 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 72 | pr_debug("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
| 72 | else | 73 | return -1; |
| 73 | BUG_ON(cycles_fd < 0); | 74 | } |
| 75 | |||
| 76 | return cycles_fd; | ||
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | static u64 get_cycles(void) | 79 | static u64 get_cycles(void) |
| @@ -155,8 +158,13 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * | |||
| 155 | 158 | ||
| 156 | argc = parse_options(argc, argv, options, info->usage, 0); | 159 | argc = parse_options(argc, argv, options, info->usage, 0); |
| 157 | 160 | ||
| 158 | if (use_cycles) | 161 | if (use_cycles) { |
| 159 | init_cycles(); | 162 | i = init_cycles(); |
| 163 | if (i < 0) { | ||
| 164 | fprintf(stderr, "Failed to open cycles counter\n"); | ||
| 165 | return i; | ||
| 166 | } | ||
| 167 | } | ||
| 160 | 168 | ||
| 161 | size = (size_t)perf_atoll((char *)size_str); | 169 | size = (size_t)perf_atoll((char *)size_str); |
| 162 | size_total = (double)size * nr_loops; | 170 | size_total = (double)size * nr_loops; |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 1d5be0bd426f..8d9b88af901d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -691,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 691 | .ordered_events = true, | 691 | .ordered_events = true, |
| 692 | .ordering_requires_timestamps = true, | 692 | .ordering_requires_timestamps = true, |
| 693 | }, | 693 | }, |
| 694 | .max_stack = PERF_MAX_STACK_DEPTH, | 694 | .max_stack = sysctl_perf_event_max_stack, |
| 695 | .pretty_printing_style = "normal", | 695 | .pretty_printing_style = "normal", |
| 696 | .socket_filter = -1, | 696 | .socket_filter = -1, |
| 697 | }; | 697 | }; |
| @@ -744,7 +744,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 744 | OPT_INTEGER(0, "max-stack", &report.max_stack, | 744 | OPT_INTEGER(0, "max-stack", &report.max_stack, |
| 745 | "Set the maximum stack depth when parsing the callchain, " | 745 | "Set the maximum stack depth when parsing the callchain, " |
| 746 | "anything beyond the specified depth will be ignored. " | 746 | "anything beyond the specified depth will be ignored. " |
| 747 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 747 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
| 748 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, | 748 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, |
| 749 | "alias for inverted call graph"), | 749 | "alias for inverted call graph"), |
| 750 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 750 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 5099740aa50b..efca81679bb3 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -570,12 +570,12 @@ static void print_sample_bts(struct perf_sample *sample, | |||
| 570 | /* print branch_from information */ | 570 | /* print branch_from information */ |
| 571 | if (PRINT_FIELD(IP)) { | 571 | if (PRINT_FIELD(IP)) { |
| 572 | unsigned int print_opts = output[attr->type].print_ip_opts; | 572 | unsigned int print_opts = output[attr->type].print_ip_opts; |
| 573 | struct callchain_cursor *cursor = NULL, cursor_callchain; | 573 | struct callchain_cursor *cursor = NULL; |
| 574 | 574 | ||
| 575 | if (symbol_conf.use_callchain && sample->callchain && | 575 | if (symbol_conf.use_callchain && sample->callchain && |
| 576 | thread__resolve_callchain(al->thread, &cursor_callchain, evsel, | 576 | thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
| 577 | sample, NULL, NULL, scripting_max_stack) == 0) | 577 | sample, NULL, NULL, scripting_max_stack) == 0) |
| 578 | cursor = &cursor_callchain; | 578 | cursor = &callchain_cursor; |
| 579 | 579 | ||
| 580 | if (cursor == NULL) { | 580 | if (cursor == NULL) { |
| 581 | putchar(' '); | 581 | putchar(' '); |
| @@ -789,12 +789,12 @@ static void process_event(struct perf_script *script, | |||
| 789 | printf("%16" PRIu64, sample->weight); | 789 | printf("%16" PRIu64, sample->weight); |
| 790 | 790 | ||
| 791 | if (PRINT_FIELD(IP)) { | 791 | if (PRINT_FIELD(IP)) { |
| 792 | struct callchain_cursor *cursor = NULL, cursor_callchain; | 792 | struct callchain_cursor *cursor = NULL; |
| 793 | 793 | ||
| 794 | if (symbol_conf.use_callchain && sample->callchain && | 794 | if (symbol_conf.use_callchain && sample->callchain && |
| 795 | thread__resolve_callchain(al->thread, &cursor_callchain, evsel, | 795 | thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
| 796 | sample, NULL, NULL, scripting_max_stack) == 0) | 796 | sample, NULL, NULL, scripting_max_stack) == 0) |
| 797 | cursor = &cursor_callchain; | 797 | cursor = &callchain_cursor; |
| 798 | 798 | ||
| 799 | putchar(cursor ? '\n' : ' '); | 799 | putchar(cursor ? '\n' : ' '); |
| 800 | sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); | 800 | sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); |
| @@ -2031,7 +2031,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 2031 | OPT_UINTEGER(0, "max-stack", &scripting_max_stack, | 2031 | OPT_UINTEGER(0, "max-stack", &scripting_max_stack, |
| 2032 | "Set the maximum stack depth when parsing the callchain, " | 2032 | "Set the maximum stack depth when parsing the callchain, " |
| 2033 | "anything beyond the specified depth will be ignored. " | 2033 | "anything beyond the specified depth will be ignored. " |
| 2034 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 2034 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
| 2035 | OPT_BOOLEAN('I', "show-info", &show_full_info, | 2035 | OPT_BOOLEAN('I', "show-info", &show_full_info, |
| 2036 | "display extended information from perf.data file"), | 2036 | "display extended information from perf.data file"), |
| 2037 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, | 2037 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, |
| @@ -2067,6 +2067,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 2067 | NULL | 2067 | NULL |
| 2068 | }; | 2068 | }; |
| 2069 | 2069 | ||
| 2070 | scripting_max_stack = sysctl_perf_event_max_stack; | ||
| 2071 | |||
| 2070 | setup_scripting(); | 2072 | setup_scripting(); |
| 2071 | 2073 | ||
| 2072 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, | 2074 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c130a11d3a0d..da18517b1d40 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -1103,7 +1103,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1103 | }, | 1103 | }, |
| 1104 | .proc_map_timeout = 500, | 1104 | .proc_map_timeout = 500, |
| 1105 | }, | 1105 | }, |
| 1106 | .max_stack = PERF_MAX_STACK_DEPTH, | 1106 | .max_stack = sysctl_perf_event_max_stack, |
| 1107 | .sym_pcnt_filter = 5, | 1107 | .sym_pcnt_filter = 5, |
| 1108 | }; | 1108 | }; |
| 1109 | struct record_opts *opts = &top.record_opts; | 1109 | struct record_opts *opts = &top.record_opts; |
| @@ -1171,7 +1171,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1171 | "Accumulate callchains of children and show total overhead as well"), | 1171 | "Accumulate callchains of children and show total overhead as well"), |
| 1172 | OPT_INTEGER(0, "max-stack", &top.max_stack, | 1172 | OPT_INTEGER(0, "max-stack", &top.max_stack, |
| 1173 | "Set the maximum stack depth when parsing the callchain. " | 1173 | "Set the maximum stack depth when parsing the callchain. " |
| 1174 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 1174 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
| 1175 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 1175 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
| 1176 | "ignore callees of these functions in call graphs", | 1176 | "ignore callees of these functions in call graphs", |
| 1177 | report_parse_ignore_callees_opt), | 1177 | report_parse_ignore_callees_opt), |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 5e2614bbb48d..f4f3389c92c7 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -56,22 +56,6 @@ | |||
| 56 | # define MSG_CMSG_CLOEXEC 0x40000000 | 56 | # define MSG_CMSG_CLOEXEC 0x40000000 |
| 57 | #endif | 57 | #endif |
| 58 | 58 | ||
| 59 | #ifndef PERF_FLAG_FD_NO_GROUP | ||
| 60 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) | ||
| 61 | #endif | ||
| 62 | |||
| 63 | #ifndef PERF_FLAG_FD_OUTPUT | ||
| 64 | # define PERF_FLAG_FD_OUTPUT (1UL << 1) | ||
| 65 | #endif | ||
| 66 | |||
| 67 | #ifndef PERF_FLAG_PID_CGROUP | ||
| 68 | # define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ | ||
| 69 | #endif | ||
| 70 | |||
| 71 | #ifndef PERF_FLAG_FD_CLOEXEC | ||
| 72 | # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ | ||
| 73 | #endif | ||
| 74 | |||
| 75 | struct trace { | 59 | struct trace { |
| 76 | struct perf_tool tool; | 60 | struct perf_tool tool; |
| 77 | struct syscalltbl *sctbl; | 61 | struct syscalltbl *sctbl; |
| @@ -674,34 +658,6 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, | |||
| 674 | 658 | ||
| 675 | #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags | 659 | #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags |
| 676 | 660 | ||
| 677 | static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, | ||
| 678 | struct syscall_arg *arg) | ||
| 679 | { | ||
| 680 | int printed = 0, flags = arg->val; | ||
| 681 | |||
| 682 | if (flags == 0) | ||
| 683 | return 0; | ||
| 684 | |||
| 685 | #define P_FLAG(n) \ | ||
| 686 | if (flags & PERF_FLAG_##n) { \ | ||
| 687 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 688 | flags &= ~PERF_FLAG_##n; \ | ||
| 689 | } | ||
| 690 | |||
| 691 | P_FLAG(FD_NO_GROUP); | ||
| 692 | P_FLAG(FD_OUTPUT); | ||
| 693 | P_FLAG(PID_CGROUP); | ||
| 694 | P_FLAG(FD_CLOEXEC); | ||
| 695 | #undef P_FLAG | ||
| 696 | |||
| 697 | if (flags) | ||
| 698 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 699 | |||
| 700 | return printed; | ||
| 701 | } | ||
| 702 | |||
| 703 | #define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags | ||
| 704 | |||
| 705 | static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, | 661 | static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, |
| 706 | struct syscall_arg *arg) | 662 | struct syscall_arg *arg) |
| 707 | { | 663 | { |
| @@ -894,6 +850,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, | |||
| 894 | #include "trace/beauty/pid.c" | 850 | #include "trace/beauty/pid.c" |
| 895 | #include "trace/beauty/mmap.c" | 851 | #include "trace/beauty/mmap.c" |
| 896 | #include "trace/beauty/mode_t.c" | 852 | #include "trace/beauty/mode_t.c" |
| 853 | #include "trace/beauty/perf_event_open.c" | ||
| 897 | #include "trace/beauty/sched_policy.c" | 854 | #include "trace/beauty/sched_policy.c" |
| 898 | #include "trace/beauty/socket_type.c" | 855 | #include "trace/beauty/socket_type.c" |
| 899 | #include "trace/beauty/waitid_options.c" | 856 | #include "trace/beauty/waitid_options.c" |
| @@ -1086,8 +1043,7 @@ static struct syscall_fmt { | |||
| 1086 | [1] = SCA_FILENAME, /* filename */ | 1043 | [1] = SCA_FILENAME, /* filename */ |
| 1087 | [2] = SCA_OPEN_FLAGS, /* flags */ }, }, | 1044 | [2] = SCA_OPEN_FLAGS, /* flags */ }, }, |
| 1088 | { .name = "perf_event_open", .errmsg = true, | 1045 | { .name = "perf_event_open", .errmsg = true, |
| 1089 | .arg_scnprintf = { [1] = SCA_INT, /* pid */ | 1046 | .arg_scnprintf = { [2] = SCA_INT, /* cpu */ |
| 1090 | [2] = SCA_INT, /* cpu */ | ||
| 1091 | [3] = SCA_FD, /* group_fd */ | 1047 | [3] = SCA_FD, /* group_fd */ |
| 1092 | [4] = SCA_PERF_FLAGS, /* flags */ }, }, | 1048 | [4] = SCA_PERF_FLAGS, /* flags */ }, }, |
| 1093 | { .name = "pipe2", .errmsg = true, | 1049 | { .name = "pipe2", .errmsg = true, |
| @@ -2126,6 +2082,17 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
| 2126 | union perf_event *event __maybe_unused, | 2082 | union perf_event *event __maybe_unused, |
| 2127 | struct perf_sample *sample) | 2083 | struct perf_sample *sample) |
| 2128 | { | 2084 | { |
| 2085 | int callchain_ret = 0; | ||
| 2086 | |||
| 2087 | if (sample->callchain) { | ||
| 2088 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
| 2089 | if (callchain_ret == 0) { | ||
| 2090 | if (callchain_cursor.nr < trace->min_stack) | ||
| 2091 | goto out; | ||
| 2092 | callchain_ret = 1; | ||
| 2093 | } | ||
| 2094 | } | ||
| 2095 | |||
| 2129 | trace__printf_interrupted_entry(trace, sample); | 2096 | trace__printf_interrupted_entry(trace, sample); |
| 2130 | trace__fprintf_tstamp(trace, sample->time, trace->output); | 2097 | trace__fprintf_tstamp(trace, sample->time, trace->output); |
| 2131 | 2098 | ||
| @@ -2144,11 +2111,11 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
| 2144 | 2111 | ||
| 2145 | fprintf(trace->output, ")\n"); | 2112 | fprintf(trace->output, ")\n"); |
| 2146 | 2113 | ||
| 2147 | if (sample->callchain) { | 2114 | if (callchain_ret > 0) |
| 2148 | if (trace__resolve_callchain(trace, evsel, sample, &callchain_cursor) == 0) | 2115 | trace__fprintf_callchain(trace, sample); |
| 2149 | trace__fprintf_callchain(trace, sample); | 2116 | else if (callchain_ret < 0) |
| 2150 | } | 2117 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); |
| 2151 | 2118 | out: | |
| 2152 | return 0; | 2119 | return 0; |
| 2153 | } | 2120 | } |
| 2154 | 2121 | ||
| @@ -2179,8 +2146,19 @@ static int trace__pgfault(struct trace *trace, | |||
| 2179 | char map_type = 'd'; | 2146 | char map_type = 'd'; |
| 2180 | struct thread_trace *ttrace; | 2147 | struct thread_trace *ttrace; |
| 2181 | int err = -1; | 2148 | int err = -1; |
| 2149 | int callchain_ret = 0; | ||
| 2182 | 2150 | ||
| 2183 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); | 2151 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); |
| 2152 | |||
| 2153 | if (sample->callchain) { | ||
| 2154 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
| 2155 | if (callchain_ret == 0) { | ||
| 2156 | if (callchain_cursor.nr < trace->min_stack) | ||
| 2157 | goto out_put; | ||
| 2158 | callchain_ret = 1; | ||
| 2159 | } | ||
| 2160 | } | ||
| 2161 | |||
| 2184 | ttrace = thread__trace(thread, trace->output); | 2162 | ttrace = thread__trace(thread, trace->output); |
| 2185 | if (ttrace == NULL) | 2163 | if (ttrace == NULL) |
| 2186 | goto out_put; | 2164 | goto out_put; |
| @@ -2222,6 +2200,11 @@ static int trace__pgfault(struct trace *trace, | |||
| 2222 | print_location(trace->output, sample, &al, true, false); | 2200 | print_location(trace->output, sample, &al, true, false); |
| 2223 | 2201 | ||
| 2224 | fprintf(trace->output, " (%c%c)\n", map_type, al.level); | 2202 | fprintf(trace->output, " (%c%c)\n", map_type, al.level); |
| 2203 | |||
| 2204 | if (callchain_ret > 0) | ||
| 2205 | trace__fprintf_callchain(trace, sample); | ||
| 2206 | else if (callchain_ret < 0) | ||
| 2207 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | ||
| 2225 | out: | 2208 | out: |
| 2226 | err = 0; | 2209 | err = 0; |
| 2227 | out_put: | 2210 | out_put: |
| @@ -2381,8 +2364,7 @@ static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist) | |||
| 2381 | return true; | 2364 | return true; |
| 2382 | } | 2365 | } |
| 2383 | 2366 | ||
| 2384 | static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | 2367 | static struct perf_evsel *perf_evsel__new_pgfault(u64 config) |
| 2385 | u64 config) | ||
| 2386 | { | 2368 | { |
| 2387 | struct perf_evsel *evsel; | 2369 | struct perf_evsel *evsel; |
| 2388 | struct perf_event_attr attr = { | 2370 | struct perf_event_attr attr = { |
| @@ -2396,13 +2378,10 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | |||
| 2396 | event_attr_init(&attr); | 2378 | event_attr_init(&attr); |
| 2397 | 2379 | ||
| 2398 | evsel = perf_evsel__new(&attr); | 2380 | evsel = perf_evsel__new(&attr); |
| 2399 | if (!evsel) | 2381 | if (evsel) |
| 2400 | return -ENOMEM; | 2382 | evsel->handler = trace__pgfault; |
| 2401 | 2383 | ||
| 2402 | evsel->handler = trace__pgfault; | 2384 | return evsel; |
| 2403 | perf_evlist__add(evlist, evsel); | ||
| 2404 | |||
| 2405 | return 0; | ||
| 2406 | } | 2385 | } |
| 2407 | 2386 | ||
| 2408 | static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) | 2387 | static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) |
| @@ -2504,7 +2483,7 @@ out_enomem: | |||
| 2504 | static int trace__run(struct trace *trace, int argc, const char **argv) | 2483 | static int trace__run(struct trace *trace, int argc, const char **argv) |
| 2505 | { | 2484 | { |
| 2506 | struct perf_evlist *evlist = trace->evlist; | 2485 | struct perf_evlist *evlist = trace->evlist; |
| 2507 | struct perf_evsel *evsel; | 2486 | struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL; |
| 2508 | int err = -1, i; | 2487 | int err = -1, i; |
| 2509 | unsigned long before; | 2488 | unsigned long before; |
| 2510 | const bool forks = argc > 0; | 2489 | const bool forks = argc > 0; |
| @@ -2518,14 +2497,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
| 2518 | if (trace->trace_syscalls) | 2497 | if (trace->trace_syscalls) |
| 2519 | trace->vfs_getname = perf_evlist__add_vfs_getname(evlist); | 2498 | trace->vfs_getname = perf_evlist__add_vfs_getname(evlist); |
| 2520 | 2499 | ||
| 2521 | if ((trace->trace_pgfaults & TRACE_PFMAJ) && | 2500 | if ((trace->trace_pgfaults & TRACE_PFMAJ)) { |
| 2522 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) { | 2501 | pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ); |
| 2523 | goto out_error_mem; | 2502 | if (pgfault_maj == NULL) |
| 2503 | goto out_error_mem; | ||
| 2504 | perf_evlist__add(evlist, pgfault_maj); | ||
| 2524 | } | 2505 | } |
| 2525 | 2506 | ||
| 2526 | if ((trace->trace_pgfaults & TRACE_PFMIN) && | 2507 | if ((trace->trace_pgfaults & TRACE_PFMIN)) { |
| 2527 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) | 2508 | pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN); |
| 2528 | goto out_error_mem; | 2509 | if (pgfault_min == NULL) |
| 2510 | goto out_error_mem; | ||
| 2511 | perf_evlist__add(evlist, pgfault_min); | ||
| 2512 | } | ||
| 2529 | 2513 | ||
| 2530 | if (trace->sched && | 2514 | if (trace->sched && |
| 2531 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", | 2515 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", |
| @@ -2546,24 +2530,42 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
| 2546 | 2530 | ||
| 2547 | perf_evlist__config(evlist, &trace->opts, NULL); | 2531 | perf_evlist__config(evlist, &trace->opts, NULL); |
| 2548 | 2532 | ||
| 2549 | if (callchain_param.enabled && trace->syscalls.events.sys_exit) { | 2533 | if (callchain_param.enabled) { |
| 2550 | perf_evsel__config_callchain(trace->syscalls.events.sys_exit, | 2534 | bool use_identifier = false; |
| 2551 | &trace->opts, &callchain_param); | 2535 | |
| 2552 | /* | 2536 | if (trace->syscalls.events.sys_exit) { |
| 2553 | * Now we have evsels with different sample_ids, use | 2537 | perf_evsel__config_callchain(trace->syscalls.events.sys_exit, |
| 2554 | * PERF_SAMPLE_IDENTIFIER to map from sample to evsel | 2538 | &trace->opts, &callchain_param); |
| 2555 | * from a fixed position in each ring buffer record. | 2539 | use_identifier = true; |
| 2556 | * | 2540 | } |
| 2557 | * As of this the changeset introducing this comment, this | 2541 | |
| 2558 | * isn't strictly needed, as the fields that can come before | 2542 | if (pgfault_maj) { |
| 2559 | * PERF_SAMPLE_ID are all used, but we'll probably disable | 2543 | perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param); |
| 2560 | * some of those for things like copying the payload of | 2544 | use_identifier = true; |
| 2561 | * pointer syscall arguments, and for vfs_getname we don't | 2545 | } |
| 2562 | * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this | 2546 | |
| 2563 | * here as a warning we need to use PERF_SAMPLE_IDENTIFIER. | 2547 | if (pgfault_min) { |
| 2564 | */ | 2548 | perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param); |
| 2565 | perf_evlist__set_sample_bit(evlist, IDENTIFIER); | 2549 | use_identifier = true; |
| 2566 | perf_evlist__reset_sample_bit(evlist, ID); | 2550 | } |
| 2551 | |||
| 2552 | if (use_identifier) { | ||
| 2553 | /* | ||
| 2554 | * Now we have evsels with different sample_ids, use | ||
| 2555 | * PERF_SAMPLE_IDENTIFIER to map from sample to evsel | ||
| 2556 | * from a fixed position in each ring buffer record. | ||
| 2557 | * | ||
| 2558 | * As of this the changeset introducing this comment, this | ||
| 2559 | * isn't strictly needed, as the fields that can come before | ||
| 2560 | * PERF_SAMPLE_ID are all used, but we'll probably disable | ||
| 2561 | * some of those for things like copying the payload of | ||
| 2562 | * pointer syscall arguments, and for vfs_getname we don't | ||
| 2563 | * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this | ||
| 2564 | * here as a warning we need to use PERF_SAMPLE_IDENTIFIER. | ||
| 2565 | */ | ||
| 2566 | perf_evlist__set_sample_bit(evlist, IDENTIFIER); | ||
| 2567 | perf_evlist__reset_sample_bit(evlist, ID); | ||
| 2568 | } | ||
| 2567 | } | 2569 | } |
| 2568 | 2570 | ||
| 2569 | signal(SIGCHLD, sig_handler); | 2571 | signal(SIGCHLD, sig_handler); |
| @@ -3104,7 +3106,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 3104 | OPT_UINTEGER(0, "max-stack", &trace.max_stack, | 3106 | OPT_UINTEGER(0, "max-stack", &trace.max_stack, |
| 3105 | "Set the maximum stack depth when parsing the callchain, " | 3107 | "Set the maximum stack depth when parsing the callchain, " |
| 3106 | "anything beyond the specified depth will be ignored. " | 3108 | "anything beyond the specified depth will be ignored. " |
| 3107 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 3109 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
| 3108 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, | 3110 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, |
| 3109 | "per thread proc mmap processing timeout in ms"), | 3111 | "per thread proc mmap processing timeout in ms"), |
| 3110 | OPT_END() | 3112 | OPT_END() |
| @@ -3148,7 +3150,7 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 3148 | mmap_pages_user_set = false; | 3150 | mmap_pages_user_set = false; |
| 3149 | 3151 | ||
| 3150 | if (trace.max_stack == UINT_MAX) { | 3152 | if (trace.max_stack == UINT_MAX) { |
| 3151 | trace.max_stack = PERF_MAX_STACK_DEPTH; | 3153 | trace.max_stack = sysctl_perf_event_max_stack; |
| 3152 | max_stack_user_set = false; | 3154 | max_stack_user_set = false; |
| 3153 | } | 3155 | } |
| 3154 | 3156 | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 7b2df2b46525..83ffe7cd7330 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <subcmd/parse-options.h> | 17 | #include <subcmd/parse-options.h> |
| 18 | #include "util/bpf-loader.h" | 18 | #include "util/bpf-loader.h" |
| 19 | #include "util/debug.h" | 19 | #include "util/debug.h" |
| 20 | #include <api/fs/fs.h> | ||
| 20 | #include <api/fs/tracing_path.h> | 21 | #include <api/fs/tracing_path.h> |
| 21 | #include <pthread.h> | 22 | #include <pthread.h> |
| 22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
| @@ -533,6 +534,7 @@ int main(int argc, const char **argv) | |||
| 533 | { | 534 | { |
| 534 | const char *cmd; | 535 | const char *cmd; |
| 535 | char sbuf[STRERR_BUFSIZE]; | 536 | char sbuf[STRERR_BUFSIZE]; |
| 537 | int value; | ||
| 536 | 538 | ||
| 537 | /* libsubcmd init */ | 539 | /* libsubcmd init */ |
| 538 | exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); | 540 | exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); |
| @@ -542,6 +544,9 @@ int main(int argc, const char **argv) | |||
| 542 | page_size = sysconf(_SC_PAGE_SIZE); | 544 | page_size = sysconf(_SC_PAGE_SIZE); |
| 543 | cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); | 545 | cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
| 544 | 546 | ||
| 547 | if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) | ||
| 548 | sysctl_perf_event_max_stack = value; | ||
| 549 | |||
| 545 | cmd = extract_argv0_path(argv[0]); | 550 | cmd = extract_argv0_path(argv[0]); |
| 546 | if (!cmd) | 551 | if (!cmd) |
| 547 | cmd = "perf-help"; | 552 | cmd = "perf-help"; |
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 012eab5d1df1..63ecf21750eb 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c | |||
| @@ -30,7 +30,7 @@ static int process_event_scale(struct perf_tool *tool __maybe_unused, | |||
| 30 | 30 | ||
| 31 | TEST_ASSERT_VAL("wrong id", ev->id == 123); | 31 | TEST_ASSERT_VAL("wrong id", ev->id == 123); |
| 32 | TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); | 32 | TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); |
| 33 | TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123); | 33 | TEST_ASSERT_VAL("wrong scale", ev_data->scale == 0.123); |
| 34 | return 0; | 34 | return 0; |
| 35 | } | 35 | } |
| 36 | 36 | ||
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index ed5aa9eaeb6c..4a2bbff9b1ee 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c | |||
| @@ -101,7 +101,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
| 101 | if (machine__resolve(machine, &al, &sample) < 0) | 101 | if (machine__resolve(machine, &al, &sample) < 0) |
| 102 | goto out; | 102 | goto out; |
| 103 | 103 | ||
| 104 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, | 104 | if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack, |
| 105 | NULL) < 0) { | 105 | NULL) < 0) { |
| 106 | addr_location__put(&al); | 106 | addr_location__put(&al); |
| 107 | goto out; | 107 | goto out; |
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index b825d24f8186..e846f8c42013 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c | |||
| @@ -81,7 +81,7 @@ static int add_hist_entries(struct perf_evlist *evlist, | |||
| 81 | 81 | ||
| 82 | al.socket = fake_samples[i].socket; | 82 | al.socket = fake_samples[i].socket; |
| 83 | if (hist_entry_iter__add(&iter, &al, | 83 | if (hist_entry_iter__add(&iter, &al, |
| 84 | PERF_MAX_STACK_DEPTH, NULL) < 0) { | 84 | sysctl_perf_event_max_stack, NULL) < 0) { |
| 85 | addr_location__put(&al); | 85 | addr_location__put(&al); |
| 86 | goto out; | 86 | goto out; |
| 87 | } | 87 | } |
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index d3556fbe8c5c..7cd8738e842f 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c | |||
| @@ -67,7 +67,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
| 67 | if (machine__resolve(machine, &al, &sample) < 0) | 67 | if (machine__resolve(machine, &al, &sample) < 0) |
| 68 | goto out; | 68 | goto out; |
| 69 | 69 | ||
| 70 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, | 70 | if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack, |
| 71 | NULL) < 0) { | 71 | NULL) < 0) { |
| 72 | addr_location__put(&al); | 72 | addr_location__put(&al); |
| 73 | goto out; | 73 | goto out; |
diff --git a/tools/perf/trace/beauty/perf_event_open.c b/tools/perf/trace/beauty/perf_event_open.c new file mode 100644 index 000000000000..311f09dd718d --- /dev/null +++ b/tools/perf/trace/beauty/perf_event_open.c | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #ifndef PERF_FLAG_FD_NO_GROUP | ||
| 2 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) | ||
| 3 | #endif | ||
| 4 | |||
| 5 | #ifndef PERF_FLAG_FD_OUTPUT | ||
| 6 | # define PERF_FLAG_FD_OUTPUT (1UL << 1) | ||
| 7 | #endif | ||
| 8 | |||
| 9 | #ifndef PERF_FLAG_PID_CGROUP | ||
| 10 | # define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ | ||
| 11 | #endif | ||
| 12 | |||
| 13 | #ifndef PERF_FLAG_FD_CLOEXEC | ||
| 14 | # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ | ||
| 15 | #endif | ||
| 16 | |||
| 17 | static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, | ||
| 18 | struct syscall_arg *arg) | ||
| 19 | { | ||
| 20 | int printed = 0, flags = arg->val; | ||
| 21 | |||
| 22 | if (flags == 0) | ||
| 23 | return 0; | ||
| 24 | |||
| 25 | #define P_FLAG(n) \ | ||
| 26 | if (flags & PERF_FLAG_##n) { \ | ||
| 27 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
| 28 | flags &= ~PERF_FLAG_##n; \ | ||
| 29 | } | ||
| 30 | |||
| 31 | P_FLAG(FD_NO_GROUP); | ||
| 32 | P_FLAG(FD_OUTPUT); | ||
| 33 | P_FLAG(PID_CGROUP); | ||
| 34 | P_FLAG(FD_CLOEXEC); | ||
| 35 | #undef P_FLAG | ||
| 36 | |||
| 37 | if (flags) | ||
| 38 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
| 39 | |||
| 40 | return printed; | ||
| 41 | } | ||
| 42 | |||
| 43 | #define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags | ||
diff --git a/tools/perf/trace/beauty/pid.c b/tools/perf/trace/beauty/pid.c index 111ae08d38f1..07486ea65ae3 100644 --- a/tools/perf/trace/beauty/pid.c +++ b/tools/perf/trace/beauty/pid.c | |||
| @@ -3,9 +3,12 @@ static size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_a | |||
| 3 | int pid = arg->val; | 3 | int pid = arg->val; |
| 4 | struct trace *trace = arg->trace; | 4 | struct trace *trace = arg->trace; |
| 5 | size_t printed = scnprintf(bf, size, "%d", pid); | 5 | size_t printed = scnprintf(bf, size, "%d", pid); |
| 6 | struct thread *thread = machine__find_thread(trace->host, pid, pid); | 6 | struct thread *thread = machine__findnew_thread(trace->host, pid, pid); |
| 7 | 7 | ||
| 8 | if (thread != NULL) { | 8 | if (thread != NULL) { |
| 9 | if (!thread->comm_set) | ||
| 10 | thread__set_comm_from_proc(thread); | ||
| 11 | |||
| 9 | if (thread->comm_set) | 12 | if (thread->comm_set) |
| 10 | printed += scnprintf(bf + printed, size - printed, | 13 | printed += scnprintf(bf + printed, size - printed, |
| 11 | " (%s)", thread__comm_str(thread)); | 14 | " (%s)", thread__comm_str(thread)); |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 0573c2ec861d..b6ecf87bc3e3 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
| @@ -261,14 +261,14 @@ static int machine__write_buildid_table(struct machine *machine, int fd) | |||
| 261 | 261 | ||
| 262 | if (dso__is_vdso(pos)) { | 262 | if (dso__is_vdso(pos)) { |
| 263 | name = pos->short_name; | 263 | name = pos->short_name; |
| 264 | name_len = pos->short_name_len + 1; | 264 | name_len = pos->short_name_len; |
| 265 | } else if (dso__is_kcore(pos)) { | 265 | } else if (dso__is_kcore(pos)) { |
| 266 | machine__mmap_name(machine, nm, sizeof(nm)); | 266 | machine__mmap_name(machine, nm, sizeof(nm)); |
| 267 | name = nm; | 267 | name = nm; |
| 268 | name_len = strlen(nm) + 1; | 268 | name_len = strlen(nm); |
| 269 | } else { | 269 | } else { |
| 270 | name = pos->long_name; | 270 | name = pos->long_name; |
| 271 | name_len = pos->long_name_len + 1; | 271 | name_len = pos->long_name_len; |
| 272 | } | 272 | } |
| 273 | 273 | ||
| 274 | in_kernel = pos->kernel || | 274 | in_kernel = pos->kernel || |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 6fb5725821de..85271e54a63b 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -684,6 +684,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
| 684 | struct perf_mmap *md = &evlist->mmap[idx]; | 684 | struct perf_mmap *md = &evlist->mmap[idx]; |
| 685 | u64 head; | 685 | u64 head; |
| 686 | u64 old = md->prev; | 686 | u64 old = md->prev; |
| 687 | int diff; | ||
| 687 | unsigned char *data = md->base + page_size; | 688 | unsigned char *data = md->base + page_size; |
| 688 | union perf_event *event = NULL; | 689 | union perf_event *event = NULL; |
| 689 | 690 | ||
| @@ -694,6 +695,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
| 694 | return NULL; | 695 | return NULL; |
| 695 | 696 | ||
| 696 | head = perf_mmap__read_head(md); | 697 | head = perf_mmap__read_head(md); |
| 698 | diff = head - old; | ||
| 697 | if (evlist->overwrite) { | 699 | if (evlist->overwrite) { |
| 698 | /* | 700 | /* |
| 699 | * If we're further behind than half the buffer, there's a chance | 701 | * If we're further behind than half the buffer, there's a chance |
| @@ -703,7 +705,6 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
| 703 | * | 705 | * |
| 704 | * In either case, truncate and restart at head. | 706 | * In either case, truncate and restart at head. |
| 705 | */ | 707 | */ |
| 706 | int diff = head - old; | ||
| 707 | if (diff > md->mask / 2 || diff < 0) { | 708 | if (diff > md->mask / 2 || diff < 0) { |
| 708 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); | 709 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); |
| 709 | 710 | ||
| @@ -711,15 +712,21 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
| 711 | * head points to a known good entry, start there. | 712 | * head points to a known good entry, start there. |
| 712 | */ | 713 | */ |
| 713 | old = head; | 714 | old = head; |
| 715 | diff = 0; | ||
| 714 | } | 716 | } |
| 715 | } | 717 | } |
| 716 | 718 | ||
| 717 | if (old != head) { | 719 | if (diff >= (int)sizeof(event->header)) { |
| 718 | size_t size; | 720 | size_t size; |
| 719 | 721 | ||
| 720 | event = (union perf_event *)&data[old & md->mask]; | 722 | event = (union perf_event *)&data[old & md->mask]; |
| 721 | size = event->header.size; | 723 | size = event->header.size; |
| 722 | 724 | ||
| 725 | if (size < sizeof(event->header) || diff < (int)size) { | ||
| 726 | event = NULL; | ||
| 727 | goto broken_event; | ||
| 728 | } | ||
| 729 | |||
| 723 | /* | 730 | /* |
| 724 | * Event straddles the mmap boundary -- header should always | 731 | * Event straddles the mmap boundary -- header should always |
| 725 | * be inside due to u64 alignment of output. | 732 | * be inside due to u64 alignment of output. |
| @@ -743,6 +750,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
| 743 | old += size; | 750 | old += size; |
| 744 | } | 751 | } |
| 745 | 752 | ||
| 753 | broken_event: | ||
| 746 | md->prev = old; | 754 | md->prev = old; |
| 747 | 755 | ||
| 748 | return event; | 756 | return event; |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 545bb3f0b2b0..334364e25bbe 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -1231,6 +1231,21 @@ static void __p_sample_type(char *buf, size_t size, u64 value) | |||
| 1231 | __p_bits(buf, size, value, bits); | 1231 | __p_bits(buf, size, value, bits); |
| 1232 | } | 1232 | } |
| 1233 | 1233 | ||
| 1234 | static void __p_branch_sample_type(char *buf, size_t size, u64 value) | ||
| 1235 | { | ||
| 1236 | #define bit_name(n) { PERF_SAMPLE_BRANCH_##n, #n } | ||
| 1237 | struct bit_names bits[] = { | ||
| 1238 | bit_name(USER), bit_name(KERNEL), bit_name(HV), bit_name(ANY), | ||
| 1239 | bit_name(ANY_CALL), bit_name(ANY_RETURN), bit_name(IND_CALL), | ||
| 1240 | bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX), | ||
| 1241 | bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP), | ||
| 1242 | bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES), | ||
| 1243 | { .name = NULL, } | ||
| 1244 | }; | ||
| 1245 | #undef bit_name | ||
| 1246 | __p_bits(buf, size, value, bits); | ||
| 1247 | } | ||
| 1248 | |||
| 1234 | static void __p_read_format(char *buf, size_t size, u64 value) | 1249 | static void __p_read_format(char *buf, size_t size, u64 value) |
| 1235 | { | 1250 | { |
| 1236 | #define bit_name(n) { PERF_FORMAT_##n, #n } | 1251 | #define bit_name(n) { PERF_FORMAT_##n, #n } |
| @@ -1249,6 +1264,7 @@ static void __p_read_format(char *buf, size_t size, u64 value) | |||
| 1249 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) | 1264 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) |
| 1250 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) | 1265 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) |
| 1251 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) | 1266 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) |
| 1267 | #define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) | ||
| 1252 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) | 1268 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) |
| 1253 | 1269 | ||
| 1254 | #define PRINT_ATTRn(_n, _f, _p) \ | 1270 | #define PRINT_ATTRn(_n, _f, _p) \ |
| @@ -1305,7 +1321,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | |||
| 1305 | PRINT_ATTRf(bp_type, p_unsigned); | 1321 | PRINT_ATTRf(bp_type, p_unsigned); |
| 1306 | PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); | 1322 | PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); |
| 1307 | PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); | 1323 | PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); |
| 1308 | PRINT_ATTRf(branch_sample_type, p_unsigned); | 1324 | PRINT_ATTRf(branch_sample_type, p_branch_sample_type); |
| 1309 | PRINT_ATTRf(sample_regs_user, p_hex); | 1325 | PRINT_ATTRf(sample_regs_user, p_hex); |
| 1310 | PRINT_ATTRf(sample_stack_user, p_unsigned); | 1326 | PRINT_ATTRf(sample_stack_user, p_unsigned); |
| 1311 | PRINT_ATTRf(clockid, p_signed); | 1327 | PRINT_ATTRf(clockid, p_signed); |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 991a351a8a41..0f33d7e698c4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -2062,6 +2062,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | |||
| 2062 | if (he) { | 2062 | if (he) { |
| 2063 | memset(&he->stat, 0, sizeof(he->stat)); | 2063 | memset(&he->stat, 0, sizeof(he->stat)); |
| 2064 | he->hists = hists; | 2064 | he->hists = hists; |
| 2065 | if (symbol_conf.cumulate_callchain) | ||
| 2066 | memset(he->stat_acc, 0, sizeof(he->stat)); | ||
| 2065 | rb_link_node(&he->rb_node_in, parent, p); | 2067 | rb_link_node(&he->rb_node_in, parent, p); |
| 2066 | rb_insert_color(&he->rb_node_in, root); | 2068 | rb_insert_color(&he->rb_node_in, root); |
| 2067 | hists__inc_stats(hists, he); | 2069 | hists__inc_stats(hists, he); |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 9409d014b46c..9c8f15da86ce 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
| @@ -356,7 +356,7 @@ static const char *intel_pt_err_msgs[] = { | |||
| 356 | 356 | ||
| 357 | int intel_pt__strerror(int code, char *buf, size_t buflen) | 357 | int intel_pt__strerror(int code, char *buf, size_t buflen) |
| 358 | { | 358 | { |
| 359 | if (code < 1 || code > INTEL_PT_ERR_MAX) | 359 | if (code < 1 || code >= INTEL_PT_ERR_MAX) |
| 360 | code = INTEL_PT_ERR_UNK; | 360 | code = INTEL_PT_ERR_UNK; |
| 361 | strlcpy(buf, intel_pt_err_msgs[code], buflen); | 361 | strlcpy(buf, intel_pt_err_msgs[code], buflen); |
| 362 | return 0; | 362 | return 0; |
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 656c1d7ee7d4..2cb95bbf9ea6 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
| @@ -1764,7 +1764,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
| 1764 | */ | 1764 | */ |
| 1765 | int mix_chain_nr = i + 1 + lbr_nr + 1; | 1765 | int mix_chain_nr = i + 1 + lbr_nr + 1; |
| 1766 | 1766 | ||
| 1767 | if (mix_chain_nr > PERF_MAX_STACK_DEPTH + PERF_MAX_BRANCH_DEPTH) { | 1767 | if (mix_chain_nr > (int)sysctl_perf_event_max_stack + PERF_MAX_BRANCH_DEPTH) { |
| 1768 | pr_warning("corrupted callchain. skipping...\n"); | 1768 | pr_warning("corrupted callchain. skipping...\n"); |
| 1769 | return 0; | 1769 | return 0; |
| 1770 | } | 1770 | } |
| @@ -1825,7 +1825,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
| 1825 | * Based on DWARF debug information, some architectures skip | 1825 | * Based on DWARF debug information, some architectures skip |
| 1826 | * a callchain entry saved by the kernel. | 1826 | * a callchain entry saved by the kernel. |
| 1827 | */ | 1827 | */ |
| 1828 | if (chain->nr < PERF_MAX_STACK_DEPTH) | 1828 | if (chain->nr < sysctl_perf_event_max_stack) |
| 1829 | skip_idx = arch_skip_callchain_idx(thread, chain); | 1829 | skip_idx = arch_skip_callchain_idx(thread, chain); |
| 1830 | 1830 | ||
| 1831 | /* | 1831 | /* |
| @@ -1886,7 +1886,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
| 1886 | } | 1886 | } |
| 1887 | 1887 | ||
| 1888 | check_calls: | 1888 | check_calls: |
| 1889 | if (chain->nr > PERF_MAX_STACK_DEPTH && (int)chain->nr > max_stack) { | 1889 | if (chain->nr > sysctl_perf_event_max_stack && (int)chain->nr > max_stack) { |
| 1890 | pr_warning("corrupted callchain. skipping...\n"); | 1890 | pr_warning("corrupted callchain. skipping...\n"); |
| 1891 | return 0; | 1891 | return 0; |
| 1892 | } | 1892 | } |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8319fbb08636..a9774628c6f6 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -265,6 +265,65 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address) | |||
| 265 | return true; | 265 | return true; |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | /* | ||
| 269 | * NOTE: | ||
| 270 | * '.gnu.linkonce.this_module' section of kernel module elf directly | ||
| 271 | * maps to 'struct module' from linux/module.h. This section contains | ||
| 272 | * actual module name which will be used by kernel after loading it. | ||
| 273 | * But, we cannot use 'struct module' here since linux/module.h is not | ||
| 274 | * exposed to user-space. Offset of 'name' has remained same from long | ||
| 275 | * time, so hardcoding it here. | ||
| 276 | */ | ||
| 277 | #ifdef __LP64__ | ||
| 278 | #define MOD_NAME_OFFSET 24 | ||
| 279 | #else | ||
| 280 | #define MOD_NAME_OFFSET 12 | ||
| 281 | #endif | ||
| 282 | |||
| 283 | /* | ||
| 284 | * @module can be module name of module file path. In case of path, | ||
| 285 | * inspect elf and find out what is actual module name. | ||
| 286 | * Caller has to free mod_name after using it. | ||
| 287 | */ | ||
| 288 | static char *find_module_name(const char *module) | ||
| 289 | { | ||
| 290 | int fd; | ||
| 291 | Elf *elf; | ||
| 292 | GElf_Ehdr ehdr; | ||
| 293 | GElf_Shdr shdr; | ||
| 294 | Elf_Data *data; | ||
| 295 | Elf_Scn *sec; | ||
| 296 | char *mod_name = NULL; | ||
| 297 | |||
| 298 | fd = open(module, O_RDONLY); | ||
| 299 | if (fd < 0) | ||
| 300 | return NULL; | ||
| 301 | |||
| 302 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
| 303 | if (elf == NULL) | ||
| 304 | goto elf_err; | ||
| 305 | |||
| 306 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
| 307 | goto ret_err; | ||
| 308 | |||
| 309 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
| 310 | ".gnu.linkonce.this_module", NULL); | ||
| 311 | if (!sec) | ||
| 312 | goto ret_err; | ||
| 313 | |||
| 314 | data = elf_getdata(sec, NULL); | ||
| 315 | if (!data || !data->d_buf) | ||
| 316 | goto ret_err; | ||
| 317 | |||
| 318 | mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET); | ||
| 319 | |||
| 320 | ret_err: | ||
| 321 | elf_end(elf); | ||
| 322 | elf_err: | ||
| 323 | close(fd); | ||
| 324 | return mod_name; | ||
| 325 | } | ||
| 326 | |||
| 268 | #ifdef HAVE_DWARF_SUPPORT | 327 | #ifdef HAVE_DWARF_SUPPORT |
| 269 | 328 | ||
| 270 | static int kernel_get_module_dso(const char *module, struct dso **pdso) | 329 | static int kernel_get_module_dso(const char *module, struct dso **pdso) |
| @@ -486,8 +545,10 @@ static int get_text_start_address(const char *exec, unsigned long *address) | |||
| 486 | return -errno; | 545 | return -errno; |
| 487 | 546 | ||
| 488 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 547 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
| 489 | if (elf == NULL) | 548 | if (elf == NULL) { |
| 490 | return -EINVAL; | 549 | ret = -EINVAL; |
| 550 | goto out_close; | ||
| 551 | } | ||
| 491 | 552 | ||
| 492 | if (gelf_getehdr(elf, &ehdr) == NULL) | 553 | if (gelf_getehdr(elf, &ehdr) == NULL) |
| 493 | goto out; | 554 | goto out; |
| @@ -499,6 +560,9 @@ static int get_text_start_address(const char *exec, unsigned long *address) | |||
| 499 | ret = 0; | 560 | ret = 0; |
| 500 | out: | 561 | out: |
| 501 | elf_end(elf); | 562 | elf_end(elf); |
| 563 | out_close: | ||
| 564 | close(fd); | ||
| 565 | |||
| 502 | return ret; | 566 | return ret; |
| 503 | } | 567 | } |
| 504 | 568 | ||
| @@ -583,32 +647,23 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | |||
| 583 | int ntevs, const char *module) | 647 | int ntevs, const char *module) |
| 584 | { | 648 | { |
| 585 | int i, ret = 0; | 649 | int i, ret = 0; |
| 586 | char *tmp; | 650 | char *mod_name = NULL; |
| 587 | 651 | ||
| 588 | if (!module) | 652 | if (!module) |
| 589 | return 0; | 653 | return 0; |
| 590 | 654 | ||
| 591 | tmp = strrchr(module, '/'); | 655 | mod_name = find_module_name(module); |
| 592 | if (tmp) { | ||
| 593 | /* This is a module path -- get the module name */ | ||
| 594 | module = strdup(tmp + 1); | ||
| 595 | if (!module) | ||
| 596 | return -ENOMEM; | ||
| 597 | tmp = strchr(module, '.'); | ||
| 598 | if (tmp) | ||
| 599 | *tmp = '\0'; | ||
| 600 | tmp = (char *)module; /* For free() */ | ||
| 601 | } | ||
| 602 | 656 | ||
| 603 | for (i = 0; i < ntevs; i++) { | 657 | for (i = 0; i < ntevs; i++) { |
| 604 | tevs[i].point.module = strdup(module); | 658 | tevs[i].point.module = |
| 659 | strdup(mod_name ? mod_name : module); | ||
| 605 | if (!tevs[i].point.module) { | 660 | if (!tevs[i].point.module) { |
| 606 | ret = -ENOMEM; | 661 | ret = -ENOMEM; |
| 607 | break; | 662 | break; |
| 608 | } | 663 | } |
| 609 | } | 664 | } |
| 610 | 665 | ||
| 611 | free(tmp); | 666 | free(mod_name); |
| 612 | return ret; | 667 | return ret; |
| 613 | } | 668 | } |
| 614 | 669 | ||
| @@ -2516,6 +2571,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
| 2516 | struct probe_trace_point *tp; | 2571 | struct probe_trace_point *tp; |
| 2517 | int num_matched_functions; | 2572 | int num_matched_functions; |
| 2518 | int ret, i, j, skipped = 0; | 2573 | int ret, i, j, skipped = 0; |
| 2574 | char *mod_name; | ||
| 2519 | 2575 | ||
| 2520 | map = get_target_map(pev->target, pev->uprobes); | 2576 | map = get_target_map(pev->target, pev->uprobes); |
| 2521 | if (!map) { | 2577 | if (!map) { |
| @@ -2600,9 +2656,19 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
| 2600 | tp->realname = strdup_or_goto(sym->name, nomem_out); | 2656 | tp->realname = strdup_or_goto(sym->name, nomem_out); |
| 2601 | 2657 | ||
| 2602 | tp->retprobe = pp->retprobe; | 2658 | tp->retprobe = pp->retprobe; |
| 2603 | if (pev->target) | 2659 | if (pev->target) { |
| 2604 | tev->point.module = strdup_or_goto(pev->target, | 2660 | if (pev->uprobes) { |
| 2605 | nomem_out); | 2661 | tev->point.module = strdup_or_goto(pev->target, |
| 2662 | nomem_out); | ||
| 2663 | } else { | ||
| 2664 | mod_name = find_module_name(pev->target); | ||
| 2665 | tev->point.module = | ||
| 2666 | strdup(mod_name ? mod_name : pev->target); | ||
| 2667 | free(mod_name); | ||
| 2668 | if (!tev->point.module) | ||
| 2669 | goto nomem_out; | ||
| 2670 | } | ||
| 2671 | } | ||
| 2606 | tev->uprobes = pev->uprobes; | 2672 | tev->uprobes = pev->uprobes; |
| 2607 | tev->nargs = pev->nargs; | 2673 | tev->nargs = pev->nargs; |
| 2608 | if (tev->nargs) { | 2674 | if (tev->nargs) { |
| @@ -2743,9 +2809,13 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
| 2743 | { | 2809 | { |
| 2744 | int ret; | 2810 | int ret; |
| 2745 | 2811 | ||
| 2746 | if (pev->uprobes && !pev->group) { | 2812 | if (!pev->group) { |
| 2747 | /* Replace group name if not given */ | 2813 | /* Set group name if not given */ |
| 2748 | ret = convert_exec_to_group(pev->target, &pev->group); | 2814 | if (!pev->uprobes) { |
| 2815 | pev->group = strdup(PERFPROBE_GROUP); | ||
| 2816 | ret = pev->group ? 0 : -ENOMEM; | ||
| 2817 | } else | ||
| 2818 | ret = convert_exec_to_group(pev->target, &pev->group); | ||
| 2749 | if (ret != 0) { | 2819 | if (ret != 0) { |
| 2750 | pr_warning("Failed to make a group name.\n"); | 2820 | pr_warning("Failed to make a group name.\n"); |
| 2751 | return ret; | 2821 | return ret; |
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index e3b3b92e4458..3fe6214970e6 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
| @@ -220,8 +220,7 @@ int probe_file__add_event(int fd, struct probe_trace_event *tev) | |||
| 220 | 220 | ||
| 221 | pr_debug("Writing event: %s\n", buf); | 221 | pr_debug("Writing event: %s\n", buf); |
| 222 | if (!probe_event_dry_run) { | 222 | if (!probe_event_dry_run) { |
| 223 | ret = write(fd, buf, strlen(buf)); | 223 | if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) { |
| 224 | if (ret <= 0) { | ||
| 225 | ret = -errno; | 224 | ret = -errno; |
| 226 | pr_warning("Failed to write event: %s\n", | 225 | pr_warning("Failed to write event: %s\n", |
| 227 | strerror_r(errno, sbuf, sizeof(sbuf))); | 226 | strerror_r(errno, sbuf, sizeof(sbuf))); |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index ae1cebc307c5..62c7f6988e0e 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
| @@ -265,7 +265,7 @@ static SV *perl_process_callchain(struct perf_sample *sample, | |||
| 265 | 265 | ||
| 266 | if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, | 266 | if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
| 267 | sample, NULL, NULL, | 267 | sample, NULL, NULL, |
| 268 | PERF_MAX_STACK_DEPTH) != 0) { | 268 | sysctl_perf_event_max_stack) != 0) { |
| 269 | pr_err("Failed to resolve callchain. Skipping\n"); | 269 | pr_err("Failed to resolve callchain. Skipping\n"); |
| 270 | goto exit; | 270 | goto exit; |
| 271 | } | 271 | } |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index dfd00c6dad6e..45fcb715a36b 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
| @@ -10,6 +10,8 @@ | |||
| 10 | #include "comm.h" | 10 | #include "comm.h" |
| 11 | #include "unwind.h" | 11 | #include "unwind.h" |
| 12 | 12 | ||
| 13 | #include <api/fs/fs.h> | ||
| 14 | |||
| 13 | int thread__init_map_groups(struct thread *thread, struct machine *machine) | 15 | int thread__init_map_groups(struct thread *thread, struct machine *machine) |
| 14 | { | 16 | { |
| 15 | struct thread *leader; | 17 | struct thread *leader; |
| @@ -153,6 +155,23 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, | |||
| 153 | return 0; | 155 | return 0; |
| 154 | } | 156 | } |
| 155 | 157 | ||
| 158 | int thread__set_comm_from_proc(struct thread *thread) | ||
| 159 | { | ||
| 160 | char path[64]; | ||
| 161 | char *comm = NULL; | ||
| 162 | size_t sz; | ||
| 163 | int err = -1; | ||
| 164 | |||
| 165 | if (!(snprintf(path, sizeof(path), "%d/task/%d/comm", | ||
| 166 | thread->pid_, thread->tid) >= (int)sizeof(path)) && | ||
| 167 | procfs__read_str(path, &comm, &sz) == 0) { | ||
| 168 | comm[sz - 1] = '\0'; | ||
| 169 | err = thread__set_comm(thread, comm, 0); | ||
| 170 | } | ||
| 171 | |||
| 172 | return err; | ||
| 173 | } | ||
| 174 | |||
| 156 | const char *thread__comm_str(const struct thread *thread) | 175 | const char *thread__comm_str(const struct thread *thread) |
| 157 | { | 176 | { |
| 158 | const struct comm *comm = thread__comm(thread); | 177 | const struct comm *comm = thread__comm(thread); |
| @@ -233,7 +252,7 @@ void thread__find_cpumode_addr_location(struct thread *thread, | |||
| 233 | struct addr_location *al) | 252 | struct addr_location *al) |
| 234 | { | 253 | { |
| 235 | size_t i; | 254 | size_t i; |
| 236 | const u8 const cpumodes[] = { | 255 | const u8 cpumodes[] = { |
| 237 | PERF_RECORD_MISC_USER, | 256 | PERF_RECORD_MISC_USER, |
| 238 | PERF_RECORD_MISC_KERNEL, | 257 | PERF_RECORD_MISC_KERNEL, |
| 239 | PERF_RECORD_MISC_GUEST_USER, | 258 | PERF_RECORD_MISC_GUEST_USER, |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e214207bb13a..45fba13c800b 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
| @@ -71,6 +71,8 @@ static inline int thread__set_comm(struct thread *thread, const char *comm, | |||
| 71 | return __thread__set_comm(thread, comm, timestamp, false); | 71 | return __thread__set_comm(thread, comm, timestamp, false); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | int thread__set_comm_from_proc(struct thread *thread); | ||
| 75 | |||
| 74 | int thread__comm_len(struct thread *thread); | 76 | int thread__comm_len(struct thread *thread); |
| 75 | struct comm *thread__comm(const struct thread *thread); | 77 | struct comm *thread__comm(const struct thread *thread); |
| 76 | struct comm *thread__exec_comm(const struct thread *thread); | 78 | struct comm *thread__exec_comm(const struct thread *thread); |
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b7766c577b01..619ba2061b62 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
| @@ -33,6 +33,8 @@ struct callchain_param callchain_param = { | |||
| 33 | unsigned int page_size; | 33 | unsigned int page_size; |
| 34 | int cacheline_size; | 34 | int cacheline_size; |
| 35 | 35 | ||
| 36 | unsigned int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; | ||
| 37 | |||
| 36 | bool test_attr__enabled; | 38 | bool test_attr__enabled; |
| 37 | 39 | ||
| 38 | bool perf_host = true; | 40 | bool perf_host = true; |
| @@ -117,6 +119,40 @@ int rm_rf(char *path) | |||
| 117 | return rmdir(path); | 119 | return rmdir(path); |
| 118 | } | 120 | } |
| 119 | 121 | ||
| 122 | /* A filter which removes dot files */ | ||
| 123 | bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d) | ||
| 124 | { | ||
| 125 | return d->d_name[0] != '.'; | ||
| 126 | } | ||
| 127 | |||
| 128 | /* lsdir reads a directory and store it in strlist */ | ||
| 129 | struct strlist *lsdir(const char *name, | ||
| 130 | bool (*filter)(const char *, struct dirent *)) | ||
| 131 | { | ||
| 132 | struct strlist *list = NULL; | ||
| 133 | DIR *dir; | ||
| 134 | struct dirent *d; | ||
| 135 | |||
| 136 | dir = opendir(name); | ||
| 137 | if (!dir) | ||
| 138 | return NULL; | ||
| 139 | |||
| 140 | list = strlist__new(NULL, NULL); | ||
| 141 | if (!list) { | ||
| 142 | errno = -ENOMEM; | ||
| 143 | goto out; | ||
| 144 | } | ||
| 145 | |||
| 146 | while ((d = readdir(dir)) != NULL) { | ||
| 147 | if (!filter || filter(name, d)) | ||
| 148 | strlist__add(list, d->d_name); | ||
| 149 | } | ||
| 150 | |||
| 151 | out: | ||
| 152 | closedir(dir); | ||
| 153 | return list; | ||
| 154 | } | ||
| 155 | |||
| 120 | static int slow_copyfile(const char *from, const char *to) | 156 | static int slow_copyfile(const char *from, const char *to) |
| 121 | { | 157 | { |
| 122 | int err = -1; | 158 | int err = -1; |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 3bf3de86d429..88f607af1f47 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
| @@ -79,6 +79,7 @@ | |||
| 79 | #include <termios.h> | 79 | #include <termios.h> |
| 80 | #include <linux/bitops.h> | 80 | #include <linux/bitops.h> |
| 81 | #include <termios.h> | 81 | #include <termios.h> |
| 82 | #include "strlist.h" | ||
| 82 | 83 | ||
| 83 | extern const char *graph_line; | 84 | extern const char *graph_line; |
| 84 | extern const char *graph_dotted_line; | 85 | extern const char *graph_dotted_line; |
| @@ -222,6 +223,8 @@ static inline int sane_case(int x, int high) | |||
| 222 | 223 | ||
| 223 | int mkdir_p(char *path, mode_t mode); | 224 | int mkdir_p(char *path, mode_t mode); |
| 224 | int rm_rf(char *path); | 225 | int rm_rf(char *path); |
| 226 | struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); | ||
| 227 | bool lsdir_no_dot_filter(const char *name, struct dirent *d); | ||
| 225 | int copyfile(const char *from, const char *to); | 228 | int copyfile(const char *from, const char *to); |
| 226 | int copyfile_mode(const char *from, const char *to, mode_t mode); | 229 | int copyfile_mode(const char *from, const char *to, mode_t mode); |
| 227 | int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); | 230 | int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); |
| @@ -264,6 +267,7 @@ void sighandler_dump_stack(int sig); | |||
| 264 | 267 | ||
| 265 | extern unsigned int page_size; | 268 | extern unsigned int page_size; |
| 266 | extern int cacheline_size; | 269 | extern int cacheline_size; |
| 270 | extern unsigned int sysctl_perf_event_max_stack; | ||
| 267 | 271 | ||
| 268 | struct parse_tag { | 272 | struct parse_tag { |
| 269 | char tag; | 273 | char tag; |
