mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
perf/core improvements and fixes:
perf trace: - Add syscall failure stats to -s/--summary and -S/--with-summary, works in combination with specifying just a set of syscalls, see below first with -s/--summary, then with -S/--with-summary just for the syscalls we saw failing with -s: # perf trace -s sleep 1 Summary of events: sleep (16218), 80 events, 93.0% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) ----------- ----- ------ -------- -------- -------- -------- ------ nanosleep 1 0 1000.091 1000.091 1000.091 1000.091 0.00% mmap 8 0 0.045 0.005 0.006 0.008 7.09% mprotect 4 0 0.028 0.005 0.007 0.009 11.38% openat 3 0 0.021 0.005 0.007 0.009 14.07% munmap 1 0 0.017 0.017 0.017 0.017 0.00% brk 4 0 0.010 0.001 0.002 0.004 23.15% read 4 0 0.009 0.002 0.002 0.003 8.13% close 5 0 0.008 0.001 0.002 0.002 10.83% fstat 3 0 0.006 0.002 0.002 0.002 6.97% access 1 1 0.006 0.006 0.006 0.006 0.00% lseek 3 0 0.005 0.001 0.002 0.002 7.37% arch_prctl 2 1 0.004 0.001 0.002 0.002 17.64% execve 1 0 0.000 0.000 0.000 0.000 0.00% # perf trace -e access,arch_prctl -S sleep 1 0.000 ( 0.006 ms): sleep/19503 arch_prctl(option: 0x3001, arg2: 0x7fff165996b0) = -1 EINVAL (Invalid argument) 0.024 ( 0.006 ms): sleep/19503 access(filename: 0x2177e510, mode: R) = -1 ENOENT (No such file or directory) 0.136 ( 0.002 ms): sleep/19503 arch_prctl(option: SET_FS, arg2: 0x7f9421737580) = 0 Summary of events: sleep (19503), 6 events, 50.0% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) ---------- ----- ------ ------ ------ ------ ------ ------ arch_prctl 2 1 0.008 0.002 0.004 0.006 57.22% access 1 1 0.006 0.006 0.006 0.006 0.00% # - Introduce --errno-summary, to drill down a bit more in the errno stats: # perf trace --errno-summary -e access,arch_prctl -S sleep 1 0.000 ( 0.006 ms): sleep/5587 arch_prctl(option: 0x3001, arg2: 0x7ffd6ba6aa00) = -1 EINVAL (Invalid argument) 0.028 ( 0.007 ms): sleep/5587 access(filename: 0xb83d9510, mode: R) = -1 ENOENT (No such file or directory) 0.172 ( 0.003 ms): sleep/5587 arch_prctl(option: SET_FS, arg2: 0x7f45b8392580) = 0 Summary of events: sleep (5587), 6 events, 50.0% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) ---------- ----- ------ ------ ------ ------ ------ ------ arch_prctl 2 1 0.009 0.003 0.005 0.006 38.90% EINVAL: 1 access 1 1 0.007 0.007 0.007 0.007 0.00% ENOENT: 1 # - Filter own pid to avoid a feedback look in 'perf trace record -a' - Add the glue for the auto generated x86 IRQ vector array. - Show error message when not finding a field used in a filter expression # perf trace --max-events=4 -e syscalls:sys_enter_write --filter="cnt>32767" Failed to set filter "(cnt>32767) && (common_pid != 19938 && common_pid != 8922)" on event syscalls:sys_enter_write with 22 (Invalid argument) # # perf trace --max-events=4 -e syscalls:sys_enter_write --filter="count>32767" 0.000 python3.5/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0dc53600, count: 172086) 12.641 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0db63660, count: 75994) 27.738 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0db4b1e0, count: 41635) 136.070 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0dbab510, count: 62232) # - Add a generator for x86's IRQ vectors -> strings - Introduce stroul() (string -> number) methods for the strarray and strarrays classes, also strtoul_flags, allowing to go from both strings and or-ed strings to numbers, allowing things like: # perf trace -e syscalls:sys_enter_mmap --filter="flags==DENYWRITE|PRIVATE|FIXED" sleep 1 0.000 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2aa5000, len: 1363968, prot: READ|EXEC, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x22000) 0.011 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2bf2000, len: 311296, prot: READ, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x16f000) 0.015 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2c3f000, len: 24576, prot: READ|WRITE, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x1bb000) # Allowing to narrow down from the complete set of mmap calls for that workload: # perf trace -e syscalls:sys_enter_mmap sleep 1 0.000 sleep/22695 syscalls:sys_enter_mmap(len: 134773, prot: READ, flags: PRIVATE, fd: 3) 0.041 sleep/22695 syscalls:sys_enter_mmap(len: 8192, prot: READ|WRITE, flags: PRIVATE|ANONYMOUS) 0.053 sleep/22695 syscalls:sys_enter_mmap(len: 1857472, prot: READ, flags: PRIVATE|DENYWRITE, fd: 3) 0.069 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd23ffb6000, len: 1363968, prot: READ|EXEC, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x22000) 0.077 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240103000, len: 311296, prot: READ, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x16f000) 0.083 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240150000, len: 24576, prot: READ|WRITE, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x1bb000) 0.095 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240156000, len: 14272, prot: READ|WRITE, flags: PRIVATE|FIXED|ANONYMOUS) 0.339 sleep/22695 syscalls:sys_enter_mmap(len: 217750512, prot: READ, flags: PRIVATE, fd: 3) # Works with all targets, so, for system wide, looking at who calls mmap with flags set to just "PRIVATE": # perf trace --max-events=5 -e syscalls:sys_enter_mmap --filter="flags==PRIVATE" 0.000 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14) 0.050 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14) 0.062 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14) 0.145 goa-identity-s/2240 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 18) 0.183 goa-identity-s/2240 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 18) # # perf trace --max-events=2 -e syscalls:sys_enter_lseek --filter="whence==SET && offset != 0" 0.000 Cache2 I/O/12047 syscalls:sys_enter_lseek(fd: 277, offset: 43, whence: SET) 1142.070 mozStorage #5/12302 syscalls:sys_enter_lseek(fd: 44</home/acme/.mozilla/firefox/ina67tev.default/cookies.sqlite-wal>, offset: 393536, whence: SET) # perf annotate: - Fix objdump --no-show-raw-insn flag to work with goth gcc and clang. - Streamline objdump execution, preserving the right error codes for better reporting to user. perf report: - Add warning when libunwind not compiled in. perf stat: Jin Yao: - Support --all-kernel/--all-user, to match options available in 'perf record', asking that all the events specified work just with kernel or user events. perf list: Jin Yao: - Hide deprecated events by default, allow showing them with --deprecated. libbperf: Jiri Olsa: - Allow to build with -ltcmalloc. - Finish mmap interface, getting more stuff from tools/perf while adding abstractions to avoid pulling too much stuff, to get libperf to grow as tools needs things like auxtrace, etc. perf scripting engines: Steven Rostedt (VMware): - Iterate on tep event arrays directly, fixing script generation with '-g python' when having multiple tracepoints in a perf.data file. core: - Allow to build with -ltcmalloc. perf test: Leo Yan: - Report failure for mmap events. - Avoid infinite loop for task exit case. - Remove needless headers for bp_account test. - Add dedicated checking helper is_supported(). - Disable bp_signal testing for arm64. Vendor events: arm64: John Garry: - Fix Hisi hip08 DDRC PMU eventname. - Add some missing events for Hisi hip08 DDRC, L3C and HHA PMUs. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCXa2zPgAKCRCyPKLppCJ+ J8qoAP9jm84Aoq87j/xh9wl3JeU3aeRXq4V6zpGbtt9u41OmRwD9E8CQIcLDAuNp IQaFYgHydH4OfZw3+rTJJjmJ/eb0IQg= =TDUz -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-5.5-20191021' 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: perf trace: - Add syscall failure stats to -s/--summary and -S/--with-summary, works in combination with specifying just a set of syscalls, see below first with -s/--summary, then with -S/--with-summary just for the syscalls we saw failing with -s: # perf trace -s sleep 1 Summary of events: sleep (16218), 80 events, 93.0% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) ----------- ----- ------ -------- -------- -------- -------- ------ nanosleep 1 0 1000.091 1000.091 1000.091 1000.091 0.00% mmap 8 0 0.045 0.005 0.006 0.008 7.09% mprotect 4 0 0.028 0.005 0.007 0.009 11.38% openat 3 0 0.021 0.005 0.007 0.009 14.07% munmap 1 0 0.017 0.017 0.017 0.017 0.00% brk 4 0 0.010 0.001 0.002 0.004 23.15% read 4 0 0.009 0.002 0.002 0.003 8.13% close 5 0 0.008 0.001 0.002 0.002 10.83% fstat 3 0 0.006 0.002 0.002 0.002 6.97% access 1 1 0.006 0.006 0.006 0.006 0.00% lseek 3 0 0.005 0.001 0.002 0.002 7.37% arch_prctl 2 1 0.004 0.001 0.002 0.002 17.64% execve 1 0 0.000 0.000 0.000 0.000 0.00% # perf trace -e access,arch_prctl -S sleep 1 0.000 ( 0.006 ms): sleep/19503 arch_prctl(option: 0x3001, arg2: 0x7fff165996b0) = -1 EINVAL (Invalid argument) 0.024 ( 0.006 ms): sleep/19503 access(filename: 0x2177e510, mode: R) = -1 ENOENT (No such file or directory) 0.136 ( 0.002 ms): sleep/19503 arch_prctl(option: SET_FS, arg2: 0x7f9421737580) = 0 Summary of events: sleep (19503), 6 events, 50.0% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) ---------- ----- ------ ------ ------ ------ ------ ------ arch_prctl 2 1 0.008 0.002 0.004 0.006 57.22% access 1 1 0.006 0.006 0.006 0.006 0.00% # - Introduce --errno-summary, to drill down a bit more in the errno stats: # perf trace --errno-summary -e access,arch_prctl -S sleep 1 0.000 ( 0.006 ms): sleep/5587 arch_prctl(option: 0x3001, arg2: 0x7ffd6ba6aa00) = -1 EINVAL (Invalid argument) 0.028 ( 0.007 ms): sleep/5587 access(filename: 0xb83d9510, mode: R) = -1 ENOENT (No such file or directory) 0.172 ( 0.003 ms): sleep/5587 arch_prctl(option: SET_FS, arg2: 0x7f45b8392580) = 0 Summary of events: sleep (5587), 6 events, 50.0% syscall calls errors total min avg max stddev (msec) (msec) (msec) (msec) (%) ---------- ----- ------ ------ ------ ------ ------ ------ arch_prctl 2 1 0.009 0.003 0.005 0.006 38.90% EINVAL: 1 access 1 1 0.007 0.007 0.007 0.007 0.00% ENOENT: 1 # - Filter own pid to avoid a feedback look in 'perf trace record -a' - Add the glue for the auto generated x86 IRQ vector array. - Show error message when not finding a field used in a filter expression # perf trace --max-events=4 -e syscalls:sys_enter_write --filter="cnt>32767" Failed to set filter "(cnt>32767) && (common_pid != 19938 && common_pid != 8922)" on event syscalls:sys_enter_write with 22 (Invalid argument) # # perf trace --max-events=4 -e syscalls:sys_enter_write --filter="count>32767" 0.000 python3.5/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0dc53600, count: 172086) 12.641 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0db63660, count: 75994) 27.738 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0db4b1e0, count: 41635) 136.070 python3.5.post/17535 syscalls:sys_enter_write(fd: 3, buf: 0x564b0dbab510, count: 62232) # - Add a generator for x86's IRQ vectors -> strings - Introduce stroul() (string -> number) methods for the strarray and strarrays classes, also strtoul_flags, allowing to go from both strings and or-ed strings to numbers, allowing things like: # perf trace -e syscalls:sys_enter_mmap --filter="flags==DENYWRITE|PRIVATE|FIXED" sleep 1 0.000 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2aa5000, len: 1363968, prot: READ|EXEC, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x22000) 0.011 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2bf2000, len: 311296, prot: READ, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x16f000) 0.015 sleep/22588 syscalls:sys_enter_mmap(addr: 0x7f42d2c3f000, len: 24576, prot: READ|WRITE, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x1bb000) # Allowing to narrow down from the complete set of mmap calls for that workload: # perf trace -e syscalls:sys_enter_mmap sleep 1 0.000 sleep/22695 syscalls:sys_enter_mmap(len: 134773, prot: READ, flags: PRIVATE, fd: 3) 0.041 sleep/22695 syscalls:sys_enter_mmap(len: 8192, prot: READ|WRITE, flags: PRIVATE|ANONYMOUS) 0.053 sleep/22695 syscalls:sys_enter_mmap(len: 1857472, prot: READ, flags: PRIVATE|DENYWRITE, fd: 3) 0.069 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd23ffb6000, len: 1363968, prot: READ|EXEC, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x22000) 0.077 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240103000, len: 311296, prot: READ, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x16f000) 0.083 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240150000, len: 24576, prot: READ|WRITE, flags: PRIVATE|FIXED|DENYWRITE, fd: 3, off: 0x1bb000) 0.095 sleep/22695 syscalls:sys_enter_mmap(addr: 0x7fd240156000, len: 14272, prot: READ|WRITE, flags: PRIVATE|FIXED|ANONYMOUS) 0.339 sleep/22695 syscalls:sys_enter_mmap(len: 217750512, prot: READ, flags: PRIVATE, fd: 3) # Works with all targets, so, for system wide, looking at who calls mmap with flags set to just "PRIVATE": # perf trace --max-events=5 -e syscalls:sys_enter_mmap --filter="flags==PRIVATE" 0.000 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14) 0.050 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14) 0.062 pool/2242 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 14) 0.145 goa-identity-s/2240 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 18) 0.183 goa-identity-s/2240 syscalls:sys_enter_mmap(len: 756, prot: READ, flags: PRIVATE, fd: 18) # # perf trace --max-events=2 -e syscalls:sys_enter_lseek --filter="whence==SET && offset != 0" 0.000 Cache2 I/O/12047 syscalls:sys_enter_lseek(fd: 277, offset: 43, whence: SET) 1142.070 mozStorage #5/12302 syscalls:sys_enter_lseek(fd: 44</home/acme/.mozilla/firefox/ina67tev.default/cookies.sqlite-wal>, offset: 393536, whence: SET) # perf annotate: - Fix objdump --no-show-raw-insn flag to work with goth gcc and clang. - Streamline objdump execution, preserving the right error codes for better reporting to user. perf report: - Add warning when libunwind not compiled in. perf stat: Jin Yao: - Support --all-kernel/--all-user, to match options available in 'perf record', asking that all the events specified work just with kernel or user events. perf list: Jin Yao: - Hide deprecated events by default, allow showing them with --deprecated. libbperf: Jiri Olsa: - Allow to build with -ltcmalloc. - Finish mmap interface, getting more stuff from tools/perf while adding abstractions to avoid pulling too much stuff, to get libperf to grow as tools needs things like auxtrace, etc. perf scripting engines: Steven Rostedt (VMware): - Iterate on tep event arrays directly, fixing script generation with '-g python' when having multiple tracepoints in a perf.data file. core: - Allow to build with -ltcmalloc. perf test: Leo Yan: - Report failure for mmap events. - Avoid infinite loop for task exit case. - Remove needless headers for bp_account test. - Add dedicated checking helper is_supported(). - Disable bp_signal testing for arm64. Vendor events: arm64: John Garry: - Fix Hisi hip08 DDRC PMU eventname. - Add some missing events for Hisi hip08 DDRC, L3C and HHA PMUs. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
27a0a90d63
146
tools/arch/x86/include/asm/irq_vectors.h
Normal file
146
tools/arch/x86/include/asm/irq_vectors.h
Normal file
@ -0,0 +1,146 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _ASM_X86_IRQ_VECTORS_H
|
||||
#define _ASM_X86_IRQ_VECTORS_H
|
||||
|
||||
#include <linux/threads.h>
|
||||
/*
|
||||
* Linux IRQ vector layout.
|
||||
*
|
||||
* There are 256 IDT entries (per CPU - each entry is 8 bytes) which can
|
||||
* be defined by Linux. They are used as a jump table by the CPU when a
|
||||
* given vector is triggered - by a CPU-external, CPU-internal or
|
||||
* software-triggered event.
|
||||
*
|
||||
* Linux sets the kernel code address each entry jumps to early during
|
||||
* bootup, and never changes them. This is the general layout of the
|
||||
* IDT entries:
|
||||
*
|
||||
* Vectors 0 ... 31 : system traps and exceptions - hardcoded events
|
||||
* Vectors 32 ... 127 : device interrupts
|
||||
* Vector 128 : legacy int80 syscall interface
|
||||
* Vectors 129 ... LOCAL_TIMER_VECTOR-1
|
||||
* Vectors LOCAL_TIMER_VECTOR ... 255 : special interrupts
|
||||
*
|
||||
* 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table.
|
||||
*
|
||||
* This file enumerates the exact layout of them:
|
||||
*/
|
||||
|
||||
#define NMI_VECTOR 0x02
|
||||
#define MCE_VECTOR 0x12
|
||||
|
||||
/*
|
||||
* IDT vectors usable for external interrupt sources start at 0x20.
|
||||
* (0x80 is the syscall vector, 0x30-0x3f are for ISA)
|
||||
*/
|
||||
#define FIRST_EXTERNAL_VECTOR 0x20
|
||||
|
||||
/*
|
||||
* Reserve the lowest usable vector (and hence lowest priority) 0x20 for
|
||||
* triggering cleanup after irq migration. 0x21-0x2f will still be used
|
||||
* for device interrupts.
|
||||
*/
|
||||
#define IRQ_MOVE_CLEANUP_VECTOR FIRST_EXTERNAL_VECTOR
|
||||
|
||||
#define IA32_SYSCALL_VECTOR 0x80
|
||||
|
||||
/*
|
||||
* Vectors 0x30-0x3f are used for ISA interrupts.
|
||||
* round up to the next 16-vector boundary
|
||||
*/
|
||||
#define ISA_IRQ_VECTOR(irq) (((FIRST_EXTERNAL_VECTOR + 16) & ~15) + irq)
|
||||
|
||||
/*
|
||||
* Special IRQ vectors used by the SMP architecture, 0xf0-0xff
|
||||
*
|
||||
* some of the following vectors are 'rare', they are merged
|
||||
* into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
|
||||
* TLB, reschedule and local APIC vectors are performance-critical.
|
||||
*/
|
||||
|
||||
#define SPURIOUS_APIC_VECTOR 0xff
|
||||
/*
|
||||
* Sanity check
|
||||
*/
|
||||
#if ((SPURIOUS_APIC_VECTOR & 0x0F) != 0x0F)
|
||||
# error SPURIOUS_APIC_VECTOR definition error
|
||||
#endif
|
||||
|
||||
#define ERROR_APIC_VECTOR 0xfe
|
||||
#define RESCHEDULE_VECTOR 0xfd
|
||||
#define CALL_FUNCTION_VECTOR 0xfc
|
||||
#define CALL_FUNCTION_SINGLE_VECTOR 0xfb
|
||||
#define THERMAL_APIC_VECTOR 0xfa
|
||||
#define THRESHOLD_APIC_VECTOR 0xf9
|
||||
#define REBOOT_VECTOR 0xf8
|
||||
|
||||
/*
|
||||
* Generic system vector for platform specific use
|
||||
*/
|
||||
#define X86_PLATFORM_IPI_VECTOR 0xf7
|
||||
|
||||
/*
|
||||
* IRQ work vector:
|
||||
*/
|
||||
#define IRQ_WORK_VECTOR 0xf6
|
||||
|
||||
#define UV_BAU_MESSAGE 0xf5
|
||||
#define DEFERRED_ERROR_VECTOR 0xf4
|
||||
|
||||
/* Vector on which hypervisor callbacks will be delivered */
|
||||
#define HYPERVISOR_CALLBACK_VECTOR 0xf3
|
||||
|
||||
/* Vector for KVM to deliver posted interrupt IPI */
|
||||
#ifdef CONFIG_HAVE_KVM
|
||||
#define POSTED_INTR_VECTOR 0xf2
|
||||
#define POSTED_INTR_WAKEUP_VECTOR 0xf1
|
||||
#define POSTED_INTR_NESTED_VECTOR 0xf0
|
||||
#endif
|
||||
|
||||
#define MANAGED_IRQ_SHUTDOWN_VECTOR 0xef
|
||||
|
||||
#if IS_ENABLED(CONFIG_HYPERV)
|
||||
#define HYPERV_REENLIGHTENMENT_VECTOR 0xee
|
||||
#define HYPERV_STIMER0_VECTOR 0xed
|
||||
#endif
|
||||
|
||||
#define LOCAL_TIMER_VECTOR 0xec
|
||||
|
||||
#define NR_VECTORS 256
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
#define FIRST_SYSTEM_VECTOR LOCAL_TIMER_VECTOR
|
||||
#else
|
||||
#define FIRST_SYSTEM_VECTOR NR_VECTORS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Size the maximum number of interrupts.
|
||||
*
|
||||
* If the irq_desc[] array has a sparse layout, we can size things
|
||||
* generously - it scales up linearly with the maximum number of CPUs,
|
||||
* and the maximum number of IO-APICs, whichever is higher.
|
||||
*
|
||||
* In other cases we size more conservatively, to not create too large
|
||||
* static arrays.
|
||||
*/
|
||||
|
||||
#define NR_IRQS_LEGACY 16
|
||||
|
||||
#define CPU_VECTOR_LIMIT (64 * NR_CPUS)
|
||||
#define IO_APIC_VECTOR_LIMIT (32 * MAX_IO_APICS)
|
||||
|
||||
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_PCI_MSI)
|
||||
#define NR_IRQS \
|
||||
(CPU_VECTOR_LIMIT > IO_APIC_VECTOR_LIMIT ? \
|
||||
(NR_VECTORS + CPU_VECTOR_LIMIT) : \
|
||||
(NR_VECTORS + IO_APIC_VECTOR_LIMIT))
|
||||
#elif defined(CONFIG_X86_IO_APIC)
|
||||
#define NR_IRQS (NR_VECTORS + IO_APIC_VECTOR_LIMIT)
|
||||
#elif defined(CONFIG_PCI_MSI)
|
||||
#define NR_IRQS (NR_VECTORS + CPU_VECTOR_LIMIT)
|
||||
#else
|
||||
#define NR_IRQS NR_IRQS_LEGACY
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_X86_IRQ_VECTORS_H */
|
@ -36,6 +36,9 @@ Enable debugging output.
|
||||
Print how named events are resolved internally into perf events, and also
|
||||
any extra expressions computed by perf stat.
|
||||
|
||||
--deprecated::
|
||||
Print deprecated events. By default the deprecated events are hidden.
|
||||
|
||||
[[EVENT_MODIFIERS]]
|
||||
EVENT MODIFIERS
|
||||
---------------
|
||||
|
@ -323,6 +323,12 @@ The output is SMI cycles%, equals to (aperf - unhalted core cycles) / aperf
|
||||
|
||||
Users who wants to get the actual value can apply --no-metric-only.
|
||||
|
||||
--all-kernel::
|
||||
Configure all used events to run in kernel space.
|
||||
|
||||
--all-user::
|
||||
Configure all used events to run in user space.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
|
@ -146,6 +146,10 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs.
|
||||
Show all syscalls followed by a summary by thread with min, max, and
|
||||
average times (in msec) and relative stddev.
|
||||
|
||||
--errno-summary::
|
||||
To be used with -s or -S, to show stats for the errnos experienced by
|
||||
syscalls, using only this option will trigger --summary.
|
||||
|
||||
--tool_stats::
|
||||
Show tool stats such as number of times fd->pathname was discovered thru
|
||||
hooking the open syscall return + vfs_getname or via reading /proc/pid/fd, etc.
|
||||
|
@ -265,6 +265,11 @@ LDFLAGS += -Wl,-z,noexecstack
|
||||
|
||||
EXTLIBS = -lpthread -lrt -lm -ldl
|
||||
|
||||
ifneq ($(TCMALLOC),)
|
||||
CFLAGS += -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free
|
||||
EXTLIBS += -ltcmalloc
|
||||
endif
|
||||
|
||||
ifeq ($(FEATURES_DUMP),)
|
||||
include $(srctree)/tools/build/Makefile.feature
|
||||
else
|
||||
|
@ -114,6 +114,8 @@ include ../scripts/utilities.mak
|
||||
# Define NO_LIBZSTD if you do not want support of Zstandard based runtime
|
||||
# trace compression in record mode.
|
||||
#
|
||||
# Define TCMALLOC to enable tcmalloc heap profiling.
|
||||
#
|
||||
|
||||
# As per kernel Makefile, avoid funny character set dependencies
|
||||
unexport LC_ALL
|
||||
@ -544,6 +546,12 @@ x86_arch_prctl_code_tbl := $(srctree)/tools/perf/trace/beauty/x86_arch_prctl.sh
|
||||
$(x86_arch_prctl_code_array): $(x86_arch_asm_uapi_dir)/prctl.h $(x86_arch_prctl_code_tbl)
|
||||
$(Q)$(SHELL) '$(x86_arch_prctl_code_tbl)' $(x86_arch_asm_uapi_dir) > $@
|
||||
|
||||
x86_arch_irq_vectors_array := $(beauty_outdir)/x86_arch_irq_vectors_array.c
|
||||
x86_arch_irq_vectors_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh
|
||||
|
||||
$(x86_arch_irq_vectors_array): $(x86_arch_asm_dir)/irq_vectors.h $(x86_arch_irq_vectors_tbl)
|
||||
$(Q)$(SHELL) '$(x86_arch_irq_vectors_tbl)' $(x86_arch_asm_dir) > $@
|
||||
|
||||
x86_arch_MSRs_array := $(beauty_outdir)/x86_arch_MSRs_array.c
|
||||
x86_arch_MSRs_tbl := $(srctree)/tools/perf/trace/beauty/tracepoints/x86_msr.sh
|
||||
|
||||
@ -684,6 +692,7 @@ prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders $(drm_ioc
|
||||
$(perf_ioctl_array) \
|
||||
$(prctl_option_array) \
|
||||
$(usbdevfs_ioctl_array) \
|
||||
$(x86_arch_irq_vectors_array) \
|
||||
$(x86_arch_MSRs_array) \
|
||||
$(x86_arch_prctl_code_array) \
|
||||
$(rename_flags_array) \
|
||||
@ -989,6 +998,7 @@ clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clea
|
||||
$(OUTPUT)$(perf_ioctl_array) \
|
||||
$(OUTPUT)$(prctl_option_array) \
|
||||
$(OUTPUT)$(usbdevfs_ioctl_array) \
|
||||
$(OUTPUT)$(x86_arch_irq_vectors_array) \
|
||||
$(OUTPUT)$(x86_arch_MSRs_array) \
|
||||
$(OUTPUT)$(x86_arch_prctl_code_array) \
|
||||
$(OUTPUT)$(rename_flags_array) \
|
||||
|
@ -26,6 +26,7 @@ int cmd_list(int argc, const char **argv)
|
||||
int i;
|
||||
bool raw_dump = false;
|
||||
bool long_desc_flag = false;
|
||||
bool deprecated = false;
|
||||
struct option list_options[] = {
|
||||
OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
|
||||
OPT_BOOLEAN('d', "desc", &desc_flag,
|
||||
@ -34,6 +35,8 @@ int cmd_list(int argc, const char **argv)
|
||||
"Print longer event descriptions."),
|
||||
OPT_BOOLEAN(0, "details", &details_flag,
|
||||
"Print information on the perf event names and expressions used internally by events."),
|
||||
OPT_BOOLEAN(0, "deprecated", &deprecated,
|
||||
"Print deprecated events."),
|
||||
OPT_INCR(0, "debug", &verbose,
|
||||
"Enable debugging output"),
|
||||
OPT_END()
|
||||
@ -55,7 +58,7 @@ int cmd_list(int argc, const char **argv)
|
||||
|
||||
if (argc == 0) {
|
||||
print_events(NULL, raw_dump, !desc_flag, long_desc_flag,
|
||||
details_flag);
|
||||
details_flag, deprecated);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -78,7 +81,8 @@ int cmd_list(int argc, const char **argv)
|
||||
print_hwcache_events(NULL, raw_dump);
|
||||
else if (strcmp(argv[i], "pmu") == 0)
|
||||
print_pmu_events(NULL, raw_dump, !desc_flag,
|
||||
long_desc_flag, details_flag);
|
||||
long_desc_flag, details_flag,
|
||||
deprecated);
|
||||
else if (strcmp(argv[i], "sdt") == 0)
|
||||
print_sdt_events(NULL, NULL, raw_dump);
|
||||
else if (strcmp(argv[i], "metric") == 0 || strcmp(argv[i], "metrics") == 0)
|
||||
@ -91,7 +95,8 @@ int cmd_list(int argc, const char **argv)
|
||||
if (sep == NULL) {
|
||||
print_events(argv[i], raw_dump, !desc_flag,
|
||||
long_desc_flag,
|
||||
details_flag);
|
||||
details_flag,
|
||||
deprecated);
|
||||
continue;
|
||||
}
|
||||
sep_idx = sep - argv[i];
|
||||
@ -117,7 +122,8 @@ int cmd_list(int argc, const char **argv)
|
||||
print_hwcache_events(s, raw_dump);
|
||||
print_pmu_events(s, raw_dump, !desc_flag,
|
||||
long_desc_flag,
|
||||
details_flag);
|
||||
details_flag,
|
||||
deprecated);
|
||||
print_tracepoint_events(NULL, s, raw_dump);
|
||||
print_sdt_events(NULL, s, raw_dump);
|
||||
metricgroup__print(true, true, s, raw_dump, details_flag);
|
||||
|
@ -399,6 +399,13 @@ static int report__setup_sample_type(struct report *rep)
|
||||
PERF_SAMPLE_BRANCH_ANY))
|
||||
rep->nonany_branch_mode = true;
|
||||
|
||||
#ifndef HAVE_LIBUNWIND_SUPPORT
|
||||
if (dwarf_callchain_users) {
|
||||
ui__warning("Please install libunwind development packages "
|
||||
"during the perf build.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -3864,10 +3864,11 @@ int cmd_script(int argc, const char **argv)
|
||||
goto out_delete;
|
||||
|
||||
if (script.time_str) {
|
||||
err = perf_time__parse_for_ranges(script.time_str, session,
|
||||
err = perf_time__parse_for_ranges_reltime(script.time_str, session,
|
||||
&script.ptime_range,
|
||||
&script.range_size,
|
||||
&script.range_num);
|
||||
&script.range_num,
|
||||
reltime);
|
||||
if (err < 0)
|
||||
goto out_delete;
|
||||
|
||||
|
@ -803,6 +803,12 @@ static struct option stat_options[] = {
|
||||
OPT_CALLBACK('M', "metrics", &evsel_list, "metric/metric group list",
|
||||
"monitor specified metrics or metric groups (separated by ,)",
|
||||
parse_metric_groups),
|
||||
OPT_BOOLEAN_FLAG(0, "all-kernel", &stat_config.all_kernel,
|
||||
"Configure all used events to run in kernel space.",
|
||||
PARSE_OPT_EXCLUSIVE),
|
||||
OPT_BOOLEAN_FLAG(0, "all-user", &stat_config.all_user,
|
||||
"Configure all used events to run in user space.",
|
||||
PARSE_OPT_EXCLUSIVE),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -175,6 +175,7 @@ struct trace {
|
||||
bool multiple_threads;
|
||||
bool summary;
|
||||
bool summary_only;
|
||||
bool errno_summary;
|
||||
bool failure_only;
|
||||
bool show_comm;
|
||||
bool print_sample;
|
||||
@ -284,6 +285,87 @@ struct syscall_tp {
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* The evsel->priv as used by 'perf trace'
|
||||
* sc: for raw_syscalls:sys_{enter,exit} and syscalls:sys_{enter,exit}_SYSCALLNAME
|
||||
* fmt: for all the other tracepoints
|
||||
*/
|
||||
struct evsel_trace {
|
||||
struct syscall_tp sc;
|
||||
struct syscall_arg_fmt *fmt;
|
||||
};
|
||||
|
||||
static struct evsel_trace *evsel_trace__new(void)
|
||||
{
|
||||
return zalloc(sizeof(struct evsel_trace));
|
||||
}
|
||||
|
||||
static void evsel_trace__delete(struct evsel_trace *et)
|
||||
{
|
||||
if (et == NULL)
|
||||
return;
|
||||
|
||||
zfree(&et->fmt);
|
||||
free(et);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used with raw_syscalls:sys_{enter,exit} and with the
|
||||
* syscalls:sys_{enter,exit}_SYSCALL tracepoints
|
||||
*/
|
||||
static inline struct syscall_tp *__evsel__syscall_tp(struct evsel *evsel)
|
||||
{
|
||||
struct evsel_trace *et = evsel->priv;
|
||||
|
||||
return &et->sc;
|
||||
}
|
||||
|
||||
static struct syscall_tp *evsel__syscall_tp(struct evsel *evsel)
|
||||
{
|
||||
if (evsel->priv == NULL) {
|
||||
evsel->priv = evsel_trace__new();
|
||||
if (evsel->priv == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return __evsel__syscall_tp(evsel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Used with all the other tracepoints.
|
||||
*/
|
||||
static inline struct syscall_arg_fmt *__evsel__syscall_arg_fmt(struct evsel *evsel)
|
||||
{
|
||||
struct evsel_trace *et = evsel->priv;
|
||||
|
||||
return et->fmt;
|
||||
}
|
||||
|
||||
static struct syscall_arg_fmt *evsel__syscall_arg_fmt(struct evsel *evsel)
|
||||
{
|
||||
struct evsel_trace *et = evsel->priv;
|
||||
|
||||
if (evsel->priv == NULL) {
|
||||
et = evsel->priv = evsel_trace__new();
|
||||
|
||||
if (et == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (et->fmt == NULL) {
|
||||
et->fmt = calloc(evsel->tp_format->format.nr_fields, sizeof(struct syscall_arg_fmt));
|
||||
if (et->fmt == NULL)
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
return __evsel__syscall_arg_fmt(evsel);
|
||||
|
||||
out_delete:
|
||||
evsel_trace__delete(evsel->priv);
|
||||
evsel->priv = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int perf_evsel__init_tp_uint_field(struct evsel *evsel,
|
||||
struct tp_field *field,
|
||||
const char *name)
|
||||
@ -297,7 +379,7 @@ static int perf_evsel__init_tp_uint_field(struct evsel *evsel,
|
||||
}
|
||||
|
||||
#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
|
||||
({ struct syscall_tp *sc = evsel->priv;\
|
||||
({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
|
||||
perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
|
||||
|
||||
static int perf_evsel__init_tp_ptr_field(struct evsel *evsel,
|
||||
@ -313,7 +395,7 @@ static int perf_evsel__init_tp_ptr_field(struct evsel *evsel,
|
||||
}
|
||||
|
||||
#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
|
||||
({ struct syscall_tp *sc = evsel->priv;\
|
||||
({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
|
||||
perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
|
||||
|
||||
static void evsel__delete_priv(struct evsel *evsel)
|
||||
@ -324,73 +406,61 @@ static void evsel__delete_priv(struct evsel *evsel)
|
||||
|
||||
static int perf_evsel__init_syscall_tp(struct evsel *evsel)
|
||||
{
|
||||
struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
|
||||
struct syscall_tp *sc = evsel__syscall_tp(evsel);
|
||||
|
||||
if (evsel->priv != NULL) {
|
||||
if (sc != NULL) {
|
||||
if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr") &&
|
||||
perf_evsel__init_tp_uint_field(evsel, &sc->id, "nr"))
|
||||
goto out_delete;
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
out_delete:
|
||||
zfree(&evsel->priv);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int perf_evsel__init_augmented_syscall_tp(struct evsel *evsel, struct evsel *tp)
|
||||
{
|
||||
struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
|
||||
struct syscall_tp *sc = evsel__syscall_tp(evsel);
|
||||
|
||||
if (evsel->priv != NULL) {
|
||||
if (sc != NULL) {
|
||||
struct tep_format_field *syscall_id = perf_evsel__field(tp, "id");
|
||||
if (syscall_id == NULL)
|
||||
syscall_id = perf_evsel__field(tp, "__syscall_nr");
|
||||
if (syscall_id == NULL)
|
||||
goto out_delete;
|
||||
if (__tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
|
||||
goto out_delete;
|
||||
if (syscall_id == NULL ||
|
||||
__tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
out_delete:
|
||||
zfree(&evsel->priv);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int perf_evsel__init_augmented_syscall_tp_args(struct evsel *evsel)
|
||||
{
|
||||
struct syscall_tp *sc = evsel->priv;
|
||||
struct syscall_tp *sc = __evsel__syscall_tp(evsel);
|
||||
|
||||
return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
|
||||
}
|
||||
|
||||
static int perf_evsel__init_augmented_syscall_tp_ret(struct evsel *evsel)
|
||||
{
|
||||
struct syscall_tp *sc = evsel->priv;
|
||||
struct syscall_tp *sc = __evsel__syscall_tp(evsel);
|
||||
|
||||
return __tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap);
|
||||
}
|
||||
|
||||
static int perf_evsel__init_raw_syscall_tp(struct evsel *evsel, void *handler)
|
||||
{
|
||||
evsel->priv = malloc(sizeof(struct syscall_tp));
|
||||
if (evsel->priv != NULL) {
|
||||
if (evsel__syscall_tp(evsel) != NULL) {
|
||||
if (perf_evsel__init_sc_tp_uint_field(evsel, id))
|
||||
goto out_delete;
|
||||
return -ENOENT;
|
||||
|
||||
evsel->handler = handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEM;
|
||||
|
||||
out_delete:
|
||||
zfree(&evsel->priv);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
|
||||
@ -415,13 +485,27 @@ out_delete:
|
||||
}
|
||||
|
||||
#define perf_evsel__sc_tp_uint(evsel, name, sample) \
|
||||
({ struct syscall_tp *fields = evsel->priv; \
|
||||
({ struct syscall_tp *fields = __evsel__syscall_tp(evsel); \
|
||||
fields->name.integer(&fields->name, sample); })
|
||||
|
||||
#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
|
||||
({ struct syscall_tp *fields = evsel->priv; \
|
||||
({ struct syscall_tp *fields = __evsel__syscall_tp(evsel); \
|
||||
fields->name.pointer(&fields->name, sample); })
|
||||
|
||||
size_t strarray__scnprintf_suffix(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_suffix, int val)
|
||||
{
|
||||
int idx = val - sa->offset;
|
||||
|
||||
if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL) {
|
||||
size_t printed = scnprintf(bf, size, intfmt, val);
|
||||
if (show_suffix)
|
||||
printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sa->prefix);
|
||||
return printed;
|
||||
}
|
||||
|
||||
return scnprintf(bf, size, "%s%s", sa->entries[idx], show_suffix ? sa->prefix : "");
|
||||
}
|
||||
|
||||
size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_prefix, int val)
|
||||
{
|
||||
int idx = val - sa->offset;
|
||||
@ -451,6 +535,21 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
|
||||
|
||||
#define SCA_STRARRAY syscall_arg__scnprintf_strarray
|
||||
|
||||
bool syscall_arg__strtoul_strarray(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
|
||||
{
|
||||
return strarray__strtoul(arg->parm, bf, size, ret);
|
||||
}
|
||||
|
||||
bool syscall_arg__strtoul_strarray_flags(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
|
||||
{
|
||||
return strarray__strtoul_flags(arg->parm, bf, size, ret);
|
||||
}
|
||||
|
||||
bool syscall_arg__strtoul_strarrays(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
|
||||
{
|
||||
return strarrays__strtoul(arg->parm, bf, size, ret);
|
||||
}
|
||||
|
||||
size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg)
|
||||
{
|
||||
return strarray__scnprintf_flags(arg->parm, bf, size, arg->show_string_prefix, arg->val);
|
||||
@ -492,6 +591,49 @@ bool strarray__strtoul(struct strarray *sa, char *bf, size_t size, u64 *ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool strarray__strtoul_flags(struct strarray *sa, char *bf, size_t size, u64 *ret)
|
||||
{
|
||||
u64 val = 0;
|
||||
char *tok = bf, *sep, *end;
|
||||
|
||||
*ret = 0;
|
||||
|
||||
while (size != 0) {
|
||||
int toklen = size;
|
||||
|
||||
sep = memchr(tok, '|', size);
|
||||
if (sep != NULL) {
|
||||
size -= sep - tok + 1;
|
||||
|
||||
end = sep - 1;
|
||||
while (end > tok && isspace(*end))
|
||||
--end;
|
||||
|
||||
toklen = end - tok + 1;
|
||||
}
|
||||
|
||||
while (isspace(*tok))
|
||||
++tok;
|
||||
|
||||
if (isalpha(*tok) || *tok == '_') {
|
||||
if (!strarray__strtoul(sa, tok, toklen, &val))
|
||||
return false;
|
||||
} else {
|
||||
bool is_hexa = tok[0] == 0 && (tok[1] = 'x' || tok[1] == 'X');
|
||||
|
||||
val = strtoul(tok, NULL, is_hexa ? 16 : 0);
|
||||
}
|
||||
|
||||
*ret |= (1 << (val - 1));
|
||||
|
||||
if (sep == NULL)
|
||||
break;
|
||||
tok = sep + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strarrays__strtoul(struct strarrays *sas, char *bf, size_t size, u64 *ret)
|
||||
{
|
||||
int i;
|
||||
@ -562,7 +704,7 @@ static size_t syscall_arg__scnprintf_char_array(char *bf, size_t size, struct sy
|
||||
// XXX Hey, maybe for sched:sched_switch prev/next comm fields we can
|
||||
// fill missing comms using thread__set_comm()...
|
||||
// here or in a special syscall_arg__scnprintf_pid_sched_tp...
|
||||
return scnprintf(bf, size, "\"%-.*s\"", arg->fmt->nr_entries, arg->val);
|
||||
return scnprintf(bf, size, "\"%-.*s\"", arg->fmt->nr_entries ?: arg->len, arg->val);
|
||||
}
|
||||
|
||||
#define SCA_CHAR_ARRAY syscall_arg__scnprintf_char_array
|
||||
@ -740,10 +882,12 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
|
||||
|
||||
#define STRARRAY(name, array) \
|
||||
{ .scnprintf = SCA_STRARRAY, \
|
||||
.strtoul = STUL_STRARRAY, \
|
||||
.parm = &strarray__##array, }
|
||||
|
||||
#define STRARRAY_FLAGS(name, array) \
|
||||
{ .scnprintf = SCA_STRARRAY_FLAGS, \
|
||||
.strtoul = STUL_STRARRAY_FLAGS, \
|
||||
.parm = &strarray__##array, }
|
||||
|
||||
#include "trace/beauty/arch_errno_names.c"
|
||||
@ -799,7 +943,8 @@ static struct syscall_fmt syscall_fmts[] = {
|
||||
{ .name = "fchownat",
|
||||
.arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
|
||||
{ .name = "fcntl",
|
||||
.arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
|
||||
.arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
|
||||
.strtoul = STUL_STRARRAYS,
|
||||
.parm = &strarrays__fcntl_cmds_arrays,
|
||||
.show_zero = true, },
|
||||
[2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
|
||||
@ -870,7 +1015,9 @@ static struct syscall_fmt syscall_fmts[] = {
|
||||
.alias = "old_mmap",
|
||||
#endif
|
||||
.arg = { [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
|
||||
[3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ },
|
||||
[3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */
|
||||
.strtoul = STUL_STRARRAY_FLAGS,
|
||||
.parm = &strarray__mmap_flags, },
|
||||
[5] = { .scnprintf = SCA_HEX, /* offset */ }, }, },
|
||||
{ .name = "mount",
|
||||
.arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ },
|
||||
@ -1513,7 +1660,8 @@ static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
|
||||
}
|
||||
|
||||
static struct syscall_arg_fmt syscall_arg_fmts__by_name[] = {
|
||||
{ .name = "msr", .scnprintf = SCA_X86_MSR, .strtoul = STUL_X86_MSR, }
|
||||
{ .name = "msr", .scnprintf = SCA_X86_MSR, .strtoul = STUL_X86_MSR, },
|
||||
{ .name = "vector", .scnprintf = SCA_X86_IRQ_VECTORS, .strtoul = STUL_X86_IRQ_VECTORS, },
|
||||
};
|
||||
|
||||
static int syscall_arg_fmt__cmp(const void *name, const void *fmtp)
|
||||
@ -1558,7 +1706,7 @@ syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field
|
||||
arg->scnprintf = SCA_PID;
|
||||
else if (strcmp(field->type, "umode_t") == 0)
|
||||
arg->scnprintf = SCA_MODE_T;
|
||||
else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstarts(field->type, "char")) {
|
||||
else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstr(field->type, "char")) {
|
||||
arg->scnprintf = SCA_CHAR_ARRAY;
|
||||
arg->nr_entries = field->arraylen;
|
||||
} else if ((strcmp(field->type, "int") == 0 ||
|
||||
@ -1653,11 +1801,10 @@ static int trace__read_syscall_info(struct trace *trace, int id)
|
||||
|
||||
static int perf_evsel__init_tp_arg_scnprintf(struct evsel *evsel)
|
||||
{
|
||||
int nr_args = evsel->tp_format->format.nr_fields;
|
||||
struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
|
||||
|
||||
evsel->priv = calloc(nr_args, sizeof(struct syscall_arg_fmt));
|
||||
if (evsel->priv != NULL) {
|
||||
syscall_arg_fmt__init_array(evsel->priv, evsel->tp_format->format.fields);
|
||||
if (fmt != NULL) {
|
||||
syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1958,11 +2105,18 @@ out_cant_read:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void thread__update_stats(struct thread_trace *ttrace,
|
||||
int id, struct perf_sample *sample)
|
||||
struct syscall_stats {
|
||||
struct stats stats;
|
||||
u64 nr_failures;
|
||||
int max_errno;
|
||||
u32 *errnos;
|
||||
};
|
||||
|
||||
static void thread__update_stats(struct thread *thread, struct thread_trace *ttrace,
|
||||
int id, struct perf_sample *sample, long err, bool errno_summary)
|
||||
{
|
||||
struct int_node *inode;
|
||||
struct stats *stats;
|
||||
struct syscall_stats *stats;
|
||||
u64 duration = 0;
|
||||
|
||||
inode = intlist__findnew(ttrace->syscall_stats, id);
|
||||
@ -1971,17 +2125,46 @@ static void thread__update_stats(struct thread_trace *ttrace,
|
||||
|
||||
stats = inode->priv;
|
||||
if (stats == NULL) {
|
||||
stats = malloc(sizeof(struct stats));
|
||||
stats = malloc(sizeof(*stats));
|
||||
if (stats == NULL)
|
||||
return;
|
||||
init_stats(stats);
|
||||
|
||||
stats->nr_failures = 0;
|
||||
stats->max_errno = 0;
|
||||
stats->errnos = NULL;
|
||||
init_stats(&stats->stats);
|
||||
inode->priv = stats;
|
||||
}
|
||||
|
||||
if (ttrace->entry_time && sample->time > ttrace->entry_time)
|
||||
duration = sample->time - ttrace->entry_time;
|
||||
|
||||
update_stats(stats, duration);
|
||||
update_stats(&stats->stats, duration);
|
||||
|
||||
if (err < 0) {
|
||||
++stats->nr_failures;
|
||||
|
||||
if (!errno_summary)
|
||||
return;
|
||||
|
||||
err = -err;
|
||||
if (err > stats->max_errno) {
|
||||
u32 *new_errnos = realloc(stats->errnos, err * sizeof(u32));
|
||||
|
||||
if (new_errnos) {
|
||||
memset(new_errnos + stats->max_errno, 0, (err - stats->max_errno) * sizeof(u32));
|
||||
} else {
|
||||
pr_debug("Not enough memory for errno stats for thread \"%s\"(%d/%d), results will be incomplete\n",
|
||||
thread__comm_str(thread), thread->pid_, thread->tid);
|
||||
return;
|
||||
}
|
||||
|
||||
stats->errnos = new_errnos;
|
||||
stats->max_errno = err;
|
||||
}
|
||||
|
||||
++stats->errnos[err - 1];
|
||||
}
|
||||
}
|
||||
|
||||
static int trace__printf_interrupted_entry(struct trace *trace)
|
||||
@ -2226,11 +2409,11 @@ static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
|
||||
|
||||
trace__fprintf_sample(trace, evsel, sample, thread);
|
||||
|
||||
if (trace->summary)
|
||||
thread__update_stats(ttrace, id, sample);
|
||||
|
||||
ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
|
||||
|
||||
if (trace->summary)
|
||||
thread__update_stats(thread, ttrace, id, sample, ret, trace->errno_summary);
|
||||
|
||||
if (!trace->fd_path_disabled && sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
|
||||
trace__set_fd_pathname(thread, ret, ttrace->filename.name);
|
||||
ttrace->filename.pending_open = false;
|
||||
@ -2466,7 +2649,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
|
||||
char bf[2048];
|
||||
size_t size = sizeof(bf);
|
||||
struct tep_format_field *field = evsel->tp_format->format.fields;
|
||||
struct syscall_arg_fmt *arg = evsel->priv;
|
||||
struct syscall_arg_fmt *arg = __evsel__syscall_arg_fmt(evsel);
|
||||
size_t printed = 0;
|
||||
unsigned long val;
|
||||
u8 bit = 1;
|
||||
@ -2486,10 +2669,19 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel,
|
||||
if (syscall_arg.mask & bit)
|
||||
continue;
|
||||
|
||||
syscall_arg.len = 0;
|
||||
syscall_arg.fmt = arg;
|
||||
if (field->flags & TEP_FIELD_IS_ARRAY)
|
||||
val = (uintptr_t)(sample->raw_data + field->offset);
|
||||
else
|
||||
if (field->flags & TEP_FIELD_IS_ARRAY) {
|
||||
int offset = field->offset;
|
||||
|
||||
if (field->flags & TEP_FIELD_IS_DYNAMIC) {
|
||||
offset = format_field__intval(field, sample, evsel->needs_swap);
|
||||
syscall_arg.len = offset >> 16;
|
||||
offset &= 0xffff;
|
||||
}
|
||||
|
||||
val = (uintptr_t)(sample->raw_data + offset);
|
||||
} else
|
||||
val = format_field__intval(field, sample, evsel->needs_swap);
|
||||
/*
|
||||
* Some syscall args need some mask, most don't and
|
||||
@ -2592,12 +2784,6 @@ static int trace__event_handler(struct trace *trace, struct evsel *evsel,
|
||||
} else {
|
||||
trace__fprintf_tp_fields(trace, evsel, sample, thread, NULL, 0);
|
||||
}
|
||||
++trace->nr_events_printed;
|
||||
|
||||
if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) {
|
||||
evsel__disable(evsel);
|
||||
evsel__close(evsel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2608,6 +2794,13 @@ newline:
|
||||
trace__fprintf_callchain(trace, sample);
|
||||
else if (callchain_ret < 0)
|
||||
pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
|
||||
|
||||
++trace->nr_events_printed;
|
||||
|
||||
if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) {
|
||||
evsel__disable(evsel);
|
||||
evsel__close(evsel);
|
||||
}
|
||||
out:
|
||||
thread__put(thread);
|
||||
return 0;
|
||||
@ -2759,21 +2952,23 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
|
||||
"-m", "1024",
|
||||
"-c", "1",
|
||||
};
|
||||
|
||||
pid_t pid = getpid();
|
||||
char *filter = asprintf__tp_filter_pids(1, &pid);
|
||||
const char * const sc_args[] = { "-e", };
|
||||
unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
|
||||
const char * const majpf_args[] = { "-e", "major-faults" };
|
||||
unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
|
||||
const char * const minpf_args[] = { "-e", "minor-faults" };
|
||||
unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
|
||||
int err = -1;
|
||||
|
||||
/* +1 is for the event string below */
|
||||
rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
|
||||
/* +3 is for the event string below and the pid filter */
|
||||
rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 3 +
|
||||
majpf_args_nr + minpf_args_nr + argc;
|
||||
rec_argv = calloc(rec_argc + 1, sizeof(char *));
|
||||
|
||||
if (rec_argv == NULL)
|
||||
return -ENOMEM;
|
||||
if (rec_argv == NULL || filter == NULL)
|
||||
goto out_free;
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(record_args); i++)
|
||||
@ -2790,11 +2985,13 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
|
||||
rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
|
||||
else {
|
||||
pr_err("Neither raw_syscalls nor syscalls events exist.\n");
|
||||
free(rec_argv);
|
||||
return -1;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
rec_argv[j++] = "--filter";
|
||||
rec_argv[j++] = filter;
|
||||
|
||||
if (trace->trace_pgfaults & TRACE_PFMAJ)
|
||||
for (i = 0; i < majpf_args_nr; i++)
|
||||
rec_argv[j++] = majpf_args[i];
|
||||
@ -2806,7 +3003,11 @@ static int trace__record(struct trace *trace, int argc, const char **argv)
|
||||
for (i = 0; i < (unsigned int)argc; i++)
|
||||
rec_argv[j++] = argv[i];
|
||||
|
||||
return cmd_record(j, rec_argv);
|
||||
err = cmd_record(j, rec_argv);
|
||||
out_free:
|
||||
free(filter);
|
||||
free(rec_argv);
|
||||
return err;
|
||||
}
|
||||
|
||||
static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
|
||||
@ -3488,7 +3689,7 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
|
||||
static struct syscall_arg_fmt *perf_evsel__syscall_arg_fmt(struct evsel *evsel, char *arg)
|
||||
{
|
||||
struct tep_format_field *field;
|
||||
struct syscall_arg_fmt *fmt = evsel->priv;
|
||||
struct syscall_arg_fmt *fmt = __evsel__syscall_arg_fmt(evsel);
|
||||
|
||||
if (evsel->tp_format == NULL || fmt == NULL)
|
||||
return NULL;
|
||||
@ -3526,7 +3727,7 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
|
||||
}
|
||||
|
||||
right_end = right + 1;
|
||||
while (isalnum(*right_end) || *right_end == '_')
|
||||
while (isalnum(*right_end) || *right_end == '_' || *right_end == '|')
|
||||
++right_end;
|
||||
|
||||
if (isalpha(*right)) {
|
||||
@ -3542,8 +3743,8 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
|
||||
|
||||
fmt = perf_evsel__syscall_arg_fmt(evsel, arg);
|
||||
if (fmt == NULL) {
|
||||
pr_debug("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
|
||||
arg, evsel->name, evsel->filter);
|
||||
pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
|
||||
arg, evsel->name, evsel->filter);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -3552,7 +3753,11 @@ static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel
|
||||
|
||||
if (fmt->strtoul) {
|
||||
u64 val;
|
||||
if (fmt->strtoul(right, right_size, NULL, &val)) {
|
||||
struct syscall_arg syscall_arg = {
|
||||
.parm = fmt->parm,
|
||||
};
|
||||
|
||||
if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
|
||||
char *n, expansion[19];
|
||||
int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
|
||||
int expansion_offset = right - new_filter;
|
||||
@ -4016,17 +4221,17 @@ static size_t trace__fprintf_threads_header(FILE *fp)
|
||||
}
|
||||
|
||||
DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
|
||||
struct stats *stats;
|
||||
double msecs;
|
||||
int syscall;
|
||||
struct syscall_stats *stats;
|
||||
double msecs;
|
||||
int syscall;
|
||||
)
|
||||
{
|
||||
struct int_node *source = rb_entry(nd, struct int_node, rb_node);
|
||||
struct stats *stats = source->priv;
|
||||
struct syscall_stats *stats = source->priv;
|
||||
|
||||
entry->syscall = source->i;
|
||||
entry->stats = stats;
|
||||
entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
|
||||
entry->msecs = stats ? (u64)stats->stats.n * (avg_stats(&stats->stats) / NSEC_PER_MSEC) : 0;
|
||||
}
|
||||
|
||||
static size_t thread__dump_stats(struct thread_trace *ttrace,
|
||||
@ -4042,27 +4247,37 @@ static size_t thread__dump_stats(struct thread_trace *ttrace,
|
||||
|
||||
printed += fprintf(fp, "\n");
|
||||
|
||||
printed += fprintf(fp, " syscall calls total min avg max stddev\n");
|
||||
printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
|
||||
printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
|
||||
printed += fprintf(fp, " syscall calls errors total min avg max stddev\n");
|
||||
printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
|
||||
printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n");
|
||||
|
||||
resort_rb__for_each_entry(nd, syscall_stats) {
|
||||
struct stats *stats = syscall_stats_entry->stats;
|
||||
struct syscall_stats *stats = syscall_stats_entry->stats;
|
||||
if (stats) {
|
||||
double min = (double)(stats->min) / NSEC_PER_MSEC;
|
||||
double max = (double)(stats->max) / NSEC_PER_MSEC;
|
||||
double avg = avg_stats(stats);
|
||||
double min = (double)(stats->stats.min) / NSEC_PER_MSEC;
|
||||
double max = (double)(stats->stats.max) / NSEC_PER_MSEC;
|
||||
double avg = avg_stats(&stats->stats);
|
||||
double pct;
|
||||
u64 n = (u64) stats->n;
|
||||
u64 n = (u64)stats->stats.n;
|
||||
|
||||
pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
|
||||
pct = avg ? 100.0 * stddev_stats(&stats->stats) / avg : 0.0;
|
||||
avg /= NSEC_PER_MSEC;
|
||||
|
||||
sc = &trace->syscalls.table[syscall_stats_entry->syscall];
|
||||
printed += fprintf(fp, " %-15s", sc->name);
|
||||
printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
|
||||
n, syscall_stats_entry->msecs, min, avg);
|
||||
printed += fprintf(fp, " %8" PRIu64 " %6" PRIu64 " %9.3f %9.3f %9.3f",
|
||||
n, stats->nr_failures, syscall_stats_entry->msecs, min, avg);
|
||||
printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
|
||||
|
||||
if (trace->errno_summary && stats->nr_failures) {
|
||||
const char *arch_name = perf_env__arch(trace->host->env);
|
||||
int e;
|
||||
|
||||
for (e = 0; e < stats->max_errno; ++e) {
|
||||
if (stats->errnos[e] != 0)
|
||||
fprintf(fp, "\t\t\t\t%s: %d\n", arch_syscalls__strerrno(arch_name, e + 1), stats->errnos[e]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4219,6 +4434,25 @@ static void evlist__set_default_evsel_handler(struct evlist *evlist, void *handl
|
||||
}
|
||||
}
|
||||
|
||||
static void evsel__set_syscall_arg_fmt(struct evsel *evsel, const char *name)
|
||||
{
|
||||
struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
|
||||
|
||||
if (fmt) {
|
||||
struct syscall_fmt *scfmt = syscall_fmt__find(name);
|
||||
|
||||
if (scfmt) {
|
||||
int skip = 0;
|
||||
|
||||
if (strcmp(evsel->tp_format->format.fields->name, "__syscall_nr") == 0 ||
|
||||
strcmp(evsel->tp_format->format.fields->name, "nr") == 0)
|
||||
++skip;
|
||||
|
||||
memcpy(fmt + skip, scfmt->arg, (evsel->tp_format->format.nr_fields - skip) * sizeof(*fmt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int evlist__set_syscall_tp_fields(struct evlist *evlist)
|
||||
{
|
||||
struct evsel *evsel;
|
||||
@ -4236,15 +4470,19 @@ static int evlist__set_syscall_tp_fields(struct evlist *evlist)
|
||||
return -1;
|
||||
|
||||
if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
|
||||
struct syscall_tp *sc = evsel->priv;
|
||||
struct syscall_tp *sc = __evsel__syscall_tp(evsel);
|
||||
|
||||
if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
|
||||
return -1;
|
||||
|
||||
evsel__set_syscall_arg_fmt(evsel, evsel->tp_format->name + sizeof("sys_enter_") - 1);
|
||||
} else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
|
||||
struct syscall_tp *sc = evsel->priv;
|
||||
struct syscall_tp *sc = __evsel__syscall_tp(evsel);
|
||||
|
||||
if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
|
||||
return -1;
|
||||
|
||||
evsel__set_syscall_arg_fmt(evsel, evsel->tp_format->name + sizeof("sys_exit_") - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4501,6 +4739,8 @@ int cmd_trace(int argc, const char **argv)
|
||||
"Show only syscall summary with statistics"),
|
||||
OPT_BOOLEAN('S', "with-summary", &trace.summary,
|
||||
"Show all syscalls and summary with statistics"),
|
||||
OPT_BOOLEAN(0, "errno-summary", &trace.errno_summary,
|
||||
"Show errno stats per syscall, use with -s or -S"),
|
||||
OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
|
||||
"Trace pagefaults", parse_pagefaults, "maj"),
|
||||
OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
|
||||
@ -4775,7 +5015,7 @@ int cmd_trace(int argc, const char **argv)
|
||||
init_augmented_syscall_tp:
|
||||
if (perf_evsel__init_augmented_syscall_tp(evsel, evsel))
|
||||
goto out;
|
||||
sc = evsel->priv;
|
||||
sc = __evsel__syscall_tp(evsel);
|
||||
/*
|
||||
* For now with BPF raw_augmented we hook into
|
||||
* raw_syscalls:sys_enter and there we get all
|
||||
@ -4806,6 +5046,10 @@ init_augmented_syscall_tp:
|
||||
if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
|
||||
return trace__record(&trace, argc-1, &argv[1]);
|
||||
|
||||
/* Using just --errno-summary will trigger --summary */
|
||||
if (trace.errno_summary && !trace.summary && !trace.summary_only)
|
||||
trace.summary_only = true;
|
||||
|
||||
/* summary_only implies summary option, but don't overwrite summary if set */
|
||||
if (trace.summary_only)
|
||||
trace.summary = trace.summary_only;
|
||||
|
@ -28,6 +28,7 @@ arch/x86/include/asm/disabled-features.h
|
||||
arch/x86/include/asm/required-features.h
|
||||
arch/x86/include/asm/cpufeatures.h
|
||||
arch/x86/include/asm/inat_types.h
|
||||
arch/x86/include/asm/irq_vectors.h
|
||||
arch/x86/include/asm/msr-index.h
|
||||
arch/x86/include/uapi/asm/prctl.h
|
||||
arch/x86/lib/x86-opcode-map.txt
|
||||
|
@ -107,6 +107,7 @@ else
|
||||
endif
|
||||
|
||||
LIBAPI = $(API_PATH)libapi.a
|
||||
export LIBAPI
|
||||
|
||||
$(LIBAPI): FORCE
|
||||
$(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a
|
||||
|
@ -338,15 +338,13 @@ static struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, boo
|
||||
int i;
|
||||
struct perf_mmap *map;
|
||||
|
||||
evlist->nr_mmaps = perf_cpu_map__nr(evlist->cpus);
|
||||
if (perf_cpu_map__empty(evlist->cpus))
|
||||
evlist->nr_mmaps = perf_thread_map__nr(evlist->threads);
|
||||
|
||||
map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
|
||||
if (!map)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < evlist->nr_mmaps; i++) {
|
||||
struct perf_mmap *prev = i ? &map[i - 1] : NULL;
|
||||
|
||||
/*
|
||||
* When the perf_mmap() call is made we grab one refcount, plus
|
||||
* one extra to let perf_mmap__consume() get the last
|
||||
@ -356,7 +354,7 @@ static struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, boo
|
||||
* Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
|
||||
* thus does perf_mmap__get() on it.
|
||||
*/
|
||||
perf_mmap__init(&map[i], overwrite, NULL);
|
||||
perf_mmap__init(&map[i], prev, overwrite, NULL);
|
||||
}
|
||||
|
||||
return map;
|
||||
@ -382,18 +380,22 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
|
||||
static struct perf_mmap*
|
||||
perf_evlist__mmap_cb_get(struct perf_evlist *evlist, bool overwrite, int idx)
|
||||
{
|
||||
struct perf_mmap *map = &evlist->mmap[idx];
|
||||
struct perf_mmap *maps;
|
||||
|
||||
if (overwrite) {
|
||||
if (!evlist->mmap_ovw) {
|
||||
evlist->mmap_ovw = perf_evlist__alloc_mmap(evlist, true);
|
||||
if (!evlist->mmap_ovw)
|
||||
return NULL;
|
||||
}
|
||||
map = &evlist->mmap_ovw[idx];
|
||||
maps = overwrite ? evlist->mmap_ovw : evlist->mmap;
|
||||
|
||||
if (!maps) {
|
||||
maps = perf_evlist__alloc_mmap(evlist, overwrite);
|
||||
if (!maps)
|
||||
return NULL;
|
||||
|
||||
if (overwrite)
|
||||
evlist->mmap_ovw = maps;
|
||||
else
|
||||
evlist->mmap = maps;
|
||||
}
|
||||
|
||||
return map;
|
||||
return &maps[idx];
|
||||
}
|
||||
|
||||
#define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y))
|
||||
@ -405,6 +407,15 @@ perf_evlist__mmap_cb_mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
|
||||
return perf_mmap__mmap(map, mp, output, cpu);
|
||||
}
|
||||
|
||||
static void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_mmap *map,
|
||||
bool overwrite)
|
||||
{
|
||||
if (overwrite)
|
||||
evlist->mmap_ovw_first = map;
|
||||
else
|
||||
evlist->mmap_first = map;
|
||||
}
|
||||
|
||||
static int
|
||||
mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
|
||||
int idx, struct perf_mmap_param *mp, int cpu_idx,
|
||||
@ -460,6 +471,9 @@ mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
|
||||
|
||||
if (ops->mmap(map, mp, *output, evlist_cpu) < 0)
|
||||
return -1;
|
||||
|
||||
if (!idx)
|
||||
perf_evlist__set_mmap_first(evlist, map, overwrite);
|
||||
} else {
|
||||
if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
|
||||
return -1;
|
||||
@ -542,6 +556,17 @@ out_unmap:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int perf_evlist__nr_mmaps(struct perf_evlist *evlist)
|
||||
{
|
||||
int nr_mmaps;
|
||||
|
||||
nr_mmaps = perf_cpu_map__nr(evlist->cpus);
|
||||
if (perf_cpu_map__empty(evlist->cpus))
|
||||
nr_mmaps = perf_thread_map__nr(evlist->threads);
|
||||
|
||||
return nr_mmaps;
|
||||
}
|
||||
|
||||
int perf_evlist__mmap_ops(struct perf_evlist *evlist,
|
||||
struct perf_evlist_mmap_ops *ops,
|
||||
struct perf_mmap_param *mp)
|
||||
@ -553,10 +578,9 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
|
||||
if (!ops || !ops->get || !ops->mmap)
|
||||
return -EINVAL;
|
||||
|
||||
if (!evlist->mmap)
|
||||
evlist->mmap = perf_evlist__alloc_mmap(evlist, false);
|
||||
if (!evlist->mmap)
|
||||
return -ENOMEM;
|
||||
mp->mask = evlist->mmap_len - page_size - 1;
|
||||
|
||||
evlist->nr_mmaps = perf_evlist__nr_mmaps(evlist);
|
||||
|
||||
perf_evlist__for_each_entry(evlist, evsel) {
|
||||
if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
|
||||
@ -583,7 +607,6 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages)
|
||||
};
|
||||
|
||||
evlist->mmap_len = (pages + 1) * page_size;
|
||||
mp.mask = evlist->mmap_len - page_size - 1;
|
||||
|
||||
return perf_evlist__mmap_ops(evlist, &ops, &mp);
|
||||
}
|
||||
@ -605,3 +628,13 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
|
||||
zfree(&evlist->mmap);
|
||||
zfree(&evlist->mmap_ovw);
|
||||
}
|
||||
|
||||
struct perf_mmap*
|
||||
perf_evlist__next_mmap(struct perf_evlist *evlist, struct perf_mmap *map,
|
||||
bool overwrite)
|
||||
{
|
||||
if (map)
|
||||
return map->next;
|
||||
|
||||
return overwrite ? evlist->mmap_ovw_first : evlist->mmap_first;
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ struct perf_evlist {
|
||||
struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
|
||||
struct perf_mmap *mmap;
|
||||
struct perf_mmap *mmap_ovw;
|
||||
struct perf_mmap *mmap_first;
|
||||
struct perf_mmap *mmap_ovw_first;
|
||||
};
|
||||
|
||||
typedef void
|
||||
@ -48,6 +50,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist,
|
||||
struct perf_evlist_mmap_ops *ops,
|
||||
struct perf_mmap_param *mp);
|
||||
|
||||
void perf_evlist__init(struct perf_evlist *evlist);
|
||||
void perf_evlist__exit(struct perf_evlist *evlist);
|
||||
|
||||
/**
|
||||
|
@ -50,6 +50,7 @@ struct perf_evsel {
|
||||
bool system_wide;
|
||||
};
|
||||
|
||||
void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr);
|
||||
int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
|
||||
void perf_evsel__close_fd(struct perf_evsel *evsel);
|
||||
void perf_evsel__free_fd(struct perf_evsel *evsel);
|
||||
|
@ -32,6 +32,7 @@ struct perf_mmap {
|
||||
u64 flush;
|
||||
libperf_unmap_cb_t unmap_cb;
|
||||
char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
|
||||
struct perf_mmap *next;
|
||||
};
|
||||
|
||||
struct perf_mmap_param {
|
||||
@ -41,8 +42,8 @@ struct perf_mmap_param {
|
||||
|
||||
size_t perf_mmap__mmap_len(struct perf_mmap *map);
|
||||
|
||||
void perf_mmap__init(struct perf_mmap *map, bool overwrite,
|
||||
libperf_unmap_cb_t unmap_cb);
|
||||
void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
|
||||
bool overwrite, libperf_unmap_cb_t unmap_cb);
|
||||
int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp,
|
||||
int fd, int cpu);
|
||||
void perf_mmap__munmap(struct perf_mmap *map);
|
||||
|
@ -4,14 +4,28 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define __T_START fprintf(stdout, "- running %s...", __FILE__)
|
||||
#define __T_OK fprintf(stdout, "OK\n")
|
||||
#define __T_FAIL fprintf(stdout, "FAIL\n")
|
||||
int tests_failed;
|
||||
|
||||
#define __T_START \
|
||||
do { \
|
||||
fprintf(stdout, "- running %s...", __FILE__); \
|
||||
fflush(NULL); \
|
||||
tests_failed = 0; \
|
||||
} while (0)
|
||||
|
||||
#define __T_END \
|
||||
do { \
|
||||
if (tests_failed) \
|
||||
fprintf(stdout, " FAILED (%d)\n", tests_failed); \
|
||||
else \
|
||||
fprintf(stdout, "OK\n"); \
|
||||
} while (0)
|
||||
|
||||
#define __T(text, cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
|
||||
tests_failed++; \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#endif
|
||||
|
||||
enum libperf_print_level {
|
||||
LIBPERF_ERR,
|
||||
LIBPERF_WARN,
|
||||
LIBPERF_INFO,
|
||||
LIBPERF_DEBUG,
|
||||
|
@ -3,13 +3,13 @@
|
||||
#define __LIBPERF_EVLIST_H
|
||||
|
||||
#include <perf/core.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct perf_evlist;
|
||||
struct perf_evsel;
|
||||
struct perf_cpu_map;
|
||||
struct perf_thread_map;
|
||||
|
||||
LIBPERF_API void perf_evlist__init(struct perf_evlist *evlist);
|
||||
LIBPERF_API void perf_evlist__add(struct perf_evlist *evlist,
|
||||
struct perf_evsel *evsel);
|
||||
LIBPERF_API void perf_evlist__remove(struct perf_evlist *evlist,
|
||||
@ -38,4 +38,12 @@ LIBPERF_API int perf_evlist__filter_pollfd(struct perf_evlist *evlist,
|
||||
LIBPERF_API int perf_evlist__mmap(struct perf_evlist *evlist, int pages);
|
||||
LIBPERF_API void perf_evlist__munmap(struct perf_evlist *evlist);
|
||||
|
||||
LIBPERF_API struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist,
|
||||
struct perf_mmap *map,
|
||||
bool overwrite);
|
||||
#define perf_evlist__for_each_mmap(evlist, pos, overwrite) \
|
||||
for ((pos) = perf_evlist__next_mmap((evlist), NULL, overwrite); \
|
||||
(pos) != NULL; \
|
||||
(pos) = perf_evlist__next_mmap((evlist), (pos), overwrite))
|
||||
|
||||
#endif /* __LIBPERF_EVLIST_H */
|
||||
|
@ -21,8 +21,6 @@ struct perf_counts_values {
|
||||
};
|
||||
};
|
||||
|
||||
LIBPERF_API void perf_evsel__init(struct perf_evsel *evsel,
|
||||
struct perf_event_attr *attr);
|
||||
LIBPERF_API struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr);
|
||||
LIBPERF_API void perf_evsel__delete(struct perf_evsel *evsel);
|
||||
LIBPERF_API int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus,
|
||||
|
@ -2,6 +2,8 @@
|
||||
#ifndef __LIBPERF_INTERNAL_H
|
||||
#define __LIBPERF_INTERNAL_H
|
||||
|
||||
#include <perf/core.h>
|
||||
|
||||
void libperf_print(enum libperf_print_level level,
|
||||
const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
@ -11,6 +13,7 @@ do { \
|
||||
libperf_print(level, "libperf: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define pr_err(fmt, ...) __pr(LIBPERF_ERR, fmt, ##__VA_ARGS__)
|
||||
#define pr_warning(fmt, ...) __pr(LIBPERF_WARN, fmt, ##__VA_ARGS__)
|
||||
#define pr_info(fmt, ...) __pr(LIBPERF_INFO, fmt, ##__VA_ARGS__)
|
||||
#define pr_debug(fmt, ...) __pr(LIBPERF_DEBUG, fmt, ##__VA_ARGS__)
|
||||
|
@ -21,7 +21,6 @@ LIBPERF_0.0.1 {
|
||||
perf_evsel__delete;
|
||||
perf_evsel__enable;
|
||||
perf_evsel__disable;
|
||||
perf_evsel__init;
|
||||
perf_evsel__open;
|
||||
perf_evsel__close;
|
||||
perf_evsel__read;
|
||||
@ -34,7 +33,6 @@ LIBPERF_0.0.1 {
|
||||
perf_evlist__close;
|
||||
perf_evlist__enable;
|
||||
perf_evlist__disable;
|
||||
perf_evlist__init;
|
||||
perf_evlist__add;
|
||||
perf_evlist__remove;
|
||||
perf_evlist__next;
|
||||
@ -43,6 +41,7 @@ LIBPERF_0.0.1 {
|
||||
perf_evlist__mmap;
|
||||
perf_evlist__munmap;
|
||||
perf_evlist__filter_pollfd;
|
||||
perf_evlist__next_mmap;
|
||||
perf_mmap__consume;
|
||||
perf_mmap__read_init;
|
||||
perf_mmap__read_done;
|
||||
|
@ -13,13 +13,15 @@
|
||||
#include <linux/kernel.h>
|
||||
#include "internal.h"
|
||||
|
||||
void perf_mmap__init(struct perf_mmap *map, bool overwrite,
|
||||
libperf_unmap_cb_t unmap_cb)
|
||||
void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
|
||||
bool overwrite, libperf_unmap_cb_t unmap_cb)
|
||||
{
|
||||
map->fd = -1;
|
||||
map->overwrite = overwrite;
|
||||
map->unmap_cb = unmap_cb;
|
||||
refcount_set(&map->refcnt, 0);
|
||||
if (prev)
|
||||
prev->next = map;
|
||||
}
|
||||
|
||||
size_t perf_mmap__mmap_len(struct perf_mmap *map)
|
||||
|
@ -16,13 +16,13 @@ all:
|
||||
|
||||
include $(srctree)/tools/scripts/Makefile.include
|
||||
|
||||
INCLUDE = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include
|
||||
INCLUDE = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include -I$(srctree)/tools/lib
|
||||
|
||||
$(TESTS_A): FORCE
|
||||
$(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a
|
||||
$(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a $(LIBAPI)
|
||||
|
||||
$(TESTS_SO): FORCE
|
||||
$(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -L.. -o $@ $(subst -so,.c,$@) -lperf
|
||||
$(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -L.. -o $@ $(subst -so,.c,$@) $(LIBAPI) -lperf
|
||||
|
||||
all: $(TESTS_A) $(TESTS_SO)
|
||||
|
||||
|
@ -26,6 +26,6 @@ int main(int argc, char **argv)
|
||||
perf_cpu_map__put(cpus);
|
||||
perf_cpu_map__put(cpus);
|
||||
|
||||
__T_OK;
|
||||
__T_END;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,12 +1,23 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <perf/cpumap.h>
|
||||
#include <perf/threadmap.h>
|
||||
#include <perf/evlist.h>
|
||||
#include <perf/evsel.h>
|
||||
#include <perf/mmap.h>
|
||||
#include <perf/event.h>
|
||||
#include <internal/tests.h>
|
||||
#include <api/fs/fs.h>
|
||||
|
||||
static int libperf_print(enum libperf_print_level level,
|
||||
const char *fmt, va_list ap)
|
||||
@ -181,6 +192,210 @@ static int test_stat_thread_enable(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_mmap_thread(void)
|
||||
{
|
||||
struct perf_evlist *evlist;
|
||||
struct perf_evsel *evsel;
|
||||
struct perf_mmap *map;
|
||||
struct perf_cpu_map *cpus;
|
||||
struct perf_thread_map *threads;
|
||||
struct perf_event_attr attr = {
|
||||
.type = PERF_TYPE_TRACEPOINT,
|
||||
.sample_period = 1,
|
||||
.wakeup_watermark = 1,
|
||||
.disabled = 1,
|
||||
};
|
||||
char path[PATH_MAX];
|
||||
int id, err, pid, go_pipe[2];
|
||||
union perf_event *event;
|
||||
char bf;
|
||||
int count = 0;
|
||||
|
||||
snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
|
||||
sysfs__mountpoint());
|
||||
|
||||
if (filename__read_int(path, &id)) {
|
||||
fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
attr.config = id;
|
||||
|
||||
err = pipe(go_pipe);
|
||||
__T("failed to create pipe", err == 0);
|
||||
|
||||
fflush(NULL);
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
int i;
|
||||
|
||||
read(go_pipe[0], &bf, 1);
|
||||
|
||||
/* Generate 100 prctl calls. */
|
||||
for (i = 0; i < 100; i++)
|
||||
prctl(0, 0, 0, 0, 0);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
threads = perf_thread_map__new_dummy();
|
||||
__T("failed to create threads", threads);
|
||||
|
||||
cpus = perf_cpu_map__dummy_new();
|
||||
__T("failed to create cpus", cpus);
|
||||
|
||||
perf_thread_map__set_pid(threads, 0, pid);
|
||||
|
||||
evlist = perf_evlist__new();
|
||||
__T("failed to create evlist", evlist);
|
||||
|
||||
evsel = perf_evsel__new(&attr);
|
||||
__T("failed to create evsel1", evsel);
|
||||
|
||||
perf_evlist__add(evlist, evsel);
|
||||
|
||||
perf_evlist__set_maps(evlist, cpus, threads);
|
||||
|
||||
err = perf_evlist__open(evlist);
|
||||
__T("failed to open evlist", err == 0);
|
||||
|
||||
err = perf_evlist__mmap(evlist, 4);
|
||||
__T("failed to mmap evlist", err == 0);
|
||||
|
||||
perf_evlist__enable(evlist);
|
||||
|
||||
/* kick the child and wait for it to finish */
|
||||
write(go_pipe[1], &bf, 1);
|
||||
waitpid(pid, NULL, 0);
|
||||
|
||||
/*
|
||||
* There's no need to call perf_evlist__disable,
|
||||
* monitored process is dead now.
|
||||
*/
|
||||
|
||||
perf_evlist__for_each_mmap(evlist, map, false) {
|
||||
if (perf_mmap__read_init(map) < 0)
|
||||
continue;
|
||||
|
||||
while ((event = perf_mmap__read_event(map)) != NULL) {
|
||||
count++;
|
||||
perf_mmap__consume(map);
|
||||
}
|
||||
|
||||
perf_mmap__read_done(map);
|
||||
}
|
||||
|
||||
/* calls perf_evlist__munmap/perf_evlist__close */
|
||||
perf_evlist__delete(evlist);
|
||||
|
||||
perf_thread_map__put(threads);
|
||||
perf_cpu_map__put(cpus);
|
||||
|
||||
/*
|
||||
* The generated prctl calls should match the
|
||||
* number of events in the buffer.
|
||||
*/
|
||||
__T("failed count", count == 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_mmap_cpus(void)
|
||||
{
|
||||
struct perf_evlist *evlist;
|
||||
struct perf_evsel *evsel;
|
||||
struct perf_mmap *map;
|
||||
struct perf_cpu_map *cpus;
|
||||
struct perf_event_attr attr = {
|
||||
.type = PERF_TYPE_TRACEPOINT,
|
||||
.sample_period = 1,
|
||||
.wakeup_watermark = 1,
|
||||
.disabled = 1,
|
||||
};
|
||||
cpu_set_t saved_mask;
|
||||
char path[PATH_MAX];
|
||||
int id, err, cpu, tmp;
|
||||
union perf_event *event;
|
||||
int count = 0;
|
||||
|
||||
snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
|
||||
sysfs__mountpoint());
|
||||
|
||||
if (filename__read_int(path, &id)) {
|
||||
fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
attr.config = id;
|
||||
|
||||
cpus = perf_cpu_map__new(NULL);
|
||||
__T("failed to create cpus", cpus);
|
||||
|
||||
evlist = perf_evlist__new();
|
||||
__T("failed to create evlist", evlist);
|
||||
|
||||
evsel = perf_evsel__new(&attr);
|
||||
__T("failed to create evsel1", evsel);
|
||||
|
||||
perf_evlist__add(evlist, evsel);
|
||||
|
||||
perf_evlist__set_maps(evlist, cpus, NULL);
|
||||
|
||||
err = perf_evlist__open(evlist);
|
||||
__T("failed to open evlist", err == 0);
|
||||
|
||||
err = perf_evlist__mmap(evlist, 4);
|
||||
__T("failed to mmap evlist", err == 0);
|
||||
|
||||
perf_evlist__enable(evlist);
|
||||
|
||||
err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask);
|
||||
__T("sched_getaffinity failed", err == 0);
|
||||
|
||||
perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
|
||||
cpu_set_t mask;
|
||||
|
||||
CPU_ZERO(&mask);
|
||||
CPU_SET(cpu, &mask);
|
||||
|
||||
err = sched_setaffinity(0, sizeof(mask), &mask);
|
||||
__T("sched_setaffinity failed", err == 0);
|
||||
|
||||
prctl(0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask);
|
||||
__T("sched_setaffinity failed", err == 0);
|
||||
|
||||
perf_evlist__disable(evlist);
|
||||
|
||||
perf_evlist__for_each_mmap(evlist, map, false) {
|
||||
if (perf_mmap__read_init(map) < 0)
|
||||
continue;
|
||||
|
||||
while ((event = perf_mmap__read_event(map)) != NULL) {
|
||||
count++;
|
||||
perf_mmap__consume(map);
|
||||
}
|
||||
|
||||
perf_mmap__read_done(map);
|
||||
}
|
||||
|
||||
/* calls perf_evlist__munmap/perf_evlist__close */
|
||||
perf_evlist__delete(evlist);
|
||||
|
||||
/*
|
||||
* The generated prctl events should match the
|
||||
* number of cpus or be bigger (we are system-wide).
|
||||
*/
|
||||
__T("failed count", count >= perf_cpu_map__nr(cpus));
|
||||
|
||||
perf_cpu_map__put(cpus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
__T_START;
|
||||
@ -190,7 +405,9 @@ int main(int argc, char **argv)
|
||||
test_stat_cpu();
|
||||
test_stat_thread();
|
||||
test_stat_thread_enable();
|
||||
test_mmap_thread();
|
||||
test_mmap_cpus();
|
||||
|
||||
__T_OK;
|
||||
__T_END;
|
||||
return 0;
|
||||
}
|
||||
|
@ -130,6 +130,6 @@ int main(int argc, char **argv)
|
||||
test_stat_thread();
|
||||
test_stat_thread_enable();
|
||||
|
||||
__T_OK;
|
||||
__T_END;
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,6 +26,6 @@ int main(int argc, char **argv)
|
||||
perf_thread_map__put(threads);
|
||||
perf_thread_map__put(threads);
|
||||
|
||||
__T_OK;
|
||||
__T_END;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,18 @@
|
||||
[
|
||||
{
|
||||
"EventCode": "0x00",
|
||||
"EventName": "uncore_hisi_ddrc.flux_wr",
|
||||
"BriefDescription": "DDRC total write operations",
|
||||
"PublicDescription": "DDRC total write operations",
|
||||
"Unit": "hisi_sccl,ddrc",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x01",
|
||||
"EventName": "uncore_hisi_ddrc.flux_rd",
|
||||
"BriefDescription": "DDRC total read operations",
|
||||
"PublicDescription": "DDRC total read operations",
|
||||
"Unit": "hisi_sccl,ddrc",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x02",
|
||||
"EventName": "uncore_hisi_ddrc.flux_wcmd",
|
||||
@ -15,7 +29,7 @@
|
||||
},
|
||||
{
|
||||
"EventCode": "0x04",
|
||||
"EventName": "uncore_hisi_ddrc.flux_wr",
|
||||
"EventName": "uncore_hisi_ddrc.pre_cmd",
|
||||
"BriefDescription": "DDRC precharge commands",
|
||||
"PublicDescription": "DDRC precharge commands",
|
||||
"Unit": "hisi_sccl,ddrc",
|
||||
|
@ -20,6 +20,13 @@
|
||||
"PublicDescription": "The number of all operations received by the HHA from another SCCL in this socket",
|
||||
"Unit": "hisi_sccl,hha",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x03",
|
||||
"EventName": "uncore_hisi_hha.rx_ccix",
|
||||
"BriefDescription": "Count of the number of operations that HHA has received from CCIX",
|
||||
"PublicDescription": "Count of the number of operations that HHA has received from CCIX",
|
||||
"Unit": "hisi_sccl,hha",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x1c",
|
||||
"EventName": "uncore_hisi_hha.rd_ddr_64b",
|
||||
@ -29,7 +36,7 @@
|
||||
},
|
||||
{
|
||||
"EventCode": "0x1d",
|
||||
"EventName": "uncore_hisi_hha.wr_dr_64b",
|
||||
"EventName": "uncore_hisi_hha.wr_ddr_64b",
|
||||
"BriefDescription": "The number of write operations sent by HHA to DDRC which size is 64 bytes",
|
||||
"PublicDescription": "The number of write operations sent by HHA to DDRC which size is 64 bytes",
|
||||
"Unit": "hisi_sccl,hha",
|
||||
@ -48,4 +55,18 @@
|
||||
"PublicDescription": "The number of write operations sent by HHA to DDRC which size is 128 bytes",
|
||||
"Unit": "hisi_sccl,hha",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x20",
|
||||
"EventName": "uncore_hisi_hha.spill_num",
|
||||
"BriefDescription": "Count of the number of spill operations that the HHA has sent",
|
||||
"PublicDescription": "Count of the number of spill operations that the HHA has sent",
|
||||
"Unit": "hisi_sccl,hha",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x21",
|
||||
"EventName": "uncore_hisi_hha.spill_success",
|
||||
"BriefDescription": "Count of the number of successful spill operations that the HHA has sent",
|
||||
"PublicDescription": "Count of the number of successful spill operations that the HHA has sent",
|
||||
"Unit": "hisi_sccl,hha",
|
||||
},
|
||||
]
|
||||
|
@ -34,4 +34,60 @@
|
||||
"PublicDescription": "l3c precharge commands",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x20",
|
||||
"EventName": "uncore_hisi_l3c.rd_spipe",
|
||||
"BriefDescription": "Count of the number of read lines that come from this cluster of CPU core in spipe",
|
||||
"PublicDescription": "Count of the number of read lines that come from this cluster of CPU core in spipe",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x21",
|
||||
"EventName": "uncore_hisi_l3c.wr_spipe",
|
||||
"BriefDescription": "Count of the number of write lines that come from this cluster of CPU core in spipe",
|
||||
"PublicDescription": "Count of the number of write lines that come from this cluster of CPU core in spipe",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x22",
|
||||
"EventName": "uncore_hisi_l3c.rd_hit_spipe",
|
||||
"BriefDescription": "Count of the number of read lines that hits in spipe of this L3C",
|
||||
"PublicDescription": "Count of the number of read lines that hits in spipe of this L3C",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x23",
|
||||
"EventName": "uncore_hisi_l3c.wr_hit_spipe",
|
||||
"BriefDescription": "Count of the number of write lines that hits in spipe of this L3C",
|
||||
"PublicDescription": "Count of the number of write lines that hits in spipe of this L3C",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x29",
|
||||
"EventName": "uncore_hisi_l3c.back_invalid",
|
||||
"BriefDescription": "Count of the number of L3C back invalid operations",
|
||||
"PublicDescription": "Count of the number of L3C back invalid operations",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x40",
|
||||
"EventName": "uncore_hisi_l3c.retry_cpu",
|
||||
"BriefDescription": "Count of the number of retry that L3C suppresses the CPU operations",
|
||||
"PublicDescription": "Count of the number of retry that L3C suppresses the CPU operations",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x41",
|
||||
"EventName": "uncore_hisi_l3c.retry_ring",
|
||||
"BriefDescription": "Count of the number of retry that L3C suppresses the ring operations",
|
||||
"PublicDescription": "Count of the number of retry that L3C suppresses the ring operations",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
{
|
||||
"EventCode": "0x42",
|
||||
"EventName": "uncore_hisi_l3c.prefetch_drop",
|
||||
"BriefDescription": "Count of the number of prefetch drops from this L3C",
|
||||
"PublicDescription": "Count of the number of prefetch drops from this L3C",
|
||||
"Unit": "hisi_sccl,l3c",
|
||||
},
|
||||
]
|
||||
|
@ -322,7 +322,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
|
||||
char *desc, char *long_desc,
|
||||
char *pmu, char *unit, char *perpkg,
|
||||
char *metric_expr,
|
||||
char *metric_name, char *metric_group)
|
||||
char *metric_name, char *metric_group,
|
||||
char *deprecated)
|
||||
{
|
||||
struct perf_entry_data *pd = data;
|
||||
FILE *outfp = pd->outfp;
|
||||
@ -354,6 +355,8 @@ static int print_events_table_entry(void *data, char *name, char *event,
|
||||
fprintf(outfp, "\t.metric_name = \"%s\",\n", metric_name);
|
||||
if (metric_group)
|
||||
fprintf(outfp, "\t.metric_group = \"%s\",\n", metric_group);
|
||||
if (deprecated)
|
||||
fprintf(outfp, "\t.deprecated = \"%s\",\n", deprecated);
|
||||
fprintf(outfp, "},\n");
|
||||
|
||||
return 0;
|
||||
@ -371,6 +374,7 @@ struct event_struct {
|
||||
char *metric_expr;
|
||||
char *metric_name;
|
||||
char *metric_group;
|
||||
char *deprecated;
|
||||
};
|
||||
|
||||
#define ADD_EVENT_FIELD(field) do { if (field) { \
|
||||
@ -398,6 +402,7 @@ struct event_struct {
|
||||
op(metric_expr); \
|
||||
op(metric_name); \
|
||||
op(metric_group); \
|
||||
op(deprecated); \
|
||||
} while (0)
|
||||
|
||||
static LIST_HEAD(arch_std_events);
|
||||
@ -416,7 +421,8 @@ static void free_arch_std_events(void)
|
||||
static int save_arch_std_events(void *data, char *name, char *event,
|
||||
char *desc, char *long_desc, char *pmu,
|
||||
char *unit, char *perpkg, char *metric_expr,
|
||||
char *metric_name, char *metric_group)
|
||||
char *metric_name, char *metric_group,
|
||||
char *deprecated)
|
||||
{
|
||||
struct event_struct *es;
|
||||
|
||||
@ -479,7 +485,8 @@ static int
|
||||
try_fixup(const char *fn, char *arch_std, char **event, char **desc,
|
||||
char **name, char **long_desc, char **pmu, char **filter,
|
||||
char **perpkg, char **unit, char **metric_expr, char **metric_name,
|
||||
char **metric_group, unsigned long long eventcode)
|
||||
char **metric_group, unsigned long long eventcode,
|
||||
char **deprecated)
|
||||
{
|
||||
/* try to find matching event from arch standard values */
|
||||
struct event_struct *es;
|
||||
@ -507,7 +514,8 @@ int json_events(const char *fn,
|
||||
char *long_desc,
|
||||
char *pmu, char *unit, char *perpkg,
|
||||
char *metric_expr,
|
||||
char *metric_name, char *metric_group),
|
||||
char *metric_name, char *metric_group,
|
||||
char *deprecated),
|
||||
void *data)
|
||||
{
|
||||
int err;
|
||||
@ -536,6 +544,7 @@ int json_events(const char *fn,
|
||||
char *metric_expr = NULL;
|
||||
char *metric_name = NULL;
|
||||
char *metric_group = NULL;
|
||||
char *deprecated = NULL;
|
||||
char *arch_std = NULL;
|
||||
unsigned long long eventcode = 0;
|
||||
struct msrmap *msr = NULL;
|
||||
@ -614,6 +623,8 @@ int json_events(const char *fn,
|
||||
addfield(map, &unit, "", "", val);
|
||||
} else if (json_streq(map, field, "PerPkg")) {
|
||||
addfield(map, &perpkg, "", "", val);
|
||||
} else if (json_streq(map, field, "Deprecated")) {
|
||||
addfield(map, &deprecated, "", "", val);
|
||||
} else if (json_streq(map, field, "MetricName")) {
|
||||
addfield(map, &metric_name, "", "", val);
|
||||
} else if (json_streq(map, field, "MetricGroup")) {
|
||||
@ -658,12 +669,14 @@ int json_events(const char *fn,
|
||||
err = try_fixup(fn, arch_std, &event, &desc, &name,
|
||||
&long_desc, &pmu, &filter, &perpkg,
|
||||
&unit, &metric_expr, &metric_name,
|
||||
&metric_group, eventcode);
|
||||
&metric_group, eventcode,
|
||||
&deprecated);
|
||||
if (err)
|
||||
goto free_strings;
|
||||
}
|
||||
err = func(data, name, real_event(name, event), desc, long_desc,
|
||||
pmu, unit, perpkg, metric_expr, metric_name, metric_group);
|
||||
pmu, unit, perpkg, metric_expr, metric_name,
|
||||
metric_group, deprecated);
|
||||
free_strings:
|
||||
free(event);
|
||||
free(desc);
|
||||
@ -673,6 +686,7 @@ free_strings:
|
||||
free(pmu);
|
||||
free(filter);
|
||||
free(perpkg);
|
||||
free(deprecated);
|
||||
free(unit);
|
||||
free(metric_expr);
|
||||
free(metric_name);
|
||||
|
@ -7,7 +7,8 @@ int json_events(const char *fn,
|
||||
char *long_desc,
|
||||
char *pmu,
|
||||
char *unit, char *perpkg, char *metric_expr,
|
||||
char *metric_name, char *metric_group),
|
||||
char *metric_name, char *metric_group,
|
||||
char *deprecated),
|
||||
void *data);
|
||||
char *get_cpu_str(void);
|
||||
|
||||
|
@ -17,6 +17,7 @@ struct pmu_event {
|
||||
const char *metric_expr;
|
||||
const char *metric_name;
|
||||
const char *metric_group;
|
||||
const char *deprecated;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -10,11 +10,7 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/hw_breakpoint.h>
|
||||
|
||||
#include "tests.h"
|
||||
@ -192,3 +188,19 @@ int test__bp_accounting(struct test *test __maybe_unused, int subtest __maybe_un
|
||||
|
||||
return bp_accounting(wp_cnt, share);
|
||||
}
|
||||
|
||||
bool test__bp_account_is_supported(void)
|
||||
{
|
||||
/*
|
||||
* PowerPC and S390 do not support creation of instruction
|
||||
* breakpoints using the perf_event interface.
|
||||
*
|
||||
* Just disable the test for these architectures until these
|
||||
* issues are resolved.
|
||||
*/
|
||||
#if defined(__powerpc__) || defined(__s390x__)
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
@ -49,14 +49,6 @@ asm (
|
||||
"__test_function:\n"
|
||||
"incq (%rdi)\n"
|
||||
"ret\n");
|
||||
#elif defined (__aarch64__)
|
||||
extern void __test_function(volatile long *ptr);
|
||||
asm (
|
||||
".globl __test_function\n"
|
||||
"__test_function:\n"
|
||||
"str x30, [x0]\n"
|
||||
"ret\n");
|
||||
|
||||
#else
|
||||
static void __test_function(volatile long *ptr)
|
||||
{
|
||||
@ -302,10 +294,15 @@ bool test__bp_signal_is_supported(void)
|
||||
* stepping into the SIGIO handler and getting stuck on the
|
||||
* breakpointed instruction.
|
||||
*
|
||||
* Since arm64 has the same issue with arm for the single-step
|
||||
* handling, this case also gets suck on the breakpointed
|
||||
* instruction.
|
||||
*
|
||||
* Just disable the test for these architectures until these
|
||||
* issues are resolved.
|
||||
*/
|
||||
#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__)
|
||||
#if defined(__powerpc__) || defined(__s390x__) || defined(__arm__) || \
|
||||
defined(__aarch64__)
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
|
@ -121,7 +121,7 @@ static struct test generic_tests[] = {
|
||||
{
|
||||
.desc = "Breakpoint accounting",
|
||||
.func = test__bp_accounting,
|
||||
.is_supported = test__bp_signal_is_supported,
|
||||
.is_supported = test__bp_account_is_supported,
|
||||
},
|
||||
{
|
||||
.desc = "Watchpoint",
|
||||
|
@ -54,6 +54,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused
|
||||
struct perf_cpu_map *cpus;
|
||||
struct perf_thread_map *threads;
|
||||
struct mmap *md;
|
||||
int retry_count = 0;
|
||||
|
||||
signal(SIGCHLD, sig_handler);
|
||||
|
||||
@ -111,6 +112,7 @@ int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused
|
||||
if (evlist__mmap(evlist, 128) < 0) {
|
||||
pr_debug("failed to mmap events: %d (%s)\n", errno,
|
||||
str_error_r(errno, sbuf, sizeof(sbuf)));
|
||||
err = -1;
|
||||
goto out_delete_evlist;
|
||||
}
|
||||
|
||||
@ -132,6 +134,13 @@ retry:
|
||||
out_init:
|
||||
if (!exited || !nr_exit) {
|
||||
evlist__poll(evlist, -1);
|
||||
|
||||
if (retry_count++ > 1000) {
|
||||
pr_debug("Failed after retrying 1000 times\n");
|
||||
err = -1;
|
||||
goto out_free_maps;
|
||||
}
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
@ -111,6 +111,7 @@ int test__map_groups__merge_in(struct test *t, int subtest);
|
||||
int test__time_utils(struct test *t, int subtest);
|
||||
|
||||
bool test__bp_signal_is_supported(void);
|
||||
bool test__bp_account_is_supported(void);
|
||||
bool test__wp_is_supported(void);
|
||||
|
||||
#if defined(__arm__) || defined(__aarch64__)
|
||||
|
@ -28,9 +28,11 @@ struct strarray {
|
||||
}
|
||||
|
||||
size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_prefix, int val);
|
||||
size_t strarray__scnprintf_suffix(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_suffix, int val);
|
||||
size_t strarray__scnprintf_flags(struct strarray *sa, char *bf, size_t size, bool show_prefix, unsigned long flags);
|
||||
|
||||
bool strarray__strtoul(struct strarray *sa, char *bf, size_t size, u64 *ret);
|
||||
bool strarray__strtoul_flags(struct strarray *sa, char *bf, size_t size, u64 *ret);
|
||||
|
||||
struct trace;
|
||||
struct thread;
|
||||
@ -87,6 +89,7 @@ struct syscall_arg_fmt;
|
||||
|
||||
/**
|
||||
* @val: value of syscall argument being formatted
|
||||
* @len: for tracepoint dynamic arrays, if fmt->nr_entries == 0, then its not a fixed array, look at arg->len
|
||||
* @args: All the args, use syscall_args__val(arg, nth) to access one
|
||||
* @augmented_args: Extra data that can be collected, for instance, with eBPF for expanding the pathname for open, etc
|
||||
* @augmented_args_size: augmented_args total payload size
|
||||
@ -109,6 +112,7 @@ struct syscall_arg {
|
||||
struct thread *thread;
|
||||
struct trace *trace;
|
||||
void *parm;
|
||||
u16 len;
|
||||
u8 idx;
|
||||
u8 mask;
|
||||
bool show_string_prefix;
|
||||
@ -119,6 +123,21 @@ unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx);
|
||||
size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_STRARRAY_FLAGS syscall_arg__scnprintf_strarray_flags
|
||||
|
||||
bool syscall_arg__strtoul_strarray(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
|
||||
#define STUL_STRARRAY syscall_arg__strtoul_strarray
|
||||
|
||||
bool syscall_arg__strtoul_strarray_flags(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
|
||||
#define STUL_STRARRAY_FLAGS syscall_arg__strtoul_strarray_flags
|
||||
|
||||
bool syscall_arg__strtoul_strarrays(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
|
||||
#define STUL_STRARRAYS syscall_arg__strtoul_strarrays
|
||||
|
||||
size_t syscall_arg__scnprintf_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_X86_IRQ_VECTORS syscall_arg__scnprintf_x86_irq_vectors
|
||||
|
||||
bool syscall_arg__strtoul_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg, u64 *ret);
|
||||
#define STUL_X86_IRQ_VECTORS syscall_arg__strtoul_x86_irq_vectors
|
||||
|
||||
size_t syscall_arg__scnprintf_x86_MSR(char *bf, size_t size, struct syscall_arg *arg);
|
||||
#define SCA_X86_MSR syscall_arg__scnprintf_x86_MSR
|
||||
|
||||
|
@ -33,11 +33,11 @@ static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
|
||||
|
||||
#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
|
||||
|
||||
static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
|
||||
{
|
||||
#include "trace/beauty/generated/mmap_flags_array.c"
|
||||
static DEFINE_STRARRAY(mmap_flags, "MAP_");
|
||||
|
||||
static size_t mmap__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool show_prefix)
|
||||
{
|
||||
return strarray__scnprintf_flags(&strarray__mmap_flags, bf, size, show_prefix, flags);
|
||||
}
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
perf-y += x86_irq_vectors.o
|
||||
perf-y += x86_msr.o
|
||||
|
29
tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c
Normal file
29
tools/perf/trace/beauty/tracepoints/x86_irq_vectors.c
Normal file
@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1
|
||||
/*
|
||||
* trace/beauty/x86_irq_vectors.c
|
||||
*
|
||||
* Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
|
||||
#include "trace/beauty/beauty.h"
|
||||
|
||||
#include "trace/beauty/generated/x86_arch_irq_vectors_array.c"
|
||||
|
||||
static DEFINE_STRARRAY(x86_irq_vectors, "_VECTOR");
|
||||
|
||||
static size_t x86_irq_vectors__scnprintf(unsigned long vector, char *bf, size_t size, bool show_prefix)
|
||||
{
|
||||
return strarray__scnprintf_suffix(&strarray__x86_irq_vectors, bf, size, "%#x", show_prefix, vector);
|
||||
}
|
||||
|
||||
size_t syscall_arg__scnprintf_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg)
|
||||
{
|
||||
unsigned long vector = arg->val;
|
||||
|
||||
return x86_irq_vectors__scnprintf(vector, bf, size, arg->show_string_prefix);
|
||||
}
|
||||
|
||||
bool syscall_arg__strtoul_x86_irq_vectors(char *bf, size_t size, struct syscall_arg *arg __maybe_unused, u64 *ret)
|
||||
{
|
||||
return strarray__strtoul(&strarray__x86_irq_vectors, bf, size, ret);
|
||||
}
|
27
tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh
Executable file
27
tools/perf/trace/beauty/tracepoints/x86_irq_vectors.sh
Executable file
@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: LGPL-2.1
|
||||
# (C) 2019, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
|
||||
if [ $# -ne 1 ] ; then
|
||||
arch_x86_header_dir=tools/arch/x86/include/asm/
|
||||
else
|
||||
arch_x86_header_dir=$1
|
||||
fi
|
||||
|
||||
x86_irq_vectors=${arch_x86_header_dir}/irq_vectors.h
|
||||
|
||||
# FIRST_EXTERNAL_VECTOR is not that useful, find what is its number
|
||||
# and then replace whatever is using it and that is useful, which at
|
||||
# the time of writing of this script was: IRQ_MOVE_CLEANUP_VECTOR.
|
||||
|
||||
first_external_regex='^#define[[:space:]]+FIRST_EXTERNAL_VECTOR[[:space:]]+(0x[[:xdigit:]]+)$'
|
||||
first_external_vector=$(egrep ${first_external_regex} ${x86_irq_vectors} | sed -r "s/${first_external_regex}/\1/g")
|
||||
|
||||
printf "static const char *x86_irq_vectors[] = {\n"
|
||||
regex='^#define[[:space:]]+([[:alnum:]_]+)_VECTOR[[:space:]]+(0x[[:xdigit:]]+)$'
|
||||
sed -r "s/FIRST_EXTERNAL_VECTOR/${first_external_vector}/g" ${x86_irq_vectors} | \
|
||||
egrep ${regex} | \
|
||||
sed -r "s/${regex}/\2 \1/g" | sort -n | \
|
||||
xargs printf "\t[%s] = \"%s\",\n"
|
||||
printf "};\n\n"
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include <subcmd/parse-options.h>
|
||||
#include <subcmd/run-command.h>
|
||||
|
||||
/* FIXME: For the HE_COLORSET */
|
||||
#include "ui/browser.h"
|
||||
@ -1489,44 +1490,26 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
|
||||
* means that it's not a disassembly line so should be treated differently.
|
||||
* The ops.raw part will be parsed further according to type of the instruction.
|
||||
*/
|
||||
static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
|
||||
static int symbol__parse_objdump_line(struct symbol *sym,
|
||||
struct annotate_args *args,
|
||||
int *line_nr)
|
||||
char *parsed_line, int *line_nr)
|
||||
{
|
||||
struct map *map = args->ms.map;
|
||||
struct annotation *notes = symbol__annotation(sym);
|
||||
struct disasm_line *dl;
|
||||
char *line = NULL, *parsed_line, *tmp, *tmp2;
|
||||
size_t line_len;
|
||||
char *tmp;
|
||||
s64 line_ip, offset = -1;
|
||||
regmatch_t match[2];
|
||||
|
||||
if (getline(&line, &line_len, file) < 0)
|
||||
return -1;
|
||||
|
||||
if (!line)
|
||||
return -1;
|
||||
|
||||
line_ip = -1;
|
||||
parsed_line = strim(line);
|
||||
|
||||
/* /filename:linenr ? Save line number and ignore. */
|
||||
if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
|
||||
*line_nr = atoi(parsed_line + match[1].rm_so);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = skip_spaces(parsed_line);
|
||||
if (*tmp) {
|
||||
/*
|
||||
* Parse hexa addresses followed by ':'
|
||||
*/
|
||||
line_ip = strtoull(tmp, &tmp2, 16);
|
||||
if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
|
||||
line_ip = -1;
|
||||
}
|
||||
|
||||
if (line_ip != -1) {
|
||||
/* Process hex address followed by ':'. */
|
||||
line_ip = strtoull(parsed_line, &tmp, 16);
|
||||
if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') {
|
||||
u64 start = map__rip_2objdump(map, sym->start),
|
||||
end = map__rip_2objdump(map, sym->end);
|
||||
|
||||
@ -1534,7 +1517,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
|
||||
if ((u64)line_ip < start || (u64)line_ip >= end)
|
||||
offset = -1;
|
||||
else
|
||||
parsed_line = tmp2 + 1;
|
||||
parsed_line = tmp + 1;
|
||||
}
|
||||
|
||||
args->offset = offset;
|
||||
@ -1543,7 +1526,6 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
|
||||
args->ms.sym = sym;
|
||||
|
||||
dl = disasm_line__new(args);
|
||||
free(line);
|
||||
(*line_nr)++;
|
||||
|
||||
if (dl == NULL)
|
||||
@ -1861,6 +1843,67 @@ static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
|
||||
}
|
||||
#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
|
||||
|
||||
/*
|
||||
* Possibly create a new version of line with tabs expanded. Returns the
|
||||
* existing or new line, storage is updated if a new line is allocated. If
|
||||
* allocation fails then NULL is returned.
|
||||
*/
|
||||
static char *expand_tabs(char *line, char **storage, size_t *storage_len)
|
||||
{
|
||||
size_t i, src, dst, len, new_storage_len, num_tabs;
|
||||
char *new_line;
|
||||
size_t line_len = strlen(line);
|
||||
|
||||
for (num_tabs = 0, i = 0; i < line_len; i++)
|
||||
if (line[i] == '\t')
|
||||
num_tabs++;
|
||||
|
||||
if (num_tabs == 0)
|
||||
return line;
|
||||
|
||||
/*
|
||||
* Space for the line and '\0', less the leading and trailing
|
||||
* spaces. Each tab may introduce 7 additional spaces.
|
||||
*/
|
||||
new_storage_len = line_len + 1 + (num_tabs * 7);
|
||||
|
||||
new_line = malloc(new_storage_len);
|
||||
if (new_line == NULL) {
|
||||
pr_err("Failure allocating memory for tab expansion\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy regions starting at src and expand tabs. If there are two
|
||||
* adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces
|
||||
* are inserted.
|
||||
*/
|
||||
for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) {
|
||||
if (line[i] == '\t') {
|
||||
len = i - src;
|
||||
memcpy(&new_line[dst], &line[src], len);
|
||||
dst += len;
|
||||
new_line[dst++] = ' ';
|
||||
while (dst % 8 != 0)
|
||||
new_line[dst++] = ' ';
|
||||
src = i + 1;
|
||||
num_tabs--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Expand the last region. */
|
||||
len = line_len + 1 - src;
|
||||
memcpy(&new_line[dst], &line[src], len);
|
||||
dst += len;
|
||||
new_line[dst] = '\0';
|
||||
|
||||
free(*storage);
|
||||
*storage = new_line;
|
||||
*storage_len = new_storage_len;
|
||||
return new_line;
|
||||
|
||||
}
|
||||
|
||||
static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
{
|
||||
struct annotation_options *opts = args->options;
|
||||
@ -1872,10 +1915,19 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
struct kcore_extract kce;
|
||||
bool delete_extract = false;
|
||||
bool decomp = false;
|
||||
int stdout_fd[2];
|
||||
int lineno = 0;
|
||||
int nline;
|
||||
pid_t pid;
|
||||
char *line;
|
||||
size_t line_len;
|
||||
const char *objdump_argv[] = {
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
NULL, /* Will be the objdump command to run. */
|
||||
"--",
|
||||
NULL, /* Will be the symfs path. */
|
||||
NULL,
|
||||
};
|
||||
struct child_process objdump_process;
|
||||
int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
|
||||
|
||||
if (err)
|
||||
@ -1905,7 +1957,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
|
||||
if (dso__decompress_kmodule_path(dso, symfs_filename,
|
||||
tmp, sizeof(tmp)) < 0)
|
||||
goto out;
|
||||
return -1;
|
||||
|
||||
decomp = true;
|
||||
strcpy(symfs_filename, tmp);
|
||||
@ -1914,13 +1966,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
err = asprintf(&command,
|
||||
"%s %s%s --start-address=0x%016" PRIx64
|
||||
" --stop-address=0x%016" PRIx64
|
||||
" -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand",
|
||||
" -l -d %s %s -C \"$1\"",
|
||||
opts->objdump_path ?: "objdump",
|
||||
opts->disassembler_style ? "-M " : "",
|
||||
opts->disassembler_style ?: "",
|
||||
map__rip_2objdump(map, sym->start),
|
||||
map__rip_2objdump(map, sym->end),
|
||||
opts->show_asm_raw ? "" : "--no-show-raw",
|
||||
opts->show_asm_raw ? "" : "--no-show-raw-insn",
|
||||
opts->annotate_src ? "-S" : "");
|
||||
|
||||
if (err < 0) {
|
||||
@ -1930,55 +1982,73 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
|
||||
pr_debug("Executing: %s\n", command);
|
||||
|
||||
err = -1;
|
||||
if (pipe(stdout_fd) < 0) {
|
||||
pr_err("Failure creating the pipe to run %s\n", command);
|
||||
objdump_argv[2] = command;
|
||||
objdump_argv[4] = symfs_filename;
|
||||
|
||||
/* Create a pipe to read from for stdout */
|
||||
memset(&objdump_process, 0, sizeof(objdump_process));
|
||||
objdump_process.argv = objdump_argv;
|
||||
objdump_process.out = -1;
|
||||
if (start_command(&objdump_process)) {
|
||||
pr_err("Failure starting to run %s\n", command);
|
||||
err = -1;
|
||||
goto out_free_command;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
pr_err("Failure forking to run %s\n", command);
|
||||
goto out_close_stdout;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
close(stdout_fd[0]);
|
||||
dup2(stdout_fd[1], 1);
|
||||
close(stdout_fd[1]);
|
||||
execl("/bin/sh", "sh", "-c", command, "--", symfs_filename,
|
||||
NULL);
|
||||
perror(command);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
close(stdout_fd[1]);
|
||||
|
||||
file = fdopen(stdout_fd[0], "r");
|
||||
file = fdopen(objdump_process.out, "r");
|
||||
if (!file) {
|
||||
pr_err("Failure creating FILE stream for %s\n", command);
|
||||
/*
|
||||
* If we were using debug info should retry with
|
||||
* original binary.
|
||||
*/
|
||||
goto out_free_command;
|
||||
err = -1;
|
||||
goto out_close_stdout;
|
||||
}
|
||||
|
||||
/* Storage for getline. */
|
||||
line = NULL;
|
||||
line_len = 0;
|
||||
|
||||
nline = 0;
|
||||
while (!feof(file)) {
|
||||
const char *match;
|
||||
char *expanded_line;
|
||||
|
||||
if (getline(&line, &line_len, file) < 0 || !line)
|
||||
break;
|
||||
|
||||
/* Skip lines containing "filename:" */
|
||||
match = strstr(line, symfs_filename);
|
||||
if (match && match[strlen(symfs_filename)] == ':')
|
||||
continue;
|
||||
|
||||
expanded_line = strim(line);
|
||||
expanded_line = expand_tabs(expanded_line, &line, &line_len);
|
||||
if (!expanded_line)
|
||||
break;
|
||||
|
||||
/*
|
||||
* The source code line number (lineno) needs to be kept in
|
||||
* across calls to symbol__parse_objdump_line(), so that it
|
||||
* can associate it with the instructions till the next one.
|
||||
* See disasm_line__new() and struct disasm_line::line_nr.
|
||||
*/
|
||||
if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0)
|
||||
if (symbol__parse_objdump_line(sym, args, expanded_line,
|
||||
&lineno) < 0)
|
||||
break;
|
||||
nline++;
|
||||
}
|
||||
free(line);
|
||||
|
||||
if (nline == 0)
|
||||
err = finish_command(&objdump_process);
|
||||
if (err)
|
||||
pr_err("Error running %s\n", command);
|
||||
|
||||
if (nline == 0) {
|
||||
err = -1;
|
||||
pr_err("No output from %s\n", command);
|
||||
}
|
||||
|
||||
/*
|
||||
* kallsyms does not have symbol sizes so there may a nop at the end.
|
||||
@ -1988,23 +2058,21 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
|
||||
delete_last_nop(sym);
|
||||
|
||||
fclose(file);
|
||||
err = 0;
|
||||
|
||||
out_close_stdout:
|
||||
close(objdump_process.out);
|
||||
|
||||
out_free_command:
|
||||
free(command);
|
||||
out_remove_tmp:
|
||||
close(stdout_fd[0]);
|
||||
|
||||
out_remove_tmp:
|
||||
if (decomp)
|
||||
unlink(symfs_filename);
|
||||
|
||||
if (delete_extract)
|
||||
kcore_extract__delete(&kce);
|
||||
out:
|
||||
return err;
|
||||
|
||||
out_close_stdout:
|
||||
close(stdout_fd[1]);
|
||||
goto out_free_command;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void calc_percent(struct sym_hist *sym_hist,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "../perf.h"
|
||||
#include "asm/bug.h"
|
||||
#include "bpf-event.h"
|
||||
#include "util/string2.h"
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sched.h>
|
||||
@ -598,14 +599,13 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
|
||||
int i;
|
||||
struct mmap *map;
|
||||
|
||||
evlist->core.nr_mmaps = perf_cpu_map__nr(evlist->core.cpus);
|
||||
if (perf_cpu_map__empty(evlist->core.cpus))
|
||||
evlist->core.nr_mmaps = perf_thread_map__nr(evlist->core.threads);
|
||||
map = zalloc(evlist->core.nr_mmaps * sizeof(struct mmap));
|
||||
if (!map)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < evlist->core.nr_mmaps; i++) {
|
||||
struct perf_mmap *prev = i ? &map[i - 1].core : NULL;
|
||||
|
||||
/*
|
||||
* When the perf_mmap() call is made we grab one refcount, plus
|
||||
* one extra to let perf_mmap__consume() get the last
|
||||
@ -615,7 +615,7 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
|
||||
* Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
|
||||
* thus does perf_mmap__get() on it.
|
||||
*/
|
||||
perf_mmap__init(&map[i].core, overwrite, perf_mmap__unmap_cb);
|
||||
perf_mmap__init(&map[i].core, prev, overwrite, perf_mmap__unmap_cb);
|
||||
}
|
||||
|
||||
return map;
|
||||
@ -636,19 +636,21 @@ static struct perf_mmap*
|
||||
perf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx)
|
||||
{
|
||||
struct evlist *evlist = container_of(_evlist, struct evlist, core);
|
||||
struct mmap *maps = evlist->mmap;
|
||||
struct mmap *maps;
|
||||
|
||||
if (overwrite) {
|
||||
maps = evlist->overwrite_mmap;
|
||||
maps = overwrite ? evlist->overwrite_mmap : evlist->mmap;
|
||||
|
||||
if (!maps) {
|
||||
maps = evlist__alloc_mmap(evlist, true);
|
||||
if (!maps)
|
||||
return NULL;
|
||||
if (!maps) {
|
||||
maps = evlist__alloc_mmap(evlist, overwrite);
|
||||
if (!maps)
|
||||
return NULL;
|
||||
|
||||
if (overwrite) {
|
||||
evlist->overwrite_mmap = maps;
|
||||
if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY)
|
||||
perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING);
|
||||
} else {
|
||||
evlist->mmap = maps;
|
||||
}
|
||||
}
|
||||
|
||||
@ -809,14 +811,8 @@ int evlist__mmap_ex(struct evlist *evlist, unsigned int pages,
|
||||
.mmap = perf_evlist__mmap_cb_mmap,
|
||||
};
|
||||
|
||||
if (!evlist->mmap)
|
||||
evlist->mmap = evlist__alloc_mmap(evlist, false);
|
||||
if (!evlist->mmap)
|
||||
return -ENOMEM;
|
||||
|
||||
evlist->core.mmap_len = evlist__mmap_size(pages);
|
||||
pr_debug("mmap size %zuB\n", evlist->core.mmap_len);
|
||||
mp.core.mask = evlist->core.mmap_len - page_size - 1;
|
||||
|
||||
auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->core.mmap_len,
|
||||
auxtrace_pages, auxtrace_overwrite);
|
||||
@ -959,7 +955,7 @@ int perf_evlist__append_tp_filter(struct evlist *evlist, const char *filter)
|
||||
return err;
|
||||
}
|
||||
|
||||
static char *asprintf__tp_filter_pids(size_t npids, pid_t *pids)
|
||||
char *asprintf__tp_filter_pids(size_t npids, pid_t *pids)
|
||||
{
|
||||
char *filter;
|
||||
size_t i;
|
||||
|
@ -2600,7 +2600,7 @@ out_enomem:
|
||||
* Print the help text for the event symbols:
|
||||
*/
|
||||
void print_events(const char *event_glob, bool name_only, bool quiet_flag,
|
||||
bool long_desc, bool details_flag)
|
||||
bool long_desc, bool details_flag, bool deprecated)
|
||||
{
|
||||
print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
|
||||
event_symbols_hw, PERF_COUNT_HW_MAX, name_only);
|
||||
@ -2612,7 +2612,7 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag,
|
||||
print_hwcache_events(event_glob, name_only);
|
||||
|
||||
print_pmu_events(event_glob, name_only, quiet_flag, long_desc,
|
||||
details_flag);
|
||||
details_flag, deprecated);
|
||||
|
||||
if (event_glob != NULL)
|
||||
return;
|
||||
|
@ -195,7 +195,7 @@ void parse_events_evlist_error(struct parse_events_state *parse_state,
|
||||
int idx, const char *str);
|
||||
|
||||
void print_events(const char *event_glob, bool name_only, bool quiet,
|
||||
bool long_desc, bool details_flag);
|
||||
bool long_desc, bool details_flag, bool deprecated);
|
||||
|
||||
struct event_symbol {
|
||||
const char *symbol;
|
||||
|
@ -308,7 +308,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
||||
char *long_desc, char *topic,
|
||||
char *unit, char *perpkg,
|
||||
char *metric_expr,
|
||||
char *metric_name)
|
||||
char *metric_name,
|
||||
char *deprecated)
|
||||
{
|
||||
struct parse_events_term *term;
|
||||
struct perf_pmu_alias *alias;
|
||||
@ -325,6 +326,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
||||
alias->unit[0] = '\0';
|
||||
alias->per_pkg = false;
|
||||
alias->snapshot = false;
|
||||
alias->deprecated = false;
|
||||
|
||||
ret = parse_events_terms(&alias->terms, val);
|
||||
if (ret) {
|
||||
@ -379,6 +381,9 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
|
||||
alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1;
|
||||
alias->str = strdup(newval);
|
||||
|
||||
if (deprecated)
|
||||
alias->deprecated = true;
|
||||
|
||||
if (!perf_pmu_merge_alias(alias, list))
|
||||
list_add_tail(&alias->list, list);
|
||||
|
||||
@ -400,7 +405,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
|
||||
strim(buf);
|
||||
|
||||
return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static inline bool pmu_alias_info_file(char *name)
|
||||
@ -787,7 +792,8 @@ new_alias:
|
||||
(char *)pe->long_desc, (char *)pe->topic,
|
||||
(char *)pe->unit, (char *)pe->perpkg,
|
||||
(char *)pe->metric_expr,
|
||||
(char *)pe->metric_name);
|
||||
(char *)pe->metric_name,
|
||||
(char *)pe->deprecated);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1383,7 +1389,7 @@ static void wordwrap(char *s, int start, int max, int corr)
|
||||
}
|
||||
|
||||
void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
|
||||
bool long_desc, bool details_flag)
|
||||
bool long_desc, bool details_flag, bool deprecated)
|
||||
{
|
||||
struct perf_pmu *pmu;
|
||||
struct perf_pmu_alias *alias;
|
||||
@ -1414,6 +1420,9 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag,
|
||||
format_alias(buf, sizeof(buf), pmu, alias);
|
||||
bool is_cpu = !strcmp(pmu->name, "cpu");
|
||||
|
||||
if (alias->deprecated && !deprecated)
|
||||
continue;
|
||||
|
||||
if (event_glob != NULL &&
|
||||
!(strglobmatch_nocase(name, event_glob) ||
|
||||
(!is_cpu && strglobmatch_nocase(alias->name,
|
||||
|
@ -57,6 +57,7 @@ struct perf_pmu_alias {
|
||||
double scale;
|
||||
bool per_pkg;
|
||||
bool snapshot;
|
||||
bool deprecated;
|
||||
char *metric_expr;
|
||||
char *metric_name;
|
||||
};
|
||||
@ -85,7 +86,8 @@ int perf_pmu__format_parse(char *dir, struct list_head *head);
|
||||
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
|
||||
|
||||
void print_pmu_events(const char *event_glob, bool name_only, bool quiet,
|
||||
bool long_desc, bool details_flag);
|
||||
bool long_desc, bool details_flag,
|
||||
bool deprecated);
|
||||
bool pmu_have_event(const char *pname, const char *name);
|
||||
|
||||
int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4);
|
||||
|
@ -539,10 +539,11 @@ static int perl_stop_script(void)
|
||||
|
||||
static int perl_generate_script(struct tep_handle *pevent, const char *outfile)
|
||||
{
|
||||
int i, not_first, count, nr_events;
|
||||
struct tep_event **all_events;
|
||||
struct tep_event *event = NULL;
|
||||
struct tep_format_field *f;
|
||||
char fname[PATH_MAX];
|
||||
int not_first, count;
|
||||
FILE *ofp;
|
||||
|
||||
sprintf(fname, "%s.pl", outfile);
|
||||
@ -603,8 +604,11 @@ sub print_backtrace\n\
|
||||
}\n\n\
|
||||
");
|
||||
|
||||
nr_events = tep_get_events_count(pevent);
|
||||
all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
|
||||
|
||||
while ((event = trace_find_next_event(pevent, event))) {
|
||||
for (i = 0; all_events && i < nr_events; i++) {
|
||||
event = all_events[i];
|
||||
fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
|
||||
fprintf(ofp, "\tmy (");
|
||||
|
||||
|
@ -1687,10 +1687,11 @@ static int python_stop_script(void)
|
||||
|
||||
static int python_generate_script(struct tep_handle *pevent, const char *outfile)
|
||||
{
|
||||
int i, not_first, count, nr_events;
|
||||
struct tep_event **all_events;
|
||||
struct tep_event *event = NULL;
|
||||
struct tep_format_field *f;
|
||||
char fname[PATH_MAX];
|
||||
int not_first, count;
|
||||
FILE *ofp;
|
||||
|
||||
sprintf(fname, "%s.py", outfile);
|
||||
@ -1735,7 +1736,11 @@ static int python_generate_script(struct tep_handle *pevent, const char *outfile
|
||||
fprintf(ofp, "def trace_end():\n");
|
||||
fprintf(ofp, "\tprint(\"in trace_end\")\n\n");
|
||||
|
||||
while ((event = trace_find_next_event(pevent, event))) {
|
||||
nr_events = tep_get_events_count(pevent);
|
||||
all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID);
|
||||
|
||||
for (i = 0; all_events && i < nr_events; i++) {
|
||||
event = all_events[i];
|
||||
fprintf(ofp, "def %s__%s(", event->system, event->name);
|
||||
fprintf(ofp, "event_name, ");
|
||||
fprintf(ofp, "context, ");
|
||||
|
@ -490,6 +490,16 @@ int create_perf_stat_counter(struct evsel *evsel,
|
||||
if (config->identifier)
|
||||
attr->sample_type = PERF_SAMPLE_IDENTIFIER;
|
||||
|
||||
if (config->all_user) {
|
||||
attr->exclude_kernel = 1;
|
||||
attr->exclude_user = 0;
|
||||
}
|
||||
|
||||
if (config->all_kernel) {
|
||||
attr->exclude_kernel = 0;
|
||||
attr->exclude_user = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disabling all counters initially, they will be enabled
|
||||
* either manually by us or by kernel via enable_on_exec
|
||||
|
@ -106,6 +106,8 @@ struct perf_stat_config {
|
||||
bool big_num;
|
||||
bool no_merge;
|
||||
bool walltime_run_table;
|
||||
bool all_kernel;
|
||||
bool all_user;
|
||||
FILE *output;
|
||||
unsigned int interval;
|
||||
unsigned int timeout;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <sys/types.h> // pid_t
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -32,6 +33,8 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
|
||||
return asprintf_expr_inout_ints(var, false, nints, ints);
|
||||
}
|
||||
|
||||
char *asprintf__tp_filter_pids(size_t npids, pid_t *pids);
|
||||
|
||||
char *strpbrk_esc(char *str, const char *stopset);
|
||||
char *strdup_esc(const char *str);
|
||||
|
||||
|
@ -458,10 +458,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
|
||||
return true;
|
||||
}
|
||||
|
||||
int perf_time__parse_for_ranges(const char *time_str,
|
||||
int perf_time__parse_for_ranges_reltime(const char *time_str,
|
||||
struct perf_session *session,
|
||||
struct perf_time_interval **ranges,
|
||||
int *range_size, int *range_num)
|
||||
int *range_size, int *range_num,
|
||||
bool reltime)
|
||||
{
|
||||
bool has_percent = strchr(time_str, '%');
|
||||
struct perf_time_interval *ptime_range;
|
||||
@ -471,7 +472,7 @@ int perf_time__parse_for_ranges(const char *time_str,
|
||||
if (!ptime_range)
|
||||
return -ENOMEM;
|
||||
|
||||
if (has_percent) {
|
||||
if (has_percent || reltime) {
|
||||
if (session->evlist->first_sample_time == 0 &&
|
||||
session->evlist->last_sample_time == 0) {
|
||||
pr_err("HINT: no first/last sample time found in perf data.\n"
|
||||
@ -479,7 +480,9 @@ int perf_time__parse_for_ranges(const char *time_str,
|
||||
"(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_percent) {
|
||||
num = perf_time__percent_parse_str(
|
||||
ptime_range, size,
|
||||
time_str,
|
||||
@ -492,6 +495,15 @@ int perf_time__parse_for_ranges(const char *time_str,
|
||||
if (num < 0)
|
||||
goto error_invalid;
|
||||
|
||||
if (reltime) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
ptime_range[i].start += session->evlist->first_sample_time;
|
||||
ptime_range[i].end += session->evlist->first_sample_time;
|
||||
}
|
||||
}
|
||||
|
||||
*range_size = size;
|
||||
*range_num = num;
|
||||
*ranges = ptime_range;
|
||||
@ -504,6 +516,15 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int perf_time__parse_for_ranges(const char *time_str,
|
||||
struct perf_session *session,
|
||||
struct perf_time_interval **ranges,
|
||||
int *range_size, int *range_num)
|
||||
{
|
||||
return perf_time__parse_for_ranges_reltime(time_str, session, ranges,
|
||||
range_size, range_num, false);
|
||||
}
|
||||
|
||||
int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz)
|
||||
{
|
||||
u64 sec = timestamp / NSEC_PER_SEC;
|
||||
|
@ -26,6 +26,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
|
||||
|
||||
struct perf_session;
|
||||
|
||||
int perf_time__parse_for_ranges_reltime(const char *str, struct perf_session *session,
|
||||
struct perf_time_interval **ranges,
|
||||
int *range_size, int *range_num,
|
||||
bool reltime);
|
||||
|
||||
int perf_time__parse_for_ranges(const char *str, struct perf_session *session,
|
||||
struct perf_time_interval **ranges,
|
||||
int *range_size, int *range_num);
|
||||
|
@ -173,37 +173,6 @@ int parse_event_file(struct tep_handle *pevent,
|
||||
return tep_parse_event(pevent, buf, size, sys);
|
||||
}
|
||||
|
||||
struct tep_event *trace_find_next_event(struct tep_handle *pevent,
|
||||
struct tep_event *event)
|
||||
{
|
||||
static int idx;
|
||||
int events_count;
|
||||
struct tep_event *all_events;
|
||||
|
||||
all_events = tep_get_first_event(pevent);
|
||||
events_count = tep_get_events_count(pevent);
|
||||
if (!pevent || !all_events || events_count < 1)
|
||||
return NULL;
|
||||
|
||||
if (!event) {
|
||||
idx = 0;
|
||||
return all_events;
|
||||
}
|
||||
|
||||
if (idx < events_count && event == (all_events + idx)) {
|
||||
idx++;
|
||||
if (idx == events_count)
|
||||
return NULL;
|
||||
return (all_events + idx);
|
||||
}
|
||||
|
||||
for (idx = 1; idx < events_count; idx++) {
|
||||
if (event == (all_events + (idx - 1)))
|
||||
return (all_events + idx);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct flag {
|
||||
const char *name;
|
||||
unsigned long long value;
|
||||
|
@ -47,8 +47,6 @@ void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int siz
|
||||
|
||||
ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe);
|
||||
|
||||
struct tep_event *trace_find_next_event(struct tep_handle *pevent,
|
||||
struct tep_event *event);
|
||||
unsigned long long read_size(struct tep_event *event, void *ptr, int size);
|
||||
unsigned long long eval_flag(const char *flag);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user