perf/core improvements and fixes
Subsystems (2)
Arnaldo Carvalho de Melo
maintainerHi Ingo,
Unusually big one, please conside pulling, details on the signed tag,
- Arnaldo
Test results at the end of this message, as usual.
The following changes since commit 4b1303d0b01440f224cf81493b7e8e43d9b4965e:
perf symbols: Accept zero as the kernel base address (2017-07-12 11:47:05 -0300)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git tags/perf-core-for-mingo-4.13-20170718
for you to fetch changes up to b851dd49868e295e18c5d72fc3bad85ff1c444b1:
perf report: Show branch type in callchain entry (2017-07-18 23:14:42 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:
User visible:
. Initial support for namespaces, using setns to access files in
namespaces, grabbing their build-ids, etc. We still need to work more to deal with namespaces that vanish before we can get the needed data to do analysis, but this should be as good as what is in bcc now (Krister Johansen)
. Add header record types to pipe-mode, now this command:
$ perf record -o - -e cycles sleep 1 | perf report --stdio --header
Will show the same as in non-pipe mode, i.e. involving a perf.data file (David Carrillo-Cisneros)
. Implement a visual marker for fused x86 instructions in the annotate
TUI browser, available now in 'perf report', more work needed to have it available as well in 'perf top' (Jin Yao)
Further explanation from one of Jin's patches:
│ ┌──cmpl $0x0,argp_program_version_hook
81.93 │ ├──je 20
│ │ lock cmpxchg %esi,0x38a9a4(%rip)
│ │↓ jne 29
│ │↓ jmp 43
11.47 │20:└─→cmpxch %esi,0x38a999(%rip)That means the cmpl+je is a fused instruction pair and they should be considered together.
. Record the branch type and then show statistics and info about
in callchain entries (Jin Yao)
Example from one of Jin's patches:
# perf record -g -j any,save_type # perf report --branch-history --stdio --no-children
38.50% div.c:45 [.] main div
|
---main div.c:42 (RET CROSS_2M cycles:2)
compute_flag div.c:28 (cycles:2)
compute_flag div.c:27 (RET CROSS_2M cycles:1)
rand rand.c:28 (cycles:1)
rand rand.c:28 (RET CROSS_2M cycles:1)
__random random.c:298 (cycles:1)
__random random.c:297 (COND_BWD CROSS_2M cycles:1)
__random random.c:295 (cycles:1)
__random random.c:295 (COND_BWD CROSS_2M cycles:1)
__random random.c:295 (cycles:1)
__random random.c:295 (RET CROSS_2M cycles:9). Beautify the fcntl syscall, which is an interesting one in the sense
that infrastructure had to be put in place to change the formatters of some arguments according to the value in a previous one, i.e. cmd dictates how arg and the syscall return will be formatted. (Arnaldo Carvalho de Melo
Infrastructure:
. 'perf test attr' fixes (Jiri Olsa)
Vendor events:
- Add POWER9 PMU events Sukadev (Bhattiprolu)
- Support additional POWER8+ PVR in PMU mapfile (Shriya)
----------------------------------------------------------------
Arnaldo Carvalho de Melo (39):
perf trace: Remove F_ from some of the fcntl command strings
perf trace: Beautify linux specific fcntl commands
tools: Update include/uapi/linux/fcntl.h copy from the kernel
perf trace beauty: Export the strarrays scnprintf method
perf trace: Only build tools/perf/trace/beauty/ when building 'perf trace' perf trace beauty: Mask ignored fcntl 'arg' parameter
perf trace beauty: Allow accessing syscall args values in a syscall arg formatter perf trace beauty: Export the "int" and "hex" syscall arg formatters perf trace beauty: Introduce syscall arg beautifier for long integers tools include uapi asm-generic: Grab a copy of fcntl.h
perf trace beauty fcntl: Basic 'arg' beautifier
perf trace: Beautify new write hint fcntl commands
perf beauty open: Detach the syscall_arg agnostic bits from the flags formatter perf trace: Allow syscall_arg beautifiers to set a different return formatter perf trace beauty open flags: Support O_TMPFILE and O_NOFOLLOW
perf trace beauty open flags: Do not depend on the system's O_LARGEFILE define perf trace beauty fcntl: Beautify F_GETFL return value
perf trace beauty open flags: Move RDRW to the start of the output perf trace beauty fcntl flags: Beautify F_SETFL arg
perf trace beauty fcntl: Beautify F_[GS]ETFD arg/return value
perf trace beauty: Give syscall return beautifier more context
perf trace beauty: Export the fd beautifier for use in more places perf trace beauty fcntl: Augment the return of F_DUPFD(_CLOEXEC) perf trace beauty: Export the pid beautifier for use in more places perf trace beauty fcntl: Beautify F_GETOWN and F_SETOWN
tools include uapi x86: Grab a copy of unistd.h
tools include uapi x86: Add __NR_setns, if missing
tools build: Add test for setns()
perf evsel: Allow asking for max precise_ip in new_cycles()
perf evlist: Allow asking for max precise_ip in add_default()
perf record: Do not ask for precise_ip with --no-samples
perf test sdt: Handle realpath() failure
perf trace beauty: Export strarray for use in per-object beautifiers perf trace beauty fcntl: Beautify F_GETLEASE and F_SETLEASE arg/return perf trace: Group per syscall arg formatter info into one struct perf trace: Allow syscall arg formatters to request non suppression of zeros perf trace beauty fcntl: Do not suppress 'cmd' when zero, should be DUPFD perf trace beauty fcntl: Beautify the 'arg' for DUPFD
perf trace beauty: Simplify syscall return formatting
David Carrillo-Cisneros (16):
perf header: Encapsulate read and swap
perf header: Add PROCESS_STR_FUN macro
perf header: Fail on write_padded error
perf util: Add const modifier to buf in "writen" function perf header: Revamp do_write()
perf header: Add struct feat_fd for write
perf header: Use struct feat_fd for print
perf header: Use struct feat_fd to process header records perf header: Don't pass struct perf_file_section to process_##_feat perf header: Use struct feat_fd in read header records perf header: Make write_pmu_mappings pipe-mode friendly perf header: Add a buffer to struct feat_fd
perf header: Change FEAT_OP* macros
perf tool: Add show_feature_header to perf_tool
perf tools: Add feature header record to pipe-mode
perf header: Add event desc to pipe-mode header
Jin Yao (10):
perf annotate: Check for fused instructions
perf annotate: Implement visual marker for macro fusion perf report: Enable finding kernel inline functions perf/core: Define the common branch type classification perf/x86/intel: Record branch type
perf record: Create a new option save_type in --branch-filter perf report: Refactor the branch info printing code perf util: Create branch.c/.h for common branch functions perf report: Show branch type statistics for stdio mode perf report: Show branch type in callchain entry
Jiri Olsa (13):
perf tests attr: Do not store failed events
perf tests attr: Add test_attr__ready function perf tests attr: Make compare_data global
perf tests attr: Rename compare_data to data_equal perf tests attr: Add 1s for exclude_kernel and task base bits perf tests attr: Fix record dwarf test
perf tests attr: Fix no-delay test
perf tests attr: Add proper return values
perf tests attr: Fix cpu test disabled term setup perf tests attr: Fix sample_period setup
perf tests attr: Fix precise_ip setup
perf tests attr: Fix stat sample_type setup
perf tests attr: Add optional term
Krister Johansen (5):
perf symbols: Find symbols in different mount namespace perf maps: Lookup maps in both intitial mountns and inner mountns. perf probe: Allow placing uprobes in alternate namespaces. perf buildid-cache: Support binary objects from other namespaces perf buildid-cache: Cache debuginfo
Shriya (1):
perf pmu-events: Support additional POWER8+ PVR in mapfile
Sukadev Bhattiprolu (2):
perf vendor events: Add POWER9 PMU events perf vendor events: Add POWER9 PVRs to mapfile
arch/x86/events/intel/lbr.c | 52 +-
include/uapi/linux/perf_event.h | 27 +-
tools/arch/x86/include/asm/unistd_32.h | 3 +
tools/arch/x86/include/asm/unistd_64.h | 3 +
tools/arch/x86/include/uapi/asm/unistd.h | 17 +
tools/build/Makefile.feature | 3 +-
tools/build/feature/Makefile | 6 +-
tools/build/feature/test-all.c | 5 +
tools/build/feature/test-setns.c | 7 +
tools/include/uapi/asm-generic/fcntl.h | 220 +++++
tools/include/uapi/linux/fcntl.h | 21 +
tools/include/uapi/linux/perf_event.h | 27 +-
tools/perf/Build | 2 +-
tools/perf/Documentation/perf-buildid-cache.txt | 5 +
tools/perf/Documentation/perf-probe.txt | 14 +
tools/perf/Documentation/perf-record.txt | 1 +
tools/perf/Documentation/perf.data-file-format.txt | 10 +-
tools/perf/Makefile.config | 5 +
tools/perf/arch/powerpc/util/sym-handling.c | 2 +-
tools/perf/arch/x86/annotate/instructions.c | 46 +
tools/perf/builtin-annotate.c | 1 +
tools/perf/builtin-buildid-cache.c | 54 +-
tools/perf/builtin-inject.c | 1 +
tools/perf/builtin-probe.c | 45 +-
tools/perf/builtin-record.c | 9 +-
tools/perf/builtin-report.c | 30 +
tools/perf/builtin-script.c | 4 +
tools/perf/builtin-top.c | 2 +-
tools/perf/builtin-trace.c | 602 ++++++------
tools/perf/check-headers.sh | 1 +
tools/perf/perf.h | 1 +
tools/perf/pmu-events/arch/powerpc/mapfile.csv | 4 +
.../perf/pmu-events/arch/powerpc/power9/cache.json | 176 ++++
.../arch/powerpc/power9/floating-point.json | 44 +
.../pmu-events/arch/powerpc/power9/frontend.json | 446 +++++++++
.../pmu-events/arch/powerpc/power9/marked.json | 782 +++++++++++++++
.../pmu-events/arch/powerpc/power9/memory.json | 158 +++
.../perf/pmu-events/arch/powerpc/power9/other.json | 836 ++++++++++++++++
.../pmu-events/arch/powerpc/power9/pipeline.json | 680 +++++++++++++
tools/perf/pmu-events/arch/powerpc/power9/pmc.json | 146 +++
.../arch/powerpc/power9/translation.json | 272 ++++++
tools/perf/tests/attr.c | 12 +-
tools/perf/tests/attr.py | 50 +-
tools/perf/tests/attr/base-record | 6 +-
tools/perf/tests/attr/base-stat | 4 +-
tools/perf/tests/attr/test-record-C0 | 1 +
tools/perf/tests/attr/test-record-basic | 1 +
tools/perf/tests/attr/test-record-branch-any | 2 +-
.../perf/tests/attr/test-record-branch-filter-any | 2 +-
.../tests/attr/test-record-branch-filter-any_call | 2 +-
.../tests/attr/test-record-branch-filter-any_ret | 2 +-
tools/perf/tests/attr/test-record-branch-filter-hv | 2 +-
.../tests/attr/test-record-branch-filter-ind_call | 2 +-
tools/perf/tests/attr/test-record-branch-filter-k | 2 +-
tools/perf/tests/attr/test-record-branch-filter-u | 2 +-
tools/perf/tests/attr/test-record-count | 1 +
tools/perf/tests/attr/test-record-data | 3 +-
tools/perf/tests/attr/test-record-freq | 1 +
tools/perf/tests/attr/test-record-graph-default | 1 +
tools/perf/tests/attr/test-record-graph-dwarf | 4 +-
tools/perf/tests/attr/test-record-graph-fp | 1 +
tools/perf/tests/attr/test-record-group | 1 +
tools/perf/tests/attr/test-record-group-sampling | 1 +
tools/perf/tests/attr/test-record-group1 | 1 +
...st-record-no-delay => test-record-no-buffering} | 4 +-
tools/perf/tests/attr/test-record-no-inherit | 1 +
tools/perf/tests/attr/test-record-no-samples | 1 +
tools/perf/tests/attr/test-record-period | 1 +
tools/perf/tests/attr/test-record-raw | 2 +-
tools/perf/tests/attr/test-stat-C0 | 4 +-
tools/perf/tests/attr/test-stat-default | 2 +
tools/perf/tests/attr/test-stat-detailed-1 | 2 +
tools/perf/tests/attr/test-stat-detailed-2 | 3 +
tools/perf/tests/attr/test-stat-detailed-3 | 5 +
tools/perf/tests/sdt.c | 8 +-
tools/perf/trace/beauty/Build | 1 +
tools/perf/trace/beauty/beauty.h | 65 ++
tools/perf/trace/beauty/fcntl.c | 100 ++
tools/perf/trace/beauty/open_flags.c | 29 +-
tools/perf/trace/beauty/pid.c | 4 +-
tools/perf/ui/browser.c | 29 +
tools/perf/ui/browser.h | 2 +
tools/perf/ui/browsers/annotate.c | 30 +-
tools/perf/ui/browsers/hists.c | 3 -
tools/perf/ui/gtk/annotate.c | 2 +-
tools/perf/ui/stdio/hist.c | 3 -
tools/perf/util/Build | 5 +
tools/perf/util/annotate.c | 29 +-
tools/perf/util/annotate.h | 4 +-
tools/perf/util/branch.c | 147 +++
tools/perf/util/branch.h | 24 +
tools/perf/util/build-id.c | 129 ++-
tools/perf/util/build-id.h | 16 +-
tools/perf/util/callchain.c | 134 +--
tools/perf/util/callchain.h | 5 +-
tools/perf/util/dso.c | 21 +-
tools/perf/util/dso.h | 3 +
tools/perf/util/event.c | 1 +
tools/perf/util/event.h | 11 +-
tools/perf/util/evlist.c | 4 +-
tools/perf/util/evlist.h | 9 +-
tools/perf/util/evsel.c | 18 +-
tools/perf/util/evsel.h | 3 +-
tools/perf/util/header.c | 1015 +++++++++++---------
tools/perf/util/header.h | 16 +-
tools/perf/util/hist.c | 5 +-
tools/perf/util/machine.c | 33 +-
tools/perf/util/map.c | 23 +-
tools/perf/util/map.h | 2 +-
tools/perf/util/namespaces.c | 211 ++++
tools/perf/util/namespaces.h | 38 +
tools/perf/util/parse-branch-options.c | 1 +
tools/perf/util/parse-events.c | 2 +-
tools/perf/util/probe-event.c | 86 +-
tools/perf/util/probe-event.h | 10 +-
tools/perf/util/probe-file.c | 19 +-
tools/perf/util/probe-file.h | 4 +-
tools/perf/util/python-ext-sources | 1 +
tools/perf/util/session.c | 4 +
tools/perf/util/setns.c | 8 +
tools/perf/util/symbol.c | 92 +-
tools/perf/util/thread.c | 3 +
tools/perf/util/thread.h | 1 +
tools/perf/util/tool.h | 10 +-
tools/perf/util/util.c | 40 +-
tools/perf/util/util.h | 8 +-
126 files changed, 6339 insertions(+), 1031 deletions(-)
create mode 100644 tools/arch/x86/include/uapi/asm/unistd.h
create mode 100644 tools/build/feature/test-setns.c
create mode 100644 tools/include/uapi/asm-generic/fcntl.h
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/cache.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/floating-point.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/frontend.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/marked.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/memory.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/other.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/pipeline.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/pmc.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/translation.json
rename tools/perf/tests/attr/{test-record-no-delay => test-record-no-buffering} (61%)
create mode 100644 tools/perf/trace/beauty/fcntl.c
create mode 100644 tools/perf/util/branch.c
create mode 100644 tools/perf/util/branch.h
create mode 100644 tools/perf/util/setns.cTest results at the end of this message, as usual.
Test results:
The first ones are container (docker) based builds of tools/perf with and without libelf support, objtool where it is supported and samples/bpf/, ditto. Where clang is available, it is also used to build perf with/without libelf.
Several are cross builds, the ones with -x-ARCH, and the android one, and those may not have all the features built, due to lack of multi-arch devel packages, available and being used so far on just a few, like debian:experimental-x-{arm64,mipsel}.
The 'perf test' one will perform a variety of tests exercising tools/perf/util/, tools/lib/{bpf,traceevent,etc}, as well as run perf commands with a variety of command line event specifications to then intercept the sys_perf_event syscall to check that the perf_event_attr fields are set up as expected, among a variety of other unit tests.
Then there is the 'make -C tools/perf build-test' ones, that build tools/perf/ with a variety of feature sets, exercising the build with an incomplete set of features as well as with a complete one. It is planned to have it run on each of the containers mentioned above, using some container orchestration infrastructure. Get in contact if interested in helping having this in place.
The fedora:rawhide case is being investigated, doesn't seem to have been introduced by this batch:
LINK /tmp/build/perf/perf
LINK /tmp/build/perf/libperf-gtk.so/usr/bin/ld: /tmp/build/perf/perf-in.o: relocation R_X86_64_32 against .rodata.str1.1' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: /tmp/build/perf/libperf.a(libperf-in.o): relocation R_X86_64_32S against .text' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile.perf:420: /tmp/build/perf/perf] Error 1
# dm 1 alpine:3.4: Ok 2 alpine:3.5: Ok 3 alpine:3.6: Ok 4 alpine:edge: Ok 5 android-ndk:r12b-arm: Ok 6 archlinux:latest: Ok 7 centos:5: Ok 8 centos:6: Ok 9 centos:7: Ok 10 debian:7: Ok 11 debian:8: Ok 12 debian:9: Ok 13 debian:experimental: Ok 14 debian:experimental-x-arm64: Ok 15 debian:experimental-x-mips: Ok 16 debian:experimental-x-mips64: Ok 17 debian:experimental-x-mipsel: Ok 18 fedora:20: Ok 19 fedora:21: Ok 20 fedora:22: Ok 21 fedora:23: Ok 22 fedora:24: Ok 23 fedora:24-x-ARC-uClibc: Ok 24 fedora:25: Ok 25 fedora:26: Ok 26 fedora:rawhide: FAIL 27 mageia:5: Ok 28 opensuse:13.2: Ok 29 opensuse:42.1: Ok 30 opensuse:42.2: Ok 31 opensuse:tumbleweed: Ok 32 oraclelinux:6: Ok 33 oraclelinux:7: Ok 34 ubuntu:12.04.5: Ok 35 ubuntu:14.04.4: Ok 36 ubuntu:14.04.4-x-linaro-arm64: Ok 37 ubuntu:15.10: Ok 38 ubuntu:16.04: Ok 39 ubuntu:16.04-x-arm: Ok 40 ubuntu:16.04-x-arm64: Ok 41 ubuntu:16.04-x-powerpc: Ok 42 ubuntu:16.04-x-powerpc64: Ok 43 ubuntu:16.04-x-powerpc64el: Ok 44 ubuntu:16.04-x-s390: Ok 45 ubuntu:16.10: Ok 46 ubuntu:17.04: Ok 47 ubuntu:17.10: Ok #
# uname -a Linux jouet 4.12.0-rc6+ #3 SMP Tue Jun 27 15:12:38 -03 2017 x86_64 x86_64 x86_64 GNU/Linux # perf test 1: vmlinux symtab matches kallsyms : Ok 2: Detect openat syscall event : Ok 3: Detect openat syscall event on all cpus : Ok 4: Read samples using the mmap interface : Ok 5: Parse event definition strings : Ok 6: Simple expression parser : Ok 7: PERF_RECORD_* events & perf_sample fields : Ok 8: Parse perf pmu format : Ok 9: DSO data read : Ok 10: DSO data cache : Ok 11: DSO data reopen : Ok 12: Roundtrip evsel->name : Ok 13: Parse sched tracepoints fields : Ok 14: syscalls:sys_enter_openat event fields : Ok 15: Setup struct perf_event_attr : Ok 16: Match and link multiple hists : Ok 17: 'import perf' in python : Ok 18: Breakpoint overflow signal handler : Ok 19: Breakpoint overflow sampling : Ok 20: Number of exit events of a simple workload : Ok 21: Software clock events period values : Ok 22: Object code reading : Ok 23: Sample parsing : Ok 24: Use a dummy software event to keep tracking: Ok 25: Parse with no sample_id_all bit set : Ok 26: Filter hist entries : Ok 27: Lookup mmap thread : Ok 28: Share thread mg : Ok 29: Sort output of hist entries : Ok 30: Cumulate child hist entries : Ok 31: Track with sched_switch : Ok 32: Filter fds with revents mask in a fdarray : Ok 33: Add fd to a fdarray, making it autogrow : Ok 34: kmod_path__parse : Ok 35: Thread map : Ok 36: LLVM search and compile : 36.1: Basic BPF llvm compile : Ok 36.2: kbuild searching : Ok 36.3: Compile source for BPF prologue generation: Ok 36.4: Compile source for BPF relocation : Ok 37: Session topology : Ok 38: BPF filter : 38.1: Basic BPF filtering : Ok 38.2: BPF pinning : Ok 38.3: BPF prologue generation : Ok 38.4: BPF relocation checker : Ok 39: Synthesize thread map : Ok 40: Remove thread map : Ok 41: Synthesize cpu map : Ok 42: Synthesize stat config : Ok 43: Synthesize stat : Ok 44: Synthesize stat round : Ok 45: Synthesize attr update : Ok 46: Event times : Ok 47: Read backward ring buffer : Ok 48: Print cpu map : Ok 49: Probe SDT events : Ok 50: is_printable_array : Ok 51: Print bitmap : Ok 52: perf hooks : Ok 53: builtin clang support : Skip (not compiled in) 54: unit_number__scnprintf : Ok 55: x86 rdpmc : Ok 56: Convert perf time to TSC : Ok 57: DWARF unwind : Ok 58: x86 instruction decoder - new instructions : Ok 59: Intel cqm nmi context read : Skip #
Arnaldo Carvalho de Melo
maintainerPATCH 1/86 perf annotate: Check for fused instructions
From: Jin Yao <[email protected]>
Macro fusion merges two instructions to a single micro-op. Intel core platform performs this hardware optimization under limited circumstances.
For example, CMP + JCC can be "fused" and executed /retired together. While with sampling this can result in the sample sometimes being on the JCC and sometimes on the CMP. So for the fused instruction pair, they could be considered together.
On Nehalem, fused instruction pairs:
cmp/test + jcc.
On other new CPU:
cmp/test/add/sub/and/inc/dec + jcc.
This patch adds an x86-specific function which checks if 2 instructions are in a "fused" pair. For non-x86 arch, the function is just NULL.
Changelog:
v4: Move the CPU model checking to symbol__disassemble and save the CPU
family/model in arch structure.
It avoids checking every time when jump arrow printed.
v3: Add checking for Nehalem (CMP, TEST). For other newer Intel CPUs
just check it by default (CMP, TEST, ADD, SUB, AND, INC, DEC).
v2: Remove the original weak function. Arnaldo points out that doing it
as a weak function that will be overridden by the host arch doesn't work. So now it's implemented as an arch-specific function.
Committer fix:
Do not access evsel->evlist->env->cpuid, ->env can be null, introduce perf_evsel__env_cpuid(), just like perf_evsel__env_arch(), also used in this function call.
The original patch was segfaulting 'perf top' + annotation.
But this essentially disables this fused instructions augmentation in 'perf top', the right thing is to get the cpuid from the running kernel, left for a later patch tho.
--- tools/perf/arch/x86/annotate/instructions.c | 46 +++++++++++++++++++++++++++++ tools/perf/builtin-top.c | 2 +- tools/perf/ui/browsers/annotate.c | 4 ++- tools/perf/ui/gtk/annotate.c | 2 +- tools/perf/util/annotate.c | 22 ++++++++++++-- tools/perf/util/annotate.h | 3 +- tools/perf/util/evsel.c | 7 +++++ tools/perf/util/evsel.h | 1 + 8 files changed, 81 insertions(+), 6 deletions(-)
tools/perf/arch/x86/annotate/instructions.c +46 -0
@@ -76,3 +76,49 @@ static struct ins x86__instructions[] = { { .name = "xbeginq", .ops = &jump_ops, }, { .name = "retq", .ops = &ret_ops, }, }; + +static bool x86__ins_is_fused (struct arch *arch,const char *ins1, +const char *ins2) +{ +if (arch->family !=6 || arch->model <0x1e ||strstr (ins2,"jmp" )) +return false; + +if (arch->model ==0x1e ) { +/* Nehalem */ +if ((strstr (ins1,"cmp" ) && !strstr (ins1,"xchg" )) || +strstr (ins1,"test" )) { +return true; + } + }else { +/* Newer platform */ +if ((strstr (ins1,"cmp" ) && !strstr (ins1,"xchg" )) || +strstr (ins1,"test" ) || +strstr (ins1,"add" ) || +strstr (ins1,"sub" ) || +strstr (ins1,"and" ) || +strstr (ins1,"inc" ) || +strstr (ins1,"dec" )) { +return true; + } + } + +return false; +} + +static int x86__cpuid_parse (struct arch *arch,char *cpuid) +{ +unsigned int family, model, stepping; +int ret; + +/* +* cpuid = "GenuineIntel,family,model,stepping" +*/ + ret =sscanf (cpuid,"%*[^,],%u,%u,%u" , &family, &model, &stepping); +if (ret ==3 ) { + arch->family = family; + arch->model = model; +return 0 ; + } + +return -1 ; +}
tools/perf/builtin-top.c +1 -1
@@ -134,7 +134,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)return err; } - err =symbol__disassemble (sym, map,NULL ,0 ,NULL ); + err =symbol__disassemble (sym, map,NULL ,0 ,NULL ,NULL );if (err ==0 ) { out_assign: top->sym_filter_entry = he;
tools/perf/ui/browsers/annotate.c +3 -1
@@ -9,6 +9,7 @@#include "../../util/symbol.h" #include "../../util/evsel.h" #include "../../util/config.h" +#include "../../util/evlist.h" #include <inttypes.h> #include <pthread.h> #include <linux/kernel.h>
@@ -1074,7 +1075,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, } err =symbol__disassemble (sym, map,perf_evsel__env_arch (evsel), - sizeof_bdl, &browser.arch); + sizeof_bdl, &browser.arch, +perf_evsel__env_cpuid (evsel));if (err) {char msg[BUFSIZ ];symbol__strerror_disassemble (sym, map, err, msg,sizeof (msg));
tools/perf/ui/gtk/annotate.c +1 -1
@@ -169,7 +169,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map,return -1 ; err =symbol__disassemble (sym, map,perf_evsel__env_arch (evsel), -0 ,NULL ); +0 ,NULL ,NULL );if (err) {char msg[BUFSIZ ];symbol__strerror_disassemble (sym, map, err, msg,sizeof (msg));
tools/perf/util/annotate.c +20 -2
@@ -47,7 +47,12 @@ struct arch {bool sorted_instructions;bool initialized;void *priv; +unsigned int model; +unsigned int family;int (*init)(struct arch *arch); +bool (*ins_is_fused)(struct arch *arch,const char *ins1, +const char *ins2); +int (*cpuid_parse)(struct arch *arch,char *cpuid);struct {char comment_char;char skip_functions_char;
@@ -129,6 +134,8 @@ static struct arch architectures[] = { .name = "x86", .instructions = x86__instructions, .nr_instructions = ARRAY_SIZE(x86__instructions), + .ins_is_fused = x86__ins_is_fused, + .cpuid_parse = x86__cpuid_parse, .objdump = { .comment_char = '#', },
@@ -171,6 +178,14 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size,return ins__raw_scnprintf (ins, bf, size, ops); } +bool ins__is_fused (struct arch *arch,const char *ins1,const char *ins2) +{ +if (!arch || !arch->ins_is_fused) +return false; + +return arch->ins_is_fused (arch, ins1, ins2); +} +static int call__parse (struct arch *arch,struct ins_operands *ops,struct map *map) {char *endptr, *tok, *name;
@@ -1381,7 +1396,7 @@ static const char *annotate__norm_arch(const char *arch_name)int symbol__disassemble (struct symbol *sym,struct map *map,const char *arch_name,size_t privsize, -struct arch **parch) +struct arch **parch,char *cpuid) {struct dso *dso = map->dso;char command[PATH_MAX *2 ];
@@ -1418,6 +1433,9 @@ int symbol__disassemble(struct symbol *sym, struct map *map, } } +if (arch->cpuid_parse && cpuid) + arch->cpuid_parse (arch, cpuid); +pr_debug ("%s: filename=%s, sym=%s, start=%#" PRIx64", end=%#" PRIx64"\n" , __func__, symfs_filename, sym->name, map->unmap_ip (map, sym->start), map->unmap_ip (map, sym->end));
@@ -1907,7 +1925,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,u64 len;if (symbol__disassemble (sym, map,perf_evsel__env_arch (evsel), -0 ,NULL ) <0 ) +0 ,NULL ,NULL ) <0 )return -1 ; len =symbol__size (sym);
tools/perf/util/annotate.h +2 -1
@@ -53,6 +53,7 @@ bool ins__is_jump(const struct ins *ins);bool ins__is_call (const struct ins *ins);bool ins__is_ret (const struct ins *ins);int ins__scnprintf (struct ins *ins,char *bf,size_t size,struct ins_operands *ops); +bool ins__is_fused (struct arch *arch,const char *ins1,const char *ins2);struct annotation ;
@@ -160,7 +161,7 @@ void symbol__annotate_zero_histograms(struct symbol *sym);int symbol__disassemble (struct symbol *sym,struct map *map,const char *arch_name,size_t privsize, -struct arch **parch); +struct arch **parch,char *cpuid);enum symbol_disassemble_errno {SYMBOL_ANNOTATE_ERRNO__SUCCESS =0 ,
tools/perf/util/evsel.c +7 -0
@@ -2610,3 +2610,10 @@ char *perf_evsel__env_arch(struct perf_evsel *evsel)return evsel->evlist->env->arch;return NULL ; } + +char *perf_evsel__env_cpuid (struct perf_evsel *evsel) +{ +if (evsel && evsel->evlist && evsel->evlist->env) +return evsel->evlist->env->cpuid; +return NULL ; +}
tools/perf/util/evsel.h +1 -0
@@ -436,5 +436,6 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, attr__fprintf_f attr__fprintf, void *priv);char *perf_evsel__env_arch (struct perf_evsel *evsel); +char *perf_evsel__env_cpuid (struct perf_evsel *evsel);#endif /* __PERF_EVSEL_H */
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 2/86 perf annotate: Implement visual marker for macro fusion
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
For marking fused instructions clearly this patch adds a line before the first instruction of pair and joins it with the arrow of the jump to its target.
For example, when "je" is selected in annotate view, the line before cmpl is displayed and joins the arrow of "je".
│ ┌──cmpl $0x0,argp_program_version_hook
81.93 │ ├──je 20
│ │ lock cmpxchg %esi,0x38a9a4(%rip)
│ │↓ jne 29
│ │↓ jmp 43
11.47 │20:└─→cmpxch %esi,0x38a999(%rip)That means the cmpl+je is a fused instruction pair and they should be considered together.
Changelog:
v3: Use Arnaldo's fix to improve the arrow origin rendering. To get the
evsel->evlist->env->cpuid, save the evsel in annotate_browser.
v2: new function "ins__is_fused" to check if the instructions are fused.
--- tools/perf/ui/browser.c | 29 +++++++++++++++++++++++++++++ tools/perf/ui/browser.h | 2 ++ tools/perf/ui/browsers/annotate.c | 26 ++++++++++++++++++++++++++ tools/perf/util/annotate.c | 5 +++++ tools/perf/util/annotate.h | 1 + 5 files changed, 63 insertions(+)
tools/perf/ui/browser.c +29 -0
@@ -738,6 +738,35 @@ void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,__ui_browser__line_arrow_down (browser, column, start, end); } +void ui_browser__mark_fused (struct ui_browser *browser,unsigned int column, +unsigned int row,bool arrow_down) +{ +unsigned int end_row; + +if (row >= browser->top_idx) + end_row = row - browser->top_idx; +else +return ; + +SLsmg_set_char_set (1 ); + +if (arrow_down) { +ui_browser__gotorc (browser, end_row, column -1 ); +SLsmg_write_char (SLSMG_ULCORN_CHAR ); +ui_browser__gotorc (browser, end_row, column); +SLsmg_draw_hline (2 ); +ui_browser__gotorc (browser, end_row +1 , column -1 ); +SLsmg_write_char (SLSMG_LTEE_CHAR ); + }else { +ui_browser__gotorc (browser, end_row, column -1 ); +SLsmg_write_char (SLSMG_LTEE_CHAR ); +ui_browser__gotorc (browser, end_row, column); +SLsmg_draw_hline (2 ); + } + +SLsmg_set_char_set (0 ); +} +void ui_browser__init (void ) {int i =0 ;
tools/perf/ui/browser.h +2 -0
@@ -43,6 +43,8 @@ void ui_browser__printf(struct ui_browser *browser, const char *fmt, ...);void ui_browser__write_graph (struct ui_browser *browser,int graph);void __ui_browser__line_arrow (struct ui_browser *browser,unsigned int column,u64 start,u64 end); +void ui_browser__mark_fused (struct ui_browser *browser,unsigned int column, +unsigned int row,bool arrow_down);void __ui_browser__show_title (struct ui_browser *browser,const char *title);void ui_browser__show_title (struct ui_browser *browser,const char *title); int ui_browser__show(struct ui_browser *browser, const char *title,
tools/perf/ui/browsers/annotate.c +26 -0
@@ -273,6 +273,25 @@ static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *syreturn true; } +static bool is_fused (struct annotate_browser *ab,struct disasm_line *cursor) +{ +struct disasm_line *pos =list_prev_entry (cursor, node); +const char *name; + +if (!pos) +return false; + +if (ins__is_lock (&pos->ins)) + name = pos->ops.locked.ins.name; +else + name = pos->ins.name; + +if (!name || !cursor->ins.name) +return false; + +return ins__is_fused (ab->arch, name, cursor->ins.name); +} +static void annotate_browser__draw_current_jump (struct ui_browser *browser) { struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
@@ -308,6 +327,13 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)ui_browser__set_color (browser,HE_COLORSET_JUMP_ARROWS );__ui_browser__line_arrow (browser, pcnt_width +2 + ab->addr_width, from, to); + +if (is_fused (ab, cursor)) { +ui_browser__mark_fused (browser, + pcnt_width +3 + ab->addr_width, + from -1 , + to > from ? true : false); + } }static unsigned int annotate_browser__refresh (struct ui_browser *browser)
tools/perf/util/annotate.c +5 -0
@@ -517,6 +517,11 @@ bool ins__is_ret(const struct ins *ins)return ins->ops == &ret_ops; } +bool ins__is_lock (const struct ins *ins) +{ +return ins->ops == &lock_ops; +} +static int ins__key_cmp (const void *name,const void *insp) {const struct ins *ins = insp;
tools/perf/util/annotate.h +1 -0
@@ -52,6 +52,7 @@ struct ins_ops {bool ins__is_jump (const struct ins *ins);bool ins__is_call (const struct ins *ins);bool ins__is_ret (const struct ins *ins); +bool ins__is_lock (const struct ins *ins);int ins__scnprintf (struct ins *ins,char *bf,size_t size,struct ins_operands *ops);bool ins__is_fused (struct arch *arch,const char *ins1,const char *ins2);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 3/86 perf trace: Remove F_ from some of the fcntl command strings
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The initial ones already had that "F_" prefix stripped to make things shorter, some hadn't, do it now.
We do this to make the 'perf trace' output more compact. At some point perhaps the best thing to do is to have the tool do this stripping automatically, letting the user also decide if this is to be done or not. For now, be consistent.
--- tools/perf/builtin-trace.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/perf/builtin-trace.c +3 -3
@@ -407,9 +407,9 @@ static DEFINE_STRARRAY(whences);static const char *fcntl_cmds[] = {"DUPFD" ,"GETFD" ,"SETFD" ,"GETFL" ,"SETFL" ,"GETLK" ,"SETLK" , -"SETLKW" ,"SETOWN" ,"GETOWN" ,"SETSIG" ,"GETSIG" ,"F_GETLK64" , -"F_SETLK64" ,"F_SETLKW64" ,"F_SETOWN_EX" ,"F_GETOWN_EX" , -"F_GETOWNER_UIDS" , +"SETLKW" ,"SETOWN" ,"GETOWN" ,"SETSIG" ,"GETSIG" ,"GETLK64" , +"SETLK64" ,"SETLKW64" ,"SETOWN_EX" ,"GETOWN_EX" , +"GETOWNER_UIDS" , };static DEFINE_STRARRAY (fcntl_cmds);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 4/86 perf trace: Beautify linux specific fcntl commands
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We were only beautifying (transforming from an integer to its name) the non-linux specific fcntl syscall cmd args, fix it:
Before:
# perf trace -e fcntl -p 2472
0.000 ( 0.017 ms): gnome-terminal/2472 fcntl(fd: 55, cmd: 1030) = 56
^C#After:
# trace -e fcntl -p 2472
0.000 ( 0.015 ms): gnome-terminal/2472 fcntl(fd: 55, cmd: DUPFD_CLOEXEC) = 56
^C#--- tools/perf/builtin-trace.c | 57 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-)
tools/perf/builtin-trace.c +54 -3
@@ -64,6 +64,10 @@# define O_CLOEXEC 02000000#endif +#ifndef F_LINUX_SPECIFIC_BASE +# define F_LINUX_SPECIFIC_BASE 1024 +#endif +struct trace {struct perf_tool tool;struct syscalltbl *sctbl;
@@ -317,6 +321,38 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,#define SCA_STRARRAY syscall_arg__scnprintf_strarray +struct strarrays { +int nr_entries; +struct strarray **entries; +}; + +#define DEFINE_STRARRAYS (array) struct strarrays strarrays__##array = { \ + .nr_entries = ARRAY_SIZE(array), \ + .entries = array, \ +} + +static size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size, +struct syscall_arg *arg) +{ +struct strarrays *sas = arg->parm; +int i; + +for (i =0 ; i < sas->nr_entries; ++i) { +struct strarray *sa = sas->entries[i]; +int idx = arg->val - sa->offset; + +if (idx >=0 && idx < sa->nr_entries) { +if (sa->entries[idx] ==NULL ) +break ; +return scnprintf (bf, size,"%s" , sa->entries[idx]); + } + } + +return scnprintf (bf, size,"%d" , arg->val); +} + +#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays +#if defined(__i386__) || defined(__x86_64__)/* * FIXME: Make this available to all arches as soon as the ioctl beautifier
@@ -413,6 +449,20 @@ static const char *fcntl_cmds[] = { };static DEFINE_STRARRAY (fcntl_cmds); +static const char *fcntl_linux_specific_cmds[] = { +"SETLEASE" ,"GETLEASE" ,"NOTIFY" , [5 ] ="CANCELLK" ,"DUPFD_CLOEXEC" , +"SETPIPE_SZ" ,"GETPIPE_SZ" ,"ADD_SEALS" ,"GET_SEALS" , +}; + +static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE); + +static struct strarray *fcntl_cmds_arrays[] = { + &strarray__fcntl_cmds, + &strarray__fcntl_linux_specific_cmds, +}; + +static DEFINE_STRARRAYS (fcntl_cmds_arrays); +static const char *rlimit_resources[] = {"CPU" ,"FSIZE" ,"DATA" ,"STACK" ,"CORE" ,"RSS" ,"NPROC" ,"NOFILE" ,"MEMLOCK" ,"AS" ,"LOCKS" ,"SIGPENDING" ,"MSGQUEUE" ,"NICE" ,"RTPRIO" ,
@@ -613,8 +663,8 @@ static struct syscall_fmt { { .name = "fchownat", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, { .name = "fcntl", .errmsg = true, - .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ }, - .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, }, + .arg_scnprintf = { [1] = SCA_STRARRAYS, /* cmd */ }, + .arg_parm = { [1] = &strarrays__fcntl_cmds_arrays, /* cmd */ }, }, { .name = "fdatasync", .errmsg = true, }, { .name = "flock", .errmsg = true, .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
@@ -1356,7 +1406,8 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,*/ if (val ==0 && !(sc->arg_scnprintf && - sc->arg_scnprintf[arg.idx] ==SCA_STRARRAY && + (sc->arg_scnprintf[arg.idx] ==SCA_STRARRAY || + sc->arg_scnprintf[arg.idx] ==SCA_STRARRAYS ) && sc->arg_parm[arg.idx]))continue ;
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 5/86 tools: Update include/uapi/linux/fcntl.h copy from the kernel
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
To get the changes in the commit c75b1d9421f8 ("fs: add fcntl() interface for setting/getting write life time hints").
Silencing this perf build warning:
Warning: include/uapi/linux/fcntl.h differs from kernel
We already beautify the fcntl cmd argument, so an upcoming cset will update the 'cmd' strarray to cover these new commands.
The hints are in the 3rd arg, a pointer, so not yet supported in 'perf trace', for that we need to copy it somehow, probably using eBPF, a new attempt at doing that is planned.
--- tools/include/uapi/linux/fcntl.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
tools/include/uapi/linux/fcntl.h +21 -0
@@ -43,6 +43,27 @@/* (1U << 31) is reserved for signed error codes */ /* +* Set/Get write life time hints. {GET,SET}_RW_HINT operate on the +* underlying inode, while {GET,SET}_FILE_RW_HINT operate only on +* the specific file. +*/ +#define F_GET_RW_HINT (F_LINUX_SPECIFIC_BASE + 11) +#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12) +#define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13) +#define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14) + +/* +* Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be +* used to clear any hints previously set. +*/ +#define RWF_WRITE_LIFE_NOT_SET 0 +#define RWH_WRITE_LIFE_NONE 1 +#define RWH_WRITE_LIFE_SHORT 2 +#define RWH_WRITE_LIFE_MEDIUM 3 +#define RWH_WRITE_LIFE_LONG 4 +#define RWH_WRITE_LIFE_EXTREME 5 + +/* * Types of directory notifications that may be requested. */ #define DN_ACCESS 0x00000001/* File accessed */
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 6/86 perf trace beauty: Export the strarrays scnprintf method
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
As we'll call it from the fcntl cmd scnprintf method, that needs to look at the cmd to mask the next fcntl argument when it is ignored.
--- tools/perf/builtin-trace.c | 6 ++---- tools/perf/trace/beauty/beauty.h | 3 +++ 2 files changed, 5 insertions(+), 4 deletions(-)
tools/perf/builtin-trace.c +2 -4
@@ -331,8 +331,8 @@ struct strarrays { .entries = array, \ } -static size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size, -struct syscall_arg *arg) +size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size, +struct syscall_arg *arg) {struct strarrays *sas = arg->parm;int i;
@@ -351,8 +351,6 @@ static size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,return scnprintf (bf, size,"%d" , arg->val); } -#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays -#if defined(__i386__) || defined(__x86_64__)/* * FIXME: Make this available to all arches as soon as the ioctl beautifier
tools/perf/trace/beauty/beauty.h +3 -0
@@ -15,6 +15,9 @@ struct syscall_arg {u8 mask; }; +size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays +size_t syscall_arg__scnprintf_statx_flags (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 7/86 perf trace: Only build tools/perf/trace/beauty/ when building 'perf trace'
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
As it calls functions in builtin-trace.c.
--- tools/perf/Build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/Build +1 -1
@@ -50,6 +50,6 @@ libperf-y += util/ libperf-y += arch/ libperf-y += ui/ libperf-y += scripts/ -libperf-y += trace/beauty/ +libperf-$(CONFIG_AUDIT) += trace/beauty/ gtk-y += ui/gtk/
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 8/86 perf trace beauty: Mask ignored fcntl 'arg' parameter
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
A series of fcntl cmds ignore the third argument, so mask it.
--- tools/perf/builtin-trace.c | 2 +- tools/perf/trace/beauty/Build | 1 + tools/perf/trace/beauty/beauty.h | 3 +++ tools/perf/trace/beauty/fcntl.c | 23 +++++++++++++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 tools/perf/trace/beauty/fcntl.c
tools/perf/builtin-trace.c +1 -1
@@ -661,7 +661,7 @@ static struct syscall_fmt { { .name = "fchownat", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, { .name = "fcntl", .errmsg = true, - .arg_scnprintf = { [1] = SCA_STRARRAYS, /* cmd */ }, + .arg_scnprintf = { [1] = SCA_FCNTL_CMD, /* cmd */ }, .arg_parm = { [1] = &strarrays__fcntl_cmds_arrays, /* cmd */ }, }, { .name = "fdatasync", .errmsg = true, }, { .name = "flock", .errmsg = true,
tools/perf/trace/beauty/Build +1 -0
@@ -1 +1,2 @@ +libperf-y += fcntl.o libperf-y += statx.o
tools/perf/trace/beauty/beauty.h +3 -0
@@ -18,6 +18,9 @@ struct syscall_arg {size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd +size_t syscall_arg__scnprintf_statx_flags (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
tools/perf/trace/beauty/fcntl.c new file +23 -0
@@ -0,0 +1,23 @@ +/* +* trace/beauty/fcntl.c +* +* Copyright (C) 2017, Red Hat Inc, Arnaldo Carvalho de Melo <[email protected]> +* +* Released under the GPL v2. (and only v2, not any later version) +*/ + +#include "trace/beauty/beauty.h" +#include <uapi/linux/fcntl.h> + +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg) +{ +/* +* Some commands ignore the third fcntl argument, "arg", so mask it +*/ +if (arg->val ==F_GETFD || arg->val ==F_GETFL || + arg->val ==F_GETOWN || arg->val ==F_GET_SEALS || + arg->val ==F_GETLEASE || arg->val ==F_GETSIG ) + arg->mask |= (1 <<2 ); + +return syscall_arg__scnprintf_strarrays (bf, size, arg); +}
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 9/86 perf trace beauty: Allow accessing syscall args values in a syscall arg formatter
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
For instance, fcntl's upcoming 'arg' formatter needs to look at the 'cmd' value to decide how to format its value, sometimes it is a file flags, sometimes an fd, a pointer to a structure, etc.
--- tools/perf/builtin-trace.c | 23 ++++++++++++++++------- tools/perf/trace/beauty/beauty.h | 13 +++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-)
tools/perf/builtin-trace.c +16 -7
@@ -1369,19 +1369,32 @@ static int trace__validate_ev_qualifier(struct trace *trace)* variable to read it. Most notably this avoids extended load instructions * on unaligned addresses */ +static unsigned long __syscall_arg__val (unsigned char *args,u8 idx) +{ +unsigned long val; +unsigned char *p = args +sizeof (unsigned long ) * idx; + +memcpy (&val, p,sizeof (val)); +return val; +} + +unsigned long syscall_arg__val (struct syscall_arg *arg,u8 idx) +{ +return __syscall_arg__val (arg->args, idx); +}static size_t syscall__scnprintf_args (struct syscall *sc,char *bf,size_t size,unsigned char *args,struct trace *trace,struct thread *thread) {size_t printed =0 ; -unsigned char *p;unsigned long val;if (sc->args !=NULL ) {struct format_field *field;u8 bit =1 ;struct syscall_arg arg = { + .args = args, .idx =0 , .mask =0 , .trace = trace,
@@ -1393,9 +1406,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,if (arg.mask & bit)continue ; -/* special care for unaligned accesses */ - p = args +sizeof (unsigned long ) * arg.idx; -memcpy (&val, p,sizeof (val)); + val =syscall_arg__val (&arg, arg.idx);/* * Suppress this argument if its value is zero and
@@ -1431,9 +1442,7 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,int i =0 ;while (i <6 ) { -/* special care for unaligned accesses */ - p = args +sizeof (unsigned long ) * i; -memcpy (&val, p,sizeof (val)); + val =__syscall_arg__val (args, i); printed +=scnprintf (bf + printed, size - printed,"%sarg%d: %ld" , printed ?", " :"" , i, val);
tools/perf/trace/beauty/beauty.h +13 -0
@@ -6,8 +6,19 @@struct trace ;struct thread ; +/** +* @val: value of syscall argument being formatted +* @args: All the args, use syscall_args__val(arg, nth) to access one +* @thread: tid state (maps, pid, tid, etc) +* @trace: 'perf trace' internals: all threads, etc +* @parm: private area, may be an strarray, for instance +* @idx: syscall arg idx (is this the first?) +* @mask: a syscall arg may mask another arg, see syscall_arg__scnprintf_futex_op +*/ +struct syscall_arg {unsigned long val; +unsigned char *args;struct thread *thread;struct trace *trace;void *parm;
@@ -15,6 +26,8 @@ struct syscall_arg {u8 mask; }; +unsigned long syscall_arg__val (struct syscall_arg *arg,u8 idx); +size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 10/86 perf trace beauty: Export the "int" and "hex" syscall arg formatters
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The most basic ones, for pointers, unaugmented fds, etc, to be used in the initial fcntl 'arg' beautifier.
--- tools/perf/builtin-trace.c | 10 ++-------- tools/perf/trace/beauty/beauty.h | 6 ++++++ 2 files changed, 8 insertions(+), 8 deletions(-)
tools/perf/builtin-trace.c +2 -8
@@ -392,22 +392,16 @@ static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd -static size_t syscall_arg__scnprintf_hex (char *bf,size_t size, -struct syscall_arg *arg) +size_t syscall_arg__scnprintf_hex (char *bf,size_t size,struct syscall_arg *arg) {return scnprintf (bf, size,"%#lx" , arg->val); } -#define SCA_HEX syscall_arg__scnprintf_hex - -static size_t syscall_arg__scnprintf_int (char *bf,size_t size, -struct syscall_arg *arg) +size_t syscall_arg__scnprintf_int (char *bf,size_t size,struct syscall_arg *arg) {return scnprintf (bf, size,"%d" , arg->val); } -#define SCA_INT syscall_arg__scnprintf_int -static const char *bpf_cmd[] = {"MAP_CREATE" ,"MAP_LOOKUP_ELEM" ,"MAP_UPDATE_ELEM" ,"MAP_DELETE_ELEM" ,"MAP_GET_NEXT_KEY" ,"PROG_LOAD" ,
tools/perf/trace/beauty/beauty.h +6 -0
@@ -31,6 +31,12 @@ unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx);size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays +size_t syscall_arg__scnprintf_hex (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_HEX syscall_arg__scnprintf_hex + +size_t syscall_arg__scnprintf_int (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_INT syscall_arg__scnprintf_int +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg);#define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 11/86 perf trace beauty: Introduce syscall arg beautifier for long integers
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Will be used in the fcntl arg beautifier, that nowadays formats as '%ld' because there is no explicit arg beautifier attached, but as we will have to first decide what beautifier to use (i.e. it may be a pointer, etc) then we need to have this exported as a separate beautifier to be called from there.
--- tools/perf/builtin-trace.c | 5 +++++ tools/perf/trace/beauty/beauty.h | 3 +++ 2 files changed, 8 insertions(+)
tools/perf/builtin-trace.c +5 -0
@@ -402,6 +402,11 @@ size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *argreturn scnprintf (bf, size,"%d" , arg->val); } +size_t syscall_arg__scnprintf_long (char *bf,size_t size,struct syscall_arg *arg) +{ +return scnprintf (bf, size,"%ld" , arg->val); +} +static const char *bpf_cmd[] = {"MAP_CREATE" ,"MAP_LOOKUP_ELEM" ,"MAP_UPDATE_ELEM" ,"MAP_DELETE_ELEM" ,"MAP_GET_NEXT_KEY" ,"PROG_LOAD" ,
tools/perf/trace/beauty/beauty.h +3 -0
@@ -37,6 +37,9 @@ size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *argsize_t syscall_arg__scnprintf_int (char *bf,size_t size,struct syscall_arg *arg);#define SCA_INT syscall_arg__scnprintf_int +size_t syscall_arg__scnprintf_long (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_LONG syscall_arg__scnprintf_long +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg);#define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 12/86 tools include uapi asm-generic: Grab a copy of fcntl.h
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We'll need defines for beautifying fcntl arguments that are not available in older distros, these:
trace/beauty/fcntl.c: In function 'syscall_arg__scnprintf_fcntl_arg':
trace/beauty/fcntl.c:93: error: 'F_OFD_SETLK' undeclared (first use in this function) trace/beauty/fcntl.c:93: error: (Each undeclared identifier is reported only once trace/beauty/fcntl.c:93: error: for each function it appears in.) trace/beauty/fcntl.c:93: error: 'F_OFD_SETLKW' undeclared (first use in this function) trace/beauty/fcntl.c:93: error: 'F_OFD_GETLK' undeclared (first use in this function) trace/beauty/fcntl.c:94: error: 'F_GETOWN_EX' undeclared (first use in this function) trace/beauty/fcntl.c:94: error: 'F_SETOWN_EX' undeclared (first use in this function)
--- tools/include/uapi/asm-generic/fcntl.h | 220 +++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 tools/include/uapi/asm-generic/fcntl.h
tools/include/uapi/asm-generic/fcntl.h new file +220 -0
@@ -0,0 +1,220 @@ +#ifndef _ASM_GENERIC_FCNTL_H +#define _ASM_GENERIC_FCNTL_H + +#include <linux/types.h> + +/* + * FMODE_EXEC is 0x20 + * FMODE_NONOTIFY is 0x4000000 + * These cannot be used by userspace O_* until internal and external open + * flags are split. + * -Eric Paris + */ + +/* + * When introducing new O_* bits, please check its uniqueness in fcntl_init(). + */ + +#define O_ACCMODE 00000003 +#define O_RDONLY 00000000 +#define O_WRONLY 00000001 +#define O_RDWR 00000002 +#ifndef O_CREAT +#define O_CREAT 00000100 /* not fcntl */ +#endif +#ifndef O_EXCL +#define O_EXCL 00000200 /* not fcntl */ +#endif +#ifndef O_NOCTTY +#define O_NOCTTY 00000400 /* not fcntl */ +#endif +#ifndef O_TRUNC +#define O_TRUNC 00001000 /* not fcntl */ +#endif +#ifndef O_APPEND +#define O_APPEND 00002000 +#endif +#ifndef O_NONBLOCK +#define O_NONBLOCK 00004000 +#endif +#ifndef O_DSYNC +#define O_DSYNC 00010000 /* used to be O_SYNC, see below */ +#endif +#ifndef FASYNC +#define FASYNC 00020000 /* fcntl, for BSD compatibility */ +#endif +#ifndef O_DIRECT +#define O_DIRECT 00040000 /* direct disk access hint */ +#endif +#ifndef O_LARGEFILE +#define O_LARGEFILE 00100000 +#endif +#ifndef O_DIRECTORY +#define O_DIRECTORY 00200000 /* must be a directory */ +#endif +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 00400000 /* don't follow links */ +#endif +#ifndef O_NOATIME +#define O_NOATIME 01000000 +#endif +#ifndef O_CLOEXEC +#define O_CLOEXEC 02000000 /* set close_on_exec */ +#endif + +/* + * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using + * the O_SYNC flag. We continue to use the existing numerical value + * for O_DSYNC semantics now, but using the correct symbolic name for it. + * This new value is used to request true Posix O_SYNC semantics. It is + * defined in this strange way to make sure applications compiled against + * new headers get at least O_DSYNC semantics on older kernels. + * + * This has the nice side-effect that we can simply test for O_DSYNC + * wherever we do not care if O_DSYNC or O_SYNC is used. + * + * Note: __O_SYNC must never be used directly. + */ +#ifndef O_SYNC +#define __O_SYNC 04000000 +#define O_SYNC (__O_SYNC|O_DSYNC) +#endif + +#ifndef O_PATH +#define O_PATH 010000000 +#endif + +#ifndef __O_TMPFILE +#define __O_TMPFILE 020000000 +#endif + +/* a horrid kludge trying to make sure that this will fail on old kernels */ +#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) +#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT) + +#ifndef O_NDELAY +#define O_NDELAY O_NONBLOCK +#endif + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get close_on_exec */ +#define F_SETFD 2 /* set/clear close_on_exec */ +#define F_GETFL 3 /* get file->f_flags */ +#define F_SETFL 4 /* set file->f_flags */ +#ifndef F_GETLK +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 +#endif +#ifndef F_SETOWN +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ +#endif +#ifndef F_SETSIG +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ +#endif + +#ifndef CONFIG_64BIT +#ifndef F_GETLK64 +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 +#endif +#endif + +#ifndef F_SETOWN_EX +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 +#endif + +#ifndef F_GETOWNER_UIDS +#define F_GETOWNER_UIDS 17 +#endif + +/* + * Open File Description Locks + * + * Usually record locks held by a process are released on *any* close and are + * not inherited across a fork(). + * + * These cmd values will set locks that conflict with process-associated + * record locks, but are "owned" by the open file description, not the + * process. This means that they are inherited across fork() like BSD (flock) + * locks, and they are only released automatically when the last reference to + * the the open file against which they were acquired is put. + */ +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_OWNER_TID 0 +#define F_OWNER_PID 1 +#define F_OWNER_PGRP 2 + +struct f_owner_ex { + int type; + __kernel_pid_t pid; +}; + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#ifndef F_RDLCK +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 +#endif + +/* for old implementation of bsd flock () */ +#ifndef F_EXLCK +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ +#endif + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +#define LOCK_MAND 32 /* This is a mandatory flock ... */ +#define LOCK_READ 64 /* which allows concurrent read operations */ +#define LOCK_WRITE 128 /* which allows concurrent write operations */ +#define LOCK_RW 192 /* which allows concurrent read & write ops */ + +#define F_LINUX_SPECIFIC_BASE 1024 + +#ifndef HAVE_ARCH_STRUCT_FLOCK +#ifndef __ARCH_FLOCK_PAD +#define __ARCH_FLOCK_PAD +#endif + +struct flock { + short l_type; + short l_whence; + __kernel_off_t l_start; + __kernel_off_t l_len; + __kernel_pid_t l_pid; + __ARCH_FLOCK_PAD +}; +#endif + +#ifndef HAVE_ARCH_STRUCT_FLOCK64 +#ifndef __ARCH_FLOCK64_PAD +#define __ARCH_FLOCK64_PAD +#endif + +struct flock64 { + short l_type; + short l_whence; + __kernel_loff_t l_start; + __kernel_loff_t l_len; + __kernel_pid_t l_pid; + __ARCH_FLOCK64_PAD +}; +#endif + +#endif /* _ASM_GENERIC_FCNTL_H */
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 13/86 perf trace beauty fcntl: Basic 'arg' beautifier
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Sometimes it should be printed as an hex number, like with F_SETLK, F_SETLKW and F_GETLK, that treat 'arg' as a struct flock pointer, in other cases it is just an integer.
--- tools/perf/builtin-trace.c | 3 ++- tools/perf/trace/beauty/beauty.h | 3 +++ tools/perf/trace/beauty/fcntl.c | 18 ++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-)
tools/perf/builtin-trace.c +2 -1
@@ -660,7 +660,8 @@ static struct syscall_fmt { { .name = "fchownat", .errmsg = true, .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, { .name = "fcntl", .errmsg = true, - .arg_scnprintf = { [1] = SCA_FCNTL_CMD, /* cmd */ }, + .arg_scnprintf = { [1] = SCA_FCNTL_CMD, /* cmd */ + [2] = SCA_FCNTL_ARG, /* arg */ }, .arg_parm = { [1] = &strarrays__fcntl_cmds_arrays, /* cmd */ }, }, { .name = "fdatasync", .errmsg = true, }, { .name = "flock", .errmsg = true,
tools/perf/trace/beauty/beauty.h +3 -0
@@ -43,6 +43,9 @@ size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arsize_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg);#define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd +size_t syscall_arg__scnprintf_fcntl_arg (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_FCNTL_ARG syscall_arg__scnprintf_fcntl_arg +size_t syscall_arg__scnprintf_statx_flags (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
tools/perf/trace/beauty/fcntl.c +18 -0
@@ -21,3 +21,21 @@ size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arreturn syscall_arg__scnprintf_strarrays (bf, size, arg); } + +size_t syscall_arg__scnprintf_fcntl_arg (char *bf,size_t size,struct syscall_arg *arg) +{ +int cmd =syscall_arg__val (arg,1 ); + +/* +* We still don't grab the contents of pointers on entry or exit, +* so just print them as hex numbers +*/ +if (cmd ==F_SETLK || cmd ==F_SETLKW || cmd ==F_GETLK || + cmd ==F_OFD_SETLK || cmd ==F_OFD_SETLKW || cmd ==F_OFD_GETLK || + cmd ==F_GETOWN_EX || cmd ==F_SETOWN_EX || + cmd ==F_GET_RW_HINT || cmd ==F_SET_RW_HINT || + cmd ==F_GET_FILE_RW_HINT || cmd ==F_SET_FILE_RW_HINT ) +return syscall_arg__scnprintf_hex (bf, size, arg); + +return syscall_arg__scnprintf_long (bf, size, arg); +}
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 14/86 perf trace: Beautify new write hint fcntl commands
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Those introduced by the commit c75b1d9421f8 ("fs: add fcntl() interface for setting/getting write life time hints"), tested using the proggie in that commit comment:
# perf trace -e fcntl ./write_hint write_hint.c
fcntl: F_GET_RW_HINT: Invalid argument
0.000 ( 0.006 ms): write_hint/7576 fcntl(fd: 3, cmd: GET_RW_HINT, arg: 0x7ffc6c918da0) = -1 EINVAL Invalid argument
0.014 ( 0.004 ms): write_hint/7576 fcntl(fd: 4, cmd: GETFL) = 33794
# perf trace -e fcntl ./write_hint write_hint.c 1
fcntl: F_SET_RW_HINT: Invalid argument
0.000 ( 0.007 ms): write_hint/7578 fcntl(fd: 3, cmd: SET_RW_HINT, arg: 0x7fff03866d70) = -1 EINVAL Invalid argument
0.019 ( 0.002 ms): write_hint/7578 fcntl(fd: 4, cmd: GETFL) = 33794
#--- tools/perf/builtin-trace.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/builtin-trace.c +1 -0
@@ -449,6 +449,7 @@ static DEFINE_STRARRAY(fcntl_cmds);static const char *fcntl_linux_specific_cmds[] = {"SETLEASE" ,"GETLEASE" ,"NOTIFY" , [5 ] ="CANCELLK" ,"DUPFD_CLOEXEC" ,"SETPIPE_SZ" ,"GETPIPE_SZ" ,"ADD_SEALS" ,"GET_SEALS" , +"GET_RW_HINT" ,"SET_RW_HINT" ,"GET_FILE_RW_HINT" ,"SET_FILE_RW_HINT" , }; static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 15/86 perf beauty open: Detach the syscall_arg agnostic bits from the flags formatter
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We may want to use this in other contexts, like when formatting the return of fcntl(fd, F_GETFL).
Make it have the following signature, so that we can set the formatter for the return argument while processing the arguments of a syscall, as fcntl, for instance, may return fds, flags, etc, so need different return value formatters:
size_t formatter(unsigned long value, char *bf, size_t size);
This gets so detached from 'perf trace' internals that we may well get all these and move to a tools/lib/syscall_beauty/ library at some point and use it in other tools/ living utilities.
--- tools/perf/trace/beauty/beauty.h | 2 ++ tools/perf/trace/beauty/open_flags.c | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-)
tools/perf/trace/beauty/beauty.h +2 -0
@@ -52,4 +52,6 @@ size_t syscall_arg__scnprintf_statx_flags(char *bf, size_t size, struct syscall_size_t syscall_arg__scnprintf_statx_mask (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STATX_MASK syscall_arg__scnprintf_statx_mask +size_t open__scnprintf_flags (unsigned long flags,char *bf,size_t size); +#endif /* _PERF_TRACE_BEAUTY_H */
tools/perf/trace/beauty/open_flags.c +13 -6
@@ -14,13 +14,9 @@#define O_NOATIME 01000000#endif -static size_t syscall_arg__scnprintf_open_flags (char *bf,size_t size, -struct syscall_arg *arg) +size_t open__scnprintf_flags (unsigned long flags,char *bf,size_t size) { -int printed =0 , flags = arg->val; - -if (!(flags &O_CREAT )) - arg->mask |=1 << (arg->idx +1 );/* Mask the mode parm */ +int printed =0 ;if (flags ==0 )return scnprintf (bf, size,"RDONLY" );
@@ -68,4 +64,15 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,return printed; } +static size_t syscall_arg__scnprintf_open_flags (char *bf,size_t size,struct syscall_arg *arg) +{ +int flags = arg->val; + +if (!(flags &O_CREAT )) + arg->mask |=1 << (arg->idx +1 );/* Mask the mode parm */ + +return open__scnprintf_flags (flags, bf, size); +} + +#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 16/86 perf trace: Allow syscall_arg beautifiers to set a different return formatter
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Things like fcntl will use this to set the right formatter based on its 'cmd' argument.
--- tools/perf/builtin-trace.c | 27 ++++++++++++++++++++++++++- tools/perf/trace/beauty/beauty.h | 3 +++ 2 files changed, 29 insertions(+), 1 deletion(-)
tools/perf/builtin-trace.c +26 -1
@@ -908,6 +908,8 @@ static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)* filename.ptr: The filename char pointer that will be vfs_getname'd * filename.entry_str_pos: Where to insert the string translated from * filename.ptr by the vfs_getname tracepoint/kprobe. +* ret_scnprintf: syscall args may set this to a different syscall return +* formatter, for instance, fcntl may return fds, file flags, etc. */ struct thread_trace {u64 entry_time;
@@ -916,6 +918,7 @@ struct thread_trace {unsigned long pfmaj, pfmin;char *entry_str;double runtime_ms; +size_t (*ret_scnprintf)(unsigned long value,char *bf,size_t size);struct {unsigned long ptr;short int entry_str_pos;
@@ -966,6 +969,15 @@ static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)return NULL ; } + +void syscall_arg__set_ret_scnprintf (struct syscall_arg *arg, +size_t (*ret_scnprintf)(unsigned long val,char *bf,size_t size)) +{ +struct thread_trace *ttrace =thread__priv (arg->thread); + + ttrace->ret_scnprintf = ret_scnprintf; +} +#define TRACE_PFMAJ (1 << 0)#define TRACE_PFMIN (1 << 1)
@@ -1390,6 +1402,14 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, {size_t printed =0 ;unsigned long val; +struct thread_trace *ttrace =thread__priv (thread); + +/* +* Things like fcntl will set this in its 'cmd' formatter to pick the +* right formatter for the return value (an fd? file flags?), which is +* not needed for syscalls that always return a given type, say an fd. +*/ + ttrace->ret_scnprintf =NULL ;if (sc->args !=NULL ) {struct format_field *field;
@@ -1704,7 +1724,12 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,fprintf (trace->output,") = -1 %s %s" , e, emsg); }else if (ret ==0 && sc->fmt->timeout)fprintf (trace->output,") = 0 Timeout" ); -else if (sc->fmt->hexret) +else if (ttrace->ret_scnprintf) { +char bf[1024 ]; + ttrace->ret_scnprintf (ret, bf,sizeof (bf)); + ttrace->ret_scnprintf =NULL ; +fprintf (trace->output,") = %s" , bf); + }else if (sc->fmt->hexret)fprintf (trace->output,") = %#lx" , ret);else if (sc->fmt->errpid) {struct thread *child =machine__find_thread (trace->host, ret, ret);
tools/perf/trace/beauty/beauty.h +3 -0
@@ -54,4 +54,7 @@ size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_asize_t open__scnprintf_flags (unsigned long flags,char *bf,size_t size); +void syscall_arg__set_ret_scnprintf (struct syscall_arg *arg, +size_t (*ret_scnprintf)(unsigned long val,char *bf,size_t size)); +#endif /* _PERF_TRACE_BEAUTY_H */
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 17/86 perf trace beauty open flags: Support O_TMPFILE and O_NOFOLLOW
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The open syscall flags beautifier wasn't considering those flags, fix it.
--- tools/perf/trace/beauty/open_flags.c | 6 ++++++ 1 file changed, 6 insertions(+)
tools/perf/trace/beauty/open_flags.c +6 -0
@@ -14,6 +14,10 @@#define O_NOATIME 01000000#endif +#ifndef O_TMPFILE +#define O_TMPFILE 020000000 +#endif +size_t open__scnprintf_flags (unsigned long flags,char *bf,size_t size) {int printed =0 ;
@@ -34,6 +38,8 @@ size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size)P_FLAG (DIRECTORY );P_FLAG (EXCL );P_FLAG (LARGEFILE ); +P_FLAG (NOFOLLOW ); +P_FLAG (TMPFILE );P_FLAG (NOATIME );P_FLAG (NOCTTY );#ifdef O_NONBLOCK
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 18/86 perf trace beauty open flags: Do not depend on the system's O_LARGEFILE define
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
In x86_64 /usr/include/bits/fcntl.h sets it to zero, so just undef it and use the standard 00100000 value when decoding the open flags arg.
--- tools/perf/trace/beauty/open_flags.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/trace/beauty/open_flags.c +3 -0
@@ -18,6 +18,9 @@#define O_TMPFILE 020000000#endif +#undef O_LARGEFILE +#define O_LARGEFILE 00100000 +size_t open__scnprintf_flags (unsigned long flags,char *bf,size_t size) {int printed =0 ;
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 19/86 perf trace beauty fcntl: Beautify F_GETFL return value
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The return for fcntl(fd, F_GETFL) is the fd file flags, so reuse the one for the open syscall flags parameter:
997.992 (0.002 ms): Chrome_IOThrea/19863 fcntl(fd: 144</dev/shm/.com.google.Chrome.OhA8YL>, cmd: GETFL) = RDWR|LARGEFILE
--- tools/perf/trace/beauty/fcntl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/perf/trace/beauty/fcntl.c +8 -2
@@ -11,13 +11,19 @@size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg) { +if (arg->val ==F_GETFL ) { +syscall_arg__set_ret_scnprintf (arg, open__scnprintf_flags); + goto mask_arg; + }/* * Some commands ignore the third fcntl argument, "arg", so mask it */ -if (arg->val ==F_GETFD || arg->val ==F_GETFL || +if (arg->val ==F_GETFD || arg->val ==F_GETOWN || arg->val ==F_GET_SEALS || - arg->val ==F_GETLEASE || arg->val ==F_GETSIG ) + arg->val ==F_GETLEASE || arg->val ==F_GETSIG ) { +mask_arg: arg->mask |= (1 <<2 ); + }return syscall_arg__scnprintf_strarrays (bf, size, arg); }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 20/86 perf trace beauty open flags: Move RDRW to the start of the output
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We were getting:
62597.859 ( 0.005 ms): TaskSchedulerF/18107 fcntl(fd: 194, cmd: GETFL) = LARGEFILE|RDWR
Instead of the more familiar (from looking at strace output):
62597.859 ( 0.005 ms): TaskSchedulerF/18107 fcntl(fd: 194, cmd: GETFL) = RDWR|LARGEFILE
Fix it.
--- tools/perf/trace/beauty/open_flags.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/trace/beauty/open_flags.c +1 -1
@@ -33,6 +33,7 @@ size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size) flags &= ~O_##n; \ } +P_FLAG (RDWR );P_FLAG (APPEND );P_FLAG (ASYNC );P_FLAG (CLOEXEC );
@@ -53,7 +54,6 @@ size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size)#ifdef O_PATH P_FLAG (PATH );#endif -P_FLAG (RDWR );#ifdef O_DSYNC if ((flags &O_SYNC ) ==O_SYNC ) printed +=scnprintf (bf + printed, size - printed,"%s%s" , printed ?"|" :"" ,"SYNC" );
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 21/86 perf trace beauty fcntl flags: Beautify F_SETFL arg
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Result:
0.011 (0.001 ms): Chrome_IOThrea/19863 fcntl(fd: 130</dev/shm/.com.google.Chrome.w5UBtZ (deleted)>, cmd: SETFL, arg: RDWR|APPEND|LARGEFILE) = 0
--- tools/perf/trace/beauty/fcntl.c | 2 ++ 1 file changed, 2 insertions(+)
tools/perf/trace/beauty/fcntl.c +2 -0
@@ -32,6 +32,8 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_ar {int cmd =syscall_arg__val (arg,1 ); +if (cmd ==F_SETFL ) +return open__scnprintf_flags (arg->val, bf, size);/* * We still don't grab the contents of pointers on entry or exit, * so just print them as hex numbers
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 22/86 perf trace beauty fcntl: Beautify F_[GS]ETFD arg/return value
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Now it will show 0 or CLOEXEC, the only !0 value returned by the kernel for fcntl(fd, F_GETFD).
And for F_SETFD:
6870.267 ( 0.004 ms): make/29812 fcntl(fd: 7</home/acme/git/linux/tools/build/Build.include>, cmd: SETFD, arg: CLOEXEC) = 0 6873.805 ( 0.002 ms): make/29816 fcntl(fd: 6</home/acme/git/linux/tools/build/Makefile.build>, cmd: SETFD, arg: CLOEXEC) = 0
<SNIP>
77986.150 ( 0.006 ms): alsa-sink-ALC3/2042 fcntl(fd: 45</dev/snd/pcmC1D0p>, cmd: SETFD, arg: CLOEXEC) = 0 77986.271 ( 0.006 ms): alsa-sink-ALC3/2042 fcntl(fd: 23</dev/snd/controlC1>, cmd: SETFD, arg: CLOEXEC) = 0
--- tools/perf/trace/beauty/fcntl.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
tools/perf/trace/beauty/fcntl.c +14 -2
@@ -7,19 +7,28 @@*/ #include "trace/beauty/beauty.h" +#include <linux/kernel.h> #include <uapi/linux/fcntl.h> +static size_t fcntl__scnprintf_getfd (unsigned long val,char *bf,size_t size) +{ +return scnprintf (bf, size,"%s" , val ?"CLOEXEC" :"0" ); +} +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg) {if (arg->val ==F_GETFL ) {syscall_arg__set_ret_scnprintf (arg, open__scnprintf_flags); goto mask_arg; } +if (arg->val ==F_GETFD ) { +syscall_arg__set_ret_scnprintf (arg, fcntl__scnprintf_getfd); + goto mask_arg; + }/* * Some commands ignore the third fcntl argument, "arg", so mask it */ -if (arg->val ==F_GETFD || - arg->val ==F_GETOWN || arg->val ==F_GET_SEALS || +if (arg->val ==F_GETOWN || arg->val ==F_GET_SEALS || arg->val ==F_GETLEASE || arg->val ==F_GETSIG ) { mask_arg: arg->mask |= (1 <<2 );
@@ -32,6 +41,9 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_ar {int cmd =syscall_arg__val (arg,1 ); +if (cmd ==F_SETFD ) +return fcntl__scnprintf_getfd (arg->val, bf, size); +if (cmd ==F_SETFL )return open__scnprintf_flags (arg->val, bf, size);/*
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 23/86 perf trace beauty: Give syscall return beautifier more context
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We need the current thread and the trace internal state so that we can use the fd beautifier to augment syscall returns, so use struct syscall_arg with some fields that make sense on returns (val, thread, trace).
--- tools/perf/builtin-trace.c | 11 ++++++++--- tools/perf/trace/beauty/beauty.h | 5 ++++- tools/perf/trace/beauty/fcntl.c | 9 +++++++-- tools/perf/trace/beauty/open_flags.c | 5 +---- 4 files changed, 20 insertions(+), 10 deletions(-)
tools/perf/builtin-trace.c +8 -3
@@ -918,7 +918,7 @@ struct thread_trace {unsigned long pfmaj, pfmin;char *entry_str;double runtime_ms; -size_t (*ret_scnprintf)(unsigned long value,char *bf,size_t size); +size_t (*ret_scnprintf)(char *bf,size_t size,struct syscall_arg *arg);struct {unsigned long ptr;short int entry_str_pos;
@@ -971,7 +971,7 @@ static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)void syscall_arg__set_ret_scnprintf (struct syscall_arg *arg, -size_t (*ret_scnprintf)(unsigned long val,char *bf,size_t size)) +size_t (*ret_scnprintf)(char *bf,size_t size,struct syscall_arg *arg)) {struct thread_trace *ttrace =thread__priv (arg->thread);
@@ -1726,7 +1726,12 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,fprintf (trace->output,") = 0 Timeout" ); else if (ttrace->ret_scnprintf) {char bf[1024 ]; - ttrace->ret_scnprintf (ret, bf,sizeof (bf)); +struct syscall_arg arg = { + .val = ret, + .thread = thread, + .trace = trace, + }; + ttrace->ret_scnprintf (bf,sizeof (bf), &arg); ttrace->ret_scnprintf =NULL ;fprintf (trace->output,") = %s" , bf); } else if (sc->fmt->hexret)
tools/perf/trace/beauty/beauty.h +4 -1
@@ -46,6 +46,9 @@ size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arsize_t syscall_arg__scnprintf_fcntl_arg (char *bf,size_t size,struct syscall_arg *arg);#define SCA_FCNTL_ARG syscall_arg__scnprintf_fcntl_arg +size_t syscall_arg__scnprintf_open_flags (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags +size_t syscall_arg__scnprintf_statx_flags (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STATX_FLAGS syscall_arg__scnprintf_statx_flags
@@ -55,6 +58,6 @@ size_t syscall_arg__scnprintf_statx_mask(char *bf, size_t size, struct syscall_asize_t open__scnprintf_flags (unsigned long flags,char *bf,size_t size);void syscall_arg__set_ret_scnprintf (struct syscall_arg *arg, -size_t (*ret_scnprintf)(unsigned long val,char *bf,size_t size)); +size_t (*ret_scnprintf)(char *bf,size_t size,struct syscall_arg *arg));#endif /* _PERF_TRACE_BEAUTY_H */
tools/perf/trace/beauty/fcntl.c +7 -2
@@ -15,14 +15,19 @@ static size_t fcntl__scnprintf_getfd(unsigned long val, char *bf, size_t size)return scnprintf (bf, size,"%s" , val ?"CLOEXEC" :"0" ); } +static size_t syscall_arg__scnprintf_fcntl_getfd (char *bf,size_t size,struct syscall_arg *arg) +{ +return fcntl__scnprintf_getfd (arg->val, bf, size); +} +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg) {if (arg->val ==F_GETFL ) { -syscall_arg__set_ret_scnprintf (arg, open__scnprintf_flags); +syscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_open_flags); goto mask_arg; }if (arg->val ==F_GETFD ) { -syscall_arg__set_ret_scnprintf (arg, fcntl__scnprintf_getfd); +syscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_fcntl_getfd); goto mask_arg; }/*
tools/perf/trace/beauty/open_flags.c +1 -4
@@ -73,7 +73,7 @@ size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size)return printed; } -static size_t syscall_arg__scnprintf_open_flags (char *bf,size_t size,struct syscall_arg *arg) +size_t syscall_arg__scnprintf_open_flags (char *bf,size_t size,struct syscall_arg *arg) {int flags = arg->val;
@@ -82,6 +82,3 @@ static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, struct syreturn open__scnprintf_flags (flags, bf, size); } - - -#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 24/86 perf trace beauty: Export the fd beautifier for use in more places
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Now that the beautifiers are being split into multiple source and object files, we will need more of them exported, do it for the 'fd' one, will be used to augment the return of some syscalls that may return an 'fd', such as fcntl(fd, F_DUPFD).
--- tools/perf/builtin-trace.c | 8 +------- tools/perf/trace/beauty/beauty.h | 3 +++ 2 files changed, 4 insertions(+), 7 deletions(-)
tools/perf/builtin-trace.c +1 -7
@@ -365,11 +365,6 @@ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray#endif /* defined(__i386__) || defined(__x86_64__) */ -static size_t syscall_arg__scnprintf_fd (char *bf,size_t size, -struct syscall_arg *arg); - -#define SCA_FD syscall_arg__scnprintf_fd -#ifndef AT_FDCWD #define AT_FDCWD -100#endif
@@ -1057,8 +1052,7 @@ static const char *thread__fd_path(struct thread *thread, int fd,return ttrace->paths.table[fd]; } -static size_t syscall_arg__scnprintf_fd (char *bf,size_t size, -struct syscall_arg *arg) +size_t syscall_arg__scnprintf_fd (char *bf,size_t size,struct syscall_arg *arg) {int fd = arg->val;size_t printed =scnprintf (bf, size,"%d" , fd);
tools/perf/trace/beauty/beauty.h +3 -0
@@ -31,6 +31,9 @@ unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx);size_t syscall_arg__scnprintf_strarrays (char *bf,size_t size,struct syscall_arg *arg);#define SCA_STRARRAYS syscall_arg__scnprintf_strarrays +size_t syscall_arg__scnprintf_fd (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_FD syscall_arg__scnprintf_fd +size_t syscall_arg__scnprintf_hex (char *bf,size_t size,struct syscall_arg *arg);#define SCA_HEX syscall_arg__scnprintf_hex
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 25/86 perf trace beauty fcntl: Augment the return of F_DUPFD(_CLOEXEC)
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Using the existing 'fd' beautifier, now we can see the path for the just dup'ed fd:
18031.338 ( 0.009 ms): gnome-terminal/2472 fcntl(fd: 55, cmd: DUPFD_CLOEXEC) = 56</memfd:gdk-wayland (deleted)>
--- tools/perf/trace/beauty/fcntl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/perf/trace/beauty/fcntl.c +5 -1
@@ -30,6 +30,10 @@ size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arsyscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_fcntl_getfd); goto mask_arg; } +if (arg->val ==F_DUPFD_CLOEXEC || arg->val ==F_DUPFD ) { +syscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_fd); + goto out; + }/* * Some commands ignore the third fcntl argument, "arg", so mask it */
@@ -38,7 +42,7 @@ size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_ar mask_arg: arg->mask |= (1 <<2 ); } - +out:return syscall_arg__scnprintf_strarrays (bf, size, arg); }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 26/86 perf trace beauty: Export the pid beautifier for use in more places
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Now that the beautifiers are being split into multiple source and object files, we will need more of them exported, do it for the 'pid' one, will be used to augment the return of some syscalls that may return a 'pid', such as fcntl(fd, F_GETOWN).
Will also be used for fcntl(fd, F_SETOWN, pid).
--- tools/perf/trace/beauty/beauty.h | 3 +++ tools/perf/trace/beauty/pid.c | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-)
tools/perf/trace/beauty/beauty.h +3 -0
@@ -43,6 +43,9 @@ size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *argsize_t syscall_arg__scnprintf_long (char *bf,size_t size,struct syscall_arg *arg);#define SCA_LONG syscall_arg__scnprintf_long +size_t syscall_arg__scnprintf_pid (char *bf,size_t size,struct syscall_arg *arg); +#define SCA_PID syscall_arg__scnprintf_pid +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg);#define SCA_FCNTL_CMD syscall_arg__scnprintf_fcntl_cmd
tools/perf/trace/beauty/pid.c +1 -3
@@ -1,4 +1,4 @@ -static size_t syscall_arg__scnprintf_pid (char *bf,size_t size,struct syscall_arg *arg) +size_t syscall_arg__scnprintf_pid (char *bf,size_t size,struct syscall_arg *arg) {int pid = arg->val;struct trace *trace = arg->trace;
@@ -17,5 +17,3 @@ static size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_areturn printed; } - -#define SCA_PID syscall_arg__scnprintf_pid
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 27/86 perf trace beauty fcntl: Beautify F_GETOWN and F_SETOWN
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
By attaching the pid beautifier to the args in the F_SETOWN case and to the syscall return on the F_GETOWN one.
--- tools/perf/trace/beauty/fcntl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
tools/perf/trace/beauty/fcntl.c +8 -1
@@ -34,10 +34,14 @@ size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arsyscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_fd); goto out; } +if (arg->val ==F_GETOWN ) { +syscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_pid); + goto mask_arg; + }/* * Some commands ignore the third fcntl argument, "arg", so mask it */ -if (arg->val ==F_GETOWN || arg->val ==F_GET_SEALS || +if (arg->val ==F_GET_SEALS || arg->val ==F_GETLEASE || arg->val ==F_GETSIG ) { mask_arg: arg->mask |= (1 <<2 );
@@ -55,6 +59,9 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_arif (cmd ==F_SETFL )return open__scnprintf_flags (arg->val, bf, size); + +if (cmd ==F_SETOWN ) +return syscall_arg__scnprintf_pid (bf, size, arg);/* * We still don't grab the contents of pointers on entry or exit, * so just print them as hex numbers
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 28/86 perf pmu-events: Support additional POWER8+ PVR in mapfile
In reply to Arnaldo Carvalho de MeloFrom: Shriya <[email protected]>
Add support for POWER8+ PVR 004c0100 for Garrison
--- tools/perf/pmu-events/arch/powerpc/mapfile.csv | 1 + 1 file changed, 1 insertion(+)
tools/perf/pmu-events/arch/powerpc/mapfile.csv +1 -0
@@ -19,3 +19,4 @@ 004d0000,1,power8.json,core 004d0100,1,power8.json,core 004d0200,1,power8.json,core +004c0100,1,power8.json,core
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 29/86 perf vendor events: Add POWER9 PMU events
In reply to Arnaldo Carvalho de MeloFrom: Sukadev Bhattiprolu <[email protected]>
Add POWER9 PMU events.
--- .../perf/pmu-events/arch/powerpc/power9/cache.json | 176 +++++ .../arch/powerpc/power9/floating-point.json | 44 ++ .../pmu-events/arch/powerpc/power9/frontend.json | 446 +++++++++++ .../pmu-events/arch/powerpc/power9/marked.json | 782 +++++++++++++++++++ .../pmu-events/arch/powerpc/power9/memory.json | 158 ++++ .../perf/pmu-events/arch/powerpc/power9/other.json | 836 +++++++++++++++++++++ .../pmu-events/arch/powerpc/power9/pipeline.json | 680 +++++++++++++++++ tools/perf/pmu-events/arch/powerpc/power9/pmc.json | 146 ++++ .../arch/powerpc/power9/translation.json | 272 +++++++ 9 files changed, 3540 insertions(+) create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/cache.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/floating-point.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/frontend.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/marked.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/memory.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/other.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/pipeline.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/pmc.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/translation.json
tools/perf/pmu-events/arch/powerpc/power9/cache.json new file +176 -0
@@ -0,0 +1,176 @@ +[ + {, + "EventCode": "0x1002A", + "EventName": "PM_CMPLU_STALL_LARX", + "BriefDescription": "Finish stall because the NTF instruction was a larx waiting to be satisfied", + "PublicDescription": "" + }, + {, + "EventCode": "0x1003C", + "EventName": "PM_CMPLU_STALL_DMISS_L2L3", + "BriefDescription": "Completion stall by Dcache miss which resolved in L2/L3", + "PublicDescription": "" + }, + {, + "EventCode": "0x14048", + "EventName": "PM_INST_FROM_ON_CHIP_CACHE", + "BriefDescription": "The processor's Instruction cache was reloaded either shared or modified data from another core's L2/L3 on the same chip due to an instruction fetch (not prefetch)", + "PublicDescription": "" + }, + {, + "EventCode": "0x3E054", + "EventName": "PM_LD_MISS_L1", + "BriefDescription": "Load Missed L1, counted at execution time (can be greater than loads finished). LMQ merges are not included in this count. i.e. if a load instruction misses on an address that is already allocated on the LMQ, this event will not increment for that load). Note that this count is per slice, so if a load spans multiple slices this event will increment multiple times for a single load.", + "PublicDescription": "" + }, + {, + "EventCode": "0x400F0", + "EventName": "PM_LD_MISS_L1", + "BriefDescription": "Load Missed L1, at execution time (not gated by finish, which means this counter can be greater than loads finished)", + "PublicDescription": "" + }, + {, + "EventCode": "0x1404A", + "EventName": "PM_INST_FROM_RL2L3_SHR", + "BriefDescription": "The processor's Instruction cache was reloaded with Shared (S) data from another chip's L2 or L3 on the same Node or Group (Remote), as this chip due to an instruction fetch (not prefetch)", + "PublicDescription": "" + }, + {, + "EventCode": "0x1C058", + "EventName": "PM_DTLB_MISS_16G", + "BriefDescription": "Data TLB Miss page size 16G", + "PublicDescription": "" + }, + {, + "EventCode": "0x1D15C", + "EventName": "PM_MRK_DTLB_MISS_1G", + "BriefDescription": "Marked Data TLB reload (after a miss) page size 2M. Implies radix translation was used", + "PublicDescription": "" + }, + {, + "EventCode": "0x1E056", + "EventName": "PM_CMPLU_STALL_FLUSH_ANY_THREAD", + "BriefDescription": "Cycles in which the NTC instruction is not allowed to complete because any of the 4 threads in the same core suffered a flush, which blocks completion", + "PublicDescription": "" + }, + {, + "EventCode": "0x101E6", + "EventName": "PM_THRESH_EXC_4096", + "BriefDescription": "Threshold counter exceed a count of 4096", + "PublicDescription": "" + }, + {, + "EventCode": "0x2C01A", + "EventName": "PM_CMPLU_STALL_LHS", + "BriefDescription": "Finish stall because the NTF instruction was a load that hit on an older store and it was waiting for store data", + "PublicDescription": "" + }, + {, + "EventCode": "0x2D016", + "EventName": "PM_CMPLU_STALL_FXU", + "BriefDescription": "Finish stall due to a scalar fixed point or CR instruction in the execution pipeline. These instructions get routed to the ALU, ALU2, and DIV pipes", + "PublicDescription": "" + }, + {, + "EventCode": "0x24046", + "EventName": "PM_INST_FROM_RL2L3_MOD", + "BriefDescription": "The processor's Instruction cache was reloaded with Modified (M) data from another chip's L2 or L3 on the same Node or Group (Remote), as this chip due to an instruction fetch (not prefetch)", + "PublicDescription": "" + }, + {, + "EventCode": "0x2404A", + "EventName": "PM_INST_FROM_RL4", + "BriefDescription": "The processor's Instruction cache was reloaded from another chip's L4 on the same Node or Group ( Remote) due to an instruction fetch (not prefetch)", + "PublicDescription": "" + }, + {, + "EventCode": "0x2F140", + "EventName": "PM_MRK_DPTEG_FROM_L2_MEPF", + "BriefDescription": "A Page Table Entry was loaded into the TLB from local core's L2 hit without dispatch conflicts on Mepf state. due to a marked data side request. When using Radix Page Translation, this count excludes PDE reloads. Only PTE reloads are included", + "PublicDescription": "" + }, + {, + "EventCode": "0x2D15E", + "EventName": "PM_MRK_DTLB_MISS_16G", + "BriefDescription": "Marked Data TLB Miss page size 16G", + "PublicDescription": "" + }, + {, + "EventCode": "0x3F14A", + "EventName": "PM_MRK_DPTEG_FROM_RMEM", + "BriefDescription": "A Page Table Entry was loaded into the TLB from another chip's memory on the same Node or Group ( Remote) due to a marked data side request. When using Radix Page Translation, this count excludes PDE reloads. Only PTE reloads are included", + "PublicDescription": "" + }, + {, + "EventCode": "0x3D156", + "EventName": "PM_MRK_DTLB_MISS_64K", + "BriefDescription": "Marked Data TLB Miss page size 64K", + "PublicDescription": "" + }, + {, + "EventCode": "0x3006C", + "EventName": "PM_RUN_CYC_SMT2_MODE", + "BriefDescription": "Cycles in which this thread's run latch is set and the core is in SMT2 mode", + "PublicDescription": "" + }, + {, + "EventCode": "0x300F4", + "EventName": "PM_THRD_CONC_RUN_INST", + "BriefDescription": "PPC Instructions Finished by this thread when all threads in the core had the run-latch set", + "PublicDescription": "" + }, + {, + "EventCode": "0x4C014", + "EventName": "PM_CMPLU_STALL_LMQ_FULL", + "BriefDescription": "Finish stall because the NTF instruction was a load that missed in the L1 and the LMQ was unable to accept this load miss request because it was full", + "PublicDescription": "" + }, + {, + "EventCode": "0x4C016", + "EventName": "PM_CMPLU_STALL_DMISS_L2L3_CONFLICT", + "BriefDescription": "Completion stall due to cache miss that resolves in the L2 or L3 with a conflict", + "PublicDescription": "" + }, + {, + "EventCode": "0x4D014", + "EventName": "PM_CMPLU_STALL_LOAD_FINISH", + "BriefDescription": "Finish stall because the NTF instruction was a load instruction with all its dependencies satisfied just going through the LSU pipe to finish", + "PublicDescription": "" + }, + {, + "EventCode": "0x4D016", + "EventName": "PM_CMPLU_STALL_FXLONG", + "BriefDescription": "Completion stall due to a long latency scalar fixed point instruction (division, square root)", + "PublicDescription": "" + }, + {, + "EventCode": "0x4D12A", + "EventName": "PM_MRK_DATA_FROM_RL4_CYC", + "BriefDescription": "Duration in cycles to reload from another chip's L4 on the same Node or Group ( Remote) due to a marked load", + "PublicDescription": "" + }, + {, + "EventCode": "0x4C15E", + "EventName": "PM_MRK_DTLB_MISS_16M", + "BriefDescription": "Marked Data TLB Miss page size 16M", + "PublicDescription": "" + }, + {, + "EventCode": "0x401E4", + "EventName": "PM_MRK_DTLB_MISS", + "BriefDescription": "Marked dtlb miss", + "PublicDescription": "" + }, + {, + "EventCode": "0x401EA", + "EventName": "PM_THRESH_EXC_128", + "BriefDescription": "Threshold counter exceeded a value of 128", + "PublicDescription": "" + }, + {, + "EventCode": "0x400F6", + "EventName": "PM_BR_MPRED_CMPL", + "BriefDescription": "Number of Branch Mispredicts", + "PublicDescription": "" + } +]
tools/perf/pmu-events/arch/powerpc/power9/floating-point.json new file +44 -0
44 lines not on this page · raw message
tools/perf/pmu-events/arch/powerpc/power9/frontend.json new file +446 -0
446 lines not on this page · raw message
tools/perf/pmu-events/arch/powerpc/power9/marked.json new file +782 -0
782 lines not on this page · raw message
tools/perf/pmu-events/arch/powerpc/power9/memory.json new file +158 -0
159 lines not on this page · raw message
tools/perf/pmu-events/arch/powerpc/power9/other.json new file +836 -0
836 lines not on this page · raw message
tools/perf/pmu-events/arch/powerpc/power9/pipeline.json new file +680 -0
557 lines not on this page · raw message
tools/perf/pmu-events/arch/powerpc/power9/pmc.json new file +146 -0
146 lines not on this page · raw message
tools/perf/pmu-events/arch/powerpc/power9/translation.json new file +272 -0
272 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.9.4
Part of the diff is not shown here. View the raw message.
Arnaldo Carvalho de Melo
maintainerPATCH 30/86 perf vendor events: Add POWER9 PVRs to mapfile
In reply to Arnaldo Carvalho de MeloFrom: Sukadev Bhattiprolu <[email protected]>
Add currently supported POWER9 PVRs to the mapfile
--- tools/perf/pmu-events/arch/powerpc/mapfile.csv | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/pmu-events/arch/powerpc/mapfile.csv +3 -0
@@ -20,3 +20,6 @@ 004d0100,1,power8.json,core 004d0200,1,power8.json,core 004c0100,1,power8.json,core +004e0100,1,power9.json,core +004e0200,1,power9.json,core +004e1200,1,power9.json,core
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 31/86 tools include uapi x86: Grab a copy of unistd.h
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
In older distros we were not including our copies of unistd_{32,64}.h, as we were relying on the system's asm/unistd.h, and a log time ago the files to be included were asm-{x86_64,i386}/unistd.h.
Fix it by also carrying a copy of asm/unistd.h, that will be the same as in modern distros and will allow us to provide missing __NR_setns, for instance, in older distros.
--- tools/arch/x86/include/uapi/asm/unistd.h | 17 +++++++++++++++++ tools/perf/check-headers.sh | 1 + 2 files changed, 18 insertions(+) create mode 100644 tools/arch/x86/include/uapi/asm/unistd.h
tools/arch/x86/include/uapi/asm/unistd.h new file +17 -0
@@ -0,0 +1,17 @@ +#ifndef _UAPI_ASM_X86_UNISTD_H +#define _UAPI_ASM_X86_UNISTD_H + +/* x32 syscall flag bit */ +#define __X32_SYSCALL_BIT 0x40000000 + +#ifndef __KERNEL__ +# ifdef __i386__ +# include <asm/unistd_32.h> +# elif defined(__ILP32__) +# include <asm/unistd_x32.h> +# else +# include <asm/unistd_64.h> +# endif +#endif + +#endif /* _UAPI_ASM_X86_UNISTD_H */
tools/perf/check-headers.sh +1 -0
@@ -16,6 +16,7 @@ arch/x86/include/uapi/asm/perf_regs.h arch/x86/include/uapi/asm/kvm.h arch/x86/include/uapi/asm/kvm_perf.h arch/x86/include/uapi/asm/svm.h +arch/x86/include/uapi/asm/unistd.h arch/x86/include/uapi/asm/vmx.h arch/powerpc/include/uapi/asm/kvm.h arch/s390/include/uapi/asm/kvm.h
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 32/86 tools include uapi x86: Add __NR_setns, if missing
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
To help us provide a simple setns() in older distros.
--- tools/arch/x86/include/asm/unistd_32.h | 3 +++ tools/arch/x86/include/asm/unistd_64.h | 3 +++ 2 files changed, 6 insertions(+)
tools/arch/x86/include/asm/unistd_32.h +3 -0
@@ -10,3 +10,6 @@#ifndef __NR_getcpu# define __NR_getcpu 318#endif +#ifndef __NR_setns +# define __NR_setns 346 +#endif
tools/arch/x86/include/asm/unistd_64.h +3 -0
@@ -10,3 +10,6 @@#ifndef __NR_getcpu# define __NR_getcpu 309#endif +#ifndef __NR_setns +#define __NR_setns 308 +#endif
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 33/86 tools build: Add test for setns()
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
And provide an alternative implementation to keep perf building on older distros as we're about to add initial support for namespaces.
--- tools/build/Makefile.feature | 3 ++- tools/build/feature/Makefile | 6 +++++- tools/build/feature/test-all.c | 5 +++++ tools/build/feature/test-setns.c | 7 +++++++ tools/perf/Makefile.config | 5 +++++ tools/perf/util/Build | 4 ++++ tools/perf/util/setns.c | 8 ++++++++ tools/perf/util/util.h | 4 ++++ 8 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 tools/build/feature/test-setns.c create mode 100644 tools/perf/util/setns.c
tools/build/Makefile.feature +2 -1
@@ -64,7 +64,8 @@ FEATURE_TESTS_BASIC := \ get_cpuid \ bpf \ sched_getcpu \ - sdt + sdt \ + setns # FEATURE_TESTS_BASIC + FEATURE_TESTS_EXTRA is the complete list # of all feature tests
tools/build/feature/Makefile +5 -1
@@ -49,7 +49,8 @@ FILES= \ test-sdt.bin \ test-cxx.bin \ test-jvmti.bin \ - test-sched_getcpu.bin + test-sched_getcpu.bin \ + test-setns.bin FILES := $(addprefix $(OUTPUT),$(FILES))
@@ -95,6 +96,9 @@ $(OUTPUT)test-glibc.bin: $(OUTPUT)test-sched_getcpu.bin: $(BUILD) +$(OUTPUT)test-setns.bin: + $(BUILD) + DWARFLIBS := -ldw ifeq ($(findstring -static,${LDFLAGS}),-static) DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
tools/build/feature/test-all.c +5 -0
@@ -153,6 +153,10 @@# include "test-sdt.c" #undef main +#define main main_test_setns +# include "test-setns.c" +#undef main +int main (int argc,char *argv[]) {main_test_libpython ();
@@ -188,6 +192,7 @@ int main(int argc, char *argv[])main_test_libcrypto ();main_test_sched_getcpu ();main_test_sdt (); +main_test_setns ();return 0 ; }
tools/build/feature/test-setns.c new file +7 -0
@@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include <sched.h> + +int main (void ) +{ +return setns (0 ,0 ); +}
tools/perf/Makefile.config +5 -0
@@ -330,6 +330,11 @@ ifeq ($(feature-sched_getcpu), 1) CFLAGS += -DHAVE_SCHED_GETCPU_SUPPORT endif +ifeq ($(feature-setns), 1) + CFLAGS += -DHAVE_SETNS_SUPPORT + $(call detected,CONFIG_SETNS) +endif + ifndef NO_LIBELF CFLAGS += -DHAVE_LIBELF_SUPPORT EXTLIBS += -lelf
tools/perf/util/Build +4 -0
@@ -104,6 +104,10 @@ ifndef CONFIG_LIBELF libperf-y += symbol-minimal.o endif +ifndef CONFIG_SETNS +libperf-y += setns.o +endif + libperf-$(CONFIG_DWARF) += probe-finder.o libperf-$(CONFIG_DWARF) += dwarf-aux.o libperf-$(CONFIG_DWARF) += dwarf-regs.o
tools/perf/util/setns.c new file +8 -0
@@ -0,0 +1,8 @@ +#include "util.h" +#include <unistd.h> +#include <sys/syscall.h> + +int setns (int fd,int nstype) +{ +return syscall (__NR_setns, fd, nstype); +}
tools/perf/util/util.h +4 -0
@@ -58,4 +58,8 @@ const char *perf_tip(const char *dirpath);int sched_getcpu (void );#endif +#ifndef HAVE_SETNS_SUPPORT +int setns (int fd,int nstype); +#endif +#endif /* GIT_COMPAT_UTIL_H */
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 34/86 perf symbols: Find symbols in different mount namespace
In reply to Arnaldo Carvalho de MeloFrom: Krister Johansen <[email protected]>
Teach perf how to resolve symbols from binaries that are in a different mount namespace from the tool. This allows perf to generate meaningful stack traces even if the binary resides in a different mount namespace from the tool.
--- tools/perf/util/dso.c | 1 + tools/perf/util/dso.h | 2 + tools/perf/util/map.c | 2 + tools/perf/util/namespaces.c | 127 +++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/namespaces.h | 33 +++++++++++ tools/perf/util/symbol.c | 11 ++++ tools/perf/util/thread.c | 3 + tools/perf/util/thread.h | 1 + 8 files changed, 180 insertions(+)
tools/perf/util/dso.c +1 -0
@@ -1236,6 +1236,7 @@ void dso__delete(struct dso *dso)dso_cache__free (dso);dso__free_a2l (dso);zfree (&dso->symsrc_filename); +nsinfo__zput (dso->nsinfo);pthread_mutex_destroy (&dso->lock);free (dso); }
tools/perf/util/dso.h +2 -0
@@ -10,6 +10,7 @@#include <linux/types.h> #include <linux/bitops.h> #include "map.h" +#include "namespaces.h" #include "build-id.h" enum dso_binary_type {
@@ -187,6 +188,7 @@ struct dso {void *priv;u64 db_id; }; +struct nsinfo *nsinfo;refcount_t refcnt;char name[0 ]; };
tools/perf/util/map.c +2 -0
@@ -16,6 +16,7 @@#include "machine.h" #include <linux/string.h> #include "srcline.h" +#include "namespaces.h" #include "unwind.h" static void __maps__insert (struct maps *maps,struct map *map);
@@ -200,6 +201,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,if (type !=MAP__FUNCTION )dso__set_loaded (dso, map->type); } + dso->nsinfo =nsinfo__get (thread->nsinfo);dso__put (dso); }return map;
tools/perf/util/namespaces.c +127 -0
139 lines not on this page · raw message
tools/perf/util/namespaces.h +33 -0
@@ -11,6 +11,7 @@#include "../perf.h" #include <linux/list.h> +#include <linux/refcount.h> struct namespaces_event ;
@@ -23,4 +24,36 @@ struct namespaces {struct namespaces *namespaces__new (struct namespaces_event *event);void namespaces__free (struct namespaces *namespaces); +struct nsinfo { +pid_t pid; +bool need_setns; +char *mntns_path; +refcount_t refcnt; +}; + +struct nscookie { +int oldns; +int newns; +}; + +void nsinfo__init (struct nsinfo *nsi); +struct nsinfo *nsinfo__new (pid_t pid); +void nsinfo__delete (struct nsinfo *nsi); + +struct nsinfo *nsinfo__get (struct nsinfo *nsi); +void nsinfo__put (struct nsinfo *nsi); + +void nsinfo__mountns_enter (struct nsinfo *nsi,struct nscookie *nc); +void nsinfo__mountns_exit (struct nscookie *nc); + +static inline void __nsinfo__zput (struct nsinfo **nsip) +{ +if (nsip) { +nsinfo__put (*nsip); + *nsip =NULL ; + } +} + +#define nsinfo__zput (nsi) __nsinfo__zput(&nsi) +#endif /* __PERF_NAMESPACES_H */
tools/perf/util/symbol.c +11 -0
@@ -18,6 +18,8 @@#include "symbol.h" #include "strlist.h" #include "intlist.h" +#include "namespaces.h" +#include "vdso.h" #include "header.h" #include "path.h" #include "sane_ctype.h"
@@ -1436,9 +1438,17 @@ int dso__load(struct dso *dso, struct map *map)struct symsrc *syms_ss =NULL , *runtime_ss =NULL ;bool kmod;unsigned char build_id[BUILD_ID_SIZE ]; +struct nscookie nsc; +nsinfo__mountns_enter (dso->nsinfo, &nsc);pthread_mutex_lock (&dso->lock); +/* The vdso files always live in the host container, so don't go looking +* for them in the container's mount namespace. +*/ +if (dso__is_vdso (dso)) +nsinfo__mountns_exit (&nsc); +/* check again under the dso->lock */ if (dso__loaded (dso, map->type)) { ret =1 ;
@@ -1584,6 +1594,7 @@ int dso__load(struct dso *dso, struct map *map) out:dso__set_loaded (dso, map->type);pthread_mutex_unlock (&dso->lock); +nsinfo__mountns_exit (&nsc);return ret; }
tools/perf/util/thread.c +3 -0
@@ -59,6 +59,8 @@ struct thread *thread__new(pid_t pid, pid_t tid)list_add (&comm->list, &thread->comm_list);refcount_set (&thread->refcnt,1 );RB_CLEAR_NODE (&thread->rb_node); +/* Thread holds first ref to nsdata. */ + thread->nsinfo =nsinfo__new (pid); }return thread;
@@ -91,6 +93,7 @@ void thread__delete(struct thread *thread)comm__free (comm); }unwind__finish_access (thread); +nsinfo__zput (thread->nsinfo);free (thread); }
tools/perf/util/thread.h +1 -0
@@ -34,6 +34,7 @@ struct thread {void *priv;struct thread_stack *ts; +struct nsinfo *nsinfo;#ifdef HAVE_LIBUNWIND_SUPPORT void *addr_space;struct unwind_libunwind_ops *unwind_libunwind_ops;
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 35/86 perf maps: Lookup maps in both intitial mountns and inner mountns.
In reply to Arnaldo Carvalho de MeloFrom: Krister Johansen <[email protected]>
If a process is in a mountns and has symbols in /tmp/perf-<pid>.map, look first in the namespace using the tgid for the pidns that the process might be in. If the map isn't found there, try looking in the mountns where perf is running, and use the tgid that's appropriate for perf's pid namespace. If all else fails, use the original pid.
This allows us to locate a symbol map file in the mount namespace, if it was generated there. However, we also try the tool's /tmp in case it's there instead.
--- tools/perf/util/machine.c | 4 +-- tools/perf/util/map.c | 23 +++++++++--- tools/perf/util/map.h | 2 +- tools/perf/util/namespaces.c | 83 ++++++++++++++++++++++++++++++++++++++++---- tools/perf/util/namespaces.h | 5 ++- tools/perf/util/symbol.c | 70 ++++++++++++++++++++++++++++++------- 6 files changed, 160 insertions(+), 27 deletions(-)
tools/perf/util/machine.c +2 -2
@@ -1392,7 +1392,7 @@ int machine__process_mmap2_event(struct machine *machine, map = map__new(machine, event->mmap2.start, event->mmap2.len, event->mmap2.pgoff, - event->mmap2.pid, event->mmap2.maj, + event->mmap2.maj, event->mmap2.min, event->mmap2.ino, event->mmap2.ino_generation, event->mmap2.prot,
@@ -1450,7 +1450,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event map =map__new (machine, event->mmap.start, event->mmap.len, event->mmap.pgoff, - event->mmap.pid,0 ,0 ,0 ,0 ,0 ,0 , +0 ,0 ,0 ,0 ,0 ,0 , event->mmap.filename, type, thread);
tools/perf/util/map.c +19 -4
@@ -146,11 +146,13 @@ void map__init(struct map *map, enum map_type type, }struct map *map__new (struct machine *machine,u64 start,u64 len, -u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino, +u64 pgoff,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename,enum map_type type,struct thread *thread) {struct map *map =malloc (sizeof (*map)); +struct nsinfo *nsi =NULL ; +struct nsinfo *nnsi;if (map !=NULL ) {char newfilename[PATH_MAX ];
@@ -168,9 +170,11 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, map->ino_generation = ino_gen; map->prot = prot; map->flags = flags; + nsi =nsinfo__get (thread->nsinfo); -if ((anon || no_dso) && type ==MAP__FUNCTION ) { -snprintf (newfilename,sizeof (newfilename),"/tmp/perf-%d.map" , pid); +if ((anon || no_dso) && nsi && type ==MAP__FUNCTION ) { +snprintf (newfilename,sizeof (newfilename), +"/tmp/perf-%d.map" , nsi->pid); filename = newfilename; }
@@ -180,6 +184,16 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, }if (vdso) { +/* The vdso maps are always on the host and not the +* container. Ensure that we don't use setns to look +* them up. +*/ + nnsi =nsinfo__copy (nsi); +if (nnsi) { +nsinfo__put (nsi); + nnsi->need_setns = false; + nsi = nnsi; + } pgoff =0 ; dso =machine__findnew_vdso (machine, thread); }else
@@ -201,11 +215,12 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,if (type !=MAP__FUNCTION )dso__set_loaded (dso, map->type); } - dso->nsinfo =nsinfo__get (thread->nsinfo); + dso->nsinfo = nsi;dso__put (dso); }return map; out_delete: +nsinfo__put (nsi);free (map);return NULL ; }
tools/perf/util/map.h +1 -1
@@ -141,7 +141,7 @@ struct thread;void map__init (struct map *map,enum map_type type,u64 start,u64 end,u64 pgoff,struct dso *dso);struct map *map__new (struct machine *machine,u64 start,u64 len, -u64 pgoff,u32 pid,u32 d_maj,u32 d_min,u64 ino, +u64 pgoff,u32 d_maj,u32 d_min,u64 ino,u64 ino_gen,u32 prot,u32 flags,char *filename,enum map_type type,struct thread *thread);struct map *map__new2 (u64 start,struct dso *dso,enum map_type type);
tools/perf/util/namespaces.c +77 -6
126 lines not on this page · raw message
tools/perf/util/namespaces.h +4 -1
@@ -26,6 +26,8 @@ void namespaces__free(struct namespaces *namespaces);struct nsinfo {pid_t pid; +pid_t tgid; +pid_t nstgid;bool need_setns;char *mntns_path;refcount_t refcnt;
@@ -36,8 +38,9 @@ struct nscookie {int newns; }; -void nsinfo__init (struct nsinfo *nsi); +int nsinfo__init (struct nsinfo *nsi);struct nsinfo *nsinfo__new (pid_t pid); +struct nsinfo *nsinfo__copy (struct nsinfo *nsi);void nsinfo__delete (struct nsinfo *nsi);struct nsinfo *nsinfo__get (struct nsinfo *nsi);
tools/perf/util/symbol.c +57 -13
121 lines not on this page · raw message
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 36/86 perf probe: Allow placing uprobes in alternate namespaces.
In reply to Arnaldo Carvalho de MeloFrom: Krister Johansen <[email protected]>
Teaches perf how to place a uprobe on a file that's in a different mount namespace. The user must add the probe using the --target-ns argument to perf probe. Once it has been placed, it may be recorded against without further namespace-specific commands.
--- tools/perf/Documentation/perf-probe.txt | 9 ++++ tools/perf/arch/powerpc/util/sym-handling.c | 2 +- tools/perf/builtin-probe.c | 43 ++++++++++++++-- tools/perf/util/namespaces.c | 13 +++++ tools/perf/util/namespaces.h | 2 + tools/perf/util/probe-event.c | 80 +++++++++++++++++++---------- tools/perf/util/probe-event.h | 10 ++-- 7 files changed, 125 insertions(+), 34 deletions(-)
tools/perf/Documentation/perf-probe.txt +9 -0
@@ -130,6 +130,11 @@ OPTIONS --max-probes=NUM:: Set the maximum number of probe points for an event. Default is 128. +--target-ns=PID: + Obtain mount namespace information from the target pid. This is + used when creating a uprobe for a process that resides in a + different mount namespace from the perf(1) utility. + -x:: --exec=PATH:: Specify path to the executable or shared library file for user
@@ -264,6 +269,10 @@ Add probes at malloc() function on libc ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc +Add a uprobe to a target process running in a different mount namespace + + ./perf probe --target-ns <target pid> -x /lib64/libc.so.6 malloc + SEE ALSO -------- linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
tools/perf/arch/powerpc/util/sym-handling.c +1 -1
@@ -126,7 +126,7 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev,struct rb_node *tmp;int i =0 ; - map =get_target_map (pev->target, pev->uprobes); + map =get_target_map (pev->target, pev->nsi, pev->uprobes);if (!map ||map__load (map) <0 )return ;
tools/perf/builtin-probe.c +39 -4
91 lines not on this page · raw message
tools/perf/util/namespaces.c +13 -0
@@ -11,6 +11,7 @@#include "event.h" #include <sys/types.h> #include <sys/stat.h> +#include <limits.h> #include <sched.h> #include <stdlib.h> #include <stdio.h>
@@ -233,3 +234,15 @@ void nsinfo__mountns_exit(struct nscookie *nc) nc->newns =-1 ; } } + +char *nsinfo__realpath (const char *path,struct nsinfo *nsi) +{ +char *rpath; +struct nscookie nsc; + +nsinfo__mountns_enter (nsi, &nsc); + rpath =realpath (path,NULL ); +nsinfo__mountns_exit (&nsc); + +return rpath; +}
tools/perf/util/namespaces.h +2 -0
@@ -49,6 +49,8 @@ void nsinfo__put(struct nsinfo *nsi);void nsinfo__mountns_enter (struct nsinfo *nsi,struct nscookie *nc);void nsinfo__mountns_exit (struct nscookie *nc); +char *nsinfo__realpath (const char *path,struct nsinfo *nsi); +static inline void __nsinfo__zput (struct nsinfo **nsip) {if (nsip) {
tools/perf/util/probe-event.c +54 -26
272 lines not on this page · raw message
tools/perf/util/probe-event.h +7 -3
@@ -4,6 +4,7 @@#include <linux/compiler.h> #include <stdbool.h> #include "intlist.h" +#include "namespaces.h" /* Probe related configurations */ struct probe_conf {
@@ -92,6 +93,7 @@ struct perf_probe_event {struct perf_probe_arg *args;/* Arguments */ struct probe_trace_event *tevs;int ntevs; +struct nsinfo *nsi;/* Target namespace */ };/* Line range */
@@ -163,10 +165,12 @@ int show_perf_probe_event(const char *group, const char *event,struct perf_probe_event *pev, const char *module, bool use_stdout);int show_perf_probe_events (struct strfilter *filter); -int show_line_range (struct line_range *lr,const char *module,bool user); +int show_line_range (struct line_range *lr,const char *module, +struct nsinfo *nsi,bool user);int show_available_vars (struct perf_probe_event *pevs,int npevs,struct strfilter *filter); -int show_available_funcs (const char *module,struct strfilter *filter,bool user); +int show_available_funcs (const char *module,struct nsinfo *nsi, +struct strfilter *filter,bool user);void arch__fix_tev_from_maps (struct perf_probe_event *pev,struct probe_trace_event *tev,struct map *map,struct symbol *sym);
@@ -180,7 +184,7 @@ int e_snprintf(char *str, size_t size, const char *format, ...) __printf(3, 4);int copy_to_probe_trace_arg (struct probe_trace_arg *tvar,struct perf_probe_arg *pvar); -struct map *get_target_map (const char *target,bool user); +struct map *get_target_map (const char *target,struct nsinfo *nsi,bool user);void arch__post_process_probe_trace_events (struct perf_probe_event *pev,int ntevs);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 37/86 perf buildid-cache: Support binary objects from other namespaces
In reply to Arnaldo Carvalho de MeloFrom: Krister Johansen <[email protected]>
Teach buildid-cache how to add, remove, and update binary objects from other mount namespaces. Allow probe events tracing binaries in different namespaces to add their objects to the probe and build-id caches too. As a handy side effect, this also lets us access SDT probes in binaries from alternate mount namespaces.
--- tools/perf/Documentation/perf-buildid-cache.txt | 5 +++ tools/perf/Documentation/perf-probe.txt | 5 +++ tools/perf/builtin-buildid-cache.c | 52 ++++++++++++++++++------- tools/perf/builtin-probe.c | 2 +- tools/perf/tests/sdt.c | 4 +- tools/perf/util/build-id.c | 47 ++++++++++++++-------- tools/perf/util/build-id.h | 9 +++-- tools/perf/util/dso.c | 12 +++++- tools/perf/util/parse-events.c | 2 +- tools/perf/util/probe-event.c | 6 +-- tools/perf/util/probe-file.c | 19 +++++---- tools/perf/util/probe-file.h | 4 +- tools/perf/util/python-ext-sources | 1 + tools/perf/util/symbol.c | 19 ++++++--- tools/perf/util/util.c | 34 +++++++++++++--- tools/perf/util/util.h | 2 + 16 files changed, 160 insertions(+), 63 deletions(-)
tools/perf/Documentation/perf-buildid-cache.txt +5 -0
@@ -61,6 +61,11 @@ OPTIONS --verbose:: Be more verbose. +--target-ns=PID: + Obtain mount namespace information from the target pid. This is + used when creating a uprobe for a process that resides in a + different mount namespace from the perf(1) utility. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-buildid-list[1]
tools/perf/Documentation/perf-probe.txt +5 -0
@@ -273,6 +273,11 @@ Add a uprobe to a target process running in a different mount namespace ./perf probe --target-ns <target pid> -x /lib64/libc.so.6 malloc +Add a USDT probe to a target process running in a different mount namespace + + ./perf probe --target-ns <target pid> -x /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.121-0.b13.el7_3.x86_64/jre/lib/amd64/server/libjvm.so %sdt_hotspot:thread__sleep__end + + SEE ALSO -------- linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1]
tools/perf/builtin-buildid-cache.c +37 -15
171 lines not on this page · raw message
tools/perf/builtin-probe.c +1 -1
@@ -416,7 +416,7 @@ static int del_perf_probe_caches(struct strfilter *filter) }strlist__for_each_entry (nd, bidlist) { - cache =probe_cache__new (nd->s); + cache =probe_cache__new (nd->s,NULL );if (!cache)continue ; if (probe_cache__filter_purge(cache, filter) < 0 ||
tools/perf/tests/sdt.c +2 -2
@@ -33,7 +33,7 @@ static int build_id_cache__add_file(const char *filename) }build_id__sprintf (build_id,sizeof (build_id), sbuild_id); - err =build_id_cache__add_s (sbuild_id, filename, false, false); + err =build_id_cache__add_s (sbuild_id, filename,NULL , false, false);if (err <0 )pr_debug ("Failed to add build id cache of %s\n" , filename);return err;
@@ -54,7 +54,7 @@ static char *get_self_path(void)static int search_cached_probe (const char *target,const char *group,const char *event) { -struct probe_cache *cache =probe_cache__new (target); +struct probe_cache *cache =probe_cache__new (target,NULL );int ret =0 ;if (!cache) {
tools/perf/util/build-id.c +30 -17
131 lines not on this page · raw message
tools/perf/util/build-id.h +6 -3
@@ -5,6 +5,7 @@#define SBUILD_ID_SIZE (BUILD_ID_SIZE * 2 + 1)#include "tool.h" +#include "namespaces.h" #include <linux/types.h> extern struct perf_tool build_id__mark_dso_hit_ops;
@@ -31,17 +32,19 @@ int perf_session__cache_build_ids(struct perf_session *session);char *build_id_cache__origname (const char *sbuild_id);char *build_id_cache__linkname (const char *sbuild_id,char *bf,size_t size);char *build_id_cache__cachedir (const char *sbuild_id,const char *name, -bool is_kallsyms,bool is_vdso); +struct nsinfo *nsi,bool is_kallsyms, +bool is_vdso);struct strlist ;struct strlist *build_id_cache__list_all (bool validonly);char *build_id_cache__complement (const char *incomplete_sbuild_id); -int build_id_cache__list_build_ids (const char *pathname, +int build_id_cache__list_build_ids (const char *pathname,struct nsinfo *nsi,struct strlist **result);bool build_id_cache__cached (const char *sbuild_id);int build_id_cache__add_s (const char *sbuild_id, -const char *name,bool is_kallsyms,bool is_vdso); +const char *name,struct nsinfo *nsi, +bool is_kallsyms,bool is_vdso);int build_id_cache__remove_s (const char *sbuild_id);extern char buildid_dir[];
tools/perf/util/dso.c +11 -1
@@ -504,7 +504,14 @@ static void check_data_close(void);*/ static int open_dso (struct dso *dso,struct machine *machine) { -int fd =__open_dso (dso, machine); +int fd; +struct nscookie nsc; + +if (dso->binary_type !=DSO_BINARY_TYPE__BUILD_ID_CACHE ) +nsinfo__mountns_enter (dso->nsinfo, &nsc); + fd =__open_dso (dso, machine); +if (dso->binary_type !=DSO_BINARY_TYPE__BUILD_ID_CACHE ) +nsinfo__mountns_exit (&nsc);if (fd >=0 ) {dso__list_add (dso);
@@ -1302,6 +1309,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) {bool have_build_id = false;struct dso *pos; +struct nscookie nsc;list_for_each_entry (pos, head, node) {if (with_hits && !pos->hit && !dso__is_vdso (pos))
@@ -1310,11 +1318,13 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) have_build_id = true;continue ; } +nsinfo__mountns_enter (pos->nsinfo, &nsc);if (filename__read_build_id (pos->long_name, pos->build_id,sizeof (pos->build_id)) >0 ) { have_build_id = true; pos->has_build_id = true; } +nsinfo__mountns_exit (&nsc); }return have_build_id;
tools/perf/util/parse-events.c +1 -1
@@ -2124,7 +2124,7 @@ void print_sdt_events(const char *subsys_glob, const char *event_glob,return ; }strlist__for_each_entry (nd, bidlist) { - pcache =probe_cache__new (nd->s); + pcache =probe_cache__new (nd->s,NULL );if (!pcache)continue ;list_for_each_entry (ent, &pcache->entries, node) {
tools/perf/util/probe-event.c +3 -3
@@ -2769,7 +2769,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,if (ret == -EINVAL && pev->uprobes)warn_uprobe_event_compat (tev);if (ret ==0 && probe_conf.cache) { - cache =probe_cache__new (pev->target); + cache =probe_cache__new (pev->target, pev->nsi);if (!cache ||probe_cache__add_entry (cache, pev, tevs, ntevs) <0 ||probe_cache__commit (cache) <0 )
@@ -3119,7 +3119,7 @@ static int find_cached_events(struct perf_probe_event *pev,int ntevs =0 ;int ret =0 ; - cache =probe_cache__new (target); + cache =probe_cache__new (target, pev->nsi);/* Return 0 ("not found") if the target has no probe cache. */ if (!cache)return 0 ;
@@ -3209,7 +3209,7 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,else return find_cached_events (pev, tevs, pev->target); } - cache =probe_cache__new (pev->target); + cache =probe_cache__new (pev->target, pev->nsi);if (!cache)return 0 ;
tools/perf/util/probe-file.c +12 -7
@@ -412,13 +412,15 @@ int probe_cache_entry__get_event(struct probe_cache_entry *entry, }/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */ -static int probe_cache__open (struct probe_cache *pcache,const char *target) +static int probe_cache__open (struct probe_cache *pcache,const char *target, +struct nsinfo *nsi) {char cpath[PATH_MAX ];char sbuildid[SBUILD_ID_SIZE ];char *dir_name =NULL ;bool is_kallsyms = false;int ret, fd; +struct nscookie nsc;if (target &&build_id_cache__cached (target)) {/* This is a cached buildid */
@@ -431,8 +433,11 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) target =DSO__NAME_KALLSYMS ; is_kallsyms = true; ret =sysfs__sprintf_build_id ("/" , sbuildid); - }else + }else { +nsinfo__mountns_enter (nsi, &nsc); ret =filename__sprintf_build_id (target, sbuildid); +nsinfo__mountns_exit (&nsc); + }if (ret <0 ) {pr_debug ("Failed to get build-id from %s.\n" , target);
@@ -441,7 +446,7 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target)/* If we have no buildid cache, make it */ if (!build_id_cache__cached (sbuildid)) { - ret =build_id_cache__add_s (sbuildid, target, + ret =build_id_cache__add_s (sbuildid, target, nsi, is_kallsyms,NULL );if (ret <0 ) {pr_debug ("Failed to add build-id cache: %s\n" , target);
@@ -449,7 +454,7 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) } } - dir_name =build_id_cache__cachedir (sbuildid, target, is_kallsyms, + dir_name =build_id_cache__cachedir (sbuildid, target, nsi, is_kallsyms, false); found:if (!dir_name) {
@@ -554,7 +559,7 @@ void probe_cache__delete(struct probe_cache *pcache)free (pcache); } -struct probe_cache *probe_cache__new (const char *target) +struct probe_cache *probe_cache__new (const char *target,struct nsinfo *nsi) {struct probe_cache *pcache =probe_cache__alloc ();int ret;
@@ -562,7 +567,7 @@ struct probe_cache *probe_cache__new(const char *target)if (!pcache)return NULL ; - ret =probe_cache__open (pcache, target); + ret =probe_cache__open (pcache, target, nsi);if (ret <0 ) {pr_debug ("Cache open error: %d\n" , ret); goto out_err;
@@ -974,7 +979,7 @@ int probe_cache__show_all_caches(struct strfilter *filter)return -EINVAL ; }strlist__for_each_entry (nd, bidlist) { - pcache =probe_cache__new (nd->s); + pcache =probe_cache__new (nd->s,NULL );if (!pcache)continue ;if (!list_empty (&pcache->entries)) {
tools/perf/util/probe-file.h +2 -2
@@ -51,7 +51,7 @@ int probe_file__del_strlist(int fd, struct strlist *namelist);int probe_cache_entry__get_event (struct probe_cache_entry *entry,struct probe_trace_event **tevs); -struct probe_cache *probe_cache__new (const char *target); +struct probe_cache *probe_cache__new (const char *target,struct nsinfo *nsi);int probe_cache__add_entry (struct probe_cache *pcache,struct perf_probe_event *pev,struct probe_trace_event *tevs,int ntevs);
@@ -69,7 +69,7 @@ int probe_cache__show_all_caches(struct strfilter *filter);bool probe_type_is_available (enum probe_type type);bool kretprobe_offset_is_supported (void );#else /* ! HAVE_LIBELF_SUPPORT */ -static inline struct probe_cache *probe_cache__new (const char *tgt__maybe_unused ) +static inline struct probe_cache *probe_cache__new (const char *tgt__maybe_unused ,struct nsinfo *nsi__maybe_unused ) {return NULL ; }
tools/perf/util/python-ext-sources +1 -0
@@ -10,6 +10,7 @@ util/ctype.c util/evlist.c util/evsel.c util/cpumap.c +util/namespaces.c ../lib/bitmap.c ../lib/find_bit.c ../lib/hweight.c
tools/perf/util/symbol.c +14 -5
@@ -1464,7 +1464,6 @@ static int dso__find_perf_map(char *filebuf, size_t bufsz,return rc; } -int dso__load (struct dso *dso,struct map *map) {char *name;
@@ -1565,6 +1564,8 @@ int dso__load(struct dso *dso, struct map *map)for (i =0 ; i <DSO_BINARY_TYPE__SYMTAB_CNT ; i++) {struct symsrc *ss = &ss_[ss_pos];bool next_slot = false; +bool is_reg; +int sirc;enum dso_binary_type symtab_type = binary_type_symtab[i];
@@ -1575,12 +1576,20 @@ int dso__load(struct dso *dso, struct map *map) root_dir, name, PATH_MAX))continue ; -if (!is_regular_file (name)) -continue ; +if (symtab_type ==DSO_BINARY_TYPE__BUILD_ID_CACHE ) +nsinfo__mountns_exit (&nsc); + + is_reg =is_regular_file (name); + sirc =symsrc__init (ss, dso, name, symtab_type); -/* Name is now the name of the next image to try */ -if (symsrc__init (ss, dso, name, symtab_type) <0 ) +if (symtab_type ==DSO_BINARY_TYPE__BUILD_ID_CACHE ) +nsinfo__mountns_enter (dso->nsinfo, &nsc); + +if (!is_reg || sirc <0 ) { +if (sirc >=0 ) +symsrc__destroy (ss);continue ; + }if (!syms_ss &&symsrc__has_symtab (ss)) { syms_ss = ss;
tools/perf/util/util.c +28 -6
@@ -143,13 +143,17 @@ struct strlist *lsdir(const char *name,return list; } -static int slow_copyfile (const char *from,const char *to) +static int slow_copyfile (const char *from,const char *to,struct nsinfo *nsi) {int err =-1 ;char *line =NULL ;size_t n; -FILE *from_fp =fopen (from,"r" ), *to_fp; +FILE *from_fp, *to_fp; +struct nscookie nsc; +nsinfo__mountns_enter (nsi, &nsc); + from_fp =fopen (from,"r" ); +nsinfo__mountns_exit (&nsc);if (from_fp ==NULL ) goto out;
@@ -198,15 +202,21 @@ int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size)return size ?-1 :0 ; } -int copyfile_mode (const char *from,const char *to,mode_t mode) +static int copyfile_mode_ns (const char *from,const char *to,mode_t mode, +struct nsinfo *nsi) {int fromfd, tofd;struct stat st; -int err =-1 ; +int err;char *tmp =NULL , *ptr =NULL ; +struct nscookie nsc; -if (stat (from, &st)) +nsinfo__mountns_enter (nsi, &nsc); + err =stat (from, &st); +nsinfo__mountns_exit (&nsc); +if (err) goto out; + err =-1 ;/* extra 'x' at the end is to reserve space for '.' */ if (asprintf (&tmp,"%s.XXXXXXx" , to) <0 ) {
@@ -227,11 +237,13 @@ int copyfile_mode(const char *from, const char *to, mode_t mode) goto out_close_to;if (st.st_size ==0 ) {/* /proc? do it slowly... */ - err =slow_copyfile (from, tmp); + err =slow_copyfile (from, tmp, nsi); goto out_close_to; } +nsinfo__mountns_enter (nsi, &nsc); fromfd =open (from,O_RDONLY ); +nsinfo__mountns_exit (&nsc);if (fromfd <0 ) goto out_close_to;
@@ -248,6 +260,16 @@ int copyfile_mode(const char *from, const char *to, mode_t mode)return err; } +int copyfile_ns (const char *from,const char *to,struct nsinfo *nsi) +{ +return copyfile_mode_ns (from, to,0755 , nsi); +} + +int copyfile_mode (const char *from,const char *to,mode_t mode) +{ +return copyfile_mode_ns (from, to, mode,NULL ); +} +int copyfile (const char *from,const char *to) {return copyfile_mode (from, to,0755 );
tools/perf/util/util.h +2 -0
@@ -12,6 +12,7 @@#include <stdarg.h> #include <linux/compiler.h> #include <linux/types.h> +#include "namespaces.h" /* General helper functions */ void usage (const char *err)__noreturn ;
@@ -33,6 +34,7 @@ struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct direbool lsdir_no_dot_filter (const char *name,struct dirent *d);int copyfile (const char *from,const char *to);int copyfile_mode (const char *from,const char *to,mode_t mode); +int copyfile_ns (const char *from,const char *to,struct nsinfo *nsi);int copyfile_offset (int fromfd,loff_t from_ofs,int tofd,loff_t to_ofs,u64 size);ssize_t readn (int fd,void *buf,size_t n);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 38/86 perf buildid-cache: Cache debuginfo
In reply to Arnaldo Carvalho de MeloFrom: Krister Johansen <[email protected]>
If a stripped binary is placed in the cache, the user is in a situation where there's a cached elf file present, but it doesn't have any symtab to use for name resolution. Grab the debuginfo for binaries that don't end in .ko. This yields a better chance of resolving symbols from older traces.
--- tools/perf/builtin-buildid-cache.c | 2 +- tools/perf/util/annotate.c | 2 +- tools/perf/util/build-id.c | 72 +++++++++++++++++++++++++++++++++++--- tools/perf/util/build-id.h | 3 +- tools/perf/util/dso.c | 8 ++++- tools/perf/util/dso.h | 1 + tools/perf/util/machine.c | 3 +- tools/perf/util/symbol.c | 12 +++++-- 8 files changed, 90 insertions(+), 13 deletions(-)
tools/perf/builtin-buildid-cache.c +1 -1
@@ -243,7 +243,7 @@ static bool dso__missing_buildid_cache(struct dso *dso, int parm __maybe_unused)char filename[PATH_MAX ];u8 build_id[BUILD_ID_SIZE ]; -if (dso__build_id_filename (dso, filename,sizeof (filename)) && +if (dso__build_id_filename (dso, filename,sizeof (filename), false) &&filename__read_build_id (filename, build_id,sizeof (build_id)) !=sizeof (build_id)) {if (errno ==ENOENT )
tools/perf/util/annotate.c +1 -1
@@ -1347,7 +1347,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil !dso__is_kcore(dso))return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX ; - build_id_filename =dso__build_id_filename (dso,NULL ,0 ); + build_id_filename =dso__build_id_filename (dso,NULL ,0 , false);if (build_id_filename) {__symbol__join_symfs (filename, filename_size, build_id_filename);free (build_id_filename);
tools/perf/util/build-id.c +67 -5
117 lines not on this page · raw message
tools/perf/util/build-id.h +2 -1
@@ -17,7 +17,8 @@ int filename__sprintf_build_id(const char *pathname, char *sbuild_id);char *build_id_cache__kallsyms_path (const char *sbuild_id,char *bf,size_t size); -char *dso__build_id_filename (const struct dso *dso,char *bf,size_t size); +char *dso__build_id_filename (const struct dso *dso,char *bf,size_t size, +bool is_debug); int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel,
tools/perf/util/dso.c +7 -1
@@ -32,6 +32,7 @@ char dso__symtab_origin(const struct dso *dso) [DSO_BINARY_TYPE__JAVA_JIT] = 'j', [DSO_BINARY_TYPE__DEBUGLINK] = 'l', [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', + [DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO] = 'D', [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', [DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o',
@@ -97,7 +98,12 @@ int dso__read_binary_type_filename(const struct dso *dso,break ; }case DSO_BINARY_TYPE__BUILD_ID_CACHE : -if (dso__build_id_filename (dso, filename, size) ==NULL ) +if (dso__build_id_filename (dso, filename, size, false) ==NULL ) + ret =-1 ; +break ; + +case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO : +if (dso__build_id_filename (dso, filename, size, true) ==NULL ) ret =-1 ;break ;
tools/perf/util/dso.h +1 -0
@@ -21,6 +21,7 @@ enum dso_binary_type {DSO_BINARY_TYPE__JAVA_JIT ,DSO_BINARY_TYPE__DEBUGLINK ,DSO_BINARY_TYPE__BUILD_ID_CACHE , +DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO ,DSO_BINARY_TYPE__FEDORA_DEBUGINFO ,DSO_BINARY_TYPE__UBUNTU_DEBUGINFO , DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
tools/perf/util/machine.c +2 -1
@@ -705,7 +705,8 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp)if (kdso->has_build_id) {char filename[PATH_MAX ]; -if (dso__build_id_filename (kdso, filename,sizeof (filename))) +if (dso__build_id_filename (kdso, filename,sizeof (filename), + false)) printed +=fprintf (fp,"[0] %s\n" , filename); }
tools/perf/util/symbol.c +9 -3
@@ -53,6 +53,7 @@ static enum dso_binary_type binary_type_symtab[] = {DSO_BINARY_TYPE__JAVA_JIT ,DSO_BINARY_TYPE__DEBUGLINK ,DSO_BINARY_TYPE__BUILD_ID_CACHE , +DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO ,DSO_BINARY_TYPE__FEDORA_DEBUGINFO ,DSO_BINARY_TYPE__UBUNTU_DEBUGINFO , DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
@@ -1418,6 +1419,7 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,return kmod && dso->symtab_type == type;case DSO_BINARY_TYPE__BUILD_ID_CACHE : +case DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO :return true;case DSO_BINARY_TYPE__NOT_FOUND :
@@ -1565,10 +1567,14 @@ int dso__load(struct dso *dso, struct map *map)struct symsrc *ss = &ss_[ss_pos];bool next_slot = false;bool is_reg; +bool nsexit;int sirc;enum dso_binary_type symtab_type = binary_type_symtab[i]; + nsexit = (symtab_type ==DSO_BINARY_TYPE__BUILD_ID_CACHE || + symtab_type ==DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO ); +if (!dso__is_compatible_symtab_type (dso, kmod, symtab_type))continue ;
@@ -1576,13 +1582,13 @@ int dso__load(struct dso *dso, struct map *map) root_dir, name, PATH_MAX))continue ; -if (symtab_type ==DSO_BINARY_TYPE__BUILD_ID_CACHE ) +if (nsexit)nsinfo__mountns_exit (&nsc); is_reg =is_regular_file (name); sirc =symsrc__init (ss, dso, name, symtab_type); -if (symtab_type ==DSO_BINARY_TYPE__BUILD_ID_CACHE ) +if (nsexit)nsinfo__mountns_enter (dso->nsinfo, &nsc);if (!is_reg || sirc <0 ) {
@@ -1724,7 +1730,7 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map) }if (!symbol_conf.ignore_vmlinux_buildid) - filename =dso__build_id_filename (dso,NULL ,0 ); + filename =dso__build_id_filename (dso,NULL ,0 , false);if (filename !=NULL ) { err =dso__load_vmlinux (dso, map, filename, true);if (err >0 )
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 39/86 perf evsel: Allow asking for max precise_ip in new_cycles()
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
There are cases where we want to leave attr.precise_ip as zero, such as when using 'perf record --no-samples', where this would make the kernel return -EINVAL.
--- tools/perf/util/evlist.c | 2 +- tools/perf/util/evsel.c | 7 +++++-- tools/perf/util/evsel.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-)
tools/perf/util/evlist.c +1 -1
@@ -244,7 +244,7 @@ void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr)int perf_evlist__add_default (struct perf_evlist *evlist) { -struct perf_evsel *evsel =perf_evsel__new_cycles (); +struct perf_evsel *evsel =perf_evsel__new_cycles (true);if (evsel ==NULL )return -ENOMEM ;
tools/perf/util/evsel.c +5 -2
@@ -268,7 +268,7 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)return evsel; } -struct perf_evsel *perf_evsel__new_cycles (void ) +struct perf_evsel *perf_evsel__new_cycles (bool precise) {struct perf_event_attr attr = { .type =PERF_TYPE_HARDWARE ,
@@ -278,6 +278,9 @@ struct perf_evsel *perf_evsel__new_cycles(void)struct perf_evsel *evsel;event_attr_init (&attr); + +if (!precise) + goto new_event;/* * Unnamed union member, not supported as struct member named * initializer in older compilers such as gcc 4.4.7
@@ -292,7 +295,7 @@ struct perf_evsel *perf_evsel__new_cycles(void)* to kick in when we return and before perf_evsel__open() is called. */ attr.sample_period =0 ; - +new_event: evsel =perf_evsel__new (&attr);if (evsel ==NULL ) goto out;
tools/perf/util/evsel.h +1 -1
@@ -185,7 +185,7 @@ static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *return perf_evsel__newtp_idx (sys, name,0 ); } -struct perf_evsel *perf_evsel__new_cycles (void ); +struct perf_evsel *perf_evsel__new_cycles (bool precise);struct event_format *event_format__new (const char *sys,const char *name);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 40/86 perf evlist: Allow asking for max precise_ip in add_default()
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
There are cases where we want to leave attr.precise_ip as zero, such as when using 'perf record --no-samples', where this would make the kernel return -EINVAL.
--- tools/perf/util/evlist.c | 4 ++-- tools/perf/util/evlist.h | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-)
tools/perf/util/evlist.c +2 -2
@@ -242,9 +242,9 @@ void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr) } } -int perf_evlist__add_default (struct perf_evlist *evlist) +int __perf_evlist__add_default (struct perf_evlist *evlist,bool precise) { -struct perf_evsel *evsel =perf_evsel__new_cycles (true); +struct perf_evsel *evsel =perf_evsel__new_cycles (precise);if (evsel ==NULL )return -ENOMEM ;
tools/perf/util/evlist.h +8 -1
@@ -115,7 +115,14 @@ void perf_evlist__delete(struct perf_evlist *evlist);void perf_evlist__add (struct perf_evlist *evlist,struct perf_evsel *entry);void perf_evlist__remove (struct perf_evlist *evlist,struct perf_evsel *evsel); -int perf_evlist__add_default (struct perf_evlist *evlist); + +int __perf_evlist__add_default (struct perf_evlist *evlist,bool precise); + +static inline int perf_evlist__add_default (struct perf_evlist *evlist) +{ +return __perf_evlist__add_default (evlist, true); +} +int __perf_evlist__add_default_attrs (struct perf_evlist *evlist,struct perf_event_attr *attrs,size_t nr_attrs);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 41/86 perf record: Do not ask for precise_ip with --no-samples
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
When the user doesn't specify an event with -e/--event, 'perf record' will use as a default the "cycles" event with the highest level of precision in perf_event_attr.precise_ip, but --no-samples, if present, is incompatible with precise_ip != 0, so use the newly introduced __perf_event__add_default(precise = false) to fix that:
Before:
# perf record -n usleep 1 Please consider tweaking /proc/sys/kernel/perf_event_max_sample_rate. Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (cycles:ppp). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured? #
After:
# perf record -n usleep 1 Please consider tweaking /proc/sys/kernel/perf_event_max_sample_rate. [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.018 MB perf.data ] [root@jouet /]# perf evlist -v cycles: size: 112, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 [root@jouet /]#
--- tools/perf/builtin-record.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/builtin-record.c +1 -1
@@ -1821,7 +1821,7 @@ int cmd_record(int argc, const char **argv) record.opts.tail_synthesize = true;if (rec->evlist->nr_entries ==0 && -perf_evlist__add_default (rec->evlist) <0 ) { +__perf_evlist__add_default (rec->evlist, !record.opts.no_samples) <0 ) {pr_err ("Not enough memory for event selector list\n" ); goto out; }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 42/86 perf test sdt: Handle realpath() failure
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
It can return NULL, in which case we should bail out and remove the directory created with mkdtemp(), which is stored in the "__tempdir" variable, not in "tempdir".
--- tools/perf/tests/sdt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/tests/sdt.c +3 -1
@@ -83,6 +83,8 @@ int test__sdt_event(int subtests __maybe_unused) }/* Note that buildid_dir must be an absolute path */ tempdir =realpath (__tempdir,NULL ); +if (tempdir ==NULL ) + goto error_rmdir;/* At first, scan itself */ set_buildid_dir (tempdir);
@@ -100,7 +102,7 @@ int test__sdt_event(int subtests __maybe_unused) error_rmdir:/* Cleanup temporary buildid dir */ -rm_rf (tempdir); +rm_rf (__tempdir); error:free (tempdir);free (myself);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 43/86 perf tests attr: Do not store failed events
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Do not mess up our temp space with files we don't need - failed event open attempts.
--- tools/perf/tests/attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/attr.c +1 -1
@@ -136,7 +136,7 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, {int errno_saved = errno; -if (store_event (attr, pid, cpu, fd, group_fd, flags)) { +if ((fd !=-1 ) &&store_event (attr, pid, cpu, fd, group_fd, flags)) {pr_err ("test attr FAILED" );exit (128 ); }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 44/86 perf tests attr: Add test_attr__ready function
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
We create many test events before the real ones just to test specific features. But there's no way for attr tests to separate those test events from those it needs to check.
Adding 'ready' call from the events open interface to trigger/start events collection for attr test.
--- tools/perf/perf.h | 1 + tools/perf/tests/attr.c | 10 ++++++++++ tools/perf/util/evsel.c | 4 ++++ 3 files changed, 15 insertions(+)
tools/perf/perf.h +1 -0
@@ -7,6 +7,7 @@#include <linux/perf_event.h> extern bool test_attr__enabled; +void test_attr__ready (void );void test_attr__init (void );void test_attr__open (struct perf_event_attr *attr,pid_t pid,int cpu,int fd,int group_fd,unsigned long flags);
tools/perf/tests/attr.c +10 -0
@@ -36,6 +36,7 @@#define ENV "PERF_TEST_ATTR"static char *dir; +static bool ready;void test_attr__init (void ) {
@@ -67,6 +68,9 @@ static int store_event(struct perf_event_attr *attr, pid_t pid, int cpu,FILE *file;char path[PATH_MAX ]; +if (!ready) +return 0 ; +snprintf (path,PATH_MAX ,"%s/event-%d-%llu-%d" , dir, attr->type, attr->config, fd);
@@ -144,6 +148,12 @@ void test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu, errno = errno_saved; } +void test_attr__ready (void ) +{ +if (unlikely (test_attr__enabled) && !ready) + ready = true; +} +static int run_dir (const char *d,const char *perf) {char v[] ="-vvvvv" ;
tools/perf/util/evsel.c +4 -0
@@ -58,6 +58,8 @@ static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused)return 0 ; } +void __weak test_attr__ready (void ) { } +static void perf_evsel__no_extra_fini (struct perf_evsel *evsel__maybe_unused ) { }
@@ -1572,6 +1574,8 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,pr_debug2 ("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx" , pid, cpus->map[cpu], group_fd, flags); +test_attr__ready (); + fd =sys_perf_event_open (&evsel->attr, pid, cpus->map[cpu], group_fd, flags);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 45/86 perf tests attr: Make compare_data global
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Making compare_data global, so it could be used outside the Test class scope to compare command results.
--- tools/perf/tests/attr.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-)
tools/perf/tests/attr.py +18 -18
@@ -9,6 +9,20 @@ import logging import shutil import ConfigParser +def compare_data(a, b): + # Allow multiple values in assignment separated by '|' + a_list = a.split('|') + b_list = b.split('|') + + for a_item in a_list: + for b_item in b_list: + if (a_item == b_item): + return True + elif (a_item == '*') or (b_item == '*'): + return True + + return False + class Fail(Exception): def __init__(self, test, msg): self.msg = msg
@@ -82,26 +96,12 @@ class Event(dict): self.add(base) self.add(data) - def compare_data(self, a, b): - # Allow multiple values in assignment separated by '|' - a_list = a.split('|') - b_list = b.split('|') - - for a_item in a_list: - for b_item in b_list: - if (a_item == b_item): - return True - elif (a_item == '*') or (b_item == '*'): - return True - - return False - def equal(self, other): for t in Event.terms: log.debug(" [%s] %s %s" % (t, self[t], other[t])); if not self.has_key(t) or not other.has_key(t): return False - if not self.compare_data(self[t], other[t]): + if not compare_data(self[t], other[t]): return False return True
@@ -109,7 +109,7 @@ class Event(dict): for t in Event.terms: if not self.has_key(t) or not other.has_key(t): continue - if not self.compare_data(self[t], other[t]): + if not compare_data(self[t], other[t]): log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) # Test file description needs to have following sections:
@@ -218,9 +218,9 @@ class Test(object): self.perf, self.command, tempdir, self.args) ret = os.WEXITSTATUS(os.system(cmd)) - log.info(" '%s' ret %d " % (cmd, ret)) + log.info(" '%s' ret '%s', expected '%s'" % (cmd, str(ret), str(self.ret))) - if ret != int(self.ret): + if not compare_data(str(ret), str(self.ret)): raise Unsup(self) def compare(self, expect, result):
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 46/86 perf tests attr: Rename compare_data to data_equal
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The data_equal name fits better to the return value of the function. It's true when the data is equal.
--- tools/perf/tests/attr.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/perf/tests/attr.py +4 -4
@@ -9,7 +9,7 @@ import logging import shutil import ConfigParser -def compare_data(a, b): +def data_equal(a, b): # Allow multiple values in assignment separated by '|' a_list = a.split('|') b_list = b.split('|')
@@ -101,7 +101,7 @@ class Event(dict): log.debug(" [%s] %s %s" % (t, self[t], other[t])); if not self.has_key(t) or not other.has_key(t): return False - if not compare_data(self[t], other[t]): + if not data_equal(self[t], other[t]): return False return True
@@ -109,7 +109,7 @@ class Event(dict): for t in Event.terms: if not self.has_key(t) or not other.has_key(t): continue - if not compare_data(self[t], other[t]): + if not data_equal(self[t], other[t]): log.warning("expected %s=%s, got %s" % (t, self[t], other[t])) # Test file description needs to have following sections:
@@ -220,7 +220,7 @@ class Test(object): log.info(" '%s' ret '%s', expected '%s'" % (cmd, str(ret), str(self.ret))) - if not compare_data(str(ret), str(self.ret)): + if not data_equal(str(ret), str(self.ret)): raise Unsup(self) def compare(self, expect, result):
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 47/86 perf tests attr: Add 1s for exclude_kernel and task base bits
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
There's an event open fallback which set exclude_kernel=1 in case use does not have enough privileges. Adding both 0|1 for this attribute, because we don't know what value it is.
--- tools/perf/tests/attr/base-record | 2 +- tools/perf/tests/attr/base-stat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
tools/perf/tests/attr/base-record +1 -1
@@ -15,7 +15,7 @@ inherit=1 pinned=0 exclusive=0 exclude_user=0 -exclude_kernel=0 +exclude_kernel=0|1 exclude_hv=0 exclude_idle=0 mmap=1
tools/perf/tests/attr/base-stat +1 -1
@@ -15,7 +15,7 @@ inherit=1 pinned=0 exclusive=0 exclude_user=0 -exclude_kernel=0 +exclude_kernel=0|1 exclude_hv=0 exclude_idle=0 mmap=0
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 48/86 perf tests attr: Fix record dwarf test
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Following commit:
commit 5c0cf22477ea ("perf record: Store data mmaps for dwarf unwind")
have enabled address sampling for dwarf unwind, we need to reflect that in this test by adding ADDR sample_type and enabling mmap_data.
--- tools/perf/tests/attr/test-record-graph-dwarf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/tests/attr/test-record-graph-dwarf +2 -1
@@ -3,8 +3,9 @@ command = record args = --call-graph dwarf -- kill >/dev/null 2>&1 [event:base-record] -sample_type=12583 +sample_type=45359 exclude_callchain_user=1 sample_stack_user=8192 # TODO different for each arch, no support for that now sample_regs_user=* +mmap_data=1
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 49/86 perf tests attr: Fix no-delay test
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Following commit:
commit 509051ea8427 ("perf record: Rename --no-delay to --no-buffering")
removed '-D' option and renamed --no-delay into --no-buffering. Fixing that in the attr tests.
---
.../perf/tests/attr/{test-record-no-delay => test-record-no-buffering} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename tools/perf/tests/attr/{test-record-no-delay => test-record-no-buffering} (70%)tools/perf/tests/attr/test-record-no-buffering renamed from tools/perf/tests/attr/test-record-no-delay +1 -1
@@ -1,6 +1,6 @@ [config] command = record -args = -D kill >/dev/null 2>&1 +args = --no-buffering kill >/dev/null 2>&1 [event:base-record] sample_period=4000
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 50/86 perf tests attr: Add proper return values
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The record command now properly returns the status of the tracee if there's any. We need to properly set the expected return value of the tracee in the attr tests.
--- tools/perf/tests/attr/test-record-C0 | 1 + tools/perf/tests/attr/test-record-basic | 1 + tools/perf/tests/attr/test-record-branch-any | 1 + tools/perf/tests/attr/test-record-branch-filter-any | 1 + tools/perf/tests/attr/test-record-branch-filter-any_call | 1 + tools/perf/tests/attr/test-record-branch-filter-any_ret | 1 + tools/perf/tests/attr/test-record-branch-filter-hv | 1 + tools/perf/tests/attr/test-record-branch-filter-ind_call | 1 + tools/perf/tests/attr/test-record-branch-filter-k | 1 + tools/perf/tests/attr/test-record-branch-filter-u | 1 + tools/perf/tests/attr/test-record-count | 1 + tools/perf/tests/attr/test-record-data | 1 + tools/perf/tests/attr/test-record-freq | 1 + tools/perf/tests/attr/test-record-graph-default | 1 + tools/perf/tests/attr/test-record-graph-dwarf | 1 + tools/perf/tests/attr/test-record-graph-fp | 1 + tools/perf/tests/attr/test-record-group | 1 + tools/perf/tests/attr/test-record-group-sampling | 1 + tools/perf/tests/attr/test-record-group1 | 1 + tools/perf/tests/attr/test-record-no-buffering | 1 + tools/perf/tests/attr/test-record-no-inherit | 1 + tools/perf/tests/attr/test-record-no-samples | 1 + tools/perf/tests/attr/test-record-period | 1 + tools/perf/tests/attr/test-record-raw | 1 + 24 files changed, 24 insertions(+)
tools/perf/tests/attr/test-record-C0 +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -C 0 kill >/dev/null 2>&1 +ret = 1 [event:base-record] cpu=0
tools/perf/tests/attr/test-record-basic +1 -0
@@ -1,5 +1,6 @@ [config] command = record args = kill >/dev/null 2>&1 +ret = 1 [event:base-record]
tools/perf/tests/attr/test-record-branch-any +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -b kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-branch-filter-any +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -j any kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-branch-filter-any_call +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -j any_call kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-branch-filter-any_ret +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -j any_ret kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-branch-filter-hv +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -j hv kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-branch-filter-ind_call +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -j ind_call kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-branch-filter-k +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -j k kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-branch-filter-u +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -j u kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-count +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -c 123 kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=123
tools/perf/tests/attr/test-record-data +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -d kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-freq +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -F 100 kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=100
tools/perf/tests/attr/test-record-graph-default +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -g kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_type=295
tools/perf/tests/attr/test-record-graph-dwarf +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = --call-graph dwarf -- kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_type=45359
tools/perf/tests/attr/test-record-graph-fp +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = --call-graph fp kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_type=295
tools/perf/tests/attr/test-record-group +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = --group -e cycles,instructions kill >/dev/null 2>&1 +ret = 1 [event-1:base-record] fd=1
tools/perf/tests/attr/test-record-group-sampling +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -e '{cycles,cache-misses}:S' kill >/dev/null 2>&1 +ret = 1 [event-1:base-record] fd=1
tools/perf/tests/attr/test-record-group1 +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -e '{cycles,instructions}' kill >/dev/null 2>&1 +ret = 1 [event-1:base-record] fd=1
tools/perf/tests/attr/test-record-no-buffering +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = --no-buffering kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
tools/perf/tests/attr/test-record-no-inherit +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -i kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_type=263
tools/perf/tests/attr/test-record-no-samples +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -n kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=0
tools/perf/tests/attr/test-record-period +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -c 100 -P kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=100
tools/perf/tests/attr/test-record-raw +1 -0
@@ -1,6 +1,7 @@ [config] command = record args = -R kill >/dev/null 2>&1 +ret = 1 [event:base-record] sample_period=4000
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 51/86 perf tests attr: Fix cpu test disabled term setup
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The stat command creates all events disabled and enables them either manualy or via the enable_on_exec bit.
--- tools/perf/tests/attr/test-stat-C0 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/tests/attr/test-stat-C0 +2 -2
@@ -4,6 +4,6 @@ args = -e cycles -C 0 kill >/dev/null 2>&1 ret = 1 [event:base-stat] -# events are enabled by default when attached to cpu -disabled=0 +# events are disabled by default when attached to cpu +disabled=1 enable_on_exec=0
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 52/86 perf tests attr: Fix sample_period setup
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
The final period can differ from what user specifies on command line due to the perf_event_max_sample_rate sysctl setup.
Thus we can't predixt the sample_period value any more.
--- tools/perf/tests/attr/base-record | 2 +- tools/perf/tests/attr/test-record-branch-any | 1 - tools/perf/tests/attr/test-record-branch-filter-any | 1 - tools/perf/tests/attr/test-record-branch-filter-any_call | 1 - tools/perf/tests/attr/test-record-branch-filter-any_ret | 1 - tools/perf/tests/attr/test-record-branch-filter-hv | 1 - tools/perf/tests/attr/test-record-branch-filter-ind_call | 1 - tools/perf/tests/attr/test-record-branch-filter-k | 1 - tools/perf/tests/attr/test-record-branch-filter-u | 1 - tools/perf/tests/attr/test-record-data | 2 -- tools/perf/tests/attr/test-record-no-buffering | 1 - tools/perf/tests/attr/test-record-raw | 1 - 12 files changed, 1 insertion(+), 13 deletions(-)
tools/perf/tests/attr/base-record +1 -1
@@ -7,7 +7,7 @@ cpu=* type=0|1 size=112 config=0 -sample_period=4000 +sample_period=* sample_type=263 read_format=0 disabled=1
tools/perf/tests/attr/test-record-branch-any +0 -1
@@ -4,6 +4,5 @@ args = -b kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=8
tools/perf/tests/attr/test-record-branch-filter-any +0 -1
@@ -4,6 +4,5 @@ args = -j any kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=8
tools/perf/tests/attr/test-record-branch-filter-any_call +0 -1
@@ -4,6 +4,5 @@ args = -j any_call kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=16
tools/perf/tests/attr/test-record-branch-filter-any_ret +0 -1
@@ -4,6 +4,5 @@ args = -j any_ret kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=32
tools/perf/tests/attr/test-record-branch-filter-hv +0 -1
@@ -4,6 +4,5 @@ args = -j hv kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=8
tools/perf/tests/attr/test-record-branch-filter-ind_call +0 -1
@@ -4,6 +4,5 @@ args = -j ind_call kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=64
tools/perf/tests/attr/test-record-branch-filter-k +0 -1
@@ -4,6 +4,5 @@ args = -j k kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=8
tools/perf/tests/attr/test-record-branch-filter-u +0 -1
@@ -4,6 +4,5 @@ args = -j u kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=2311 branch_sample_type=8
tools/perf/tests/attr/test-record-data +0 -2
@@ -4,8 +4,6 @@ args = -d kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 - # sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | # PERF_SAMPLE_ADDR | PERF_SAMPLE_PERIOD | PERF_SAMPLE_DATA_SRC sample_type=33039
tools/perf/tests/attr/test-record-no-buffering +0 -1
@@ -4,7 +4,6 @@ args = --no-buffering kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=263 watermark=0 wakeup_events=1
tools/perf/tests/attr/test-record-raw +0 -1
@@ -4,5 +4,4 @@ args = -R kill >/dev/null 2>&1 ret = 1 [event:base-record] -sample_period=4000 sample_type=1415
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 53/86 perf tests attr: Fix precise_ip setup
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
We have a test to detect to highest precise possible, so test can't just predict precise_ip value.
--- tools/perf/tests/attr/base-record | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/attr/base-record +1 -1
@@ -25,7 +25,7 @@ inherit_stat=0 enable_on_exec=1 task=0 watermark=0 -precise_ip=0 +precise_ip=0|1|2|3 mmap_data=0 sample_id_all=1 exclude_host=0|1
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 54/86 perf tests attr: Fix stat sample_type setup
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
From following commit:
commit 4979d0c7d0c7 ("perf stat record: Add record command")
we started to assign PERF_SAMPLE_IDENTIFIER to sample_type.
Fixing the attr stat tests accordingly.
--- tools/perf/tests/attr/base-stat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/tests/attr/base-stat +1 -1
@@ -8,7 +8,7 @@ type=0 size=112 config=0 sample_period=0 -sample_type=0 +sample_type=65536 read_format=3 disabled=1 inherit=1
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 55/86 perf tests attr: Add optional term
In reply to Arnaldo Carvalho de MeloFrom: Jiri Olsa <[email protected]>
Some of the stat events are quite rare to find on common machines (like front end cycles).
Adding an 'optional' term to mark such events in attr tests. Event marked as optional will not fail the test case if it's not found in results.
--- tools/perf/tests/attr.py | 14 +++++++++++--- tools/perf/tests/attr/test-stat-default | 2 ++ tools/perf/tests/attr/test-stat-detailed-1 | 2 ++ tools/perf/tests/attr/test-stat-detailed-2 | 3 +++ tools/perf/tests/attr/test-stat-detailed-3 | 5 +++++ 5 files changed, 23 insertions(+), 3 deletions(-)
tools/perf/tests/attr.py +11 -3
@@ -105,6 +105,11 @@ class Event(dict): return False return True + def optional(self): + if self.has_key('optional') and self['optional'] == '1': + return True + return False + def diff(self, other): for t in Event.terms: if not self.has_key(t) or not other.has_key(t):
@@ -244,9 +249,12 @@ class Test(object): log.debug(" match: [%s] matches %s" % (exp_name, str(exp_list))) # we did not any matching event - fail - if (not exp_list): - exp_event.diff(res_event) - raise Fail(self, 'match failure'); + if not exp_list: + if exp_event.optional(): + log.debug(" %s does not match, but is optional" % exp_name) + else: + exp_event.diff(res_event) + raise Fail(self, 'match failure'); match[exp_name] = exp_list
tools/perf/tests/attr/test-stat-default +2 -0
@@ -38,12 +38,14 @@ config=0 fd=6 type=0 config=7 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND [event7:base-stat] fd=7 type=0 config=8 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS [event8:base-stat]
tools/perf/tests/attr/test-stat-detailed-1 +2 -0
@@ -39,12 +39,14 @@ config=0 fd=6 type=0 config=7 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND [event7:base-stat] fd=7 type=0 config=8 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS [event8:base-stat]
tools/perf/tests/attr/test-stat-detailed-2 +3 -0
@@ -39,12 +39,14 @@ config=0 fd=6 type=0 config=7 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND [event7:base-stat] fd=7 type=0 config=8 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS [event8:base-stat]
@@ -108,6 +110,7 @@ config=65538 fd=15 type=3 config=1 +optional=1 # PERF_TYPE_HW_CACHE, # PERF_COUNT_HW_CACHE_L1I << 0 |
tools/perf/tests/attr/test-stat-detailed-3 +5 -0
@@ -39,12 +39,14 @@ config=0 fd=6 type=0 config=7 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_STALLED_CYCLES_BACKEND [event7:base-stat] fd=7 type=0 config=8 +optional=1 # PERF_TYPE_HARDWARE / PERF_COUNT_HW_INSTRUCTIONS [event8:base-stat]
@@ -108,6 +110,7 @@ config=65538 fd=15 type=3 config=1 +optional=1 # PERF_TYPE_HW_CACHE, # PERF_COUNT_HW_CACHE_L1I << 0 |
@@ -162,6 +165,7 @@ config=65540 fd=21 type=3 config=512 +optional=1 # PERF_TYPE_HW_CACHE, # PERF_COUNT_HW_CACHE_L1D << 0 |
@@ -171,3 +175,4 @@ config=512 fd=22 type=3 config=66048 +optional=1
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 56/86 perf trace beauty: Export strarray for use in per-object beautifiers
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Like will be done with fcntl(fd, F_GETLEASE, F_RDLCK|F_WRLCK|F_UNLCK)
--- tools/perf/builtin-trace.c | 27 +++++++-------------------- tools/perf/trace/beauty/beauty.h | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 20 deletions(-)
tools/perf/builtin-trace.c +7 -20
@@ -283,34 +283,21 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void ({struct syscall_tp *fields = evsel->priv; \ fields->name.pointer(&fields->name, sample); }) -struct strarray { -int offset; -int nr_entries; -const char **entries; -}; +size_t strarray__scnprintf (struct strarray *sa,char *bf,size_t size,const char *intfmt,int val) +{ +int idx = val - sa->offset; -#define DEFINE_STRARRAY (array) struct strarray strarray__##array = { \ - .nr_entries = ARRAY_SIZE(array), \ - .entries = array, \ -} +if (idx <0 || idx >= sa->nr_entries) +return scnprintf (bf, size, intfmt, val); -#define DEFINE_STRARRAY_OFFSET (array, off) struct strarray strarray__##array = { \ - .offset = off, \ - .nr_entries = ARRAY_SIZE(array), \ - .entries = array, \ +return scnprintf (bf, size,"%s" , sa->entries[idx]); }static size_t __syscall_arg__scnprintf_strarray (char *bf,size_t size,const char *intfmt,struct syscall_arg *arg) { -struct strarray *sa = arg->parm; -int idx = arg->val - sa->offset; - -if (idx <0 || idx >= sa->nr_entries) -return scnprintf (bf, size, intfmt, arg->val); - -return scnprintf (bf, size,"%s" , sa->entries[idx]); +return strarray__scnprintf (arg->parm, bf, size, intfmt, arg->val); } static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
tools/perf/trace/beauty/beauty.h +20 -0
@@ -1,8 +1,28 @@#ifndef _PERF_TRACE_BEAUTY_H#define _PERF_TRACE_BEAUTY_H +#include <linux/kernel.h> #include <linux/types.h> +struct strarray { +int offset; +int nr_entries; +const char **entries; +}; + +#define DEFINE_STRARRAY (array) struct strarray strarray__##array = { \ + .nr_entries = ARRAY_SIZE(array), \ + .entries = array, \ +} + +#define DEFINE_STRARRAY_OFFSET (array, off) struct strarray strarray__##array = { \ + .offset = off, \ + .nr_entries = ARRAY_SIZE(array), \ + .entries = array, \ +} + +size_t strarray__scnprintf (struct strarray *sa,char *bf,size_t size,const char *intfmt,int val); +struct trace ;struct thread ;
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 57/86 perf trace beauty fcntl: Beautify F_GETLEASE and F_SETLEASE arg/return
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
One more looking prettier.
--- tools/perf/trace/beauty/fcntl.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
tools/perf/trace/beauty/fcntl.c +21 -1
@@ -20,6 +20,19 @@ static size_t syscall_arg__scnprintf_fcntl_getfd(char *bf, size_t size, struct sreturn fcntl__scnprintf_getfd (arg->val, bf, size); } +static size_t fcntl__scnprintf_getlease (unsigned long val,char *bf,size_t size) +{ +static const char *fcntl_setlease[] = {"RDLCK" ,"WRLCK" ,"UNLCK" , }; +static DEFINE_STRARRAY (fcntl_setlease); + +return strarray__scnprintf (&strarray__fcntl_setlease, bf, size,"%x" , val); +} + +static size_t syscall_arg__scnprintf_fcntl_getlease (char *bf,size_t size,struct syscall_arg *arg) +{ +return fcntl__scnprintf_getlease (arg->val, bf, size); +} +size_t syscall_arg__scnprintf_fcntl_cmd (char *bf,size_t size,struct syscall_arg *arg) {if (arg->val ==F_GETFL ) {
@@ -38,11 +51,15 @@ size_t syscall_arg__scnprintf_fcntl_cmd(char *bf, size_t size, struct syscall_arsyscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_pid); goto mask_arg; } +if (arg->val ==F_GETLEASE ) { +syscall_arg__set_ret_scnprintf (arg, syscall_arg__scnprintf_fcntl_getlease); + goto mask_arg; + }/* * Some commands ignore the third fcntl argument, "arg", so mask it */ if (arg->val ==F_GET_SEALS || - arg->val ==F_GETLEASE || arg->val ==F_GETSIG ) { + arg->val ==F_GETSIG ) { mask_arg: arg->mask |= (1 <<2 ); }
@@ -62,6 +79,9 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_arif (cmd ==F_SETOWN )return syscall_arg__scnprintf_pid (bf, size, arg); + +if (cmd ==F_SETLEASE ) +return fcntl__scnprintf_getlease (arg->val, bf, size);/* * We still don't grab the contents of pointers on entry or exit, * so just print them as hex numbers
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 58/86 perf trace: Group per syscall arg formatter info into one struct
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Instead of having syscall_fmt.{arg_scnprintf,arg_parm}, introduce struct syscall_arg_fmt and have these two, paving the way for more state to change the formatting algorithms.
For instance, in the 'fcntl' 'cmd' case it is better not to suppress it when being zero, showing instead its name "DUPFD".
We had that in an ad-hoc way just for strarrays, but with more involved cases like fcntl, that can't be done with just a strarray, we'll need a ".show_zero" arg in the 'cmd' syscall_arg_fmt.
--- tools/perf/builtin-trace.c | 256 +++++++++++++++++++++++---------------------- 1 file changed, 133 insertions(+), 123 deletions(-)
tools/perf/builtin-trace.c +133 -123
@@ -582,9 +582,9 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags -#define STRARRAY (arg, name, array) \ - .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ - .arg_parm = { [arg] = &strarray__##array, } +#define STRARRAY (name, array) \ + { .scnprintf = SCA_STRARRAY, \ + .parm = &strarray__##array, }#include "trace/beauty/eventfd.c" #include "trace/beauty/flock.c"
@@ -601,54 +601,61 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,#include "trace/beauty/socket_type.c" #include "trace/beauty/waitid_options.c" +struct syscall_arg_fmt { +size_t (*scnprintf)(char *bf,size_t size,struct syscall_arg *arg); +void *parm; +}; +static struct syscall_fmt {const char *name;const char *alias; -size_t (*arg_scnprintf[6 ])(char *bf,size_t size,struct syscall_arg *arg); -void *arg_parm[6 ]; +struct syscall_arg_fmt arg[6 ];bool errmsg;bool errpid;bool timeout;bool hexret; } syscall_fmts[] = { { .name ="access" , .errmsg = true, - .arg_scnprintf = { [1 ] =SCA_ACCMODE ,/* mode */ }, }, + .arg = { [1 ] = { .scnprintf =SCA_ACCMODE ,/* mode */ }, }, }, { .name ="arch_prctl" , .errmsg = true, .alias ="prctl" , }, - { .name ="bpf" , .errmsg = true,STRARRAY (0 , cmd, bpf_cmd), }, + { .name ="bpf" , .errmsg = true, + .arg = { [0 ] =STRARRAY (cmd, bpf_cmd), }, }, { .name ="brk" , .hexret = true, - .arg_scnprintf = { [0 ] =SCA_HEX ,/* brk */ }, }, + .arg = { [0 ] = { .scnprintf =SCA_HEX ,/* brk */ }, }, }, { .name ="chdir" , .errmsg = true, }, { .name ="chmod" , .errmsg = true, }, { .name ="chroot" , .errmsg = true, }, - { .name ="clock_gettime" , .errmsg = true,STRARRAY (0 , clk_id, clockid), }, + { .name ="clock_gettime" , .errmsg = true, + .arg = { [0 ] =STRARRAY (clk_id, clockid), }, }, { .name ="clone" , .errpid = true, }, { .name ="close" , .errmsg = true, - .arg_scnprintf = { [0 ] =SCA_CLOSE_FD ,/* fd */ }, }, + .arg = { [0 ] = { .scnprintf =SCA_CLOSE_FD ,/* fd */ }, }, }, { .name ="connect" , .errmsg = true, }, { .name ="creat" , .errmsg = true, }, { .name ="dup" , .errmsg = true, }, { .name ="dup2" , .errmsg = true, }, { .name ="dup3" , .errmsg = true, }, - { .name ="epoll_ctl" , .errmsg = true,STRARRAY (1 , op, epoll_ctl_ops), }, + { .name ="epoll_ctl" , .errmsg = true, + .arg = { [1 ] =STRARRAY (op, epoll_ctl_ops), }, }, { .name ="eventfd2" , .errmsg = true, - .arg_scnprintf = { [1 ] =SCA_EFD_FLAGS ,/* flags */ }, }, + .arg = { [1 ] = { .scnprintf =SCA_EFD_FLAGS ,/* flags */ }, }, }, { .name ="faccessat" , .errmsg = true, }, { .name ="fadvise64" , .errmsg = true, }, { .name ="fallocate" , .errmsg = true, }, { .name ="fchdir" , .errmsg = true, }, { .name ="fchmod" , .errmsg = true, }, { .name ="fchmodat" , .errmsg = true, - .arg_scnprintf = { [0 ] =SCA_FDAT ,/* fd */ }, }, + .arg = { [0 ] = { .scnprintf =SCA_FDAT ,/* fd */ }, }, }, { .name ="fchown" , .errmsg = true, }, { .name ="fchownat" , .errmsg = true, - .arg_scnprintf = { [0 ] =SCA_FDAT ,/* fd */ }, }, + .arg = { [0 ] = { .scnprintf =SCA_FDAT ,/* fd */ }, }, }, { .name ="fcntl" , .errmsg = true, - .arg_scnprintf = { [1 ] =SCA_FCNTL_CMD ,/* cmd */ - [2 ] =SCA_FCNTL_ARG ,/* arg */ }, - .arg_parm = { [1 ] = &strarrays__fcntl_cmds_arrays,/* cmd */ }, }, + .arg = { [1 ] = { .scnprintf =SCA_FCNTL_CMD ,/* cmd */ + .parm = &strarrays__fcntl_cmds_arrays,/* cmd */ }, + [2 ] = { .scnprintf =SCA_FCNTL_ARG ,/* arg */ }, }, }, { .name ="fdatasync" , .errmsg = true, }, { .name ="flock" , .errmsg = true, - .arg_scnprintf = { [1 ] =SCA_FLOCK ,/* cmd */ }, }, + .arg = { [1 ] = { .scnprintf =SCA_FLOCK ,/* cmd */ }, }, }, { .name ="fsetxattr" , .errmsg = true, }, { .name ="fstat" , .errmsg = true, .alias ="newfstat" , }, { .name ="fstatat" , .errmsg = true, .alias ="newfstatat" , },
@@ -656,186 +663,190 @@ static struct syscall_fmt { { .name = "fsync", .errmsg = true, }, { .name = "ftruncate", .errmsg = true, }, { .name = "futex", .errmsg = true, - .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, }, + .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, }, { .name = "futimesat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, { .name = "getdents", .errmsg = true, }, { .name = "getdents64", .errmsg = true, }, - { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, + { .name = "getitimer", .errmsg = true, + .arg = { [0] = STRARRAY(which, itimers), }, }, { .name = "getpid", .errpid = true, }, { .name = "getpgid", .errpid = true, }, { .name = "getppid", .errpid = true, }, { .name = "getrandom", .errmsg = true, - .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, }, - { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, + .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, }, + { .name = "getrlimit", .errmsg = true, + .arg = { [0] = STRARRAY(resource, rlimit_resources), }, }, { .name = "getxattr", .errmsg = true, }, - { .name = "inotify_add_watch", .errmsg = true, }, + { .name = "inotify_add_watch", .errmsg = true, }, { .name = "ioctl", .errmsg = true, - .arg_scnprintf = { + .arg = { #if defined(__i386__) || defined(__x86_64__) /* * FIXME: Make this available to all arches. */ - [1] = SCA_STRHEXARRAY, /* cmd */ - [2] = SCA_HEX, /* arg */ }, - .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, }, + [1] = { .scnprintf = SCA_STRHEXARRAY, /* cmd */ + .parm = &strarray__tioctls, }, + [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, }, #else - [2] = SCA_HEX, /* arg */ }, }, + [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, }, #endif - { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), }, + { .name = "keyctl", .errmsg = true, + .arg = { [0] = STRARRAY(option, keyctl_options), }, }, { .name = "kill", .errmsg = true, - .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, + .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, { .name = "lchown", .errmsg = true, }, { .name = "lgetxattr", .errmsg = true, }, { .name = "linkat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, { .name = "listxattr", .errmsg = true, }, { .name = "llistxattr", .errmsg = true, }, { .name = "lremovexattr", .errmsg = true, }, { .name = "lseek", .errmsg = true, - .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ }, - .arg_parm = { [2] = &strarray__whences, /* whence */ }, }, + .arg = { [2] = STRARRAY(whence, whences), }, }, { .name = "lsetxattr", .errmsg = true, }, { .name = "lstat", .errmsg = true, .alias = "newlstat", }, { .name = "lsxattr", .errmsg = true, }, { .name = "madvise", .errmsg = true, - .arg_scnprintf = { [0] = SCA_HEX, /* start */ - [2] = SCA_MADV_BHV, /* behavior */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, + [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, }, { .name = "mkdir", .errmsg = true, }, { .name = "mkdirat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, { .name = "mknod", .errmsg = true, }, { .name = "mknodat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, { .name = "mlock", .errmsg = true, - .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, { .name = "mlockall", .errmsg = true, - .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, { .name = "mmap", .hexret = true, /* The standard mmap maps to old_mmap on s390x */ #if defined(__s390x__) .alias = "old_mmap", #endif - .arg_scnprintf = { [0] = SCA_HEX, /* addr */ - [2] = SCA_MMAP_PROT, /* prot */ - [3] = SCA_MMAP_FLAGS, /* flags */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, + [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, + [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, }, { .name = "mprotect", .errmsg = true, - .arg_scnprintf = { [0] = SCA_HEX, /* start */ - [2] = SCA_MMAP_PROT, /* prot */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, + [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, }, { .name = "mq_unlink", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, }, + .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, }, { .name = "mremap", .hexret = true, - .arg_scnprintf = { [0] = SCA_HEX, /* addr */ - [3] = SCA_MREMAP_FLAGS, /* flags */ - [4] = SCA_HEX, /* new_addr */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, + [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ }, + [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, }, { .name = "munlock", .errmsg = true, - .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, { .name = "munmap", .errmsg = true, - .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, + .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, { .name = "name_to_handle_at", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "newfstatat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "open", .errmsg = true, - .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, }, + .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, }, { .name = "open_by_handle_at", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [2] = SCA_OPEN_FLAGS, /* flags */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, + [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, }, { .name = "openat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ - [2] = SCA_OPEN_FLAGS, /* flags */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, + [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, }, { .name = "perf_event_open", .errmsg = true, - .arg_scnprintf = { [2] = SCA_INT, /* cpu */ - [3] = SCA_FD, /* group_fd */ - [4] = SCA_PERF_FLAGS, /* flags */ }, }, + .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ }, + [3] = { .scnprintf = SCA_FD, /* group_fd */ }, + [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, }, { .name = "pipe2", .errmsg = true, - .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, }, + .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, }, { .name = "poll", .errmsg = true, .timeout = true, }, { .name = "ppoll", .errmsg = true, .timeout = true, }, { .name = "pread", .errmsg = true, .alias = "pread64", }, { .name = "preadv", .errmsg = true, .alias = "pread", }, - { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), }, + { .name = "prlimit64", .errmsg = true, + .arg = { [1] = STRARRAY(resource, rlimit_resources), }, }, { .name = "pwrite", .errmsg = true, .alias = "pwrite64", }, { .name = "pwritev", .errmsg = true, }, { .name = "read", .errmsg = true, }, { .name = "readlink", .errmsg = true, }, { .name = "readlinkat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "readv", .errmsg = true, }, { .name = "recvfrom", .errmsg = true, - .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "recvmmsg", .errmsg = true, - .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "recvmsg", .errmsg = true, - .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "removexattr", .errmsg = true, }, { .name = "renameat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "rmdir", .errmsg = true, }, { .name = "rt_sigaction", .errmsg = true, - .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, }, - { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), }, + .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, + { .name = "rt_sigprocmask", .errmsg = true, + .arg = { [0] = STRARRAY(how, sighow), }, }, { .name = "rt_sigqueueinfo", .errmsg = true, - .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, + .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, { .name = "rt_tgsigqueueinfo", .errmsg = true, - .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, + .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, { .name = "sched_getattr", .errmsg = true, }, { .name = "sched_setattr", .errmsg = true, }, { .name = "sched_setscheduler", .errmsg = true, - .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, }, + .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, }, { .name = "seccomp", .errmsg = true, - .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */ - [1] = SCA_SECCOMP_FLAGS, /* flags */ }, }, + .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ }, + [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, }, { .name = "select", .errmsg = true, .timeout = true, }, { .name = "sendmmsg", .errmsg = true, - .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "sendmsg", .errmsg = true, - .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "sendto", .errmsg = true, - .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, }, + .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "set_tid_address", .errpid = true, }, - { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, + { .name = "setitimer", .errmsg = true, + .arg = { [0] = STRARRAY(which, itimers), }, }, { .name = "setpgid", .errmsg = true, }, - { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, + { .name = "setrlimit", .errmsg = true, + .arg = { [0] = STRARRAY(resource, rlimit_resources), }, }, { .name = "setxattr", .errmsg = true, }, { .name = "shutdown", .errmsg = true, }, { .name = "socket", .errmsg = true, - .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ - [1] = SCA_SK_TYPE, /* type */ }, - .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, + .arg = { [0] = STRARRAY(family, socket_families), + [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, }, { .name = "socketpair", .errmsg = true, - .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ - [1] = SCA_SK_TYPE, /* type */ }, - .arg_parm = { [0] = &strarray__socket_families, /* family */ }, }, + .arg = { [0] = STRARRAY(family, socket_families), + [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, }, { .name = "stat", .errmsg = true, .alias = "newstat", }, { .name = "statfs", .errmsg = true, }, { .name = "statx", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* flags */ - [2] = SCA_STATX_FLAGS, /* flags */ - [3] = SCA_STATX_MASK, /* mask */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ }, + [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } , + [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, }, { .name = "swapoff", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, }, + .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, }, { .name = "swapon", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, }, + .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, }, { .name = "symlinkat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "tgkill", .errmsg = true, - .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, + .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, { .name = "tkill", .errmsg = true, - .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, + .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, { .name = "truncate", .errmsg = true, }, { .name = "uname", .errmsg = true, .alias = "newuname", }, { .name = "unlinkat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, { .name = "utime", .errmsg = true, }, { .name = "utimensat", .errmsg = true, - .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, }, + .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, }, { .name = "utimes", .errmsg = true, }, { .name = "vmsplice", .errmsg = true, }, { .name = "wait4", .errpid = true, - .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, }, + .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, }, { .name = "waitid", .errpid = true, - .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, }, + .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, }, { .name = "write", .errmsg = true, }, { .name = "writev", .errmsg = true, }, };
@@ -859,8 +870,7 @@ struct syscall {const char *name;bool is_exit;struct syscall_fmt *fmt; -size_t (**arg_scnprintf)(char *bf,size_t size,struct syscall_arg *arg); -void **arg_parm; +struct syscall_arg_fmt *arg_fmt; };/*
@@ -1209,27 +1219,29 @@ static int syscall__set_arg_fmts(struct syscall *sc)struct format_field *field;int idx =0 , len; - sc->arg_scnprintf =calloc (sc->nr_args,sizeof (void *)); -if (sc->arg_scnprintf ==NULL ) + sc->arg_fmt =calloc (sc->nr_args,sizeof (*sc->arg_fmt)); +if (sc->arg_fmt ==NULL )return -1 ; -if (sc->fmt) - sc->arg_parm = sc->fmt->arg_parm; +for (field = sc->args; field; field = field->next, ++idx) { +if (sc->fmt) { + sc->arg_fmt[idx] = sc->fmt->arg[idx]; + +if (sc->fmt->arg[idx].scnprintf) +continue ; + } -for (field = sc->args; field; field = field->next) { -if (sc->fmt && sc->fmt->arg_scnprintf[idx]) - sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; -else if (strcmp (field->type,"const char *" ) ==0 && +if (strcmp (field->type,"const char *" ) ==0 && (strcmp (field->name,"filename" ) ==0 ||strcmp (field->name,"path" ) ==0 ||strcmp (field->name,"pathname" ) ==0 )) - sc->arg_scnprintf[idx] =SCA_FILENAME ; + sc->arg_fmt[idx].scnprintf =SCA_FILENAME ;else if (field->flags &FIELD_IS_POINTER ) - sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; + sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;else if (strcmp (field->type,"pid_t" ) ==0 ) - sc->arg_scnprintf[idx] =SCA_PID ; + sc->arg_fmt[idx].scnprintf =SCA_PID ;else if (strcmp (field->type,"umode_t" ) ==0 ) - sc->arg_scnprintf[idx] =SCA_MODE_T ; + sc->arg_fmt[idx].scnprintf =SCA_MODE_T ; else if ((strcmp(field->type, "int") == 0 || strcmp(field->type, "unsigned int") == 0 || strcmp(field->type, "long") == 0) &&
@@ -1242,9 +1254,8 @@ static int syscall__set_arg_fmts(struct syscall *sc)* 23 unsigned int * 7 unsigned long */ - sc->arg_scnprintf[idx] =SCA_FD ; + sc->arg_fmt[idx].scnprintf =SCA_FD ; } - ++idx; }return 0 ;
@@ -1416,20 +1427,19 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,* strarray for it. */ if (val ==0 && - !(sc->arg_scnprintf && - (sc->arg_scnprintf[arg.idx] ==SCA_STRARRAY || - sc->arg_scnprintf[arg.idx] ==SCA_STRARRAYS ) && - sc->arg_parm[arg.idx])) + !(sc->arg_fmt && + (sc->arg_fmt[arg.idx].scnprintf ==SCA_STRARRAY || + sc->arg_fmt[arg.idx].scnprintf ==SCA_STRARRAYS ) && + sc->arg_fmt[arg.idx].parm))continue ; printed +=scnprintf (bf + printed, size - printed,"%s%s: " , printed ?", " :"" , field->name); -if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) { +if (sc->arg_fmt && sc->arg_fmt[arg.idx].scnprintf) { arg.val = val; -if (sc->arg_parm) - arg.parm = sc->arg_parm[arg.idx]; - printed += sc->arg_scnprintf[arg.idx](bf + printed, - size - printed, &arg); +if (sc->arg_fmt[arg.idx].parm) + arg.parm = sc->arg_fmt[arg.idx].parm; + printed += sc->arg_fmt[arg.idx].scnprintf (bf + printed, size - printed, &arg); }else { printed +=scnprintf (bf + printed, size - printed,"%ld" , val);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 59/86 perf trace: Allow syscall arg formatters to request non suppression of zeros
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The 'perf trace' tool is suppressing args set to zero, with the exception of string tables (strarrays), which are kinda like enums, i.e. we have maps to go from numbers to strings.
But the 'cmd' fcntl arg requires more specialized treatment, as its value will regulate if the next fcntl syscall arg, 'arg', should be ignored (not used) and also how to format the syscall return (fd, file flags, etc), so add a 'show_zero" bool to struct syscall_arg_fmt, to regulate this more explicitely.
Will be used in a following patch with fcntl, here is just the mechanism.
--- tools/perf/builtin-trace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/builtin-trace.c +3 -1
@@ -604,6 +604,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,struct syscall_arg_fmt {size_t (*scnprintf)(char *bf,size_t size,struct syscall_arg *arg);void *parm; +bool show_zero; }; static struct syscall_fmt {
@@ -1428,7 +1429,8 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,*/ if (val ==0 && !(sc->arg_fmt && - (sc->arg_fmt[arg.idx].scnprintf ==SCA_STRARRAY || + (sc->arg_fmt[arg.idx].show_zero || + sc->arg_fmt[arg.idx].scnprintf ==SCA_STRARRAY || sc->arg_fmt[arg.idx].scnprintf ==SCA_STRARRAYS ) && sc->arg_fmt[arg.idx].parm))continue ;
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 60/86 perf trace beauty fcntl: Do not suppress 'cmd' when zero, should be DUPFD
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Before:
77059.513 ( 0.005 ms): bash/6649 fcntl(fd: 1</dev/pts/12>, arg: 10) = 10</dev/pts/12>
After:
77059.513 ( 0.005 ms): bash/6649 fcntl(fd: 1</dev/pts/12>, cmd: DUPFD, arg: 10) = 10</dev/pts/12>
--- tools/perf/builtin-trace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/builtin-trace.c +2 -1
@@ -652,7 +652,8 @@ static struct syscall_fmt { .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, { .name = "fcntl", .errmsg = true, .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */ - .parm = &strarrays__fcntl_cmds_arrays, /* cmd */ }, + .parm = &strarrays__fcntl_cmds_arrays, + .show_zero = true, }, [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, }, { .name = "fdatasync", .errmsg = true, }, { .name = "flock", .errmsg = true,
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 61/86 perf trace beauty fcntl: Beautify the 'arg' for DUPFD
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Before:
77059.513 ( 0.005 ms): bash/6649 fcntl(fd: 1</dev/pts/12>, cmd: DUPFD, arg: 10) = 10</dev/pts/12>
After:
77059.513 ( 0.005 ms): bash/6649 fcntl(fd: 1</dev/pts/12>, cmd: DUPFD, arg: 10</dev/pts/12>) = 10</dev/pts/12>
--- tools/perf/trace/beauty/fcntl.c | 3 +++ 1 file changed, 3 insertions(+)
tools/perf/trace/beauty/fcntl.c +3 -0
@@ -71,6 +71,9 @@ size_t syscall_arg__scnprintf_fcntl_arg(char *bf, size_t size, struct syscall_ar {int cmd =syscall_arg__val (arg,1 ); +if (cmd ==F_DUPFD ) +return syscall_arg__scnprintf_fd (bf, size, arg); +if (cmd ==F_SETFD )return fcntl__scnprintf_getfd (arg->val, bf, size);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 62/86 perf trace beauty: Simplify syscall return formatting
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Removing syscall_fmt::err_msg and instead always formatting negative returns as errno values.
With this we can remove a lot of entries that have no special handling besides the ones we can do by looking at the tracefs format files, i.e. the types for the fields (e.g. pid_t), well known names (e.g. fd).
--- tools/perf/builtin-trace.c | 209 ++++++++++++++++++--------------------------- 1 file changed, 81 insertions(+), 128 deletions(-)
tools/perf/builtin-trace.c +81 -128
@@ -611,77 +611,53 @@ static struct syscall_fmt {const char *name;const char *alias;struct syscall_arg_fmt arg[6 ]; - bool errmsg;bool errpid;bool timeout;bool hexret; } syscall_fmts[] = { - { .name = "access", .errmsg = true, + { .name = "access", .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, }, - { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, - { .name = "bpf", .errmsg = true, + { .name = "arch_prctl", .alias = "prctl", }, + { .name = "bpf", .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, }, { .name = "brk", .hexret = true, .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, }, - { .name = "chdir", .errmsg = true, }, - { .name = "chmod", .errmsg = true, }, - { .name = "chroot", .errmsg = true, }, - { .name = "clock_gettime", .errmsg = true, + { .name = "clock_gettime", .arg = { [0] = STRARRAY(clk_id, clockid), }, }, { .name = "clone", .errpid = true, }, - { .name = "close", .errmsg = true, + { .name = "close", .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, }, - { .name = "connect", .errmsg = true, }, - { .name = "creat", .errmsg = true, }, - { .name = "dup", .errmsg = true, }, - { .name = "dup2", .errmsg = true, }, - { .name = "dup3", .errmsg = true, }, - { .name = "epoll_ctl", .errmsg = true, + { .name = "epoll_ctl", .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, }, - { .name = "eventfd2", .errmsg = true, + { .name = "eventfd2", .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, }, - { .name = "faccessat", .errmsg = true, }, - { .name = "fadvise64", .errmsg = true, }, - { .name = "fallocate", .errmsg = true, }, - { .name = "fchdir", .errmsg = true, }, - { .name = "fchmod", .errmsg = true, }, - { .name = "fchmodat", .errmsg = true, + { .name = "fchmodat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, - { .name = "fchown", .errmsg = true, }, - { .name = "fchownat", .errmsg = true, + { .name = "fchownat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, - { .name = "fcntl", .errmsg = true, + { .name = "fcntl", .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */ .parm = &strarrays__fcntl_cmds_arrays, .show_zero = true, }, [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, }, - { .name = "fdatasync", .errmsg = true, }, - { .name = "flock", .errmsg = true, + { .name = "flock", .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, }, - { .name = "fsetxattr", .errmsg = true, }, - { .name = "fstat", .errmsg = true, .alias = "newfstat", }, - { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, - { .name = "fstatfs", .errmsg = true, }, - { .name = "fsync", .errmsg = true, }, - { .name = "ftruncate", .errmsg = true, }, - { .name = "futex", .errmsg = true, + { .name = "fstat", .alias = "newfstat", }, + { .name = "fstatat", .alias = "newfstatat", }, + { .name = "futex", .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, }, - { .name = "futimesat", .errmsg = true, + { .name = "futimesat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, - { .name = "getdents", .errmsg = true, }, - { .name = "getdents64", .errmsg = true, }, - { .name = "getitimer", .errmsg = true, + { .name = "getitimer", .arg = { [0] = STRARRAY(which, itimers), }, }, { .name = "getpid", .errpid = true, }, { .name = "getpgid", .errpid = true, }, { .name = "getppid", .errpid = true, }, - { .name = "getrandom", .errmsg = true, + { .name = "getrandom", .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, }, - { .name = "getrlimit", .errmsg = true, + { .name = "getrlimit", .arg = { [0] = STRARRAY(resource, rlimit_resources), }, }, - { .name = "getxattr", .errmsg = true, }, - { .name = "inotify_add_watch", .errmsg = true, }, - { .name = "ioctl", .errmsg = true, + { .name = "ioctl", .arg = {#if defined(__i386__) || defined(__x86_64__)/*
@@ -693,34 +669,25 @@ static struct syscall_fmt { #else [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, }, #endif - { .name = "keyctl", .errmsg = true, + { .name = "keyctl", .arg = { [0] = STRARRAY(option, keyctl_options), }, }, - { .name = "kill", .errmsg = true, + { .name = "kill", .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, - { .name = "lchown", .errmsg = true, }, - { .name = "lgetxattr", .errmsg = true, }, - { .name = "linkat", .errmsg = true, + { .name = "linkat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, - { .name = "listxattr", .errmsg = true, }, - { .name = "llistxattr", .errmsg = true, }, - { .name = "lremovexattr", .errmsg = true, }, - { .name = "lseek", .errmsg = true, + { .name = "lseek", .arg = { [2] = STRARRAY(whence, whences), }, }, - { .name = "lsetxattr", .errmsg = true, }, - { .name = "lstat", .errmsg = true, .alias = "newlstat", }, - { .name = "lsxattr", .errmsg = true, }, - { .name = "madvise", .errmsg = true, + { .name = "lstat", .alias = "newlstat", }, + { .name = "madvise", .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, }, - { .name = "mkdir", .errmsg = true, }, - { .name = "mkdirat", .errmsg = true, + { .name = "mkdirat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, - { .name = "mknod", .errmsg = true, }, - { .name = "mknodat", .errmsg = true, + { .name = "mknodat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, }, - { .name = "mlock", .errmsg = true, + { .name = "mlock", .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, - { .name = "mlockall", .errmsg = true, + { .name = "mlockall", .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, { .name = "mmap", .hexret = true, /* The standard mmap maps to old_mmap on s390x */
@@ -730,127 +697,109 @@ static struct syscall_fmt { .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, }, - { .name = "mprotect", .errmsg = true, + { .name = "mprotect", .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ }, [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, }, - { .name = "mq_unlink", .errmsg = true, + { .name = "mq_unlink", .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, }, { .name = "mremap", .hexret = true, .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ }, [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, }, - { .name = "munlock", .errmsg = true, + { .name = "munlock", .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, - { .name = "munmap", .errmsg = true, + { .name = "munmap", .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, }, - { .name = "name_to_handle_at", .errmsg = true, + { .name = "name_to_handle_at", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, - { .name = "newfstatat", .errmsg = true, + { .name = "newfstatat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, - { .name = "open", .errmsg = true, + { .name = "open", .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, }, - { .name = "open_by_handle_at", .errmsg = true, + { .name = "open_by_handle_at", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, }, - { .name = "openat", .errmsg = true, + { .name = "openat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, }, - { .name = "perf_event_open", .errmsg = true, + { .name = "perf_event_open", .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ }, [3] = { .scnprintf = SCA_FD, /* group_fd */ }, [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, }, - { .name = "pipe2", .errmsg = true, + { .name = "pipe2", .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, }, - { .name = "poll", .errmsg = true, .timeout = true, }, - { .name = "ppoll", .errmsg = true, .timeout = true, }, - { .name = "pread", .errmsg = true, .alias = "pread64", }, - { .name = "preadv", .errmsg = true, .alias = "pread", }, - { .name = "prlimit64", .errmsg = true, + { .name = "poll", .timeout = true, }, + { .name = "ppoll", .timeout = true, }, + { .name = "pread", .alias = "pread64", }, + { .name = "preadv", .alias = "pread", }, + { .name = "prlimit64", .arg = { [1] = STRARRAY(resource, rlimit_resources), }, }, - { .name = "pwrite", .errmsg = true, .alias = "pwrite64", }, - { .name = "pwritev", .errmsg = true, }, - { .name = "read", .errmsg = true, }, - { .name = "readlink", .errmsg = true, }, - { .name = "readlinkat", .errmsg = true, + { .name = "pwrite", .alias = "pwrite64", }, + { .name = "readlinkat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, - { .name = "readv", .errmsg = true, }, - { .name = "recvfrom", .errmsg = true, + { .name = "recvfrom", .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, - { .name = "recvmmsg", .errmsg = true, + { .name = "recvmmsg", .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, - { .name = "recvmsg", .errmsg = true, + { .name = "recvmsg", .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, - { .name = "removexattr", .errmsg = true, }, - { .name = "renameat", .errmsg = true, + { .name = "renameat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, - { .name = "rmdir", .errmsg = true, }, - { .name = "rt_sigaction", .errmsg = true, + { .name = "rt_sigaction", .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, - { .name = "rt_sigprocmask", .errmsg = true, + { .name = "rt_sigprocmask", .arg = { [0] = STRARRAY(how, sighow), }, }, - { .name = "rt_sigqueueinfo", .errmsg = true, + { .name = "rt_sigqueueinfo", .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, - { .name = "rt_tgsigqueueinfo", .errmsg = true, + { .name = "rt_tgsigqueueinfo", .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, - { .name = "sched_getattr", .errmsg = true, }, - { .name = "sched_setattr", .errmsg = true, }, - { .name = "sched_setscheduler", .errmsg = true, + { .name = "sched_setscheduler", .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, }, - { .name = "seccomp", .errmsg = true, + { .name = "seccomp", .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ }, [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, }, - { .name = "select", .errmsg = true, .timeout = true, }, - { .name = "sendmmsg", .errmsg = true, + { .name = "select", .timeout = true, }, + { .name = "sendmmsg", .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, - { .name = "sendmsg", .errmsg = true, + { .name = "sendmsg", .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, - { .name = "sendto", .errmsg = true, + { .name = "sendto", .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, }, { .name = "set_tid_address", .errpid = true, }, - { .name = "setitimer", .errmsg = true, + { .name = "setitimer", .arg = { [0] = STRARRAY(which, itimers), }, }, - { .name = "setpgid", .errmsg = true, }, - { .name = "setrlimit", .errmsg = true, + { .name = "setrlimit", .arg = { [0] = STRARRAY(resource, rlimit_resources), }, }, - { .name = "setxattr", .errmsg = true, }, - { .name = "shutdown", .errmsg = true, }, - { .name = "socket", .errmsg = true, + { .name = "socket", .arg = { [0] = STRARRAY(family, socket_families), [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, }, - { .name = "socketpair", .errmsg = true, + { .name = "socketpair", .arg = { [0] = STRARRAY(family, socket_families), [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, }, - { .name = "stat", .errmsg = true, .alias = "newstat", }, - { .name = "statfs", .errmsg = true, }, - { .name = "statx", .errmsg = true, + { .name = "stat", .alias = "newstat", }, + { .name = "statx", .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ }, [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } , [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, }, - { .name = "swapoff", .errmsg = true, + { .name = "swapoff", .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, }, - { .name = "swapon", .errmsg = true, + { .name = "swapon", .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, }, - { .name = "symlinkat", .errmsg = true, + { .name = "symlinkat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, - { .name = "tgkill", .errmsg = true, + { .name = "tgkill", .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, - { .name = "tkill", .errmsg = true, + { .name = "tkill", .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, }, - { .name = "truncate", .errmsg = true, }, - { .name = "uname", .errmsg = true, .alias = "newuname", }, - { .name = "unlinkat", .errmsg = true, + { .name = "uname", .alias = "newuname", }, + { .name = "unlinkat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, }, - { .name = "utime", .errmsg = true, }, - { .name = "utimensat", .errmsg = true, + { .name = "utimensat", .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, }, - { .name = "utimes", .errmsg = true, }, - { .name = "vmsplice", .errmsg = true, }, { .name = "wait4", .errpid = true, .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, }, { .name = "waitid", .errpid = true, .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, }, - { .name = "write", .errmsg = true, }, - { .name = "writev", .errmsg = true, }, };static int syscall_fmt__cmp (const void *name,const void *fmtp)
@@ -1708,14 +1657,18 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, }if (sc->fmt ==NULL ) { +if (ret <0 ) + goto errno_print; signed_print: -fprintf (trace->output,") = %ld" , ret); - }else if (ret <0 && (sc->fmt->errmsg || sc->fmt->errpid)) { +fprintf (trace->output,") %ld" , ret); + }else if (ret <0 ) { +errno_print: {char bf[STRERR_BUFSIZE ];const char *emsg =str_error_r (-ret, bf,sizeof (bf)), *e =audit_errno_to_name (-ret);fprintf (trace->output,") = -1 %s %s" , e, emsg); + } }else if (ret ==0 && sc->fmt->timeout)fprintf (trace->output,") = 0 Timeout" );else if (ttrace->ret_scnprintf) {
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 63/86 perf report: Enable finding kernel inline functions
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
Currently perf supports a mode to query inline stack. It works well for finding user space inline functions but it doesn't work for kernel ones, due to some unnecessary check.
This patch removes these unnecessary checks. Now kernel inline functions can be reported.
For example:
perf report --inline -g func --stdio
|--46.19%--do_huge_pmd_anonymous_page | do_huge_pmd_anonymous_page (inline) | __do_huge_pmd_anonymous_page (inline) | __SetPageUptodate (inline) | __set_bit (inline)
The result is compared with the output of addr2line. They match.
--- tools/perf/ui/browsers/hists.c | 3 --- tools/perf/ui/stdio/hist.c | 3 --- 2 files changed, 6 deletions(-)
tools/perf/ui/browsers/hists.c +0 -3
@@ -166,9 +166,6 @@ static struct inline_node *inline_node__create(struct map *map, u64 ip)if (dso ==NULL )return NULL ; -if (dso->kernel !=DSO_TYPE_USER ) -return NULL ; - node =dso__parse_addr_inlines (dso,map__rip_2objdump (map, ip));
tools/perf/ui/stdio/hist.c +0 -3
@@ -35,9 +35,6 @@ static size_t inline__fprintf(struct map *map, u64 ip, int left_margin,if (dso ==NULL )return 0 ; -if (dso->kernel !=DSO_TYPE_USER ) -return 0 ; - node =dso__parse_addr_inlines (dso,map__rip_2objdump (map, ip));if (node ==NULL )
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 64/86 perf header: Encapsulate read and swap
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Most callers of readn() in perf header read either a 32 or a 64 bits number, error check it and swap it, if necessary.
Create do_read_u32 and do_read_u64 to simplify these use cases.
--- tools/perf/util/header.c | 210 +++++++++++++++++------------------------------ 1 file changed, 77 insertions(+), 133 deletions(-)
tools/perf/util/header.c +77 -133
@@ -119,25 +119,54 @@ static int do_write_string(int fd, const char *str)return write_padded (fd, str, olen, len); } +static int __do_read (int fd,void *addr,ssize_t size) +{ +ssize_t ret =readn (fd, addr, size); + +if (ret != size) +return ret <0 ? (int )ret :-1 ; +return 0 ; +} + +static int do_read_u32 (int fd,struct perf_header *ph,u32 *addr) +{ +int ret; + + ret =__do_read (fd, addr,sizeof (*addr)); +if (ret) +return ret; + +if (ph->needs_swap) + *addr =bswap_32 (*addr); +return 0 ; +} + +static int do_read_u64 (int fd,struct perf_header *ph,u64 *addr) +{ +int ret; + + ret =__do_read (fd, addr,sizeof (*addr)); +if (ret) +return ret; + +if (ph->needs_swap) + *addr =bswap_64 (*addr); +return 0 ; +} +static char *do_read_string (int fd,struct perf_header *ph) { -ssize_t sz, ret;u32 len;char *buf; - sz =readn (fd, &len,sizeof (len)); -if (sz < (ssize_t )sizeof (len)) +if (do_read_u32 (fd, ph, &len))return NULL ; -if (ph->needs_swap) - len =bswap_32 (len); - buf =malloc (len);if (!buf)return NULL ; - ret =readn (fd, buf, len); -if (ret == (ssize_t )len) { +if (!__do_read (fd, buf, len)) {/* * strings are padded by zeroes * thus the actual strlen of buf
@@ -1188,24 +1217,15 @@ read_event_desc(struct perf_header *ph, int fd)u64 *id;void *buf =NULL ;u32 nre, sz, nr, i, j; -ssize_t ret;size_t msz;/* number of events */ - ret =readn (fd, &nre,sizeof (nre)); -if (ret != (ssize_t )sizeof (nre)) +if (do_read_u32 (fd, ph, &nre)) goto error; -if (ph->needs_swap) - nre =bswap_32 (nre); - - ret =readn (fd, &sz,sizeof (sz)); -if (ret != (ssize_t )sizeof (sz)) +if (do_read_u32 (fd, ph, &sz)) goto error; -if (ph->needs_swap) - sz =bswap_32 (sz); -/* buffer to hold on file attr struct */ buf =malloc (sz);if (!buf)
@@ -1227,8 +1247,7 @@ read_event_desc(struct perf_header *ph, int fd)* must read entire on-file attr struct to * sync up with layout. */ - ret =readn (fd, buf, sz); -if (ret != (ssize_t )sz) +if (__do_read (fd, buf, sz)) goto error;if (ph->needs_swap)
@@ -1236,16 +1255,15 @@ read_event_desc(struct perf_header *ph, int fd)memcpy (&evsel->attr, buf, msz); - ret =readn (fd, &nr,sizeof (nr)); -if (ret != (ssize_t )sizeof (nr)) +if (do_read_u32 (fd, ph, &nr)) goto error; -if (ph->needs_swap) { - nr =bswap_32 (nr); +if (ph->needs_swap) evsel->needs_swap = true; - } evsel->name =do_read_string (fd, ph); +if (!evsel->name) + goto error;if (!nr)continue ;
@@ -1257,11 +1275,8 @@ read_event_desc(struct perf_header *ph, int fd) evsel->id = id;for (j =0 ; j < nr; j++) { - ret =readn (fd, id,sizeof (*id)); -if (ret != (ssize_t )sizeof (*id)) +if (do_read_u64 (fd, ph, id)) goto error; -if (ph->needs_swap) - *id =bswap_64 (*id); id++; } }
@@ -1641,26 +1656,18 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused, struct perf_header *ph, int fd, void *data __maybe_unused) { - ssize_t ret; -u32 nr; - - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) -return -1 ; - -if (ph->needs_swap) - nr =bswap_32 (nr); - - ph->env.nr_cpus_avail = nr; - - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) -return -1 ; + int ret; +u32 nr_cpus_avail, nr_cpus_online; -if (ph->needs_swap) - nr =bswap_32 (nr); + ret =do_read_u32 (fd, ph, &nr_cpus_avail); +if (ret) +return ret; - ph->env.nr_cpus_online = nr; + ret =do_read_u32 (fd, ph, &nr_cpus_online); +if (ret) +return ret; + ph->env.nr_cpus_avail = (int )nr_cpus_avail; + ph->env.nr_cpus_online = (int )nr_cpus_online;return 0 ; }
@@ -1684,17 +1691,13 @@ static int process_total_mem(struct perf_file_section *section __maybe_unused, struct perf_header *ph, int fd, void *data __maybe_unused) { - uint64_t mem; -ssize_t ret; + u64 total_mem; +int ret; - ret =readn (fd, &mem,sizeof (mem)); -if (ret !=sizeof (mem)) + ret =do_read_u64 (fd, ph, &total_mem); +if (ret)return -1 ; - -if (ph->needs_swap) - mem =bswap_64 (mem); - - ph->env.total_mem = mem; + ph->env.total_mem = (unsigned long long )total_mem;return 0 ; }
@@ -1754,17 +1757,12 @@ static int process_cmdline(struct perf_file_section *section, struct perf_header *ph, int fd, void *data __maybe_unused) { - ssize_t ret; char *str, *cmdline = NULL, **argv = NULL;u32 nr, i, len =0 ; - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) +if (do_read_u32 (fd, ph, &nr))return -1 ; -if (ph->needs_swap) - nr =bswap_32 (nr); - ph->env.nr_cmdline = nr; cmdline =zalloc (section->size + nr +1 );
@@ -1799,7 +1797,6 @@ static int process_cpu_topology(struct perf_file_section *section, struct perf_header *ph, int fd, void *data __maybe_unused) { - ssize_t ret; u32 nr, i;char *str;struct strbuf sb;
@@ -1810,13 +1807,9 @@ static int process_cpu_topology(struct perf_file_section *section,if (!ph->env.cpu)return -1 ; - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) +if (do_read_u32 (fd, ph, &nr)) goto free_cpu; -if (ph->needs_swap) - nr =bswap_32 (nr); - ph->env.nr_sibling_cores = nr; size +=sizeof (u32);if (strbuf_init (&sb,128 ) <0 )
@@ -1835,13 +1828,9 @@ static int process_cpu_topology(struct perf_file_section *section, } ph->env.sibling_cores =strbuf_detach (&sb,NULL ); - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) +if (do_read_u32 (fd, ph, &nr))return -1 ; -if (ph->needs_swap) - nr =bswap_32 (nr); - ph->env.nr_sibling_threads = nr; size +=sizeof (u32);
@@ -1868,22 +1857,14 @@ static int process_cpu_topology(struct perf_file_section *section, }for (i =0 ; i < (u32 )cpu_nr; i++) { - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) +if (do_read_u32 (fd, ph, &nr)) goto free_cpu; -if (ph->needs_swap) - nr =bswap_32 (nr); - ph->env.cpu[i].core_id = nr; - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) +if (do_read_u32 (fd, ph, &nr)) goto free_cpu; -if (ph->needs_swap) - nr =bswap_32 (nr); -if (nr != (u32)-1 && nr > (u32 )cpu_nr) {pr_debug ("socket_id number is too big." "You may need to upgrade the perf tool.\n" );
@@ -1907,18 +1888,13 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse void *data __maybe_unused) {struct numa_node *nodes, *n; -ssize_t ret;u32 nr, i;char *str;/* nr nodes */ - ret =readn (fd, &nr,sizeof (nr)); -if (ret !=sizeof (nr)) +if (do_read_u32 (fd, ph, &nr))return -1 ; -if (ph->needs_swap) - nr =bswap_32 (nr); - nodes =zalloc (sizeof (*nodes) * nr);if (!nodes)return -ENOMEM ;
@@ -1927,24 +1903,15 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse n = &nodes[i];/* node number */ - ret =readn (fd, &n->node,sizeof (u32)); -if (ret !=sizeof (n->node)) +if (do_read_u32 (fd, ph, &n->node)) goto error; - ret =readn (fd, &n->mem_total,sizeof (u64)); -if (ret !=sizeof (u64)) +if (do_read_u64 (fd, ph, &n->mem_total)) goto error; - ret =readn (fd, &n->mem_free,sizeof (u64)); -if (ret !=sizeof (u64)) +if (do_read_u64 (fd, ph, &n->mem_free)) goto error; -if (ph->needs_swap) { - n->node =bswap_32 (n->node); - n->mem_total =bswap_64 (n->mem_total); - n->mem_free =bswap_64 (n->mem_free); - } - str =do_read_string (fd, ph);if (!str) goto error;
@@ -1968,19 +1935,14 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused struct perf_header *ph, int fd, void *data __maybe_unused) { - ssize_t ret; char *name;u32 pmu_num;u32 type;struct strbuf sb; - ret =readn (fd, &pmu_num,sizeof (pmu_num)); -if (ret !=sizeof (pmu_num)) +if (do_read_u32 (fd, ph, &pmu_num))return -1 ; -if (ph->needs_swap) - pmu_num =bswap_32 (pmu_num); -if (!pmu_num) {pr_debug ("pmu mappings not available\n" );return 0 ;
@@ -1991,10 +1953,8 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unusedreturn -1 ;while (pmu_num) { -if (readn (fd, &type,sizeof (type)) !=sizeof (type)) +if (do_read_u32 (fd, ph, &type)) goto error; -if (ph->needs_swap) - type =bswap_32 (type); name =do_read_string (fd, ph);if (!name)
@@ -2034,12 +1994,9 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,u32 nr_members; } *desc; -if (readn (fd, &nr_groups,sizeof (nr_groups)) !=sizeof (nr_groups)) +if (do_read_u32 (fd, ph, &nr_groups))return -1 ; -if (ph->needs_swap) - nr_groups =bswap_32 (nr_groups); - ph->env.nr_groups = nr_groups;if (!nr_groups) {pr_debug ("group desc not available\n" );
@@ -2055,16 +2012,11 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,if (!desc[i].name) goto out_free; -if (readn (fd, &desc[i].leader_idx,sizeof (u32)) !=sizeof (u32)) +if (do_read_u32 (fd, ph, &desc[i].leader_idx)) goto out_free; -if (readn (fd, &desc[i].nr_members,sizeof (u32)) !=sizeof (u32)) +if (do_read_u32 (fd, ph, &desc[i].nr_members)) goto out_free; - -if (ph->needs_swap) { - desc[i].leader_idx =bswap_32 (desc[i].leader_idx); - desc[i].nr_members =bswap_32 (desc[i].nr_members); - } }/*
@@ -2137,21 +2089,15 @@ static int process_cache(struct perf_file_section *section __maybe_unused,struct cpu_cache_level *caches;u32 cnt, i, version; -if (readn (fd, &version,sizeof (version)) !=sizeof (version)) +if (do_read_u32 (fd, ph, &version))return -1 ; -if (ph->needs_swap) - version =bswap_32 (version); -if (version !=1 )return -1 ; -if (readn (fd, &cnt,sizeof (cnt)) !=sizeof (cnt)) +if (do_read_u32 (fd, ph, &cnt))return -1 ; -if (ph->needs_swap) - cnt =bswap_32 (cnt); - caches =zalloc (sizeof (*caches) * cnt);if (!caches)return -1 ;
@@ -2160,10 +2106,8 @@ static int process_cache(struct perf_file_section *section __maybe_unused,struct cpu_cache_level c;#define _R (v) \ - if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\ + if (do_read_u32(fd, ph, &c.v))\ goto out_free_caches; \ - if (ph->needs_swap) \ - c.v = bswap_32(c.v); \_R (level)_R (line_size)
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 65/86 perf header: Add PROCESS_STR_FUN macro
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Simplify code by adding a macro to handle the common case of processing header features that are a simple string.
--- tools/perf/util/header.c | 65 +++++++++++++----------------------------------- 1 file changed, 17 insertions(+), 48 deletions(-)
tools/perf/util/header.c +17 -48
@@ -1603,6 +1603,23 @@ static int perf_header__read_build_ids(struct perf_header *header,return err; } +/* Macro for features that simply need to read and store a string. */ +#define FEAT_PROCESS_STR_FUN (__feat, __feat_env) \ +static int process_##__feat(struct perf_file_section *section __maybe_unused, \ + struct perf_header *ph, int fd, \ + void *data __maybe_unused) \ +{\ + ph->env.__feat_env = do_read_string(fd, ph); \ + return ph->env.__feat_env ? 0 : -ENOMEM; \ +} + +FEAT_PROCESS_STR_FUN (hostname, hostname); +FEAT_PROCESS_STR_FUN (osrelease, os_release); +FEAT_PROCESS_STR_FUN (version, version); +FEAT_PROCESS_STR_FUN (arch, arch); +FEAT_PROCESS_STR_FUN (cpudesc, cpu_desc); +FEAT_PROCESS_STR_FUN (cpuid, cpuid); +static int process_tracing_data (struct perf_file_section *section__maybe_unused ,struct perf_header *ph__maybe_unused ,int fd,void *data)
@@ -1620,38 +1637,6 @@ static int process_build_id(struct perf_file_section *section,return 0 ; } -static int process_hostname (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) -{ - ph->env.hostname =do_read_string (fd, ph); -return ph->env.hostname ?0 : -ENOMEM ; -} - -static int process_osrelease (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) -{ - ph->env.os_release =do_read_string (fd, ph); -return ph->env.os_release ?0 : -ENOMEM ; -} - -static int process_version (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) -{ - ph->env.version =do_read_string (fd, ph); -return ph->env.version ?0 : -ENOMEM ; -} - -static int process_arch (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) -{ - ph->env.arch =do_read_string (fd, ph); -return ph->env.arch ?0 : -ENOMEM ; -} -static int process_nrcpus (struct perf_file_section *section__maybe_unused ,struct perf_header *ph,int fd,void *data__maybe_unused )
@@ -1671,22 +1656,6 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,return 0 ; } -static int process_cpudesc (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) -{ - ph->env.cpu_desc =do_read_string (fd, ph); -return ph->env.cpu_desc ?0 : -ENOMEM ; -} - -static int process_cpuid (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) -{ - ph->env.cpuid =do_read_string (fd, ph); -return ph->env.cpuid ?0 : -ENOMEM ; -} -static int process_total_mem (struct perf_file_section *section__maybe_unused ,struct perf_header *ph,int fd,void *data__maybe_unused )
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 66/86 perf header: Fail on write_padded error
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Do not proceed if write_padded() error failed.
Also, add comments to remind that the return value of write_* functions in util/header.c is an errno code and not the number of bytes written.
--- tools/perf/util/header.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
tools/perf/util/header.c +5 -1
@@ -74,6 +74,7 @@ bool perf_header__has_feat(const struct perf_header *header, int feat)return test_bit (feat, header->adds_features); } +/* Return: 0 if succeded, -ERR if failed. */ static int do_write (int fd,const void *buf,size_t size) {while (size) {
@@ -89,6 +90,7 @@ static int do_write(int fd, const void *buf, size_t size)return 0 ; } +/* Return: 0 if succeded, -ERR if failed. */ int write_padded (int fd,const void *bf,size_t count,size_t count_aligned) {static const char zero_buf[NAME_ALIGN ];
@@ -103,6 +105,7 @@ int write_padded(int fd, const void *bf, size_t count, size_t count_aligned)#define string_size (str) \ (PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32)) +/* Return: 0 if succeded, -ERR if failed. */ static int do_write_string (int fd,const char *str) {u32 len, olen;
@@ -3200,7 +3203,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,*/ tracing_data_put (tdata); -write_padded (fd,NULL ,0 , padding); +if (write_padded (fd,NULL ,0 , padding)) +return -1 ;return aligned_size; }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 67/86 perf util: Add const modifier to buf in "writen" function
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Make buf in helper function "writen" constant to simplify the life of its callers.
This requires to hack a cast of buf prior to passing it to "ion" which is simpler than the alternative of reworking the "ion" function to provide a read and a write paths, the latter with constant buf argument.
--- tools/perf/util/util.c | 6 ++++-- tools/perf/util/util.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-)
tools/perf/util/util.c +4 -2
@@ -281,6 +281,7 @@ static ssize_t ion(bool is_read, int fd, void *buf, size_t n)size_t left = n;while (left) { +/* buf must be treated as const if !is_read. */ ssize_t ret = is_read ?read (fd, buf, left) :write (fd, buf, left);
@@ -308,9 +309,10 @@ ssize_t readn(int fd, void *buf, size_t n)/* * Write exactly 'n' bytes or return an error. */ -ssize_t writen (int fd,void *buf,size_t n) +ssize_t writen (int fd,const void *buf,size_t n) { -return ion (false, fd, buf, n); +/* ion does not modify buf. */ +return ion (false, fd, (void *)buf, n); }size_t hex_width (u64 v)
tools/perf/util/util.h +1 -1
@@ -38,7 +38,7 @@ int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi);int copyfile_offset (int fromfd,loff_t from_ofs,int tofd,loff_t to_ofs,u64 size);ssize_t readn (int fd,void *buf,size_t n); -ssize_t writen (int fd,void *buf,size_t n); +ssize_t writen (int fd,const void *buf,size_t n);size_t hex_width (u64 v);int hex2u64 (const char *ptr,u64 *val);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 68/86 perf header: Revamp do_write()
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Now that writen takes a const buffer, use it in do_write instead of duplicating its functionality.
Export do_write to use it consistently in header.c and build_id.c .
--- tools/perf/util/build-id.c | 2 +- tools/perf/util/header.c | 14 +++++--------- tools/perf/util/header.h | 2 ++ 3 files changed, 8 insertions(+), 10 deletions(-)
tools/perf/util/build-id.c +1 -1
@@ -304,7 +304,7 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id, b.header.misc = misc; b.header.size =sizeof (b) + len; - err =writen (fd, &b,sizeof (b)); + err =do_write (fd, &b,sizeof (b));if (err <0 )return err;
tools/perf/util/header.c +5 -9
@@ -75,17 +75,13 @@ bool perf_header__has_feat(const struct perf_header *header, int feat) }/* Return: 0 if succeded, -ERR if failed. */ -static int do_write (int fd,const void *buf,size_t size) +int do_write (int fd,const void *buf,size_t size) { -while (size) { -int ret =write (fd, buf, size); - -if (ret <0 ) -return -errno; +ssize_t ret; - size -= ret; - buf += ret; - } + ret =writen (fd, buf, size); +if (ret != (ssize_t )size) +return ret <0 ? (int )ret :-1 ;return 0 ; }
tools/perf/util/header.h +2 -0
@@ -144,6 +144,8 @@ bool is_perf_magic(u64 magic);#define NAME_ALIGN 64 +int do_write (int fd,const void *buf,size_t size); +int write_padded (int fd,const void *bf,size_t count,size_t count_aligned);/*
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 69/86 perf header: Add struct feat_fd for write
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Introduce struct feat_fd. This patch uses it as a wrapper around fd in write_* functions for feature headers. Next patches will extend its functionality to other feature header functions.
This patch does not change behavior.
--- tools/perf/util/build-id.c | 8 +- tools/perf/util/build-id.h | 4 +- tools/perf/util/header.c | 230 ++++++++++++++++++++++++--------------------- tools/perf/util/header.h | 7 +- 4 files changed, 138 insertions(+), 111 deletions(-)
tools/perf/util/build-id.c +5 -3
@@ -289,7 +289,7 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size,else static int write_buildid(const char *name, size_t name_len, u8 *build_id, -pid_t pid,u16 misc,int fd) +pid_t pid,u16 misc,struct feat_fd *fd) {int err;struct build_id_event b;
@@ -311,7 +311,8 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,return write_padded (fd, name, name_len +1 , len); } -static int machine__write_buildid_table (struct machine *machine,int fd) +static int machine__write_buildid_table (struct machine *machine, +struct feat_fd *fd) {int err =0 ;char nm[PATH_MAX ];
@@ -356,7 +357,8 @@ static int machine__write_buildid_table(struct machine *machine, int fd)return err; } -int perf_session__write_buildid_table (struct perf_session *session,int fd) +int perf_session__write_buildid_table (struct perf_session *session, +struct feat_fd *fd) {struct rb_node *nd;int err =machine__write_buildid_table (&session->machines.host, fd);
tools/perf/util/build-id.h +3 -1
@@ -10,6 +10,7 @@extern struct perf_tool build_id__mark_dso_hit_ops;struct dso ; +struct feat_fd ;int build_id__sprintf (const u8 *build_id,int len,char *bf);int sysfs__sprintf_build_id (const char *root_dir,char *sbuild_id);
@@ -27,7 +28,8 @@ int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,int dsos__hit_all (struct perf_session *session);bool perf_session__read_build_ids (struct perf_session *session,bool with_hits); -int perf_session__write_buildid_table (struct perf_session *session,int fd); +int perf_session__write_buildid_table (struct perf_session *session, +struct feat_fd *fd);int perf_session__cache_build_ids (struct perf_session *session);char *build_id_cache__origname (const char *sbuild_id);
tools/perf/util/header.c +125 -105
723 lines not on this page · raw message
tools/perf/util/header.h +5 -2
@@ -144,9 +144,12 @@ bool is_perf_magic(u64 magic);#define NAME_ALIGN 64 -int do_write (int fd,const void *buf,size_t size); +struct feat_fd ; -int write_padded (int fd,const void *bf,size_t count,size_t count_aligned); +int do_write (struct feat_fd *fd,const void *buf,size_t size); + +int write_padded (struct feat_fd *fd,const void *bf, +size_t count,size_t count_aligned);/* * arch specific callback
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 70/86 perf header: Use struct feat_fd for print
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
As preparation for using header records in pipe mode, replace int fd with struct feat_fd ff in print functions for all header record types.
--- tools/perf/util/header.c | 102 ++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 55 deletions(-)
tools/perf/util/header.c +47 -55
@@ -1116,62 +1116,56 @@ static int write_stat(struct feat_fd *ff __maybe_unused,return 0 ; } -static void print_hostname (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_hostname (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# hostname : %s\n" , ph->env.hostname); +fprintf (fp,"# hostname : %s\n" , ff->ph->env.hostname); } -static void print_osrelease (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_osrelease (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# os release : %s\n" , ph->env.os_release); +fprintf (fp,"# os release : %s\n" , ff->ph->env.os_release); } -static void print_arch (struct perf_header *ph,int fd__maybe_unused ,FILE *fp) +static void print_arch (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# arch : %s\n" , ph->env.arch); +fprintf (fp,"# arch : %s\n" , ff->ph->env.arch); } -static void print_cpudesc (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_cpudesc (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# cpudesc : %s\n" , ph->env.cpu_desc); +fprintf (fp,"# cpudesc : %s\n" , ff->ph->env.cpu_desc); } -static void print_nrcpus (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_nrcpus (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# nrcpus online : %u\n" , ph->env.nr_cpus_online); -fprintf (fp,"# nrcpus avail : %u\n" , ph->env.nr_cpus_avail); +fprintf (fp,"# nrcpus online : %u\n" , ff->ph->env.nr_cpus_online); +fprintf (fp,"# nrcpus avail : %u\n" , ff->ph->env.nr_cpus_avail); } -static void print_version (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_version (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# perf version : %s\n" , ph->env.version); +fprintf (fp,"# perf version : %s\n" , ff->ph->env.version); } -static void print_cmdline (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_cmdline (struct feat_fd *ff,FILE *fp) {int nr, i; - nr = ph->env.nr_cmdline; + nr = ff->ph->env.nr_cmdline;fprintf (fp,"# cmdline : " );for (i =0 ; i < nr; i++) -fprintf (fp,"%s " , ph->env.cmdline_argv[i]); +fprintf (fp,"%s " , ff->ph->env.cmdline_argv[i]);fputc ('\n' , fp); } -static void print_cpu_topology (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_cpu_topology (struct feat_fd *ff,FILE *fp) { +struct perf_header *ph = ff->ph; +int cpu_nr = ph->env.nr_cpus_avail;int nr, i;char *str; -int cpu_nr = ph->env.nr_cpus_avail; nr = ph->env.nr_sibling_cores; str = ph->env.sibling_cores;
@@ -1297,9 +1291,9 @@ static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val,return fprintf (fp,", %s = %s" , name, val); } -static void print_event_desc (struct perf_header *ph,int fd,FILE *fp) +static void print_event_desc (struct feat_fd *ff,FILE *fp) { -struct perf_evsel *evsel, *events =read_event_desc (ph, fd); +struct perf_evsel *evsel, *events =read_event_desc (ff->ph, ff->fd);u32 j;u64 *id;
@@ -1329,20 +1323,18 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)free_event_desc (events); } -static void print_total_mem (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_total_mem (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# total memory : %Lu kB\n" , ph->env.total_mem); +fprintf (fp,"# total memory : %llu kB\n" , ff->ph->env.total_mem); } -static void print_numa_topology (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_numa_topology (struct feat_fd *ff,FILE *fp) {int i;struct numa_node *n; -for (i =0 ; i < ph->env.nr_numa_nodes; i++) { - n = &ph->env.numa_nodes[i]; +for (i =0 ; i < ff->ph->env.nr_numa_nodes; i++) { + n = &ff->ph->env.numa_nodes[i]; fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB," " free = %"PRIu64" kB\n",
@@ -1353,56 +1345,51 @@ static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused, } } -static void print_cpuid (struct perf_header *ph,int fd__maybe_unused ,FILE *fp) +static void print_cpuid (struct feat_fd *ff,FILE *fp) { -fprintf (fp,"# cpuid : %s\n" , ph->env.cpuid); +fprintf (fp,"# cpuid : %s\n" , ff->ph->env.cpuid); } -static void print_branch_stack (struct perf_header *ph__maybe_unused , -int fd__maybe_unused ,FILE *fp) +static void print_branch_stack (struct feat_fd *ff__maybe_unused ,FILE *fp) {fprintf (fp,"# contains samples with branch stack\n" ); } -static void print_auxtrace (struct perf_header *ph__maybe_unused , -int fd__maybe_unused ,FILE *fp) +static void print_auxtrace (struct feat_fd *ff__maybe_unused ,FILE *fp) {fprintf (fp,"# contains AUX area data (e.g. instruction trace)\n" ); } -static void print_stat (struct perf_header *ph__maybe_unused , -int fd__maybe_unused ,FILE *fp) +static void print_stat (struct feat_fd *ff__maybe_unused ,FILE *fp) {fprintf (fp,"# contains stat data\n" ); } -static void print_cache (struct perf_header *ph__maybe_unused , -int fd__maybe_unused ,FILE *fp__maybe_unused ) +static void print_cache (struct feat_fd *ff,FILE *fp__maybe_unused ) {int i;fprintf (fp,"# CPU cache info:\n" ); -for (i =0 ; i < ph->env.caches_cnt; i++) { +for (i =0 ; i < ff->ph->env.caches_cnt; i++) {fprintf (fp,"# " ); -cpu_cache_level__fprintf (fp, &ph->env.caches[i]); +cpu_cache_level__fprintf (fp, &ff->ph->env.caches[i]); } } -static void print_pmu_mappings (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_pmu_mappings (struct feat_fd *ff,FILE *fp) {const char *delimiter ="# pmu mappings: " ;char *str, *tmp;u32 pmu_num;u32 type; - pmu_num = ph->env.nr_pmu_mappings; + pmu_num = ff->ph->env.nr_pmu_mappings;if (!pmu_num) {fprintf (fp,"# pmu mappings: not available\n" );return ; } - str = ph->env.pmu_mappings; + str = ff->ph->env.pmu_mappings;while (pmu_num) { type =strtoul (str, &tmp,0 );
@@ -1425,14 +1412,13 @@ static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,fprintf (fp,"# pmu mappings: unable to read\n" ); } -static void print_group_desc (struct perf_header *ph,int fd__maybe_unused , -FILE *fp) +static void print_group_desc (struct feat_fd *ff,FILE *fp) {struct perf_session *session;struct perf_evsel *evsel;u32 nr =0 ; - session = container_of(ph, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header);evlist__for_each_entry (session->evlist, evsel) { if (perf_evsel__is_group_leader(evsel) &&
@@ -2109,7 +2095,7 @@ static int process_cache(struct perf_file_section *section __maybe_unused,struct feature_ops {int (*write)(struct feat_fd *ff,struct perf_evlist *evlist); -void (*print)(struct perf_header *h,int fd,FILE *fp); +void (*print)(struct feat_fd *ff,FILE *fp);int (*process)(struct perf_file_section *section,struct perf_header *h,int fd,void *data);const char *name;
@@ -2162,6 +2148,7 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section, int feat, int fd, void *data) { struct header_print_data *hd = data; +struct feat_fd ff;if (lseek (fd, section->offset,SEEK_SET ) == (off_t)-1 ) { pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@@ -2175,8 +2162,13 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section,if (!feat_ops[feat].print)return 0 ; + ff = (struct feat_fd ) { + .fd = fd, + .ph = ph, + }; +if (!feat_ops[feat].full_only || hd->full) - feat_ops[feat].else fprintf (hd->fp,"# %s info available, use -I to display\n" , feat_ops[feat].name);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 71/86 perf header: Use struct feat_fd to process header records
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
As preparation for using header records in pipe-mode, replace int fd with struct feat_fd ff in process functions for all header record types.
This patch does not change behavior.
--- tools/perf/util/header.c | 164 +++++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 85 deletions(-)
tools/perf/util/header.c +79 -85
@@ -1594,11 +1594,10 @@ static int perf_header__read_build_ids(struct perf_header *header,/* Macro for features that simply need to read and store a string. */ #define FEAT_PROCESS_STR_FUN (__feat, __feat_env) \ static int process_##__feat(struct perf_file_section *section __maybe_unused, \ - struct perf_header *ph, int fd, \ - void *data __maybe_unused) \ + struct feat_fd *ff, void *data __maybe_unused) \ {\ - ph->env.__feat_env = do_read_string(fd, ph); \ - return ph->env.__feat_env ? 0 : -ENOMEM; \ + ff->ph->env.__feat_env = do_read_string(ff->fd, ff->ph); \ + return ff->ph->env.__feat_env ? 0 : -ENOMEM; \ }FEAT_PROCESS_STR_FUN (hostname, hostname);
@@ -1609,52 +1608,49 @@ FEAT_PROCESS_STR_FUN(cpudesc, cpu_desc);FEAT_PROCESS_STR_FUN (cpuid, cpuid);static int process_tracing_data (struct perf_file_section *section__maybe_unused , -struct perf_header *ph__maybe_unused , -int fd,void *data) +struct feat_fd *ff,void *data) { -ssize_t ret =trace_report (fd, data, false); +ssize_t ret =trace_report (ff->fd, data, false); +return ret <0 ?-1 :0 ; }static int process_build_id (struct perf_file_section *section, -struct perf_header *ph,int fd, -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) { -if (perf_header__read_build_ids (ph, fd, section->offset, section->size)) +if (perf_header__read_build_ids (ff->ph, ff->fd, section->offset, section->size))pr_debug ("Failed to read buildids, continuing...\n" );return 0 ; }static int process_nrcpus (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) {int ret;u32 nr_cpus_avail, nr_cpus_online; - ret =do_read_u32 (fd, ph, &nr_cpus_avail); + ret =do_read_u32 (ff->fd, ff->ph, &nr_cpus_avail);if (ret)return ret; - ret =do_read_u32 (fd, ph, &nr_cpus_online); + ret =do_read_u32 (ff->fd, ff->ph, &nr_cpus_online);if (ret)return ret; - ph->env.nr_cpus_avail = (int )nr_cpus_avail; - ph->env.nr_cpus_online = (int )nr_cpus_online; + ff->ph->env.nr_cpus_avail = (int )nr_cpus_avail; + ff->ph->env.nr_cpus_online = (int )nr_cpus_online;return 0 ; }static int process_total_mem (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) {u64 total_mem;int ret; - ret =do_read_u64 (fd, ph, &total_mem); + ret =do_read_u64 (ff->fd, ff->ph, &total_mem);if (ret)return -1 ; - ph->env.total_mem = (unsigned long long )total_mem; + ff->ph->env.total_mem = (unsigned long long )total_mem;return 0 ; }
@@ -1692,16 +1688,15 @@ perf_evlist__set_event_name(struct perf_evlist *evlist,static int process_event_desc (struct perf_file_section *section__maybe_unused , -struct perf_header *header,int fd, -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) {struct perf_session *session; -struct perf_evsel *evsel, *events =read_event_desc (header, fd); +struct perf_evsel *evsel, *events =read_event_desc (ff->ph, ff->fd);if (!events)return 0 ; - session = container_of(header, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header);for (evsel = events; evsel->attr.size; evsel++)perf_evlist__set_event_name (session->evlist, evsel);
@@ -1710,17 +1705,16 @@ process_event_desc(struct perf_file_section *section __maybe_unused,return 0 ; } -static int process_cmdline (struct perf_file_section *section, -struct perf_header *ph,int fd, -void *data__maybe_unused ) +static int process_cmdline (struct perf_file_section *section__maybe_unused , +struct feat_fd *ff,void *data__maybe_unused ) {char *str, *cmdline =NULL , **argv =NULL ;u32 nr, i, len =0 ; -if (do_read_u32 (fd, ph, &nr)) +if (do_read_u32 (ff->fd, ff->ph, &nr))return -1 ; - ph->env.nr_cmdline = nr; + ff->ph->env.nr_cmdline = nr; cmdline =zalloc (section->size + nr +1 );if (!cmdline)
@@ -1731,7 +1725,7 @@ static int process_cmdline(struct perf_file_section *section, goto error;for (i =0 ; i < nr; i++) { - str =do_read_string (fd, ph); + str =do_read_string (ff->fd, ff->ph);if (!str) goto error;
@@ -1740,8 +1734,8 @@ static int process_cmdline(struct perf_file_section *section, len +=strlen (str) +1 ;free (str); } - ph->env.cmdline = cmdline; - ph->env.cmdline_argv = (const char **) argv; + ff->ph->env.cmdline = cmdline; + ff->ph->env.cmdline_argv = (const char **) argv;return 0 ; error:
@@ -1750,21 +1744,21 @@ static int process_cmdline(struct perf_file_section *section,return -1 ; } -static int process_cpu_topology (struct perf_file_section *section, -struct perf_header *ph,int fd, -void *data__maybe_unused ) +static int process_cpu_topology (struct perf_file_section *section__maybe_unused , +struct feat_fd *ff,void *data__maybe_unused ) {u32 nr, i;char *str;struct strbuf sb; -int cpu_nr = ph->env.nr_cpus_avail; +int cpu_nr = ff->ph->env.nr_cpus_avail;u64 size =0 ; +struct perf_header *ph = ff->ph; ph->env.cpu =calloc (cpu_nr,sizeof (*ph->env.cpu));if (!ph->env.cpu)return -1 ; -if (do_read_u32 (fd, ph, &nr)) +if (do_read_u32 (ff->fd, ph, &nr)) goto free_cpu; ph->env.nr_sibling_cores = nr;
@@ -1773,7 +1767,7 @@ static int process_cpu_topology(struct perf_file_section *section, goto free_cpu;for (i =0 ; i < nr; i++) { - str =do_read_string (fd, ph); + str =do_read_string (ff->fd, ph);if (!str) goto error;
@@ -1785,14 +1779,14 @@ static int process_cpu_topology(struct perf_file_section *section, } ph->env.sibling_cores =strbuf_detach (&sb,NULL ); -if (do_read_u32 (fd, ph, &nr)) +if (do_read_u32 (ff->fd, ph, &nr))return -1 ; ph->env.nr_sibling_threads = nr; size +=sizeof (u32);for (i =0 ; i < nr; i++) { - str =do_read_string (fd, ph); + str =do_read_string (ff->fd, ph);if (!str) goto error;
@@ -1814,12 +1808,12 @@ static int process_cpu_topology(struct perf_file_section *section, }for (i =0 ; i < (u32 )cpu_nr; i++) { -if (do_read_u32 (fd, ph, &nr)) +if (do_read_u32 (ff->fd, ph, &nr)) goto free_cpu; ph->env.cpu[i].core_id = nr; -if (do_read_u32 (fd, ph, &nr)) +if (do_read_u32 (ff->fd, ph, &nr)) goto free_cpu;if (nr != (u32)-1 && nr > (u32 )cpu_nr) {
@@ -1841,15 +1835,14 @@ static int process_cpu_topology(struct perf_file_section *section, }static int process_numa_topology (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) {struct numa_node *nodes, *n;u32 nr, i;char *str;/* nr nodes */ -if (do_read_u32 (fd, ph, &nr)) +if (do_read_u32 (ff->fd, ff->ph, &nr))return -1 ; nodes =zalloc (sizeof (*nodes) * nr);
@@ -1860,16 +1853,16 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse n = &nodes[i];/* node number */ -if (do_read_u32 (fd, ph, &n->node)) +if (do_read_u32 (ff->fd, ff->ph, &n->node)) goto error; -if (do_read_u64 (fd, ph, &n->mem_total)) +if (do_read_u64 (ff->fd, ff->ph, &n->mem_total)) goto error; -if (do_read_u64 (fd, ph, &n->mem_free)) +if (do_read_u64 (ff->fd, ff->ph, &n->mem_free)) goto error; - str =do_read_string (fd, ph); + str =do_read_string (ff->fd, ff->ph);if (!str) goto error;
@@ -1879,8 +1872,8 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unusefree (str); } - ph->env.nr_numa_nodes = nr; - ph->env.numa_nodes = nodes; + ff->ph->env.nr_numa_nodes = nr; + ff->ph->env.numa_nodes = nodes;return 0 ; error:
@@ -1889,15 +1882,14 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse }static int process_pmu_mappings (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) {char *name;u32 pmu_num;u32 type;struct strbuf sb; -if (do_read_u32 (fd, ph, &pmu_num)) +if (do_read_u32 (ff->fd, ff->ph, &pmu_num))return -1 ;if (!pmu_num) {
@@ -1905,15 +1897,15 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unusedreturn 0 ; } - ph->env.nr_pmu_mappings = pmu_num; + ff->ph->env.nr_pmu_mappings = pmu_num;if (strbuf_init (&sb,128 ) <0 )return -1 ;while (pmu_num) { -if (do_read_u32 (fd, ph, &type)) +if (do_read_u32 (ff->fd, ff->ph, &type)) goto error; - name =do_read_string (fd, ph); + name =do_read_string (ff->fd, ff->ph);if (!name) goto error;
@@ -1924,12 +1916,12 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused goto error;if (!strcmp (name,"msr" )) - ph->env.msr_pmu_type = type; + ff->ph->env.msr_pmu_type = type;free (name); pmu_num--; } - ph->env.pmu_mappings =strbuf_detach (&sb,NULL ); + ff->ph->env.pmu_mappings =strbuf_detach (&sb,NULL );return 0 ; error:
@@ -1938,8 +1930,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused }static int process_group_desc (struct perf_file_section *section__maybe_unused , -struct perf_header *ph,int fd, -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) {size_t ret =-1 ;u32 i, nr, nr_groups;
@@ -1951,10 +1942,10 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,u32 nr_members; } *desc; -if (do_read_u32 (fd, ph, &nr_groups)) +if (do_read_u32 (ff->fd, ff->ph, &nr_groups))return -1 ; - ph->env.nr_groups = nr_groups; + ff->ph->env.nr_groups = nr_groups;if (!nr_groups) {pr_debug ("group desc not available\n" );return 0 ;
@@ -1965,21 +1956,21 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,return -1 ;for (i =0 ; i < nr_groups; i++) { - desc[i].name =do_read_string (fd, ph); + desc[i].name =do_read_string (ff->fd, ff->ph);if (!desc[i].name) goto out_free; -if (do_read_u32 (fd, ph, &desc[i].leader_idx)) +if (do_read_u32 (ff->fd, ff->ph, &desc[i].leader_idx)) goto out_free; -if (do_read_u32 (fd, ph, &desc[i].nr_members)) +if (do_read_u32 (ff->fd, ff->ph, &desc[i].nr_members)) goto out_free; }/* * Rebuild group relationship based on the group_desc */ - session = container_of(ph, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header); session->evlist->nr_groups = nr_groups; i = nr =0 ;
@@ -2023,36 +2014,34 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,return ret; } -static int process_auxtrace (struct perf_file_section *section, -struct perf_header *ph,int fd, -void *data__maybe_unused ) +static int process_auxtrace (struct perf_file_section *section__maybe_unused , +struct feat_fd *ff,void *data__maybe_unused ) {struct perf_session *session;int err; - session = container_of(ph, struct perf_session, header); + session = container_of(ff->ph, struct perf_session, header); - err =auxtrace_index__process (fd, section->size, session, - ph->needs_swap); + err =auxtrace_index__process (ff->fd, section->size, session, + ff->ph->needs_swap);if (err <0 )pr_err ("Failed to process auxtrace index\n" );return err; }static int process_cache (struct perf_file_section *section__maybe_unused , -struct perf_header *ph__maybe_unused ,int fd__maybe_unused , -void *data__maybe_unused ) +struct feat_fd *ff,void *data__maybe_unused ) {struct cpu_cache_level *caches;u32 cnt, i, version; -if (do_read_u32 (fd, ph, &version)) +if (do_read_u32 (ff->fd, ff->ph, &version))return -1 ;if (version !=1 )return -1 ; -if (do_read_u32 (fd, ph, &cnt)) +if (do_read_u32 (ff->fd, ff->ph, &cnt))return -1 ; caches =zalloc (sizeof (*caches) * cnt);
@@ -2063,7 +2052,7 @@ static int process_cache(struct perf_file_section *section __maybe_unused,struct cpu_cache_level c;#define _R (v) \ - if (do_read_u32(fd, ph, &c.v))\ + if (do_read_u32(ff->fd, ff->ph, &c.v))\ goto out_free_caches; \_R (level)
@@ -2072,9 +2061,9 @@ static int process_cache(struct perf_file_section *section __maybe_unused, _R(ways)#undef _R -#define _R (v) \ - c.v = do_read_string(fd, ph); \ - if (!c.v) \ +#define _R (v) \ + c.v = do_read_string(ff->fd, ff->ph); \ + if (!c.v) \ goto out_free_caches;_R (type)
@@ -2085,8 +2074,8 @@ static int process_cache(struct perf_file_section *section __maybe_unused, caches[i] = c; } - ph->env.caches = caches; - ph->env.caches_cnt = cnt; + ff->ph->env.caches = caches; + ff->ph->env.caches_cnt = cnt;return 0 ; out_free_caches:free (caches);
@@ -2097,7 +2086,7 @@ struct feature_ops {int (*write)(struct feat_fd *ff,struct perf_evlist *evlist);void (*print)(struct feat_fd *ff,FILE *fp);int (*process)(struct perf_file_section *section, -struct perf_header *h,int fd,void *data); +struct feat_fd *ff,void *data);const char *name;bool full_only; };
@@ -2628,6 +2617,11 @@ static int perf_file_section__process(struct perf_file_section *section,struct perf_header *ph, int feat, int fd, void *data) { + struct feat_fd ff = { + .fd = fd, + .ph = ph, + }; +if (lseek (fd, section->offset,SEEK_SET ) == (off_t)-1 ) {pr_debug ("Failed to lseek to %" PRIu64" offset for feature " "%d, continuing...\n" , section->offset, feat);
@@ -2642,7 +2636,7 @@ static int perf_file_section__process(struct perf_file_section *section,if (!feat_ops[feat].process)return 0 ; -return feat_ops[feat].process (section, ph, fd, data); +return feat_ops[feat].process (section, &ff, data); } static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 72/86 perf header: Don't pass struct perf_file_section to process_##_feat
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
struct perf_file_section is used in process_##_feat as container for size and offset in the file descriptor. These attributes are meaninful in pipe-mode but struct perf_file_section is not.
Add offset and size variables to struct feat_fd to store perf_file_section's values in file-mode. Later on, the same variables can be reused for pipe-mode.
This patch does not change behavior.
--- tools/perf/util/header.c | 58 ++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 34 deletions(-)
tools/perf/util/header.c +24 -34
@@ -62,6 +62,8 @@ struct perf_file_attr {struct feat_fd {struct perf_header *ph;int fd; +ssize_t offset; +size_t size; };void perf_header__set_feat (struct perf_header *header,int feat)
@@ -1593,8 +1595,7 @@ static int perf_header__read_build_ids(struct perf_header *header,/* Macro for features that simply need to read and store a string. */ #define FEAT_PROCESS_STR_FUN (__feat, __feat_env) \ -static int process_##__feat(struct perf_file_section *section __maybe_unused, \ - struct feat_fd *ff, void *data __maybe_unused) \ +static int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \ {\ ff->ph->env.__feat_env = do_read_string(ff->fd, ff->ph); \ return ff->ph->env.__feat_env ? 0 : -ENOMEM; \
@@ -1607,24 +1608,21 @@ FEAT_PROCESS_STR_FUN(arch, arch);FEAT_PROCESS_STR_FUN (cpudesc, cpu_desc);FEAT_PROCESS_STR_FUN (cpuid, cpuid); -static int process_tracing_data (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data) +static int process_tracing_data (struct feat_fd *ff,void *data) {ssize_t ret =trace_report (ff->fd, data, false);return ret <0 ?-1 :0 ; } -static int process_build_id (struct perf_file_section *section, -struct feat_fd *ff,void *data__maybe_unused ) +static int process_build_id (struct feat_fd *ff,void *data__maybe_unused ) { -if (perf_header__read_build_ids (ff->ph, ff->fd, section->offset, section->size)) +if (perf_header__read_build_ids (ff->ph, ff->fd, ff->offset, ff->size))pr_debug ("Failed to read buildids, continuing...\n" );return 0 ; } -static int process_nrcpus (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_nrcpus (struct feat_fd *ff,void *data__maybe_unused ) {int ret;u32 nr_cpus_avail, nr_cpus_online;
@@ -1641,8 +1639,7 @@ static int process_nrcpus(struct perf_file_section *section __maybe_unused,return 0 ; } -static int process_total_mem (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_total_mem (struct feat_fd *ff,void *data__maybe_unused ) {u64 total_mem;int ret;
@@ -1687,8 +1684,7 @@ perf_evlist__set_event_name(struct perf_evlist *evlist, }static int -process_event_desc (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +process_event_desc (struct feat_fd *ff,void *data__maybe_unused ) {struct perf_session *session;struct perf_evsel *evsel, *events =read_event_desc (ff->ph, ff->fd);
@@ -1705,8 +1701,7 @@ process_event_desc(struct perf_file_section *section __maybe_unused,return 0 ; } -static int process_cmdline (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_cmdline (struct feat_fd *ff,void *data__maybe_unused ) {char *str, *cmdline =NULL , **argv =NULL ;u32 nr, i, len =0 ;
@@ -1716,7 +1711,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused, ff->ph->env.nr_cmdline = nr; - cmdline =zalloc (section->size + nr +1 ); + cmdline =zalloc (ff->size + nr +1 );if (!cmdline)return -1 ;
@@ -1744,8 +1739,7 @@ static int process_cmdline(struct perf_file_section *section __maybe_unused,return -1 ; } -static int process_cpu_topology (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_cpu_topology (struct feat_fd *ff,void *data__maybe_unused ) {u32 nr, i;char *str;
@@ -1802,7 +1796,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused* The header may be from old perf, * which doesn't include core id and socket id information. */ -if (section->size <= size) { +if (ff->size <= size) {zfree (&ph->env.cpu);return 0 ; }
@@ -1834,8 +1828,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unusedreturn -1 ; } -static int process_numa_topology (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_numa_topology (struct feat_fd *ff,void *data__maybe_unused ) {struct numa_node *nodes, *n;u32 nr, i;
@@ -1881,8 +1874,7 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unusereturn -1 ; } -static int process_pmu_mappings (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_pmu_mappings (struct feat_fd *ff,void *data__maybe_unused ) {char *name;u32 pmu_num;
@@ -1929,8 +1921,7 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unusedreturn -1 ; } -static int process_group_desc (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_group_desc (struct feat_fd *ff,void *data__maybe_unused ) {size_t ret =-1 ;u32 i, nr, nr_groups;
@@ -2014,23 +2005,21 @@ static int process_group_desc(struct perf_file_section *section __maybe_unused,return ret; } -static int process_auxtrace (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_auxtrace (struct feat_fd *ff,void *data__maybe_unused ) {struct perf_session *session;int err; session = container_of(ff->ph, struct perf_session, header); - err =auxtrace_index__process (ff->fd, section->size, session, + err =auxtrace_index__process (ff->fd, ff->size, session, ff->ph->needs_swap);if (err <0 )pr_err ("Failed to process auxtrace index\n" );return err; } -static int process_cache (struct perf_file_section *section__maybe_unused , -struct feat_fd *ff,void *data__maybe_unused ) +static int process_cache (struct feat_fd *ff,void *data__maybe_unused ) {struct cpu_cache_level *caches;u32 cnt, i, version;
@@ -2085,8 +2074,7 @@ static int process_cache(struct perf_file_section *section __maybe_unused,struct feature_ops {int (*write)(struct feat_fd *ff,struct perf_evlist *evlist);void (*print)(struct feat_fd *ff,FILE *fp); -int (*process)(struct perf_file_section *section, -struct feat_fd *ff,void *data); +int (*process)(struct feat_fd *ff,void *data);const char *name;bool full_only; };
@@ -2617,9 +2605,11 @@ static int perf_file_section__process(struct perf_file_section *section,struct perf_header *ph, int feat, int fd, void *data) { - struct feat_fd ff = { + struct feat_fd fdd = { .fd = fd, .ph = ph, + .size = section->size, + .offset = section->offset, };if (lseek (fd, section->offset,SEEK_SET ) == (off_t)-1 ) {
@@ -2636,7 +2626,7 @@ static int perf_file_section__process(struct perf_file_section *section,if (!feat_ops[feat].process)return 0 ; -return feat_ops[feat].process (section, &ff, data); +return feat_ops[feat].process (&fdd, data); } static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 73/86 perf header: Use struct feat_fd in read header records
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
As preparation for using header records in-pipe mode, replace int fd with struct feat_fd ff in read functions for all header record types.
This patch does not change behavior.
--- tools/perf/util/header.c | 101 +++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 51 deletions(-)
tools/perf/util/header.c +50 -51
@@ -126,54 +126,54 @@ static int do_write_string(struct feat_fd *ff, const char *str)return write_padded (ff, str, olen, len); } -static int __do_read (int fd,void *addr,ssize_t size) +static int __do_read (struct feat_fd *ff,void *addr,ssize_t size) { -ssize_t ret =readn (fd, addr, size); +ssize_t ret =readn (ff->fd, addr, size);if (ret != size)return ret <0 ? (int )ret :-1 ;return 0 ; } -static int do_read_u32 (int fd,struct perf_header *ph,u32 *addr) +static int do_read_u32 (struct feat_fd *ff,u32 *addr) {int ret; - ret =__do_read (fd, addr,sizeof (*addr)); + ret =__do_read (ff, addr,sizeof (*addr));if (ret)return ret; -if (ph->needs_swap) +if (ff->ph->needs_swap) *addr =bswap_32 (*addr);return 0 ; } -static int do_read_u64 (int fd,struct perf_header *ph,u64 *addr) +static int do_read_u64 (struct feat_fd *ff,u64 *addr) {int ret; - ret =__do_read (fd, addr,sizeof (*addr)); + ret =__do_read (ff, addr,sizeof (*addr));if (ret)return ret; -if (ph->needs_swap) +if (ff->ph->needs_swap) *addr =bswap_64 (*addr);return 0 ; } -static char *do_read_string (int fd,struct perf_header *ph) +static char *do_read_string (struct feat_fd *ff) {u32 len;char *buf; -if (do_read_u32 (fd, ph, &len)) +if (do_read_u32 (ff, &len))return NULL ; buf =malloc (len);if (!buf)return NULL ; -if (!__do_read (fd, buf, len)) { +if (!__do_read (ff, buf, len)) {/* * strings are padded by zeroes * thus the actual strlen of buf
@@ -1208,8 +1208,7 @@ static void free_event_desc(struct perf_evsel *events)free (events); } -static struct perf_evsel * -read_event_desc (struct perf_header *ph,int fd) +static struct perf_evsel *read_event_desc (struct feat_fd *ff) {struct perf_evsel *evsel, *events =NULL ;u64 *id;
@@ -1218,10 +1217,10 @@ read_event_desc(struct perf_header *ph, int fd)size_t msz;/* number of events */ -if (do_read_u32 (fd, ph, &nre)) +if (do_read_u32 (ff, &nre)) goto error; -if (do_read_u32 (fd, ph, &sz)) +if (do_read_u32 (ff, &sz)) goto error;/* buffer to hold on file attr struct */
@@ -1245,21 +1244,21 @@ read_event_desc(struct perf_header *ph, int fd)* must read entire on-file attr struct to * sync up with layout. */ -if (__do_read (fd, buf, sz)) +if (__do_read (ff, buf, sz)) goto error; -if (ph->needs_swap) +if (ff->ph->needs_swap)perf_event__attr_swap (buf);memcpy (&evsel->attr, buf, msz); -if (do_read_u32 (fd, ph, &nr)) +if (do_read_u32 (ff, &nr)) goto error; -if (ph->needs_swap) +if (ff->ph->needs_swap) evsel->needs_swap = true; - evsel->name =do_read_string (fd, ph); + evsel->name =do_read_string (ff);if (!evsel->name) goto error;
@@ -1273,7 +1272,7 @@ read_event_desc(struct perf_header *ph, int fd) evsel->id = id;for (j =0 ; j < nr; j++) { -if (do_read_u64 (fd, ph, id)) +if (do_read_u64 (ff, id)) goto error; id++; }
@@ -1295,7 +1294,7 @@ static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val,static void print_event_desc (struct feat_fd *ff,FILE *fp) { -struct perf_evsel *evsel, *events =read_event_desc (ff->ph, ff->fd); +struct perf_evsel *evsel, *events =read_event_desc (ff);u32 j;u64 *id;
@@ -1597,7 +1596,7 @@ static int perf_header__read_build_ids(struct perf_header *header,#define FEAT_PROCESS_STR_FUN (__feat, __feat_env) \ static int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \ {\ - ff->ph->env.__feat_env = do_read_string(ff->fd, ff->ph); \ + ff->ph->env.__feat_env = do_read_string(ff); \ return ff->ph->env.__feat_env ? 0 : -ENOMEM; \ }
@@ -1627,11 +1626,11 @@ static int process_nrcpus(struct feat_fd *ff, void *data __maybe_unused)int ret;u32 nr_cpus_avail, nr_cpus_online; - ret =do_read_u32 (ff->fd, ff->ph, &nr_cpus_avail); + ret =do_read_u32 (ff, &nr_cpus_avail);if (ret)return ret; - ret =do_read_u32 (ff->fd, ff->ph, &nr_cpus_online); + ret =do_read_u32 (ff, &nr_cpus_online);if (ret)return ret; ff->ph->env.nr_cpus_avail = (int )nr_cpus_avail;
@@ -1644,7 +1643,7 @@ static int process_total_mem(struct feat_fd *ff, void *data __maybe_unused)u64 total_mem;int ret; - ret =do_read_u64 (ff->fd, ff->ph, &total_mem); + ret =do_read_u64 (ff, &total_mem);if (ret)return -1 ; ff->ph->env.total_mem = (unsigned long long )total_mem;
@@ -1687,7 +1686,7 @@ static int process_event_desc(struct feat_fd *ff, void *data __maybe_unused) { struct perf_session *session; -struct perf_evsel *evsel, *events =read_event_desc (ff->ph, ff->fd); +struct perf_evsel *evsel, *events =read_event_desc (ff);if (!events)return 0 ;
@@ -1706,7 +1705,7 @@ static int process_cmdline(struct feat_fd *ff, void *data __maybe_unused)char *str, *cmdline =NULL , **argv =NULL ;u32 nr, i, len =0 ; -if (do_read_u32 (ff->fd, ff->ph, &nr)) +if (do_read_u32 (ff, &nr))return -1 ; ff->ph->env.nr_cmdline = nr;
@@ -1720,7 +1719,7 @@ static int process_cmdline(struct feat_fd *ff, void *data __maybe_unused) goto error;for (i =0 ; i < nr; i++) { - str =do_read_string (ff->fd, ff->ph); + str =do_read_string (ff);if (!str) goto error;
@@ -1752,7 +1751,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)if (!ph->env.cpu)return -1 ; -if (do_read_u32 (ff->fd, ph, &nr)) +if (do_read_u32 (ff, &nr)) goto free_cpu; ph->env.nr_sibling_cores = nr;
@@ -1761,7 +1760,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) goto free_cpu;for (i =0 ; i < nr; i++) { - str =do_read_string (ff->fd, ph); + str =do_read_string (ff);if (!str) goto error;
@@ -1773,14 +1772,14 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) } ph->env.sibling_cores =strbuf_detach (&sb,NULL ); -if (do_read_u32 (ff->fd, ph, &nr)) +if (do_read_u32 (ff, &nr))return -1 ; ph->env.nr_sibling_threads = nr; size +=sizeof (u32);for (i =0 ; i < nr; i++) { - str =do_read_string (ff->fd, ph); + str =do_read_string (ff);if (!str) goto error;
@@ -1802,12 +1801,12 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) }for (i =0 ; i < (u32 )cpu_nr; i++) { -if (do_read_u32 (ff->fd, ph, &nr)) +if (do_read_u32 (ff, &nr)) goto free_cpu; ph->env.cpu[i].core_id = nr; -if (do_read_u32 (ff->fd, ph, &nr)) +if (do_read_u32 (ff, &nr)) goto free_cpu;if (nr != (u32)-1 && nr > (u32 )cpu_nr) {
@@ -1835,7 +1834,7 @@ static int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused)char *str;/* nr nodes */ -if (do_read_u32 (ff->fd, ff->ph, &nr)) +if (do_read_u32 (ff, &nr))return -1 ; nodes =zalloc (sizeof (*nodes) * nr);
@@ -1846,16 +1845,16 @@ static int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused) n = &nodes[i];/* node number */ -if (do_read_u32 (ff->fd, ff->ph, &n->node)) +if (do_read_u32 (ff, &n->node)) goto error; -if (do_read_u64 (ff->fd, ff->ph, &n->mem_total)) +if (do_read_u64 (ff, &n->mem_total)) goto error; -if (do_read_u64 (ff->fd, ff->ph, &n->mem_free)) +if (do_read_u64 (ff, &n->mem_free)) goto error; - str =do_read_string (ff->fd, ff->ph); + str =do_read_string (ff);if (!str) goto error;
@@ -1881,7 +1880,7 @@ static int process_pmu_mappings(struct feat_fd *ff, void *data __maybe_unused)u32 type;struct strbuf sb; -if (do_read_u32 (ff->fd, ff->ph, &pmu_num)) +if (do_read_u32 (ff, &pmu_num))return -1 ;if (!pmu_num) {
@@ -1894,10 +1893,10 @@ static int process_pmu_mappings(struct feat_fd *ff, void *data __maybe_unused)return -1 ;while (pmu_num) { -if (do_read_u32 (ff->fd, ff->ph, &type)) +if (do_read_u32 (ff, &type)) goto error; - name =do_read_string (ff->fd, ff->ph); + name =do_read_string (ff);if (!name) goto error;
@@ -1933,7 +1932,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused)u32 nr_members; } *desc; -if (do_read_u32 (ff->fd, ff->ph, &nr_groups)) +if (do_read_u32 (ff, &nr_groups))return -1 ; ff->ph->env.nr_groups = nr_groups;
@@ -1947,14 +1946,14 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused)return -1 ;for (i =0 ; i < nr_groups; i++) { - desc[i].name =do_read_string (ff->fd, ff->ph); + desc[i].name =do_read_string (ff);if (!desc[i].name) goto out_free; -if (do_read_u32 (ff->fd, ff->ph, &desc[i].leader_idx)) +if (do_read_u32 (ff, &desc[i].leader_idx)) goto out_free; -if (do_read_u32 (ff->fd, ff->ph, &desc[i].nr_members)) +if (do_read_u32 (ff, &desc[i].nr_members)) goto out_free; }
@@ -2024,13 +2023,13 @@ static int process_cache(struct feat_fd *ff, void *data __maybe_unused)struct cpu_cache_level *caches;u32 cnt, i, version; -if (do_read_u32 (ff->fd, ff->ph, &version)) +if (do_read_u32 (ff, &version))return -1 ;if (version !=1 )return -1 ; -if (do_read_u32 (ff->fd, ff->ph, &cnt)) +if (do_read_u32 (ff, &cnt))return -1 ; caches =zalloc (sizeof (*caches) * cnt);
@@ -2041,7 +2040,7 @@ static int process_cache(struct feat_fd *ff, void *data __maybe_unused)struct cpu_cache_level c;#define _R (v) \ - if (do_read_u32(ff->fd, ff->ph, &c.v))\ + if (do_read_u32(ff, &c.v))\ goto out_free_caches; \_R (level)
@@ -2051,7 +2050,7 @@ static int process_cache(struct feat_fd *ff, void *data __maybe_unused)#undef _R#define _R (v) \ - c.v = do_read_string(ff->fd, ff->ph); \ + c.v = do_read_string(ff); \ if (!c.v) \ goto out_free_caches;
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 74/86 perf header: Make write_pmu_mappings pipe-mode friendly
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
In pipe-mode, we will operate over a buffer instead of a file descriptor but write_pmu_mappings uses lseek to move over the perf.data file.
Refactor write_pmu_mappings to avoid the usage of lseek and allow reusing the same logic in pipe-mode (next patch).
--- tools/perf/util/header.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-)
tools/perf/util/header.c +11 -10
@@ -797,11 +797,19 @@ static int write_pmu_mappings(struct feat_fd *ff, struct perf_evlist *evlist __maybe_unused) {struct perf_pmu *pmu =NULL ; -off_t offset =lseek (ff->fd,0 ,SEEK_CUR ); -__u32 pmu_num =0 ; +u32 pmu_num =0 ;int ret; -/* write real pmu_num later */ +/* +* Do a first pass to count number of pmu to avoid lseek so this +* works in pipe mode as well. +*/ +while ((pmu =perf_pmu__scan (pmu))) { +if (!pmu->name) +continue ; + pmu_num++; + } + ret =do_write (ff, &pmu_num,sizeof (pmu_num));if (ret <0 )return ret;
@@ -809,7 +817,6 @@ static int write_pmu_mappings(struct feat_fd *ff,while ((pmu =perf_pmu__scan (pmu))) {if (!pmu->name)continue ; - pmu_num++; ret =do_write (ff, &pmu->type,sizeof (pmu->type));if (ret <0 )
@@ -820,12 +827,6 @@ static int write_pmu_mappings(struct feat_fd *ff,return ret; } -if (pwrite (ff->fd, &pmu_num,sizeof (pmu_num), offset) !=sizeof (pmu_num)) { -/* discard all */ -lseek (ff->fd, offset,SEEK_SET ); -return -1 ; - } -return 0 ; }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 75/86 perf header: Add a buffer to struct feat_fd
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Extend struct feat_fd to use a temporal buffer in pipe-mode, instead of perf.data's file descriptor.
The header features build_id and aux_trace already have logic to print in file-mode that heavily rely on lseek the file. For now, leave such features inactive in pipe-mode and print a warning if their functions are called in pipe-mode.
--- tools/perf/util/header.c | 75 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 5 deletions(-)
tools/perf/util/header.c +70 -5
@@ -62,6 +62,7 @@ struct perf_file_attr {struct feat_fd {struct perf_header *ph;int fd; +void *buf;/* Either buf != NULL or fd >= 0 */ ssize_t offset;size_t size; };
@@ -81,19 +82,52 @@ bool perf_header__has_feat(const struct perf_header *header, int feat)return test_bit (feat, header->adds_features); } -/* Return: 0 if succeded, -ERR if failed. */ -int do_write (struct feat_fd *ff,const void *buf,size_t size) +static int __do_write_fd (struct feat_fd *ff,const void *buf,size_t size) { -ssize_t ret; +ssize_t ret =writen (ff->fd, buf, size); - ret =writen (ff->fd, buf, size);if (ret != (ssize_t )size)return ret <0 ? (int )ret :-1 ; +return 0 ; +} + +static int __do_write_buf (struct feat_fd *ff,const void *buf,size_t size) +{ +/* struct perf_event_header::size is u16 */ +const size_t max_size =0xffff -sizeof (struct perf_event_header ); +size_t new_size = ff->size; +void *addr; + +if (size + ff->offset > max_size) +return -E2BIG ; + +while (size > (new_size - ff->offset)) + new_size <<=1 ; + new_size =min (max_size, new_size); + +if (ff->size < new_size) { + addr =realloc (ff->buf, new_size); +if (!addr) +return -ENOMEM ; + ff->buf = addr; + ff->size = new_size; + } + +memcpy (ff->buf + ff->offset, buf, size); + ff->offset += size;return 0 ; }/* Return: 0 if succeded, -ERR if failed. */ +int do_write (struct feat_fd *ff,const void *buf,size_t size) +{ +if (!ff->buf) +return __do_write_fd (ff, buf, size); +return __do_write_buf (ff, buf, size); +} + +/* Return: 0 if succeded, -ERR if failed. */ int write_padded (struct feat_fd *ff,const void *bf,size_t count,size_t count_aligned) {
@@ -126,7 +160,7 @@ static int do_write_string(struct feat_fd *ff, const char *str)return write_padded (ff, str, olen, len); } -static int __do_read (struct feat_fd *ff,void *addr,ssize_t size) +static int __do_read_fd (struct feat_fd *ff,void *addr,ssize_t size) {ssize_t ret =readn (ff->fd, addr, size);
@@ -135,6 +169,25 @@ static int __do_read(struct feat_fd *ff, void *addr, ssize_t size)return 0 ; } +static int __do_read_buf (struct feat_fd *ff,void *addr,ssize_t size) +{ +if (size > (ssize_t )ff->size - ff->offset) +return -1 ; + +memcpy (addr, ff->buf + ff->offset, size); + ff->offset += size; + +return 0 ; + +} + +static int __do_read (struct feat_fd *ff,void *addr,ssize_t size) +{ +if (!ff->buf) +return __do_read_fd (ff, addr, size); +return __do_read_buf (ff, addr, size); +} +static int do_read_u32 (struct feat_fd *ff,u32 *addr) {int ret;
@@ -189,6 +242,9 @@ static char *do_read_string(struct feat_fd *ff)static int write_tracing_data (struct feat_fd *ff,struct perf_evlist *evlist) { +if (WARN (ff->buf,"Error: calling %s in pipe-mode.\n" , __func__)) +return -1 ; +return read_tracing_data (ff->fd, &evlist->entries); }
@@ -203,6 +259,9 @@ static int write_build_id(struct feat_fd *ff,if (!perf_session__read_build_ids (session, true))return -1 ; +if (WARN (ff->buf,"Error: calling %s in pipe-mode.\n" , __func__)) +return -1 ; + err =perf_session__write_buildid_table (session, ff);if (err <0 ) {pr_debug ("failed to write buildid table\n" );
@@ -912,6 +971,9 @@ static int write_auxtrace(struct feat_fd *ff,struct perf_session *session;int err; +if (WARN (ff->buf,"Error: calling %s in pipe-mode.\n" , __func__)) +return -1 ; + session = container_of(ff->ph, struct perf_session, header); err =auxtrace_index__write (ff->fd, &session->auxtrace_index);
@@ -2197,6 +2259,9 @@ static int do_write_feat(struct feat_fd *ff, int type,if (!feat_ops[type].write)return -1 ; +if (WARN (ff->buf,"Error: calling %s in pipe-mode.\n" , __func__)) +return -1 ; + (*p)->offset =lseek (ff->fd,0 ,SEEK_CUR ); err = feat_ops[type].write (ff, evlist);
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 76/86 perf header: Change FEAT_OP* macros
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
There are three FEAT_OP* macros:
- FEAT_OPA: for features without process record.
- FEAT_OPP: for features with process record.
- FEAT_OPF: like FEAT_OPP but to show only if show_full_info flags is set.
To add pipe-mode headers we need yet another variation of the macros (one to specify whether a feature generates an auxiliar record).
Instead, we redefine macros so that:
- show_full_info is specified as an argument (to remove the FEAT_OPF variation) and,
- it always sets "process" handler (to remove the FEAT_OPA variation). Individual process handlers can be NULLed individually.
This allows to define two variations only:
- FEAT_OPR: synthesizes auxiliar event record.
- FEAT_OPN: doesn't synthesize an auxiliar event record.
--- tools/perf/util/header.c | 72 +++++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 28 deletions(-)
tools/perf/util/header.c +44 -28
@@ -12,6 +12,7 @@#include <linux/list.h> #include <linux/kernel.h> #include <linux/bitops.h> +#include <linux/stringify.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/utsname.h>
@@ -2139,42 +2140,57 @@ struct feature_ops {int (*process)(struct feat_fd *ff,void *data);const char *name;bool full_only; +bool synthesize; }; -#define FEAT_OPA (n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func } -#define FEAT_OPP (n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func, \ - .process = process_##func } -#define FEAT_OPF (n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func, \ - .process = process_##func, .full_only = true } +#define FEAT_OPR (n, func, __full_only) \ + [HEADER_##n] = { \ + .name = __stringify(n), \ + .write = write_##func, \ + .print = print_##func, \ + .full_only = __full_only, \ + .process = process_##func, \ + .synthesize = true \ + } + +#define FEAT_OPN (n, func, __full_only) \ + [HEADER_##n] = { \ + .name = __stringify(n), \ + .write = write_##func, \ + .print = print_##func, \ + .full_only = __full_only, \ + .process = process_##func \ + }/* feature_ops not implemented: */ #define print_tracing_data NULL#define print_build_id NULL +#define process_branch_stack NULL +#define process_stat NULL + +static const struct feature_ops feat_ops[HEADER_LAST_FEATURE ] = { -FEAT_OPP (HEADER_TRACING_DATA , tracing_data), -FEAT_OPP (HEADER_BUILD_ID , build_id), -FEAT_OPP (HEADER_HOSTNAME , hostname), -FEAT_OPP (HEADER_OSRELEASE , osrelease), -FEAT_OPP (HEADER_VERSION , version), -FEAT_OPP (HEADER_ARCH , arch), -FEAT_OPP (HEADER_NRCPUS , nrcpus), -FEAT_OPP (HEADER_CPUDESC , cpudesc), -FEAT_OPP (HEADER_CPUID , cpuid), -FEAT_OPP (HEADER_TOTAL_MEM , total_mem), -FEAT_OPP (HEADER_EVENT_DESC , event_desc), -FEAT_OPP (HEADER_CMDLINE , cmdline), -FEAT_OPF (HEADER_CPU_TOPOLOGY , cpu_topology), -FEAT_OPF (HEADER_NUMA_TOPOLOGY , numa_topology), -FEAT_OPA (HEADER_BRANCH_STACK , branch_stack), -FEAT_OPP (HEADER_PMU_MAPPINGS , pmu_mappings), -FEAT_OPP (HEADER_GROUP_DESC , group_desc), -FEAT_OPP (HEADER_AUXTRACE , auxtrace), -FEAT_OPA (HEADER_STAT , stat), -FEAT_OPF (HEADER_CACHE , cache), +FEAT_OPN (TRACING_DATA , tracing_data, false), +FEAT_OPN (BUILD_ID , build_id, false), +FEAT_OPR (HOSTNAME , hostname, false), +FEAT_OPR (OSRELEASE , osrelease, false), +FEAT_OPR (VERSION , version, false), +FEAT_OPR (ARCH , arch, false), +FEAT_OPR (NRCPUS , nrcpus, false), +FEAT_OPR (CPUDESC , cpudesc, false), +FEAT_OPR (CPUID , cpuid, false), +FEAT_OPR (TOTAL_MEM , total_mem, false), +FEAT_OPR (EVENT_DESC , event_desc, false), +FEAT_OPR (CMDLINE , cmdline, false), +FEAT_OPR (CPU_TOPOLOGY , cpu_topology, true), +FEAT_OPR (NUMA_TOPOLOGY , numa_topology, true), +FEAT_OPN (BRANCH_STACK , branch_stack, false), +FEAT_OPR (PMU_MAPPINGS , pmu_mappings, false), +FEAT_OPN (GROUP_DESC , group_desc, false), +FEAT_OPN (AUXTRACE , auxtrace, false), +FEAT_OPN (STAT , stat, false), +FEAT_OPN (CACHE , cache, true), };struct header_print_data {
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 77/86 perf tool: Add show_feature_header to perf_tool
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Add show_feat_hdr to control level of printed information of feature headers.
--- tools/perf/builtin-report.c | 4 ++++ tools/perf/builtin-script.c | 3 +++ tools/perf/util/tool.h | 7 +++++++ 3 files changed, 14 insertions(+)
tools/perf/builtin-report.c +4 -0
@@ -988,6 +988,10 @@ int cmd_report(int argc, const char **argv)/* Force tty output for header output and per-thread stat. */ if (report.header || report.header_only || report.show_threads) use_browser =0 ; +if (report.header || report.header_only) + report.tool.show_feat_hdr =SHOW_FEAT_HEADER ; +if (report.show_full_info) + report.tool.show_feat_hdr =SHOW_FEAT_HEADER_FULL_INFO ;if (strcmp (input_name,"-" ) !=0 )setup_browser (true);
tools/perf/builtin-script.c +3 -0
@@ -2972,10 +2972,13 @@ int cmd_script(int argc, const char **argv)return -1 ;if (header || header_only) { + script.tool.show_feat_hdr =SHOW_FEAT_HEADER ;perf_session__fprintf_info (session, stdout, show_full_info);if (header_only) goto out_delete; } +if (show_full_info) + script.tool.show_feat_hdr =SHOW_FEAT_HEADER_FULL_INFO ;if (symbol__init (&session->header.env) <0 ) goto out_delete;
tools/perf/util/tool.h +7 -0
@@ -34,6 +34,12 @@ typedef int (*event_oe)(struct perf_tool *tool, union perf_event *event,typedef s64 (*event_op3 )(struct perf_tool *tool,union perf_event *event,struct perf_session *session); +enum show_feature_header { +SHOW_FEAT_NO_HEADER =0 , +SHOW_FEAT_HEADER , +SHOW_FEAT_HEADER_FULL_INFO , +}; +struct perf_tool {event_sample sample, read;
@@ -68,6 +74,7 @@ struct perf_tool {bool ordered_events;bool ordering_requires_timestamps;bool namespace_events; + enum show_feature_header show_feat_hdr; };#endif /* __PERF_TOOL_H */
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 78/86 perf tools: Add feature header record to pipe-mode
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Add header record types to pipe-mode, reusing the functions used in file-mode and leveraging the new struct feat_fd.
For alignment, check that synthesized events don't exceed pagesize.
Add the perf_event__synthesize_feature event call back to process the new header records.
Before this patch:
$ perf record -o - -e cycles sleep 1 | perf report --stdio --header [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.000 MB - ] ...
After this patch:
$ perf record -o - -e cycles sleep 1 | perf report --stdio --header # ======== # captured on: Mon May 22 16:33:43 2017 # ======== # # hostname : my_hostname # os release : 4.11.0-dbx-up_perf # perf version : 4.11.rc6.g6277c80 # arch : x86_64 # nrcpus online : 72 # nrcpus avail : 72 # cpudesc : Intel(R) Xeon(R) CPU E5-2696 v3 @ 2.30GHz # cpuid : GenuineIntel,6,63,2 # total memory : 263457192 kB # cmdline : /root/perf record -o - -e cycles -c 100000 sleep 1 # HEADER_CPU_TOPOLOGY info available, use -I to display # HEADER_NUMA_TOPOLOGY info available, use -I to display # pmu mappings: intel_bts = 6, uncore_imc_4 = 22, uncore_sbox_1 = 47, uncore_cbox_5 = 33, uncore_ha_0 = 16, uncore_cbox [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.000 MB - ] ...
Support added for the subcommands: report, inject, annotate and script.
--- tools/perf/Documentation/perf.data-file-format.txt | 10 ++- tools/perf/builtin-annotate.c | 1 + tools/perf/builtin-inject.c | 1 + tools/perf/builtin-record.c | 7 ++ tools/perf/builtin-report.c | 1 + tools/perf/builtin-script.c | 1 + tools/perf/util/event.c | 1 + tools/perf/util/event.h | 8 ++ tools/perf/util/header.c | 98 ++++++++++++++++++++++ tools/perf/util/header.h | 9 ++ tools/perf/util/session.c | 4 + tools/perf/util/tool.h | 3 +- 12 files changed, 141 insertions(+), 3 deletions(-)
tools/perf/Documentation/perf.data-file-format.txt +8 -2
@@ -398,6 +398,11 @@ struct auxtrace_error_event { char msg[MAX_AUXTRACE_ERROR_MSG]; }; + PERF_RECORD_HEADER_FEATURE = 80, + +Describes a header feature. These are records used in pipe-mode that +contain information that otherwise would be in perf.data file's header. + Event types Define the event attributes with their IDs.
@@ -422,8 +427,9 @@ struct perf_pipe_file_header { }; The information about attrs, data, and event_types is instead in the -synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA and -PERF_RECORD_HEADER_EVENT_TYPE that are generated by perf record in pipe-mode. +synthesized events PERF_RECORD_ATTR, PERF_RECORD_HEADER_TRACING_DATA, +PERF_RECORD_HEADER_EVENT_TYPE, and PERF_RECORD_HEADER_FEATURE +that are generated by perf record in pipe-mode. References:
tools/perf/builtin-annotate.c +1 -0
@@ -397,6 +397,7 @@ int cmd_annotate(int argc, const char **argv) .namespaces = perf_event__process_namespaces, .attr = perf_event__process_attr, .build_id = perf_event__process_build_id, + .feature = perf_event__process_feature, .ordered_events = true, .ordering_requires_timestamps = true, },
tools/perf/builtin-inject.c +1 -0
@@ -770,6 +770,7 @@ int cmd_inject(int argc, const char **argv) .finished_round = perf_event__repipe_oe_synth, .build_id = perf_event__repipe_op2_synth, .id_index = perf_event__repipe_op2_synth, + .feature = perf_event__repipe_op2_synth, }, .input_name = "-", .samples = LIST_HEAD_INIT(inject.samples),
tools/perf/builtin-record.c +7 -0
@@ -799,6 +799,13 @@ static int record__synthesize(struct record *rec, bool tail)return 0 ;if (file->is_pipe) { + err =perf_event__synthesize_features ( + tool, session, rec->evlist, process_synthesized_event); +if (err <0 ) { +pr_err ("Couldn't synthesize features.\n" ); +return err; + } + err =perf_event__synthesize_attrs (tool, session, process_synthesized_event);if (err <0 ) {
tools/perf/builtin-report.c +1 -0
@@ -718,6 +718,7 @@ int cmd_report(int argc, const char **argv) .id_index = perf_event__process_id_index, .auxtrace_info = perf_event__process_auxtrace_info, .auxtrace = perf_event__process_auxtrace, + .feature = perf_event__process_feature, .ordered_events = true, .ordering_requires_timestamps = true, },
tools/perf/builtin-script.c +1 -0
@@ -2682,6 +2682,7 @@ int cmd_script(int argc, const char **argv) .attr = process_attr, .event_update = perf_event__process_event_update, .tracing_data = perf_event__process_tracing_data, + .feature = perf_event__process_feature, .build_id = perf_event__process_build_id, .id_index = perf_event__process_id_index, .auxtrace_info = perf_event__process_auxtrace_info,
tools/perf/util/event.c +1 -0
@@ -57,6 +57,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", [PERF_RECORD_TIME_CONV] = "TIME_CONV", + [PERF_RECORD_HEADER_FEATURE] = "FEATURE", };static const char *perf_ns__names[] = {
tools/perf/util/event.h +8 -0
@@ -244,6 +244,7 @@ enum perf_user_event_type { /* above any possible kernel type */PERF_RECORD_STAT_ROUND =77 ,PERF_RECORD_EVENT_UPDATE =78 ,PERF_RECORD_TIME_CONV =79 , +PERF_RECORD_HEADER_FEATURE =80 , PERF_RECORD_HEADER_MAX };
@@ -609,6 +610,12 @@ struct time_conv_event {u64 time_zero; }; +struct feature_event { +struct perf_event_header header; +u64 feat_id; +char data[]; +}; +union perf_event {struct perf_event_header header;struct mmap_event mmap;
@@ -639,6 +646,7 @@ union perf_event {struct stat_event stat;struct stat_round_event stat_round;struct time_conv_event time_conv; +struct feature_event feat; };void perf_event__print_totals (void );
tools/perf/util/header.c +98 -0
110 lines not on this page · raw message
tools/perf/util/header.h +9 -0
@@ -101,6 +101,15 @@ int perf_header__process_sections(struct perf_header *header, int fd,int perf_header__fprintf_info (struct perf_session *s,FILE *fp,bool full); +int perf_event__synthesize_features (struct perf_tool *tool, +struct perf_session *session, +struct perf_evlist *evlist, +perf_event__handler_t process); + +int perf_event__process_feature (struct perf_tool *tool, +union perf_event *event, +struct perf_session *session); +int perf_event__synthesize_attr (struct perf_tool *tool,struct perf_event_attr *attr,u32 ids,u64 *id,perf_event__handler_t process);
tools/perf/util/session.c +4 -0
@@ -428,6 +428,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->stat_round = process_stat_round_stub;if (tool->time_conv ==NULL ) tool->time_conv = process_event_op2_stub; +if (tool->feature ==NULL ) + tool->feature = process_event_op2_stub; }static void swap_sample_id_all (union perf_event *event,void *data)
@@ -1371,6 +1373,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,case PERF_RECORD_TIME_CONV : session->time_conv = event->time_conv;return tool->time_conv (tool, event, session); +case PERF_RECORD_HEADER_FEATURE : +return tool->feature (tool, event, session);default :return -EINVAL ; }
tools/perf/util/tool.h +2 -1
@@ -69,7 +69,8 @@ struct perf_tool { cpu_map, stat_config, stat, - stat_round; + stat_round, + feature;event_op3 auxtrace;bool ordered_events;bool ordering_requires_timestamps;
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 79/86 perf header: Add event desc to pipe-mode header
In reply to Arnaldo Carvalho de MeloFrom: David Carrillo-Cisneros <[email protected]>
Add event descriptor to perf header output in pipe-mode.
After this patch:
$ perf record -e cycles sleep 1 | perf report --header
# ========
# captured on: Mon Jun 5 22:52:13 2017
# ========
#
# hostname : lphh20
# os release : 4.3.5-smp-801.43.0.0
# perf version : 4.12.rc2.g439987
# arch : x86_64
# nrcpus online : 72
# nrcpus avail : 72
# cpudesc : Intel(R) Xeon(R) CPU E5-2696 v3 @ 2.30GHz
# cpuid : GenuineIntel,6,63,2
# total memory : 264134144 kB
# cmdline : /root/perf record -e cycles sleep 1
# event : name = cycles, , size = 112, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|PERIOD, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1
# CPU_TOPOLOGY info available, use -I to display
# NUMA_TOPOLOGY info available, use -I to display
# pmu mappings: intel_bts = 6, cpu = 4, msr = 49, uncore_cbox_10 = 36, uncore_cbox_11 = 37, uncore_cbox_12 = 38, uncore_cbox_13 = 39, uncore_cbox_14 = 40, uncore_cbox_15 = 41, uncore_cbox_16 = 42, uncore_cbox_17 = 43, software = 1, power = 7, uncore_irp = 24, uncore_pcu = 48, tracepoint = 2, uncore_imc_0 = 16, uncore_imc_1 = 17, uncore_imc_2 = 18, uncore_imc_3 = 19, uncore_imc_4 = 20, uncore_imc_5 = 21, uncore_imc_6 = 22, uncore_imc_7 = 23, uncore_qpi_0 = 8, uncore_qpi_1 = 9, uncore_cbox_0 = 26, uncore_cbox_1 = 27, uncore_cbox_2 = 28, uncore_cbox_3 = 29, uncore_cbox_4 = 30, uncore_cbox_5 = 31, uncore_cbox_6 = 32, uncore_cbox_7 = 33, uncore_cbox_8 = 34, uncore_cbox_9 = 35, uncore_r2pcie = 13, uncore_r3qpi_0 = 10, uncore_r3qpi_1 = 11, uncore_r3qpi_2 = 12, uncore_sbox_0 = 44, uncore_sbox_1
= 45, uncore_sbox_2 = 46, uncore_sbox_3 = 47, breakpoint = 5, uncore_ha_0 = 14, uncore_ha_1 = 15, uncore_ubox = 25
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.000 MB (null) ]Prior to this patch, event was not printed.
--- tools/perf/util/header.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
tools/perf/util/header.c +17 -2
@@ -67,6 +67,7 @@ struct feat_fd {void *buf;/* Either buf != NULL or fd >= 0 */ ssize_t offset;size_t size; +struct perf_evsel *events; };void perf_header__set_feat (struct perf_header *header,int feat)
@@ -1359,10 +1360,15 @@ static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val,static void print_event_desc (struct feat_fd *ff,FILE *fp) { -struct perf_evsel *evsel, *events =read_event_desc (ff); +struct perf_evsel *evsel, *events;u32 j;u64 *id; +if (ff->events) + events = ff->events; +else + events =read_event_desc (ff); +if (!events) {fprintf (fp,"# event desc: not available or unable to read\n" );return ;
@@ -1387,6 +1393,7 @@ static void print_event_desc(struct feat_fd *ff, FILE *fp) }free_event_desc (events); + ff->events =NULL ; }static void print_total_mem (struct feat_fd *ff,FILE *fp)
@@ -1757,10 +1764,18 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused)return 0 ; session = container_of(ff->ph, struct perf_session, header); + +if (session->file->is_pipe) { +/* Save events for reading later by print_event_desc, +* since they can't be read again in pipe mode. */ + ff->events = events; + } +for (evsel = events; evsel->attr.size; evsel++)perf_evlist__set_event_name (session->evlist, evsel); -free_event_desc (events); +if (!session->file->is_pipe) +free_event_desc (events);return 0 ; }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 80/86 perf/core: Define the common branch type classification
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
It is often useful to know the branch types while analyzing branch data. For example, a call is very different from a conditional branch.
Currently we have to look it up in binary while the binary may later not be available and even the binary is available but user has to take some time. It is very useful for user to check it directly in perf report.
Perf already has support for disassembling the branch instruction to get the x86 branch type.
To keep consistent on kernel and userspace and make the classification more common, the patch adds the common branch type classification in perf_event.h.
The patch only defines a minimum but most common set of branch types.
PERF_BR_UNKNOWN : unknown PERF_BR_COND :conditional PERF_BR_UNCOND : unconditional PERF_BR_IND : indirect PERF_BR_CALL : function call PERF_BR_IND_CALL : indirect function call PERF_BR_RET : function return PERF_BR_SYSCALL : syscall PERF_BR_SYSRET : syscall return PERF_BR_COND_CALL : conditional function call PERF_BR_COND_RET : conditional function return
The patch also adds a new field type (4 bits) in perf_branch_entry to record the branch type.
Since the disassembling of branch instruction needs some overhead, a new PERF_SAMPLE_BRANCH_TYPE_SAVE is introduced to indicate if it needs to disassemble the branch instruction and record the branch type.
Change log:
v10: Not changed.
v9: Not changed.
v8: Change PERF_BR_NONE to PERF_BR_UNKNOWN.
No other change.
v7: Just keep the most common branch types.
Others are removed.
v6: Not changed.
v5: Not changed. The v5 patch series just change the userspace.
v4: Comparing to previous version, the major changes are:
1. Remove the PERF_BR_JCC_FWD/PERF_BR_JCC_BWD, they will be computed later in userspace.
2. Remove the "cross" field in perf_branch_entry. The cross page computing will be done later in userspace.
--- include/uapi/linux/perf_event.h | 27 ++++++++++++++++++++++++++- tools/include/uapi/linux/perf_event.h | 27 ++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-)
include/uapi/linux/perf_event.h +26 -1
@@ -174,6 +174,8 @@ enum perf_branch_sample_type_shift {PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT =14 ,/* no flags */ PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT =15 ,/* no cycles */ +PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT =16 ,/* save branch type */ + PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ };
@@ -198,9 +200,30 @@ enum perf_branch_sample_type {PERF_SAMPLE_BRANCH_NO_FLAGS =1U <<PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT ,PERF_SAMPLE_BRANCH_NO_CYCLES =1U <<PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT , +PERF_SAMPLE_BRANCH_TYPE_SAVE = +1U <<PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT , + PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, }; +/* +* Common flow change classification +*/ +enum { +PERF_BR_UNKNOWN =0 ,/* unknown */ +PERF_BR_COND =1 ,/* conditional */ +PERF_BR_UNCOND =2 ,/* unconditional */ +PERF_BR_IND =3 ,/* indirect */ +PERF_BR_CALL =4 ,/* function call */ +PERF_BR_IND_CALL =5 ,/* indirect function call */ +PERF_BR_RET =6 ,/* function return */ +PERF_BR_SYSCALL =7 ,/* syscall */ +PERF_BR_SYSRET =8 ,/* syscall return */ +PERF_BR_COND_CALL =9 ,/* conditional function call */ +PERF_BR_COND_RET =10 ,/* conditional function return */ +PERF_BR_MAX , +}; +#define PERF_SAMPLE_BRANCH_PLM_ALL \ (PERF_SAMPLE_BRANCH_USER|\ PERF_SAMPLE_BRANCH_KERNEL|\
@@ -1015,6 +1038,7 @@ union perf_mem_data_src {* in_tx: running in a hardware transaction * abort: aborting a hardware transaction * cycles: cycles from last branch (or 0 if not supported) +* type: branch type */ struct perf_branch_entry {__u64 from;
@@ -1024,7 +1048,8 @@ struct perf_branch_entry { in_tx:1, /* in transaction */ abort:1, /* transaction abort */ cycles:16, /* cycle count to last branch */ - reserved:44; + type:4, /* branch type */ + reserved:40; };#endif /* _UAPI_LINUX_PERF_EVENT_H */
tools/include/uapi/linux/perf_event.h +26 -1
@@ -174,6 +174,8 @@ enum perf_branch_sample_type_shift {PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT =14 ,/* no flags */ PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT =15 ,/* no cycles */ +PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT =16 ,/* save branch type */ + PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ };
@@ -198,9 +200,30 @@ enum perf_branch_sample_type {PERF_SAMPLE_BRANCH_NO_FLAGS =1U <<PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT ,PERF_SAMPLE_BRANCH_NO_CYCLES =1U <<PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT , +PERF_SAMPLE_BRANCH_TYPE_SAVE = +1U <<PERF_SAMPLE_BRANCH_TYPE_SAVE_SHIFT , + PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, }; +/* +* Common flow change classification +*/ +enum { +PERF_BR_UNKNOWN =0 ,/* unknown */ +PERF_BR_COND =1 ,/* conditional */ +PERF_BR_UNCOND =2 ,/* unconditional */ +PERF_BR_IND =3 ,/* indirect */ +PERF_BR_CALL =4 ,/* function call */ +PERF_BR_IND_CALL =5 ,/* indirect function call */ +PERF_BR_RET =6 ,/* function return */ +PERF_BR_SYSCALL =7 ,/* syscall */ +PERF_BR_SYSRET =8 ,/* syscall return */ +PERF_BR_COND_CALL =9 ,/* conditional function call */ +PERF_BR_COND_RET =10 ,/* conditional function return */ +PERF_BR_MAX , +}; +#define PERF_SAMPLE_BRANCH_PLM_ALL \ (PERF_SAMPLE_BRANCH_USER|\ PERF_SAMPLE_BRANCH_KERNEL|\
@@ -1015,6 +1038,7 @@ union perf_mem_data_src {* in_tx: running in a hardware transaction * abort: aborting a hardware transaction * cycles: cycles from last branch (or 0 if not supported) +* type: branch type */ struct perf_branch_entry {__u64 from;
@@ -1024,7 +1048,8 @@ struct perf_branch_entry { in_tx:1, /* in transaction */ abort:1, /* transaction abort */ cycles:16, /* cycle count to last branch */ - reserved:44; + type:4, /* branch type */ + reserved:40; };#endif /* _UAPI_LINUX_PERF_EVENT_H */
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 81/86 perf/x86/intel: Record branch type
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
Perf already has support for disassembling the branch instruction and using the branch type for filtering. The patch just records the branch type in perf_branch_entry.
Before recording, the patch converts the x86 branch type to common branch type.
Change log:
v10: Set the branch_map array to be static. The previous version
has it on stack then makes the compiler to create it every time when the function gets called.
v9: Use __ffs() to find first bit in type in common_branch_type().
It lets the code be clear.
v8: Change PERF_BR_NONE to PERF_BR_UNKNOWN.
v7: Just convert following x86 branch types to common branch types.
X86_BR_CALL -> PERF_BR_CALL X86_BR_RET -> PERF_BR_RET X86_BR_JCC -> PERF_BR_COND X86_BR_JMP -> PERF_BR_UNCOND X86_BR_IND_CALL -> PERF_BR_IND_CALL X86_BR_ZERO_CALL -> PERF_BR_CALL X86_BR_IND_JMP -> PERF_BR_IND X86_BR_SYSCALL -> PERF_BR_SYSCALL X86_BR_SYSRET -> PERF_BR_SYSRET
Others are set to PERF_BR_NONE
v6: Not changed.
v5: Just fix the merge error. No other update.
v4: Comparing to previous version, the major changes are:
1. Uses a lookup table to convert x86 branch type to common branch type.
2. Move the JCC forward/JCC backward and cross page computing to user space.
3. Initialize branch type to 0 in intel_pmu_lbr_read_32 and intel_pmu_lbr_read_64
--- arch/x86/events/intel/lbr.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-)
arch/x86/events/intel/lbr.c +51 -1
@@ -109,6 +109,9 @@ enum {X86_BR_ZERO_CALL =1 <<15 ,/* zero length call */ X86_BR_CALL_STACK =1 <<16 ,/* call stack */ X86_BR_IND_JMP =1 <<17 ,/* indirect jump */ + + X86_BR_TYPE_SAVE = 1 << 18,/* indicate to save branch type */ + };#define X86_BR_PLM (X86_BR_USER | X86_BR_KERNEL)
@@ -510,6 +513,7 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc) cpuc->lbr_entries[i].in_tx =0 ; cpuc->lbr_entries[i].abort =0 ; cpuc->lbr_entries[i].cycles =0 ; + cpuc->lbr_entries[i].type =0 ; cpuc->lbr_entries[i].reserved =0 ; } cpuc->lbr_stack.nr = i;
@@ -596,6 +600,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc) cpuc->lbr_entries[out].in_tx = in_tx; cpuc->lbr_entries[out].abort = abort; cpuc->lbr_entries[out].cycles = cycles; + cpuc->lbr_entries[out].type =0 ; cpuc->lbr_entries[out].reserved =0 ; out++; }
@@ -673,6 +678,10 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event)if (br_type &PERF_SAMPLE_BRANCH_CALL ) mask |=X86_BR_CALL |X86_BR_ZERO_CALL ; + +if (br_type &PERF_SAMPLE_BRANCH_TYPE_SAVE ) + mask |=X86_BR_TYPE_SAVE ; +/* * stash actual user request into reg, it may * be used by fixup code for some CPU
@@ -926,6 +935,43 @@ static int branch_type(unsigned long from, unsigned long to, int abort)return ret; } +#define X86_BR_TYPE_MAP_MAX 16 + +static int branch_map[X86_BR_TYPE_MAP_MAX ] = { +PERF_BR_CALL ,/* X86_BR_CALL */ +PERF_BR_RET ,/* X86_BR_RET */ +PERF_BR_SYSCALL ,/* X86_BR_SYSCALL */ +PERF_BR_SYSRET ,/* X86_BR_SYSRET */ +PERF_BR_UNKNOWN ,/* X86_BR_INT */ +PERF_BR_UNKNOWN ,/* X86_BR_IRET */ +PERF_BR_COND ,/* X86_BR_JCC */ +PERF_BR_UNCOND ,/* X86_BR_JMP */ +PERF_BR_UNKNOWN ,/* X86_BR_IRQ */ +PERF_BR_IND_CALL ,/* X86_BR_IND_CALL */ +PERF_BR_UNKNOWN ,/* X86_BR_ABORT */ +PERF_BR_UNKNOWN ,/* X86_BR_IN_TX */ +PERF_BR_UNKNOWN ,/* X86_BR_NO_TX */ +PERF_BR_CALL ,/* X86_BR_ZERO_CALL */ +PERF_BR_UNKNOWN ,/* X86_BR_CALL_STACK */ +PERF_BR_IND ,/* X86_BR_IND_JMP */ +}; + +static int +common_branch_type (int type) +{ +int i; + + type >>=2 ;/* skip X86_BR_USER and X86_BR_KERNEL */ + +if (type) { + i =__ffs (type); +if (i <X86_BR_TYPE_MAP_MAX ) +return branch_map[i]; + } + +return PERF_BR_UNKNOWN ; +} +/* * implement actual branch filter based on user demand. * Hardware may not exactly satisfy that request, thus
@@ -942,7 +988,8 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc)bool compress = false;/* if sampling all branches, then nothing to filter */ -if ((br_sel &X86_BR_ALL ) ==X86_BR_ALL ) +if (((br_sel &X86_BR_ALL ) ==X86_BR_ALL ) && + ((br_sel &X86_BR_TYPE_SAVE ) !=X86_BR_TYPE_SAVE ))return ;for (i =0 ; i < cpuc->lbr_stack.nr; i++) {
@@ -963,6 +1010,9 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) cpuc->lbr_entries[i].from =0 ; compress = true; } + +if ((br_sel &X86_BR_TYPE_SAVE ) ==X86_BR_TYPE_SAVE ) + cpuc->lbr_entries[i].type =common_branch_type (type); }if (!compress)
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 82/86 perf record: Create a new option save_type in --branch-filter
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
The option indicates the kernel to save branch type during sampling.
One example:
perf record -g --branch-filter any,save_type <command>
--- tools/perf/Documentation/perf-record.txt | 1 + tools/perf/util/parse-branch-options.c | 1 + 2 files changed, 2 insertions(+)
tools/perf/Documentation/perf-record.txt +1 -0
@@ -332,6 +332,7 @@ following filters are defined: - no_tx: only when the target is not in a hardware transaction - abort_tx: only when the target is a hardware transaction abort - cond: conditional branches + - save_type: save branch type during sampling in case binary is not available later + The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
tools/perf/util/parse-branch-options.c +1 -0
@@ -28,6 +28,7 @@ static const struct branch_mode branch_modes[] = {BRANCH_OPT ("cond" ,PERF_SAMPLE_BRANCH_COND ),BRANCH_OPT ("ind_jmp" ,PERF_SAMPLE_BRANCH_IND_JUMP ),BRANCH_OPT ("call" ,PERF_SAMPLE_BRANCH_CALL ), +BRANCH_OPT ("save_type" ,PERF_SAMPLE_BRANCH_TYPE_SAVE ), BRANCH_END };
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 83/86 perf report: Refactor the branch info printing code
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
The branch info such as predicted/cycles/... are printed at the callchain entries.
For example: perf report --branch-history --no-children --stdio
--1.07%--main div.c:39 (predicted:52.4% cycles:1 iterations:17)
main div.c:44 (predicted:52.4% cycles:1)
main div.c:42 (cycles:2)
compute_flag div.c:28 (cycles:2)
compute_flag div.c:27 (cycles:1)
rand rand.c:28 (cycles:1)
rand rand.c:28 (cycles:1)
__random random.c:298 (cycles:1)
__random random.c:297 (cycles:1)
__random random.c:295 (cycles:1)
__random random.c:295 (cycles:1)
__random random.c:295 (cycles:1)But the current code is difficult to maintain and extend. This patch refactors the code for easy maintenance.
Change log:
v6: 1. Put the multiline condition code into {} brackets in
counts_str_build()
2. Keep the original display order, that is:
predicted, abort, cycles, iterations
v5: It's a new patch in v5 patch series.
--- tools/perf/util/callchain.c | 100 ++++++++++++++++++-------------------------- 1 file changed, 41 insertions(+), 59 deletions(-)
tools/perf/util/callchain.c +41 -59
@@ -1214,83 +1214,65 @@ int callchain_branch_counts(struct callchain_root *root, cycles_count); } +static int count_pri64_printf (int idx,const char *str,u64 value,char *bf,int bfsize) +{ +int printed; + + printed =scnprintf (bf, bfsize,"%s%s:%" PRId64"" , (idx) ?" " :" (" , str, value); + +return printed; +} + +static int count_float_printf (int idx,const char *str,float value,char *bf,int bfsize) +{ +int printed; + + printed =scnprintf (bf, bfsize,"%s%s:%.1f%%" , (idx) ?" " :" (" , str, value); + +return printed; +} +static int counts_str_build (char *bf,int bfsize,u64 branch_count,u64 predicted_count,u64 abort_count,u64 cycles_count,u64 iter_count,u64 samples_count) { -double predicted_percent =0.0 ; -const char *null_str ="" ; -char iter_str[32 ]; -char cycle_str[32 ]; -char *istr, *cstr;u64 cycles; +int printed =0 , i =0 ;if (branch_count ==0 )return scnprintf (bf, bfsize," (calltrace)" ); - cycles = cycles_count / branch_count; - -if (iter_count && samples_count) { -if (cycles >0 ) -scnprintf (iter_str,sizeof (iter_str), -" iterations:%" PRId64"" , - iter_count / samples_count); -else -scnprintf (iter_str,sizeof (iter_str), -"iterations:%" PRId64"" , - iter_count / samples_count); - istr = iter_str; - }else - istr = (char *)null_str; - -if (cycles >0 ) { -scnprintf (cycle_str,sizeof (cycle_str), -"cycles:%" PRId64"" , cycles); - cstr = cycle_str; - }else - cstr = (char *)null_str; - - predicted_percent = predicted_count *100.0 / branch_count; +if (predicted_count < branch_count) { + printed +=count_float_printf (i++,"predicted" , + predicted_count *100.0 / branch_count, + bf + printed, bfsize - printed); + } -if ((predicted_count == branch_count) && (abort_count ==0 )) { -if ((cycles >0 ) || (istr != (char *)null_str)) -return scnprintf (bf, bfsize," (%s%s)" , cstr, istr); -else -return scnprintf (bf, bfsize,"%s" , (char *)null_str); +if (abort_count) { + printed +=count_float_printf (i++,"abort" , + abort_count *100.0 / branch_count, + bf + printed, bfsize - printed); } -if ((predicted_count < branch_count) && (abort_count ==0 )) { -if ((cycles >0 ) || (istr != (char *)null_str)) -return scnprintf (bf, bfsize, -" (predicted:%.1f%% %s%s)" , - predicted_percent, cstr, istr); -else { -return scnprintf (bf, bfsize, -" (predicted:%.1f%%)" , - predicted_percent); - } + cycles = cycles_count / branch_count; +if (cycles) { + printed +=count_pri64_printf (i++,"cycles" , + cycles, + bf + printed, bfsize - printed); } -if ((predicted_count == branch_count) && (abort_count >0 )) { -if ((cycles >0 ) || (istr != (char *)null_str)) -return scnprintf (bf, bfsize, -" (abort:%" PRId64" %s%s)" , - abort_count, cstr, istr); -else -return scnprintf (bf, bfsize, -" (abort:%" PRId64")" , - abort_count); +if (iter_count && samples_count) { + printed +=count_pri64_printf (i++,"iterations" , + iter_count / samples_count, + bf + printed, bfsize - printed); } -if ((cycles >0 ) || (istr != (char *)null_str)) -return scnprintf (bf, bfsize, -" (predicted:%.1f%% abort:%" PRId64" %s%s)" , - predicted_percent, abort_count, cstr, istr); +if (i) +return scnprintf (bf + printed, bfsize - printed,")" ); -return scnprintf (bf, bfsize, -" (predicted:%.1f%% abort:%" PRId64")" , - predicted_percent, abort_count); + bf[0 ] =0 ; +return 0 ; } static int callchain_counts_printf(FILE *fp, char *bf, int bfsize,
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 84/86 perf util: Create branch.c/.h for common branch functions
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
Create new util/branch.c and util/branch.h to contain the common branch functions. Such as:
branch_type_count(): Count the numbers of branch types branch_type_name() : Return the name of branch type branch_type_stat_display(): Display branch type statistics info branch_type_str(): Construct the branch type string.
The branch type is saved in branch_flags.
Change log:
v8: Change PERF_BR_NONE to PERF_BR_UNKNOWN.
v7: Since the common branch type name is changed (e.g. JCC->COND),
this patch is performed the modification accordingly.
v6: Move that multiline conditional code inside {} brackets.
Move branch_type_stat_display() from builtin-report.c to
branch.c.
Move branch_type_str() from callchain.c to branch.c.
v5: It's a new patch in v5 patch series.
--- tools/perf/util/Build | 1 + tools/perf/util/branch.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/branch.h | 24 ++++++++ tools/perf/util/event.h | 3 +- 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 tools/perf/util/branch.c create mode 100644 tools/perf/util/branch.h
tools/perf/util/Build +1 -0
@@ -93,6 +93,7 @@ libperf-y += drv_configs.o libperf-y += units.o libperf-y += time-utils.o libperf-y += expr-bison.o +libperf-y += branch.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
tools/perf/util/branch.c new file +147 -0
147 lines not on this page · raw message
tools/perf/util/branch.h new file +24 -0
@@ -0,0 +1,24 @@ +#ifndef _PERF_BRANCH_H +#define _PERF_BRANCH_H 1 + +#include <stdint.h> +#include "../perf.h" + +struct branch_type_stat { +u64 counts[PERF_BR_MAX ]; +u64 cond_fwd; +u64 cond_bwd; +u64 cross_4k; +u64 cross_2m; +}; + +struct branch_flags ; + +void branch_type_count (struct branch_type_stat *st,struct branch_flags *flags, +u64 from,u64 to); + +const char *branch_type_name (int type); +void branch_type_stat_display (FILE *fp,struct branch_type_stat *st); +int branch_type_str (struct branch_type_stat *st,char *bf,int bfsize); + +#endif /* _PERF_BRANCH_H */
tools/perf/util/event.h +2 -1
@@ -142,7 +142,8 @@ struct branch_flags { u64 in_tx:1; u64 abort:1; u64 cycles:16; - u64 reserved:44; + u64 type:4; + u64 reserved:40; };struct branch_entry {
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 85/86 perf report: Show branch type statistics for stdio mode
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
Show the branch type statistics at the end of perf report --stdio.
For example:
perf report --stdio
COND_FWD: 28.5%
COND_BWD: 9.4%
CROSS_4K: 0.7%
CROSS_2M: 14.1%
COND: 37.9%
UNCOND: 0.2%
IND: 6.7%
CALL: 26.5%
RET: 28.7%
SYSRET: 0.0%The branch types are:
COND_FWD: conditional forward
COND_BWD: conditional backward
COND: conditional branch
UNCOND: unconditional branch
IND: indirect
CALL: function call
IND_CALL: indirect function call
RET: function return
SYSCALL: syscall
SYSRET: syscall return
COND_CALL: conditional function call
COND_RET: conditional function return
CROSS_4K and CROSS_2M:
They are the metrics checking for branches cross 4K or 2MB pages. It's an approximate computing. We don't know if the area is 4K or 2MB, so always compute both.
To make the output simple, if a branch crosses 2M area, CROSS_4K will not be incremented.
Change log
v7: Since the common branch type definitions are changed, some
tags/strings are updated accordingly.
v6: Remove branch_type_stat_display() since it's moved to branch.c.
v5: Remove the unnecessary sort__mode checking in
hist_iter__branch_callback().
v4: Comparing to previous version, the major changes are:
Add the computing of JCC forward/JCC backward and cross page checking by using the from and to addresses.
--- tools/perf/builtin-report.c | 25 +++++++++++++++++++++++++ tools/perf/util/hist.c | 5 +---- 2 files changed, 26 insertions(+), 4 deletions(-)
tools/perf/builtin-report.c +25 -0
@@ -38,6 +38,7 @@#include "util/time-utils.h" #include "util/auxtrace.h" #include "util/units.h" +#include "util/branch.h" #include <dlfcn.h> #include <errno.h>
@@ -73,6 +74,7 @@ struct report {u64 queue_size;int socket_filter;DECLARE_BITMAP (cpu_bitmap,MAX_NR_CPUS ); +struct branch_type_stat brtype_stat; };static int report__config (const char *var,const char *value,void *cb)
@@ -150,6 +152,22 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter,return err; } +static int hist_iter__branch_callback (struct hist_entry_iter *iter, +struct addr_location *al__maybe_unused , +bool single__maybe_unused , +void *arg) +{ +struct hist_entry *he = iter->he; +struct report *rep = arg; +struct branch_info *bi; + + bi = he->branch_info; +branch_type_count (&rep->brtype_stat, &bi->flags, + bi->from.addr, bi->to.addr); + +return 0 ; +} + static int process_sample_event(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample,
@@ -188,6 +206,8 @@ static int process_sample_event(struct perf_tool *tool,*/ if (!sample->branch_stack) goto out_put; + + iter.add_entry_cb = hist_iter__branch_callback; iter.ops = &hist_iter_branch; }else if (rep->mem_mode) { iter.ops = &hist_iter_mem;
@@ -410,6 +430,9 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,perf_read_values_destroy (&rep->show_threads_values); } +if (sort__mode ==SORT_MODE__BRANCH ) +branch_type_stat_display (stdout, &rep->brtype_stat); +return 0 ; }
@@ -944,6 +967,8 @@ int cmd_report(int argc, const char **argv)if (has_br_stack && branch_call_mode) symbol_conf.show_branchflag_count = true; +memset (&report.brtype_stat,0 ,sizeof (struct branch_type_stat )); +/* * Branch mode is a tristate: * -1 means default, so decide based on the file having branch data.
tools/perf/util/hist.c +1 -4
@@ -749,12 +749,9 @@ iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al }static int -iter_add_single_branch_entry (struct hist_entry_iter *iter, +iter_add_single_branch_entry (struct hist_entry_iter *iter__maybe_unused ,struct addr_location *al__maybe_unused ) { -/* to avoid calling callback function */ - iter->he =NULL ; -return 0 ; }
Signature · 1 line
2.9.4
Arnaldo Carvalho de Melo
maintainerPATCH 86/86 perf report: Show branch type in callchain entry
In reply to Arnaldo Carvalho de MeloFrom: Jin Yao <[email protected]>
Show branch type in callchain entry. The branch type is printed with other LBR information (such as cycles/abort/...).
For example:
perf record -g -j any,save_type perf report --branch-history --stdio --no-children
38.50% div.c:45 [.] main div
|
---main div.c:42 (RET CROSS_2M cycles:2)
compute_flag div.c:28 (cycles:2)
compute_flag div.c:27 (RET CROSS_2M cycles:1)
rand rand.c:28 (cycles:1)
rand rand.c:28 (RET CROSS_2M cycles:1)
__random random.c:298 (cycles:1)
__random random.c:297 (COND_BWD CROSS_2M cycles:1)
__random random.c:295 (cycles:1)
__random random.c:295 (COND_BWD CROSS_2M cycles:1)
__random random.c:295 (cycles:1)
__random random.c:295 (RET CROSS_2M cycles:9)Change log
v6: Remove the branch_type_str() since it's moved to branch.c.
v5: Rewrite the branch info print code in util/callchain.c.
v4: Comparing to previous version, the major changes are:
--- tools/perf/util/callchain.c | 38 +++++++++++++++++++++++++++++--------- tools/perf/util/callchain.h | 5 ++++- tools/perf/util/machine.c | 26 +++++++++++++++++--------- 3 files changed, 50 insertions(+), 19 deletions(-)
tools/perf/util/callchain.c +29 -9
@@ -23,6 +23,7 @@#include "sort.h" #include "machine.h" #include "callchain.h" +#include "branch.h" #define CALLCHAIN_PARAM_DEFAULT \ .mode = CHAIN_GRAPH_ABS, \
@@ -571,6 +572,11 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) call->cycles_count = cursor_node->branch_flags.cycles; call->iter_count = cursor_node->nr_loop_iter; call->samples_count = cursor_node->samples; + +branch_type_count (&call->brtype_stat, + &cursor_node->branch_flags, + cursor_node->branch_from, + cursor_node->ip); }list_add_tail (&call->list, &node->val);
@@ -688,6 +694,11 @@ static enum match_result match_chain(struct callchain_cursor_node *node, cnode->cycles_count += node->branch_flags.cycles; cnode->iter_count += node->nr_loop_iter; cnode->samples_count += node->samples; + +branch_type_count (&cnode->brtype_stat, + &node->branch_flags, + node->branch_from, + node->ip); }return MATCH_EQ ;
@@ -922,7 +933,7 @@ merge_chain_branch(struct callchain_cursor *cursor,list_for_each_entry_safe (list, next_list, &src->val, list) {callchain_cursor_append (cursor, list->ip, list->ms.map, list->ms.sym, - false,NULL ,0 ,0 ); + false,NULL ,0 ,0 ,0 );list_del (&list->list);map__zput (list->ms.map);free (list);
@@ -962,7 +973,7 @@ int callchain_merge(struct callchain_cursor *cursor,int callchain_cursor_append (struct callchain_cursor *cursor,u64 ip,struct map *map,struct symbol *sym,bool branch,struct branch_flags *flags, -int nr_loop_iter,int samples) +int nr_loop_iter,int samples,u64 branch_from) {struct callchain_cursor_node *node = *cursor->last;
@@ -986,6 +997,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,memcpy (&node->branch_flags, flags,sizeof (struct branch_flags )); + node->branch_from = branch_from; cursor->nr++; cursor->last = &node->next;
@@ -1235,14 +1247,19 @@ static int count_float_printf(int idx, const char *str, float value, char *bf, istatic int counts_str_build (char *bf,int bfsize,u64 branch_count,u64 predicted_count,u64 abort_count,u64 cycles_count, -u64 iter_count,u64 samples_count) +u64 iter_count,u64 samples_count, +struct branch_type_stat *brtype_stat) {u64 cycles; -int printed =0 , i =0 ; +int printed, i =0 ;if (branch_count ==0 )return scnprintf (bf, bfsize," (calltrace)" ); + printed =branch_type_str (brtype_stat, bf, bfsize); +if (printed) + i++; +if (predicted_count < branch_count) { printed += count_float_printf(i++, "predicted", predicted_count * 100.0 / branch_count,
@@ -1278,13 +1295,14 @@ static int counts_str_build(char *bf, int bfsize,static int callchain_counts_printf (FILE *fp,char *bf,int bfsize,u64 branch_count,u64 predicted_count,u64 abort_count,u64 cycles_count, -u64 iter_count,u64 samples_count) +u64 iter_count,u64 samples_count, +struct branch_type_stat *brtype_stat) { -char str[128 ]; +char str[256 ];counts_str_build (str,sizeof (str), branch_count, predicted_count, abort_count, cycles_count, - iter_count, samples_count); + iter_count, samples_count, brtype_stat);if (fp)return fprintf (fp,"%s" , str);
@@ -1316,7 +1334,8 @@ int callchain_list_counts__printf_value(struct callchain_node *node,return callchain_counts_printf (fp, bf, bfsize, branch_count, predicted_count, abort_count, - cycles_count, iter_count, samples_count); + cycles_count, iter_count, samples_count, + &clist->brtype_stat); }static void free_callchain_node (struct callchain_node *node)
@@ -1441,7 +1460,8 @@ int callchain_cursor__copy(struct callchain_cursor *dst, rc =callchain_cursor_append (dst, node->ip, node->map, node->sym, node->branch, &node->branch_flags, - node->nr_loop_iter, node->samples); + node->nr_loop_iter, node->samples, + node->branch_from);if (rc)break ;
tools/perf/util/callchain.h +4 -1
@@ -7,6 +7,7 @@#include "event.h" #include "map.h" #include "symbol.h" +#include "branch.h" #define HELP_PAD "\t\t\t\t"
@@ -119,6 +120,7 @@ struct callchain_list {u64 cycles_count;u64 iter_count;u64 samples_count; +struct branch_type_stat brtype_stat;char *srcline;struct list_head list; };
@@ -135,6 +137,7 @@ struct callchain_cursor_node {struct symbol *sym;bool branch;struct branch_flags branch_flags; +u64 branch_from;int nr_loop_iter;int samples;struct callchain_cursor_node *next;
@@ -198,7 +201,7 @@ static inline void callchain_cursor_reset(struct callchain_cursor *cursor)int callchain_cursor_append (struct callchain_cursor *cursor,u64 ip,struct map *map,struct symbol *sym,bool branch,struct branch_flags *flags, -int nr_loop_iter,int samples); +int nr_loop_iter,int samples,u64 branch_from);/* Close a cursor writing session. Initialize for the reader */ static inline void callchain_cursor_commit (struct callchain_cursor *cursor)
tools/perf/util/machine.c +17 -9
@@ -1682,7 +1682,8 @@ static int add_callchain_ip(struct thread *thread,bool branch, struct branch_flags *flags, int nr_loop_iter, - int samples) + int samples, + u64 branch_from) { struct addr_location al;
@@ -1735,7 +1736,8 @@ static int add_callchain_ip(struct thread *thread,if (symbol_conf.hide_unresolved && al.sym ==NULL )return 0 ;return callchain_cursor_append (cursor, al.addr, al.map, al.sym, - branch, flags, nr_loop_iter, samples); + branch, flags, nr_loop_iter, samples, + branch_from); } struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
@@ -1814,7 +1816,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread,struct ip_callchain *chain = sample->callchain;int chain_nr =min (max_stack, (int )chain->nr), i;u8 cpumode =PERF_RECORD_MISC_USER ; -u64 ip; +u64 ip, branch_from =0 ;for (i =0 ; i < chain_nr; i++) {if (chain->ips[i] ==PERF_CONTEXT_USER )
@@ -1856,6 +1858,8 @@ static int resolve_lbr_callchain_sample(struct thread *thread, ip = lbr_stack->entries[0 ].to; branch = true; flags = &lbr_stack->entries[0 ].flags; + branch_from = + lbr_stack->entries[0 ].from; } }else {if (j < lbr_nr) {
@@ -1870,12 +1874,15 @@ static int resolve_lbr_callchain_sample(struct thread *thread, ip = lbr_stack->entries[0 ].to; branch = true; flags = &lbr_stack->entries[0 ].flags; + branch_from = + lbr_stack->entries[0 ].from; } } err =add_callchain_ip (thread, cursor, parent, root_al, &cpumode, ip, - branch, flags,0 ,0 ); + branch, flags,0 ,0 , + branch_from);if (err)return (err <0 ) ? err :0 ; }
@@ -1974,19 +1981,20 @@ static int thread__resolve_callchain_sample(struct thread *thread, root_al,NULL , be[i].to, true, &be[i].flags, - nr_loop_iter, 1); + nr_loop_iter,1 , + be[i].from); else err =add_callchain_ip (thread, cursor, parent, root_al,NULL , be[i].to, true, &be[i].flags, -0 ,0 ); +0 ,0 , be[i].from);if (!err) err =add_callchain_ip (thread, cursor, parent, root_al,NULL , be[i].from, true, &be[i].flags, -0 ,0 ); +0 ,0 ,0 );if (err == -EINVAL )break ;if (err)
@@ -2016,7 +2024,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, err =add_callchain_ip (thread, cursor, parent, root_al, &cpumode, ip, - false,NULL ,0 ,0 ); + false,NULL ,0 ,0 ,0 );if (err)return (err <0 ) ? err :0 ;
@@ -2033,7 +2041,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)return 0 ;return callchain_cursor_append (cursor, entry->ip, entry->map, entry->sym, - false,NULL ,0 ,0 ); + false,NULL ,0 ,0 ,0 ); } static int thread__resolve_callchain_unwind(struct thread *thread,
Signature · 1 line
2.9.4
Quoted 331 lines · Arnaldo Carvalho de Melo
Hi Ingo,
Unusually big one, please conside pulling, details on the signed tag,
- Arnaldo
Test results at the end of this message, as usual.
The following changes since commit
4b1303d0b01440f224cf81493b7e8e43d9b4965e:perf symbols: Accept zero as the kernel base address (2017-07-12 11:47:05 -0300)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.gittags/perf-core-for-mingo-4.13-20170718for you to fetch changes up to
b851dd49868e295e18c5d72fc3bad85ff1c444b1:perf report: Show branch type in callchain entry (2017-07-18 23:14:42 -0300)
----------------------------------------------------------------
perf/core improvements and fixes:User visible:
. Initial support for namespaces, using setns to access files in
namespaces, grabbing their build-ids, etc. We still need to work more to deal with namespaces that vanish before we can get the needed data to do analysis, but this should be as good as what is in bcc now (Krister Johansen). Add header record types to pipe-mode, now this command:
$ perf record -o - -e cycles sleep 1 | perf report --stdio --headerWill show the same as in non-pipe mode, i.e. involving a perf.data file (David Carrillo-Cisneros)
. Implement a visual marker for fused x86 instructions in the annotate
TUI browser, available now in 'perf report', more work needed to have it available as well in 'perf top' (Jin Yao)Further explanation from one of Jin's patches:
│ ┌──cmpl $0x0,argp_program_version_hook 81.93 │ ├──je 20 │ │ lock cmpxchg %esi,0x38a9a4(%rip) │ │↓ jne 29 │ │↓ jmp 43 11.47 │20:└─→cmpxch %esi,0x38a999(%rip)That means the cmpl+je is a fused instruction pair and they should be considered together.
. Record the branch type and then show statistics and info about
in callchain entries (Jin Yao)Example from one of Jin's patches:
# perf record -g -j any,save_type # perf report --branch-history --stdio --no-children38.50% div.c:45 [.] main div
| ---main div.c:42 (RET CROSS_2M cycles:2) compute_flag div.c:28 (cycles:2) compute_flag div.c:27 (RET CROSS_2M cycles:1) rand rand.c:28 (cycles:1) rand rand.c:28 (RET CROSS_2M cycles:1) __random random.c:298 (cycles:1) __random random.c:297 (COND_BWD CROSS_2M cycles:1) __random random.c:295 (cycles:1) __random random.c:295 (COND_BWD CROSS_2M cycles:1) __random random.c:295 (cycles:1) __random random.c:295 (RET CROSS_2M cycles:9). Beautify the fcntl syscall, which is an interesting one in the sense
that infrastructure had to be put in place to change the formatters of some arguments according to the value in a previous one, i.e. cmd dictates how arg and the syscall return will be formatted. (Arnaldo Carvalho de MeloInfrastructure:
. 'perf test attr' fixes (Jiri Olsa)
Vendor events:
- Add POWER9 PMU events Sukadev (Bhattiprolu)
- Support additional POWER8+ PVR in PMU mapfile (Shriya)
Signed-off-by Arnaldo Carvalho de Melo <[email protected]>----------------------------------------------------------------
Arnaldo Carvalho de Melo (39):
perf trace: Remove F_ from some of the fcntl command strings
perf trace: Beautify linux specific fcntl commands
tools: Updateinclude/uapi/linux/fcntl.hcopy from the kernel
perf trace beauty: Export the strarrays scnprintf method
perf trace: Only buildtools/perf/trace/beauty/when building 'perf trace' perf trace beauty: Mask ignored fcntl 'arg' parameter
perf trace beauty: Allow accessing syscall args values in a syscall arg formatter perf trace beauty: Export the "int" and "hex" syscall arg formatters perf trace beauty: Introduce syscall arg beautifier for long integers tools include uapi asm-generic: Grab a copy offcntl.h
perf trace beauty fcntl: Basic 'arg' beautifier
perf trace: Beautify new write hint fcntl commands
perf beauty open: Detach thesyscall_argagnostic bits from the flags formatter perf trace: Allowsyscall_argbeautifiers to set a different return formatter perf trace beauty open flags: SupportO_TMPFILEandO_NOFOLLOW
perf trace beauty open flags: Do not depend on the system'sO_LARGEFILEdefine perf trace beauty fcntl: BeautifyF_GETFLreturn value
perf trace beauty open flags: Move RDRW to the start of the output perf trace beauty fcntl flags: BeautifyF_SETFLarg
perf trace beauty fcntl: Beautify F_[GS]ETFD arg/return value
perf trace beauty: Give syscall return beautifier more context
perf trace beauty: Export the fd beautifier for use in more places perf trace beauty fcntl: Augment the return ofF_DUPFD(_CLOEXEC)perf trace beauty: Export the pid beautifier for use in more places perf trace beauty fcntl: BeautifyF_GETOWNandF_SETOWN
tools include uapi x86: Grab a copy ofunistd.h
tools include uapi x86: Add__NR_setns, if missing
tools build: Add test forsetns()
perf evsel: Allow asking for maxprecise_ipinnew_cycles()
perf evlist: Allow asking for maxprecise_ipinadd_default()
perf record: Do not ask forprecise_ipwith --no-samples
perf test sdt: Handlerealpath()failure
perf trace beauty: Export strarray for use in per-object beautifiers perf trace beauty fcntl: BeautifyF_GETLEASEandF_SETLEASEarg/return perf trace: Group per syscall arg formatter info into one struct perf trace: Allow syscall arg formatters to request non suppression of zeros perf trace beauty fcntl: Do not suppress 'cmd' when zero, should be DUPFD perf trace beauty fcntl: Beautify the 'arg' for DUPFD
perf trace beauty: Simplify syscall return formattingDavid Carrillo-Cisneros (16):
perf header: Encapsulate read and swap
perf header: AddPROCESS_STR_FUNmacro
perf header: Fail onwrite_paddederror
perf util: Add const modifier to buf in "writen" function perf header: Revampdo_write()
perf header: Add structfeat_fdfor write
perf header: Use structfeat_fdfor print
perf header: Use structfeat_fdto process header records perf header: Don't pass structperf_file_sectionto process_##_feat perf header: Use structfeat_fdin read header records perf header: Makewrite_pmu_mappingspipe-mode friendly perf header: Add a buffer to structfeat_fd
perf header: Change FEAT_OP* macros
perf tool: Addshow_feature_headertoperf_tool
perf tools: Add feature header record to pipe-mode
perf header: Add event desc to pipe-mode headerJin Yao (10):
perf annotate: Check for fused instructions
perf annotate: Implement visual marker for macro fusion perf report: Enable finding kernel inline functions perf/core: Define the common branch type classification perf/x86/intel: Record branch type
perf record: Create a new optionsave_typein --branch-filter perf report: Refactor the branch info printing code perf util: Create branch.c/.h for common branch functions perf report: Show branch type statistics for stdio mode perf report: Show branch type in callchain entryJiri Olsa (13):
perf tests attr: Do not store failed events
perf tests attr: Addtest_attr__readyfunction perf tests attr: Makecompare_dataglobal
perf tests attr: Renamecompare_datatodata_equalperf tests attr: Add 1s forexclude_kerneland task base bits perf tests attr: Fix record dwarf test
perf tests attr: Fix no-delay test
perf tests attr: Add proper return values
perf tests attr: Fix cpu test disabled term setup perf tests attr: Fixsample_periodsetup
perf tests attr: Fixprecise_ipsetup
perf tests attr: Fix statsample_typesetup
perf tests attr: Add optional termKrister Johansen (5):
perf symbols: Find symbols in different mount namespace perf maps: Lookup maps in both intitial mountns and inner mountns. perf probe: Allow placing uprobes in alternate namespaces. perf buildid-cache: Support binary objects from other namespaces perf buildid-cache: Cache debuginfoShriya (1):
perf pmu-events: Support additional POWER8+ PVR in mapfileSukadev Bhattiprolu (2):
perf vendor events: Add POWER9 PMU events perf vendor events: Add POWER9 PVRs to mapfilearch/x86/events/intel/lbr.c | 52 +- include/uapi/linux/perf_event.h | 27 +- tools/arch/x86/include/asm/unistd_32.h | 3 + tools/arch/x86/include/asm/unistd_64.h | 3 + tools/arch/x86/include/uapi/asm/unistd.h | 17 + tools/build/Makefile.feature | 3 +- tools/build/feature/Makefile | 6 +- tools/build/feature/test-all.c | 5 + tools/build/feature/test-setns.c | 7 + tools/include/uapi/asm-generic/fcntl.h | 220 +++++ tools/include/uapi/linux/fcntl.h | 21 + tools/include/uapi/linux/perf_event.h | 27 +- tools/perf/Build | 2 +- tools/perf/Documentation/perf-buildid-cache.txt | 5 + tools/perf/Documentation/perf-probe.txt | 14 + tools/perf/Documentation/perf-record.txt | 1 + tools/perf/Documentation/perf.data-file-format.txt | 10 +- tools/perf/Makefile.config | 5 + tools/perf/arch/powerpc/util/sym-handling.c | 2 +- tools/perf/arch/x86/annotate/instructions.c | 46 + tools/perf/builtin-annotate.c | 1 + tools/perf/builtin-buildid-cache.c | 54 +- tools/perf/builtin-inject.c | 1 + tools/perf/builtin-probe.c | 45 +- tools/perf/builtin-record.c | 9 +- tools/perf/builtin-report.c | 30 + tools/perf/builtin-script.c | 4 + tools/perf/builtin-top.c | 2 +- tools/perf/builtin-trace.c | 602 ++++++------ tools/perf/check-headers.sh | 1 + tools/perf/perf.h | 1 + tools/perf/pmu-events/arch/powerpc/mapfile.csv | 4 + .../perf/pmu-events/arch/powerpc/power9/cache.json | 176 ++++ .../arch/powerpc/power9/floating-point.json | 44 + .../pmu-events/arch/powerpc/power9/frontend.json | 446 +++++++++ .../pmu-events/arch/powerpc/power9/marked.json | 782 +++++++++++++++ .../pmu-events/arch/powerpc/power9/memory.json | 158 +++ .../perf/pmu-events/arch/powerpc/power9/other.json | 836 ++++++++++++++++ .../pmu-events/arch/powerpc/power9/pipeline.json | 680 +++++++++++++ tools/perf/pmu-events/arch/powerpc/power9/pmc.json | 146 +++ .../arch/powerpc/power9/translation.json | 272 ++++++ tools/perf/tests/attr.c | 12 +- tools/perf/tests/attr.py | 50 +- tools/perf/tests/attr/base-record | 6 +- tools/perf/tests/attr/base-stat | 4 +- tools/perf/tests/attr/test-record-C0 | 1 + tools/perf/tests/attr/test-record-basic | 1 + tools/perf/tests/attr/test-record-branch-any | 2 +- .../perf/tests/attr/test-record-branch-filter-any | 2 +- .../tests/attr/test-record-branch-filter-any_call | 2 +- .../tests/attr/test-record-branch-filter-any_ret | 2 +- tools/perf/tests/attr/test-record-branch-filter-hv | 2 +- .../tests/attr/test-record-branch-filter-ind_call | 2 +- tools/perf/tests/attr/test-record-branch-filter-k | 2 +- tools/perf/tests/attr/test-record-branch-filter-u | 2 +- tools/perf/tests/attr/test-record-count | 1 + tools/perf/tests/attr/test-record-data | 3 +- tools/perf/tests/attr/test-record-freq | 1 + tools/perf/tests/attr/test-record-graph-default | 1 + tools/perf/tests/attr/test-record-graph-dwarf | 4 +- tools/perf/tests/attr/test-record-graph-fp | 1 + tools/perf/tests/attr/test-record-group | 1 + tools/perf/tests/attr/test-record-group-sampling | 1 + tools/perf/tests/attr/test-record-group1 | 1 + ...st-record-no-delay => test-record-no-buffering} | 4 +- tools/perf/tests/attr/test-record-no-inherit | 1 + tools/perf/tests/attr/test-record-no-samples | 1 + tools/perf/tests/attr/test-record-period | 1 + tools/perf/tests/attr/test-record-raw | 2 +- tools/perf/tests/attr/test-stat-C0 | 4 +- tools/perf/tests/attr/test-stat-default | 2 + tools/perf/tests/attr/test-stat-detailed-1 | 2 + tools/perf/tests/attr/test-stat-detailed-2 | 3 + tools/perf/tests/attr/test-stat-detailed-3 | 5 + tools/perf/tests/sdt.c | 8 +- tools/perf/trace/beauty/Build | 1 + tools/perf/trace/beauty/beauty.h | 65 ++ tools/perf/trace/beauty/fcntl.c | 100 ++ tools/perf/trace/beauty/open_flags.c | 29 +- tools/perf/trace/beauty/pid.c | 4 +- tools/perf/ui/browser.c | 29 + tools/perf/ui/browser.h | 2 + tools/perf/ui/browsers/annotate.c | 30 +- tools/perf/ui/browsers/hists.c | 3 - tools/perf/ui/gtk/annotate.c | 2 +- tools/perf/ui/stdio/hist.c | 3 - tools/perf/util/Build | 5 + tools/perf/util/annotate.c | 29 +- tools/perf/util/annotate.h | 4 +- tools/perf/util/branch.c | 147 +++ tools/perf/util/branch.h | 24 + tools/perf/util/build-id.c | 129 ++- tools/perf/util/build-id.h | 16 +- tools/perf/util/callchain.c | 134 +-- tools/perf/util/callchain.h | 5 +- tools/perf/util/dso.c | 21 +- tools/perf/util/dso.h | 3 + tools/perf/util/event.c | 1 + tools/perf/util/event.h | 11 +- tools/perf/util/evlist.c | 4 +- tools/perf/util/evlist.h | 9 +- tools/perf/util/evsel.c | 18 +- tools/perf/util/evsel.h | 3 +- tools/perf/util/header.c | 1015 +++++++++++--------- tools/perf/util/header.h | 16 +- tools/perf/util/hist.c | 5 +- tools/perf/util/machine.c | 33 +- tools/perf/util/map.c | 23 +- tools/perf/util/map.h | 2 +- tools/perf/util/namespaces.c | 211 ++++ tools/perf/util/namespaces.h | 38 + tools/perf/util/parse-branch-options.c | 1 + tools/perf/util/parse-events.c | 2 +- tools/perf/util/probe-event.c | 86 +- tools/perf/util/probe-event.h | 10 +- tools/perf/util/probe-file.c | 19 +- tools/perf/util/probe-file.h | 4 +- tools/perf/util/python-ext-sources | 1 + tools/perf/util/session.c | 4 + tools/perf/util/setns.c | 8 + tools/perf/util/symbol.c | 92 +- tools/perf/util/thread.c | 3 + tools/perf/util/thread.h | 1 + tools/perf/util/tool.h | 10 +- tools/perf/util/util.c | 40 +- tools/perf/util/util.h | 8 +- 126 files changed, 6339 insertions(+), 1031 deletions(-) create mode 100644 tools/arch/x86/include/uapi/asm/unistd.h create mode 100644 tools/build/feature/test-setns.c create mode 100644 tools/include/uapi/asm-generic/fcntl.h create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/cache.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/floating-point.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/frontend.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/marked.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/memory.json create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/other.json
Quoted 8 lines
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/pipeline.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/pmc.json
create mode 100644 tools/perf/pmu-events/arch/powerpc/power9/translation.json
rename tools/perf/tests/attr/{test-record-no-delay => test-record-no-buffering} (61%)
create mode 100644 tools/perf/trace/beauty/fcntl.c
create mode 100644 tools/perf/util/branch.c
create mode 100644 tools/perf/util/branch.h
create mode 100644 tools/perf/util/setns.cPulled, thanks a lot Arnaldo!
Ingo