perf tools for v5.8:

- Further Intel PT call-trace fixes
 
  - Improve SELinux docs and tool warnings
 
  - Fix race at exit in 'perf record' using eventfd.
 
  - Add missing build tests to the default set of 'make -C tools/perf build-test'
 
  - Sync msr-index.h getting new AMD MSRs to decode and filter in 'perf trace'.
 
  - Fix fallback to libaudit in 'perf trace' for arches not using per-arch *.tbl files.
 
  - Fixes for 'perf ftrace'.
 
  - Fixes and improvements for the 'perf stat' metrics.
 
  - Use dummy event to get PERF_RECORD_{FORK,MMAP,etc} while synthesizing
    those metadata events for pre-existing threads.
 
  - Fix leaks detected using clang tooling.
 
  - Improvements to PMU event metric testing.
 
  - Report summary for 'perf stat' interval mode at the end, summing up
    all the intervals.
 
  - Improve pipe mode, i.e. this now works as expected, continuously
    dumping samples:
 
     # perf record -g -e raw_syscalls:sys_enter | perf --no-pager script
 
  - Fixes for event grouping, detecting incompatible groups such as:
 
      # perf stat -e '{cycles,power/energy-cores/}' -v
      WARNING: group events cpu maps do not match, disabling group:
        anon group { power/energy-cores/, cycles }
          power/energy-cores/: 0
          cycles: 0-7
 
  - Fixes for 'perf probe': blacklist address checking, number of
    kretprobe instances, etc.
 
  - JIT processing improvements and fixes plus the addition of a 'perf
    test' entry for the java demangler.
 
  - Add support for synthesizing first/last level cache, TLB and remove
    access events from HW tracing in the auxtrace code, first to use is
    ARM SPE.
 
  - Vendor events updates and fixes, including for POWER9 and Intel.
 
  - Allow using ~/.perfconfig for removing the ',' separators in 'perf
    stat' output.
 
  - Opt-in support for libpfm4.
 
 =================================================================================
 
 Adrian Hunter (8):
   perf intel-pt: Use allocated branch stack for PEBS sample
   perf symbols: Fix debuginfo search for Ubuntu
   perf kcore_copy: Fix module map when there are no modules loaded
   perf evlist: Disable 'immediate' events last
   perf script: Fix --call-trace for Intel PT
   perf record: Respect --no-switch-events
   perf intel-pt: Refine kernel decoding only warning message
   perf symbols: Fix kernel maps for kcore and eBPF
 
 Alexey Budankov (3):
   perf docs: Extend CAP_SYS_ADMIN with CAP_PERFMON where needed
   perf tool: Make perf tool aware of SELinux access control
   perf docs: Introduce security.txt file to document related issues
 
 Anand K Mistry (1):
   perf record: Use an eventfd to wakeup when done
 
 Andi Kleen (1):
   perf script: Don't force less for non tty output with --xed
 
 Arnaldo Carvalho de Melo (21):
   perf evsel: Rename perf_evsel__object_config() to evsel__object_config()
   perf evsel: Rename perf_evsel__resort*() to evsel__resort*()
   perf evsel: Rename perf_evsel__fprintf() to evsel__fprintf()
   perf evsel: Rename *perf_evsel__get_config_term() & friends to evsel__env()
   perf evsel: Rename perf_evsel__new*() to evsel__new*()
   perf evsel: Rename perf_evsel__[hs]w_cache* to evsel__[hs]w_cache*
   perf counts: Rename perf_evsel__*counts() to evsel__*counts()
   perf parse-events: Fix incorrect conversion of 'if () free()' to 'zfree()'
   perf evsel: Initialize evsel->per_pkg_mask to NULL in evsel__init()
   tools feature: Rename HAVE_EVENTFD to HAVE_EVENTFD_SUPPORT
   perf build: Group the NO_SYSCALL_TABLE logic
   perf build: Allow explicitely disabling the NO_SYSCALL_TABLE variable
   perf trace: Remove union from syscalltbl, all the fields are needed
   perf trace: Use zalloc() to make sure all fields are zeroed in the syscalltbl constructor
   perf trace: Grow the syscall table as needed when using libaudit
   perf build: Remove libaudit from the default feature checks
   perf build: Add NO_SYSCALL_TABLE=1 to the build tests
   perf build: Add NO_LIBCRYPTO=1 to the default set of build tests
   perf build: Add NO_SDT=1 to the default set of build tests
   perf build: Add a LIBPFM4=1 build test entry
   tools arch x86: Sync the msr-index.h copy with the kernel sources
 
 Changbin Du (2):
   perf ftrace: Trace system wide if no target is given
   perf ftrace: Detect workload failure
 
 Ed Maste (1):
   perf tools: Correct license on jsmn JSON parser
 
 Gustavo A. R. Silva (2):
   perf tools: Replace zero-length array with flexible-array
   perf branch: Replace zero-length array with flexible-array
 
 Ian Rogers (38):
   perf expr: Allow for unlimited escaped characters in a symbol
   perf metrics: Fix parse errors in cascade lake metrics
   perf metrics: Fix parse errors in skylake metrics
   perf expr: Allow ',' to be an other token
   perf expr: Increase max other
   perf expr: Parse numbers as doubles
   perf expr: Debug lex if debugging yacc
   perf metrics: Fix parse errors in power8 metrics
   perf metrics: Fix parse errors in power9 metrics
   perf expr: Print a debug message for division by zero
   perf evsel: Dummy events never triggers, no need to ask for PERF_SAMPLE_BRANCH_STACK
   perf record: Add dummy event during system wide synthesis
   perf c2c: Fix 'perf c2c record -e list' to show the default events used
   perf evsel: Fix 2 memory leaks
   perf expr: Test parsing of floating point numbers
   perf expr: Fix memory leaks in metric bison
   perf parse-events: Make add PMU verbose output clearer
   perf test: Provide a subtest callback to ask for the reason for skipping a subtest
   perf test: Improve pmu event metric testing
   perf trace: Fix the selection for architectures to generate the errno name tables
   perf beauty: Allow the CC used in the arch errno names script to acccept CFLAGS
   perf tools: Grab a copy of libbpf's hashmap
   perf expr: Migrate expr ids table to a hashmap
   perf metricgroup: Make 'evlist_used' variable a bitmap instead of array of bools
   perf expr: Allow numbers to be followed by a dot
   perf metricgroup: Free metric_events on error
   perf metricgroup: Always place duration_time last
   perf metricgroup: Use early return in add_metric
   perf metricgroup: Delay events string creation
   perf metricgroup: Order event groups by size
   perf metricgroup: Remove duped metric group events
   perf metricgroup: Add options to not group or merge
   perf metricgroup: Remove unnecessary ',' from events
   perf list: Add metrics to command line usage
   tools compiler.h: Add attribute to disable tail calls
   perf tests: Don't tail call optimize in unwind test
   perf test: Initialize memory in dwarf-unwind
   perf libdw: Fix off-by 1 relative directory includes
 
 Jin Yao (6):
   perf parse-events: Use strcmp() to compare the PMU name
   perf stat: Fix wrong per-thread runtime stat for interval mode
   perf counts: Reset prev_raw_counts counts
   perf stat: Copy counts from prev_raw_counts to evsel->counts
   perf stat: Save aggr value to first member of prev_raw_counts
   perf stat: Report summary for interval mode
 
 Jiri Olsa (13):
   perf tools: Do not display extra info when there is nothing to build
   perf tools: Do not seek in pipe fd during tracing data processing
   perf session: Try to read pipe data from file
   perf callchain: Setup callchain properly in pipe mode
   perf script: Enable IP fields for callchains
   perf tools: Fix is_bpf_image function logic
   perf trace: Fix compilation error for make NO_LIBBPF=1 DEBUG=1
   perf stat: Fix duration_time value for higher intervals
   perf stat: Fail on extra comma while parsing events
   perf tests: Consider subtests when searching for user specified tests
   perf stat: Do not pass avg to generic_metric
   perf parse: Add 'struct parse_events_state' pointer to scanner
   perf stat: Ensure group is defined on top of the same cpu mask
 
 Li Bin (1):
   perf util: Fix potential SEGFAULT in put_tracepoints_path error path
 
 Masami Hiramatsu (4):
   perf probe: Accept the instance number of kretprobe event
   perf probe: Fix to check blacklist address correctly
   perf probe: Check address correctness by map instead of _etext
   perf probe: Do not show the skipped events
 
 Nick Gasson (6):
   perf jvmti: Fix jitdump for methods without debug info
   perf jvmti: Do not report error when missing debug information
   perf tests: Add test for the java demangler
   perf jvmti: Fix demangling Java symbols
   perf jvmti: Remove redundant jitdump line table entries
   perf jit: Fix inaccurate DWARF line table
 
 Paul A. Clarke (5):
   perf stat: Increase perf metric output resolution
   perf vendor events power9: Add missing metrics to POWER9 'cpi_breakdown'
   perf stat: POWER9 metrics: expand "ICT" acronym
   perf script: Better align register values in dump
   perf config: Add stat.big-num support
 
 Ravi Bangoria (1):
   perf powerpc: Don't ignore sym-handling.c file
 
 Stephane Eranian (1):
   perf tools: Add optional support for libpfm4
 
 Tan Xiaojun (3):
   perf tools: Move arm-spe-pkt-decoder.h/c to the new dir
   perf auxtrace: Add four itrace options
   perf arm-spe: Support synthetic events
 
 Tiezhu Yang (1):
   perf tools: Remove some duplicated includes
 
 Wang ShaoBo (1):
   perf bpf-loader: Add missing '*' for key_scan_pos
 
 Xie XiuQi (1):
   perf util: Fix memory leak of prefix_if_not_in
 
 =================================================================================
 
 Test results:
 
 The first ones are container based builds of tools/perf with and without libelf
 support.  Where clang is available, it is also used to build perf with/without
 libelf, and building with LIBCLANGLLVM=1 (built-in clang) with gcc and clang
 when clang and its devel libraries are installed.
 
 The objtool and samples/bpf/ builds are disabled now that I'm switching from
 using the sources in a local volume to fetching them from a http server to
 build it inside the container, to make it easier to build in a container cluster.
 Those will come back later.
 
 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.
 
 Ubuntu 19.10 is failing when linking against libllvm, which isn't the default,
 needs to be investigated, haven't tested with CC=gcc, but should be the same
 problem:
 
 + make ARCH= CROSS_COMPILE= EXTRA_CFLAGS= LIBCLANGLLVM=1 -C /git/linux/tools/perf O=/tmp/build/perf CC=clang
 
 ...
 /usr/bin/ld: /usr/lib/llvm-9/lib/libclangAnalysis.a(ExprMutationAnalyzer.cpp.o): in function `clang::ast_matchers::internal::matcher_ignoringImpCasts0Matcher::matches(clang::Expr const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const':
 (.text._ZNK5clang12ast_matchers8internal32matcher_ignoringImpCasts0Matcher7matchesERKNS_4ExprEPNS1_14ASTMatchFinderEPNS1_21BoundNodesTreeBuilderE[_ZNK5clang12ast_matchers8internal32matcher_ignoringImpCasts0Matcher7matchesERKNS_4ExprEPNS1_14ASTMatchFinderEPNS1_21BoundNodesTreeBuilderE]+0x43): undefined reference to `clang::ast_matchers::internal::DynTypedMatcher::matches(clang::ast_type_traits::DynTypedNode const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const'
 /usr/bin/ld: /usr/lib/llvm-9/lib/libclangAnalysis.a(ExprMutationAnalyzer.cpp.o): in function `clang::ast_matchers::internal::matcher_hasLoopVariable0Matcher::matches(clang::CXXForRangeStmt const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const':
 (.text._ZNK5clang12ast_matchers8internal31matcher_hasLoopVariable0Matcher7matchesERKNS_15CXXForRangeStmtEPNS1_14ASTMatchFinderEPNS1_21BoundNodesTreeBuilderE[_ZNK5clang12ast_matchers8internal31matcher_hasLoopVariable0Matcher7matchesERKNS_15CXXForRangeStmtEPNS1_14ASTMatchFinderEPNS1_21BoundNodesTreeBuilderE]+0x48): undefined reference to `clang::ast_matchers::internal::DynTypedMatcher::matches(clang::ast_type_traits::DynTypedNode const&, clang::ast_matchers::internal::ASTMatchFinder*, clang::ast_matchers::internal::BoundNodesTreeBuilder*) const'
 ...
 
   # export PERF_TARBALL=http://192.168.124.1/perf/perf-5.7.0-rc7.tar.xz
   # time dm
    1 alpine:3.4                    : Ok   gcc (Alpine 5.3.0) 5.3.0, clang version 3.8.0 (tags/RELEASE_380/final)
    2 alpine:3.5                    : Ok   gcc (Alpine 6.2.1) 6.2.1 20160822, clang version 3.8.1 (tags/RELEASE_381/final)
    3 alpine:3.6                    : Ok   gcc (Alpine 6.3.0) 6.3.0, clang version 4.0.0 (tags/RELEASE_400/final)
    4 alpine:3.7                    : Ok   gcc (Alpine 6.4.0) 6.4.0, Alpine clang version 5.0.0 (tags/RELEASE_500/final) (based on LLVM 5.0.0)
    5 alpine:3.8                    : Ok   gcc (Alpine 6.4.0) 6.4.0, Alpine clang version 5.0.1 (tags/RELEASE_501/final) (based on LLVM 5.0.1)
    6 alpine:3.9                    : Ok   gcc (Alpine 8.3.0) 8.3.0, Alpine clang version 5.0.1 (tags/RELEASE_502/final) (based on LLVM 5.0.1)
    7 alpine:3.10                   : Ok   gcc (Alpine 8.3.0) 8.3.0, Alpine clang version 8.0.0 (tags/RELEASE_800/final) (based on LLVM 8.0.0)
    8 alpine:3.11                   : Ok   gcc (Alpine 9.2.0) 9.2.0, Alpine clang version 9.0.0 (https://git.alpinelinux.org/aports f7f0d2c2b8bcd6a5843401a9a702029556492689) (based on LLVM 9.0.0)
    9 alpine:3.12                   : Ok   gcc (Alpine 9.3.0) 9.3.0, Alpine clang version 10.0.0 (https://gitlab.alpinelinux.org/alpine/aports.git 7445adce501f8473efdb93b17b5eaf2f1445ed4c)
   10 alpine:edge                   : Ok   gcc (Alpine 9.3.0) 9.3.0, Alpine clang version 10.0.0 (git://git.alpinelinux.org/aports 7445adce501f8473efdb93b17b5eaf2f1445ed4c)
   11 alt:p8                        : Ok   x86_64-alt-linux-gcc (GCC) 5.3.1 20151207 (ALT p8 5.3.1-alt3.M80P.1), clang version 3.8.0 (tags/RELEASE_380/final)
   12 alt:p9                        : Ok   x86_64-alt-linux-gcc (GCC) 8.4.1 20200305 (ALT p9 8.4.1-alt0.p9.1), clang version 7.0.1
   13 alt:sisyphus                  : Ok   x86_64-alt-linux-gcc (GCC) 9.2.1 20200123 (ALT Sisyphus 9.2.1-alt3), clang version 10.0.0
   14 amazonlinux:1                 : Ok   gcc (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2), clang version 3.6.2 (tags/RELEASE_362/final)
   15 amazonlinux:2                 : Ok   gcc (GCC) 7.3.1 20180712 (Red Hat 7.3.1-6), clang version 7.0.1 (Amazon Linux 2 7.0.1-1.amzn2.0.2)
   16 android-ndk:r12b-arm          : Ok   arm-linux-androideabi-gcc (GCC) 4.9.x 20150123 (prerelease)
   17 android-ndk:r15c-arm          : Ok   arm-linux-androideabi-gcc (GCC) 4.9.x 20150123 (prerelease)
   18 centos:5                      : Ok   gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-55)
   19 centos:6                      : Ok   gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-23)
   20 centos:7                      : Ok   gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39)
   21 centos:8                      : Ok   gcc (GCC) 8.3.1 20190507 (Red Hat 8.3.1-4), clang version 8.0.1 (Red Hat 8.0.1-1.module_el8.1.0+215+a01033fb)
   22 clearlinux:latest             : Ok   gcc (Clear Linux OS for Intel Architecture) 9.3.1 20200501 releases/gcc-9.3.0-196-gcb2c76c8b1, clang version 10.0.0
   23 debian:8                      : Ok   gcc (Debian 4.9.2-10+deb8u2) 4.9.2, Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
   24 debian:9                      : Ok   gcc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516, clang version 3.8.1-24 (tags/RELEASE_381/final)
   25 debian:10                     : Ok   gcc (Debian 8.3.0-6) 8.3.0, clang version 7.0.1-8 (tags/RELEASE_701/final)
   26 debian:experimental           : FAIL gcc (Debian 9.3.0-13) 9.3.0, clang version 9.0.1-12
   27 debian:experimental-x-arm64   : Ok   aarch64-linux-gnu-gcc (Debian 9.3.0-8) 9.3.0
   28 debian:experimental-x-mips    : Ok   mips-linux-gnu-gcc (Debian 8.3.0-19) 8.3.0
   29 debian:experimental-x-mips64  : Ok   mips64-linux-gnuabi64-gcc (Debian 9.3.0-8) 9.3.0
   30 debian:experimental-x-mipsel  : Ok   mipsel-linux-gnu-gcc (Debian 9.2.1-8) 9.2.1 20190909
   31 fedora:20                     : Ok   gcc (GCC) 4.8.3 20140911 (Red Hat 4.8.3-7)
   32 fedora:22                     : Ok   gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6), clang version 3.5.0 (tags/RELEASE_350/final)
   33 fedora:23                     : Ok   gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6), clang version 3.7.0 (tags/RELEASE_370/final)
   34 fedora:24                     : Ok   gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1), clang version 3.8.1 (tags/RELEASE_381/final)
   35 fedora:24-x-ARC-uClibc        : Ok   arc-linux-gcc (ARCompact ISA Linux uClibc toolchain 2017.09-rc2) 7.1.1 20170710
   36 fedora:25                     : Ok   gcc (GCC) 6.4.1 20170727 (Red Hat 6.4.1-1), clang version 3.9.1 (tags/RELEASE_391/final)
   37 fedora:26                     : Ok   gcc (GCC) 7.3.1 20180130 (Red Hat 7.3.1-2), clang version 4.0.1 (tags/RELEASE_401/final)
   38 fedora:27                     : Ok   gcc (GCC) 7.3.1 20180712 (Red Hat 7.3.1-6), clang version 5.0.2 (tags/RELEASE_502/final)
   39 fedora:28                     : Ok   gcc (GCC) 8.3.1 20190223 (Red Hat 8.3.1-2), clang version 6.0.1 (tags/RELEASE_601/final)
   40 fedora:29                     : Ok   gcc (GCC) 8.3.1 20190223 (Red Hat 8.3.1-2), clang version 7.0.1 (Fedora 7.0.1-6.fc29)
   41 fedora:30                     : Ok   gcc (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1), clang version 8.0.0 (Fedora 8.0.0-3.fc30)
   42 fedora:30-x-ARC-glibc         : Ok   arc-linux-gcc (ARC HS GNU/Linux glibc toolchain 2019.03-rc1) 8.3.1 20190225
   43 fedora:30-x-ARC-uClibc        : Ok   arc-linux-gcc (ARCv2 ISA Linux uClibc toolchain 2019.03-rc1) 8.3.1 20190225
   44 fedora:31                     : Ok   gcc (GCC) 9.3.1 20200408 (Red Hat 9.3.1-2), clang version 9.0.1 (Fedora 9.0.1-2.fc31)
   45 fedora:32                     : Ok   gcc (GCC) 10.1.1 20200507 (Red Hat 10.1.1-1), clang version 10.0.0 (Fedora 10.0.0-1.fc32)
   46 fedora:rawhide                : Ok   gcc (GCC) 10.0.1 20200216 (Red Hat 10.0.1-0.8), clang version 10.0.0 (Fedora 10.0.0-0.3.rc2.fc33)
   47 gentoo-stage3-amd64:latest    : Ok   gcc (Gentoo 9.2.0-r2 p3) 9.2.0
   48 mageia:5                      : Ok   gcc (GCC) 4.9.2, clang version 3.5.2 (tags/RELEASE_352/final)
   49 mageia:6                      : Ok   gcc (Mageia 5.5.0-1.mga6) 5.5.0, clang version 3.9.1 (tags/RELEASE_391/final)
   50 mageia:7                      : Ok   gcc (Mageia 8.3.1-0.20190524.1.mga7) 8.3.1 20190524, clang version 8.0.0 (Mageia 8.0.0-1.mga7)
   51 manjaro:latest                : Ok   gcc (GCC) 9.2.0, clang version 9.0.0 (tags/RELEASE_900/final)
   52 openmandriva:cooker           : Ok   gcc (GCC) 10.0.0 20200502 (OpenMandriva), clang version 10.0.1
   53 opensuse:15.0                 : Ok   gcc (SUSE Linux) 7.4.1 20190424 [gcc-7-branch revision 270538], clang version 5.0.1 (tags/RELEASE_501/final 312548)
   54 opensuse:15.1                 : Ok   gcc (SUSE Linux) 7.5.0, clang version 7.0.1 (tags/RELEASE_701/final 349238)
   55 opensuse:15.2                 : Ok   gcc (SUSE Linux) 7.5.0, clang version 7.0.1 (tags/RELEASE_701/final 349238)
   56 opensuse:42.3                 : Ok   gcc (SUSE Linux) 4.8.5, clang version 3.8.0 (tags/RELEASE_380/final 262553)
   57 opensuse:tumbleweed           : Ok   gcc (SUSE Linux) 9.3.1 20200406 [revision 6db837a5288ee3ca5ec504fbd5a765817e556ac2], clang version 10.0.0
   58 oraclelinux:6                 : Ok   gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-23.0.1)
   59 oraclelinux:7                 : Ok   gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39.0.3)
   60 oraclelinux:8                 : Ok   gcc (GCC) 8.3.1 20191121 (Red Hat 8.3.1-5.0.3), clang version 9.0.1 (Red Hat 9.0.1-2.0.1.module+el8.2.0+5599+9ed9ef6d)
   61 ubuntu:12.04                  : Ok   gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, Ubuntu clang version 3.0-6ubuntu3 (tags/RELEASE_30/final) (based on LLVM 3.0)
   62 ubuntu:14.04                  : Ok   gcc (Ubuntu 4.8.4-2ubuntu1~14.04.4) 4.8.4
   63 ubuntu:16.04                  : Ok   gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609, clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
   64 ubuntu:16.04-x-arm            : Ok   arm-linux-gnueabihf-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
   65 ubuntu:16.04-x-arm64          : Ok   aarch64-linux-gnu-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
   66 ubuntu:16.04-x-powerpc        : Ok   powerpc-linux-gnu-gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
   67 ubuntu:16.04-x-powerpc64      : Ok   powerpc64-linux-gnu-gcc (Ubuntu/IBM 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
   68 ubuntu:16.04-x-powerpc64el    : Ok   powerpc64le-linux-gnu-gcc (Ubuntu/IBM 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
   69 ubuntu:16.04-x-s390           : Ok   s390x-linux-gnu-gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
   70 ubuntu:18.04                  : Ok   gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0, clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
   71 ubuntu:18.04-x-arm            : Ok   arm-linux-gnueabihf-gcc (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0
   72 ubuntu:18.04-x-arm64          : Ok   aarch64-linux-gnu-gcc (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0
   73 ubuntu:18.04-x-m68k           : Ok   m68k-linux-gnu-gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
   74 ubuntu:18.04-x-powerpc        : Ok   powerpc-linux-gnu-gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
   75 ubuntu:18.04-x-powerpc64      : Ok   powerpc64-linux-gnu-gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
   76 ubuntu:18.04-x-powerpc64el    : Ok   powerpc64le-linux-gnu-gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
   77 ubuntu:18.04-x-riscv64        : Ok   riscv64-linux-gnu-gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
   78 ubuntu:18.04-x-s390           : Ok   s390x-linux-gnu-gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
   79 ubuntu:18.04-x-sh4            : Ok   sh4-linux-gnu-gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
   80 ubuntu:18.04-x-sparc64        : Ok   sparc64-linux-gnu-gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
   81 ubuntu:18.10                  : Ok   gcc (Ubuntu 8.3.0-6ubuntu1~18.10.1) 8.3.0, clang version 7.0.0-3 (tags/RELEASE_700/final)
   82 ubuntu:19.04                  : Ok   gcc (Ubuntu 8.3.0-6ubuntu1) 8.3.0, clang version 8.0.0-3 (tags/RELEASE_800/final)
   83 ubuntu:19.04-x-alpha          : Ok   alpha-linux-gnu-gcc (Ubuntu 8.3.0-6ubuntu1) 8.3.0
   84 ubuntu:19.04-x-arm64          : Ok   aarch64-linux-gnu-gcc (Ubuntu/Linaro 8.3.0-6ubuntu1) 8.3.0
   85 ubuntu:19.04-x-hppa           : Ok   hppa-linux-gnu-gcc (Ubuntu 8.3.0-6ubuntu1) 8.3.0
   86 ubuntu:19.10                  : FAIL gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008, clang version 9.0.0-2 (tags/RELEASE_900/final)
   87 ubuntu:20.04                  : Ok   gcc (Ubuntu 9.3.0-10ubuntu2) 9.3.0, clang version 10.0.0-4ubuntu1
   #
 
   It builds ok with the default set of options.
 
 The "7: Simple expression parser" entry is failing due to a bug in the
 hashmap in libbpf that will hit upstream via the bpf tree.
 
   # uname -a
   Linux five 5.5.17-200.fc31.x86_64 #1 SMP Mon Apr 13 15:29:42 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
   # git log --oneline -1
   3e9b26dc22 perf tools: Remove some duplicated includes
   # perf version --build-options
   perf version 5.7.rc7.g0affd0e5262b
                    dwarf: [ on  ]  # HAVE_DWARF_SUPPORT
       dwarf_getlocations: [ on  ]  # HAVE_DWARF_GETLOCATIONS_SUPPORT
                    glibc: [ on  ]  # HAVE_GLIBC_SUPPORT
                     gtk2: [ on  ]  # HAVE_GTK2_SUPPORT
            syscall_table: [ on  ]  # HAVE_SYSCALL_TABLE_SUPPORT
                   libbfd: [ on  ]  # HAVE_LIBBFD_SUPPORT
                   libelf: [ on  ]  # HAVE_LIBELF_SUPPORT
                  libnuma: [ on  ]  # HAVE_LIBNUMA_SUPPORT
   numa_num_possible_cpus: [ on  ]  # HAVE_LIBNUMA_SUPPORT
                  libperl: [ on  ]  # HAVE_LIBPERL_SUPPORT
                libpython: [ on  ]  # HAVE_LIBPYTHON_SUPPORT
                 libslang: [ on  ]  # HAVE_SLANG_SUPPORT
                libcrypto: [ on  ]  # HAVE_LIBCRYPTO_SUPPORT
                libunwind: [ on  ]  # HAVE_LIBUNWIND_SUPPORT
       libdw-dwarf-unwind: [ on  ]  # HAVE_DWARF_SUPPORT
                     zlib: [ on  ]  # HAVE_ZLIB_SUPPORT
                     lzma: [ on  ]  # HAVE_LZMA_SUPPORT
                get_cpuid: [ on  ]  # HAVE_AUXTRACE_SUPPORT
                      bpf: [ on  ]  # HAVE_LIBBPF_SUPPORT
                      aio: [ on  ]  # HAVE_AIO_SUPPORT
                     zstd: [ on  ]  # HAVE_ZSTD_SUPPORT
   # 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: Test data source output                               : Ok
    6: Parse event definition strings                        : Ok
    7: Simple expression parser                              : FAILED!
    8: PERF_RECORD_* events & perf_sample fields             : Ok
    9: Parse perf pmu format                                 : Ok
   10: PMU events                                            :
   10.1: PMU event table sanity                              : Ok
   10.2: PMU event map aliases                               : Ok
   10.3: Parsing of PMU event table metrics                  : Ok
   11: DSO data read                                         : Ok
   12: DSO data cache                                        : Ok
   13: DSO data reopen                                       : Ok
   14: Roundtrip evsel->name                                 : Ok
   15: Parse sched tracepoints fields                        : Ok
   16: syscalls:sys_enter_openat event fields                : Ok
   17: Setup struct perf_event_attr                          : Ok
   18: Match and link multiple hists                         : Ok
   19: 'import perf' in python                               : Ok
   20: Breakpoint overflow signal handler                    : Ok
   21: Breakpoint overflow sampling                          : Ok
   22: Breakpoint accounting                                 : Ok
   23: Watchpoint                                            :
   23.1: Read Only Watchpoint                                : Skip
   23.2: Write Only Watchpoint                               : Ok
   23.3: Read / Write Watchpoint                             : Ok
   23.4: Modify Watchpoint                                   : Ok
   24: Number of exit events of a simple workload            : Ok
   25: Software clock events period values                   : Ok
   26: Object code reading                                   : Ok
   27: Sample parsing                                        : Ok
   28: Use a dummy software event to keep tracking           : Ok
   29: Parse with no sample_id_all bit set                   : Ok
   30: Filter hist entries                                   : Ok
   31: Lookup mmap thread                                    : Ok
   32: Share thread maps                                     : Ok
   33: Sort output of hist entries                           : Ok
   34: Cumulate child hist entries                           : Ok
   35: Track with sched_switch                               : Ok
   36: Filter fds with revents mask in a fdarray             : Ok
   37: Add fd to a fdarray, making it autogrow               : Ok
   38: kmod_path__parse                                      : Ok
   39: Thread map                                            : Ok
   40: LLVM search and compile                               :
   40.1: Basic BPF llvm compile                              : Ok
   40.2: kbuild searching                                    : Ok
   40.3: Compile source for BPF prologue generation          : Ok
   40.4: Compile source for BPF relocation                   : Ok
   41: Session topology                                      : Ok
   42: BPF filter                                            :
   42.1: Basic BPF filtering                                 : Ok
   42.2: BPF pinning                                         : Ok
   42.3: BPF prologue generation                             : Ok
   42.4: BPF relocation checker                              : Ok
   43: Synthesize thread map                                 : Ok
   44: Remove thread map                                     : Ok
   45: Synthesize cpu map                                    : Ok
   46: Synthesize stat config                                : Ok
   47: Synthesize stat                                       : Ok
   48: Synthesize stat round                                 : Ok
   49: Synthesize attr update                                : Ok
   50: Event times                                           : Ok
   51: Read backward ring buffer                             : Ok
   52: Print cpu map                                         : Ok
   53: Merge cpu map                                         : Ok
   54: Probe SDT events                                      : Ok
   55: is_printable_array                                    : Ok
   56: Print bitmap                                          : Ok
   57: perf hooks                                            : Ok
   58: builtin clang support                                 : Skip (not compiled in)
   59: unit_number__scnprintf                                : Ok
   60: mem2node                                              : Ok
   61: time utils                                            : Ok
   62: Test jit_write_elf                                    : Ok
   63: Test libpfm4 support                                  : Skip (not compiled in)
   64: Test api io                                           : Ok
   65: maps__merge_in                                        : Ok
   66: Demangle Java                                         : Ok
   67: x86 rdpmc                                             : Ok
   68: Convert perf time to TSC                              : Ok
   69: DWARF unwind                                          : Ok
   70: x86 instruction decoder - new instructions            : Ok
   71: Intel PT packet decoder                               : Ok
   72: x86 bp modify                                         : Ok
   73: probe libc's inet_pton & backtrace it with ping       : Ok
   74: Use vfs_getname probe to get syscall args filenames   : Ok
   75: Check open filename arg using perf trace + vfs_getname: Ok
   76: Zstd perf.data compression/decompression              : Ok
   77: Add vfs_getname probe to get syscall args filenames   : Ok
   #
 
   [acme@five perf]$ git log --oneline -1 ; time make -C tools/perf build-test
   3e9b26dc22 (HEAD -> perf/core, seventh/perf/core, quaco/perf/core) perf tools: Remove some duplicated includes
   make: Entering directory '/home/acme/git/perf/tools/perf'
   - tarpkg: ./tests/perf-targz-src-pkg .
         make_no_libbpf_DEBUG_O: make NO_LIBBPF=1 DEBUG=1
          make_with_clangllvm_O: make LIBCLANGLLVM=1
             make_no_auxtrace_O: make NO_AUXTRACE=1
             make_no_demangle_O: make NO_DEMANGLE=1
               make_clean_all_O: make clean all
        make_util_pmu_bison_o_O: make util/pmu-bison.o
                 make_no_newt_O: make NO_NEWT=1
                 make_no_gtk2_O: make NO_GTK2=1
               make_no_libbpf_O: make NO_LIBBPF=1
             make_no_libaudit_O: make NO_LIBAUDIT=1
                  make_perf_o_O: make perf.o
               make_no_libelf_O: make NO_LIBELF=1
                  make_static_O: make LDFLAGS=-static NO_PERF_READ_VDSO32=1 NO_PERF_READ_VDSOX32=1 NO_JVMTI=1
                 make_install_O: make install
            make_no_libpython_O: make NO_LIBPYTHON=1
            make_no_libunwind_O: make NO_LIBUNWIND=1
   make_no_libdw_dwarf_unwind_O: make NO_LIBDW_DWARF_UNWIND=1
              make_no_scripts_O: make NO_LIBPYTHON=1 NO_LIBPERL=1
            make_with_libpfm4_O: make LIBPFM4=1
                    make_pure_O: make
                     make_doc_O: make doc
                  make_no_sdt_O: make NO_SDT=1
                make_no_slang_O: make NO_SLANG=1
          make_no_syscall_tbl_O: make NO_SYSCALL_TABLE=1
             make_install_bin_O: make install-bin
              make_no_libperl_O: make NO_LIBPERL=1
    make_install_prefix_slash_O: make install prefix=/tmp/krava/
          make_install_prefix_O: make install prefix=/tmp/krava
                   make_no_ui_O: make NO_NEWT=1 NO_SLANG=1 NO_GTK2=1
              make_no_libnuma_O: make NO_LIBNUMA=1
                 make_minimal_O: make NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1 NO_LIBCAP=1 NO_SYSCALL_TABLE=1
         make_with_babeltrace_O: make LIBBABELTRACE=1
                    make_help_O: make help
            make_no_libcrypto_O: make NO_LIBCRYPTO=1
                   make_debug_O: make DEBUG=1
            make_no_libbionic_O: make NO_LIBBIONIC=1
            make_no_backtrace_O: make NO_BACKTRACE=1
                    make_tags_O: make tags
              make_util_map_o_O: make util/map.o
   OK
   make: Leaving directory '/home/acme/git/perf/tools/perf'
   [acme@five perf]$
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQR2GiIUctdOfX2qHhGyPKLppCJ+JwUCXtaWmgAKCRCyPKLppCJ+
 J4mdAQD9wzSFCI96jZkWvCx61AkoZkcG8fyaWBpH+7Wuum3J1QD/Q9c37NGepK3T
 /sMFKufuBF7Z0Uy2toMz9i9P/KLaEQI=
 =dNn2
 -----END PGP SIGNATURE-----

Merge tag 'perf-tools-2020-06-02' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

Pull perf tooling updates from Arnaldo Carvalho de Melo:
 "These are additional changes to the perf tools, on top of what Ingo
  already submitted.

   - Further Intel PT call-trace fixes

   - Improve SELinux docs and tool warnings

   - Fix race at exit in 'perf record' using eventfd.

   - Add missing build tests to the default set of 'make -C tools/perf
     build-test'

   - Sync msr-index.h getting new AMD MSRs to decode and filter in 'perf
     trace'.

   - Fix fallback to libaudit in 'perf trace' for arches not using
     per-arch *.tbl files.

   - Fixes for 'perf ftrace'.

   - Fixes and improvements for the 'perf stat' metrics.

   - Use dummy event to get PERF_RECORD_{FORK,MMAP,etc} while
     synthesizing those metadata events for pre-existing threads.

   - Fix leaks detected using clang tooling.

   - Improvements to PMU event metric testing.

   - Report summary for 'perf stat' interval mode at the end, summing up
     all the intervals.

   - Improve pipe mode, i.e. this now works as expected, continuously
     dumping samples:

        # perf record -g -e raw_syscalls:sys_enter | perf --no-pager script

   - Fixes for event grouping, detecting incompatible groups such as:

        # perf stat -e '{cycles,power/energy-cores/}' -v
        WARNING: group events cpu maps do not match, disabling group:
          anon group { power/energy-cores/, cycles }
            power/energy-cores/: 0
            cycles: 0-7

   - Fixes for 'perf probe': blacklist address checking, number of
     kretprobe instances, etc.

   - JIT processing improvements and fixes plus the addition of a 'perf
     test' entry for the java demangler.

   - Add support for synthesizing first/last level cache, TLB and remove
     access events from HW tracing in the auxtrace code, first to use is
     ARM SPE.

   - Vendor events updates and fixes, including for POWER9 and Intel.

   - Allow using ~/.perfconfig for removing the ',' separators in 'perf
     stat' output.

   - Opt-in support for libpfm4"

* tag 'perf-tools-2020-06-02' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux: (120 commits)
  perf tools: Remove some duplicated includes
  perf symbols: Fix kernel maps for kcore and eBPF
  tools arch x86: Sync the msr-index.h copy with the kernel sources
  perf stat: Ensure group is defined on top of the same cpu mask
  perf libdw: Fix off-by 1 relative directory includes
  perf arm-spe: Support synthetic events
  perf auxtrace: Add four itrace options
  perf tools: Move arm-spe-pkt-decoder.h/c to the new dir
  perf test: Initialize memory in dwarf-unwind
  perf tests: Don't tail call optimize in unwind test
  tools compiler.h: Add attribute to disable tail calls
  perf build: Add a LIBPFM4=1 build test entry
  perf tools: Add optional support for libpfm4
  perf tools: Correct license on jsmn JSON parser
  perf jit: Fix inaccurate DWARF line table
  perf jvmti: Remove redundant jitdump line table entries
  perf build: Add NO_SDT=1 to the default set of build tests
  perf build: Add NO_LIBCRYPTO=1 to the default set of build tests
  perf build: Add NO_SYSCALL_TABLE=1 to the build tests
  perf build: Remove libaudit from the default feature checks
  ...
This commit is contained in:
Linus Torvalds 2020-06-04 10:17:59 -07:00
commit 38b3a5aaf2
145 changed files with 4309 additions and 980 deletions

View File

@ -301,6 +301,9 @@
#define MSR_PP1_ENERGY_STATUS 0x00000641
#define MSR_PP1_POLICY 0x00000642
#define MSR_AMD_PKG_ENERGY_STATUS 0xc001029b
#define MSR_AMD_RAPL_POWER_UNIT 0xc0010299
/* Config TDP MSRs */
#define MSR_CONFIG_TDP_NOMINAL 0x00000648
#define MSR_CONFIG_TDP_LEVEL_1 0x00000649

View File

@ -40,7 +40,6 @@ FEATURE_TESTS_BASIC := \
glibc \
gtk2 \
gtk2-infobar \
libaudit \
libbfd \
libcap \
libelf \
@ -112,7 +111,6 @@ FEATURE_DISPLAY ?= \
dwarf_getlocations \
glibc \
gtk2 \
libaudit \
libbfd \
libcap \
libelf \

View File

@ -91,7 +91,7 @@ __BUILDXX = $(CXX) $(CXXFLAGS) -MD -Wall -Werror -o $@ $(patsubst %.bin,%.cpp,$(
###############################
$(OUTPUT)test-all.bin:
$(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma
$(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma
$(OUTPUT)test-hello.bin:
$(BUILD)

View File

@ -74,10 +74,6 @@
# include "test-libunwind.c"
#undef main
#define main main_test_libaudit
# include "test-libaudit.c"
#undef main
#define main main_test_libslang
# include "test-libslang.c"
#undef main
@ -208,7 +204,6 @@ int main(int argc, char *argv[])
main_test_libelf_gelf_getnote();
main_test_libelf_getshdrstrndx();
main_test_libunwind();
main_test_libaudit();
main_test_libslang();
main_test_gtk2(argc, argv);
main_test_gtk2_infobar(argc, argv);

View File

@ -27,6 +27,18 @@
#define __pure __attribute__((pure))
#endif
#define noinline __attribute__((noinline))
#ifdef __has_attribute
#if __has_attribute(disable_tail_calls)
#define __no_tail_call __attribute__((disable_tail_calls))
#endif
#endif
#ifndef __no_tail_call
#if GCC_VERSION > 40201
#define __no_tail_call __attribute__((optimize("no-optimize-sibling-calls")))
#else
#define __no_tail_call
#endif
#endif
#ifndef __packed
#define __packed __attribute__((packed))
#endif

View File

@ -47,6 +47,9 @@
#ifndef noinline
#define noinline
#endif
#ifndef __no_tail_call
#define __no_tail_call
#endif
/* Are two types/vars the same type (ignoring qualifiers)? */
#ifndef __same_type

View File

@ -1,5 +1,5 @@
i synthesize instructions events
b synthesize branches events
b synthesize branches events (branch misses for Arm SPE)
c synthesize branches events (calls only)
r synthesize branches events (returns only)
x synthesize transactions events
@ -9,6 +9,10 @@
of aux-output (refer to perf record)
e synthesize error events
d create a debug log
f synthesize first level cache events
m synthesize last level cache events
t synthesize TLB events
a synthesize remote access events
g synthesize a call chain (use with i or x)
G synthesize a call chain on existing event records
l synthesize last branch entries (use with i or x)

View File

@ -40,7 +40,7 @@ RECORD OPTIONS
--------------
-e::
--event=::
Select the PMU event. Use 'perf mem record -e list'
Select the PMU event. Use 'perf c2c record -e list'
to list available events.
-v::

View File

@ -667,6 +667,11 @@ convert.*::
Limit the size of ordered_events queue, so we could control
allocation size of perf data files without proper finished
round events.
stat.*::
stat.big-num::
(boolean) Change the default for "--big-num". To make
"--no-big-num" the default, set "stat.big-num=false".
intel-pt.*::

View File

@ -687,7 +687,7 @@ The v4.2 kernel introduced support for a context switch metadata event,
PERF_RECORD_SWITCH, which allows unprivileged users to see when their processes
are scheduled out and in, just not by whom, which is left for the
PERF_RECORD_SWITCH_CPU_WIDE, that is only accessible in system wide context,
which in turn requires CAP_SYS_ADMIN.
which in turn requires CAP_PERFMON or CAP_SYS_ADMIN.
Please see the 45ac1403f564 ("perf: Add PERF_RECORD_SWITCH to indicate context
switches") commit, that introduces these metadata events for further info.

View File

@ -458,7 +458,9 @@ This option sets the time out limit. The default value is 500 ms.
--switch-events::
Record context switch events i.e. events of type PERF_RECORD_SWITCH or
PERF_RECORD_SWITCH_CPU_WIDE.
PERF_RECORD_SWITCH_CPU_WIDE. In some cases (e.g. Intel PT or CoreSight)
switch events will be enabled automatically, which can be suppressed by
by the option --no-switch-events.
--clang-path=PATH::
Path to clang binary to use for compiling BPF scriptlets.
@ -613,6 +615,17 @@ appended unit character - B/K/M/G
The number of threads to run when synthesizing events for existing processes.
By default, the number of threads equals 1.
ifdef::HAVE_LIBPFM[]
--pfm-events events::
Select a PMU event using libpfm4 syntax (see http://perfmon2.sf.net)
including support for event filters. For example '--pfm-events
inst_retired:any_p:u:c=1:i'. More than one event can be passed to the
option using the comma separator. Hardware events and generic hardware
events cannot be mixed together. The latter must be used with the -e
option. The -e option and this one can be mixed and matched. Events
can be grouped using the {} notation.
endif::HAVE_LIBPFM[]
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1], linkperf:perf-intel-pt[1]

View File

@ -71,6 +71,16 @@ report::
--tid=<tid>::
stat events on existing thread id (comma separated list)
ifdef::HAVE_LIBPFM[]
--pfm-events events::
Select a PMU event using libpfm4 syntax (see http://perfmon2.sf.net)
including support for event filters. For example '--pfm-events
inst_retired:any_p:u:c=1:i'. More than one event can be passed to the
option using the comma separator. Hardware events and generic hardware
events cannot be mixed together. The latter must be used with the -e
option. The -e option and this one can be mixed and matched. Events
can be grouped using the {} notation.
endif::HAVE_LIBPFM[]
-a::
--all-cpus::
@ -93,7 +103,9 @@ report::
-B::
--big-num::
print large numbers with thousands' separators according to locale
print large numbers with thousands' separators according to locale.
Enabled by default. Use "--no-big-num" to disable.
Default setting can be changed with "perf config stat.big-num=false".
-C::
--cpu=::
@ -234,6 +246,25 @@ filter out the startup phase of the program, which is often very different.
Print statistics of transactional execution if supported.
--metric-no-group::
By default, events to compute a metric are placed in weak groups. The
group tries to enforce scheduling all or none of the events. The
--metric-no-group option places events outside of groups and may
increase the chance of the event being scheduled - leading to more
accuracy. However, as events may not be scheduled together accuracy
for metrics like instructions per cycle can be lower - as both metrics
may no longer be being measured at the same time.
--metric-no-merge::
By default metric events in different weak groups can be shared if one
group contains all the events needed by another. In such cases one
group will be eliminated reducing event multiplexing and making it so
that certain groups of metrics sum to 100%. A downside to sharing a
group is that the group may require multiplexing and so accuracy for a
small group that need not have multiplexing is lowered. This option
forbids the event merging logic from sharing events between groups and
may be used to increase accuracy in this case.
STAT RECORD
-----------
Stores stat data into perf data file.

View File

@ -329,6 +329,17 @@ Default is to monitor all CPUS.
The known limitations include exception handing such as
setjmp/longjmp will have calls/returns not match.
ifdef::HAVE_LIBPFM[]
--pfm-events events::
Select a PMU event using libpfm4 syntax (see http://perfmon2.sf.net)
including support for event filters. For example '--pfm-events
inst_retired:any_p:u:c=1:i'. More than one event can be passed to the
option using the comma separator. Hardware events and generic hardware
events cannot be mixed together. The latter must be used with the -e
option. The -e option and this one can be mixed and matched. Events
can be grouped using the {} notation.
endif::HAVE_LIBPFM[]
INTERACTIVE PROMPTING KEYS
--------------------------

View File

@ -0,0 +1,237 @@
Overview
========
For general security related questions of perf_event_open() syscall usage,
performance monitoring and observability operations by Perf see here:
https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html
Enabling LSM based mandatory access control (MAC) to perf_event_open() syscall
==============================================================================
LSM hooks for mandatory access control for perf_event_open() syscall can be
used starting from Linux v5.3. Below are the steps to extend Fedora (v31) with
Targeted policy with perf_event_open() access control capabilities:
1. Download selinux-policy SRPM package (e.g. selinux-policy-3.14.4-48.fc31.src.rpm on FC31)
and install it so rpmbuild directory would exist in the current working directory:
# rpm -Uhv selinux-policy-3.14.4-48.fc31.src.rpm
2. Get into rpmbuild/SPECS directory and unpack the source code:
# rpmbuild -bp selinux-policy.spec
3. Place patch below at rpmbuild/BUILD/selinux-policy-b86eaaf4dbcf2d51dd4432df7185c0eaf3cbcc02
directory and apply it:
# patch -p1 < selinux-policy-perf-events-perfmon.patch
patching file policy/flask/access_vectors
patching file policy/flask/security_classes
# cat selinux-policy-perf-events-perfmon.patch
diff -Nura a/policy/flask/access_vectors b/policy/flask/access_vectors
--- a/policy/flask/access_vectors 2020-02-04 18:19:53.000000000 +0300
+++ b/policy/flask/access_vectors 2020-02-28 23:37:25.000000000 +0300
@@ -174,6 +174,7 @@
wake_alarm
block_suspend
audit_read
+ perfmon
}
#
@@ -1099,3 +1100,15 @@
class xdp_socket
inherits socket
+
+class perf_event
+{
+ open
+ cpu
+ kernel
+ tracepoint
+ read
+ write
+}
+
+
diff -Nura a/policy/flask/security_classes b/policy/flask/security_classes
--- a/policy/flask/security_classes 2020-02-04 18:19:53.000000000 +0300
+++ b/policy/flask/security_classes 2020-02-28 21:35:17.000000000 +0300
@@ -200,4 +200,6 @@
class xdp_socket
+class perf_event
+
# FLASK
4. Get into rpmbuild/SPECS directory and build policy packages from patched sources:
# rpmbuild --noclean --noprep -ba selinux-policy.spec
so you have this:
# ls -alh rpmbuild/RPMS/noarch/
total 33M
drwxr-xr-x. 2 root root 4.0K Mar 20 12:16 .
drwxr-xr-x. 3 root root 4.0K Mar 20 12:16 ..
-rw-r--r--. 1 root root 112K Mar 20 12:16 selinux-policy-3.14.4-48.fc31.noarch.rpm
-rw-r--r--. 1 root root 1.2M Mar 20 12:17 selinux-policy-devel-3.14.4-48.fc31.noarch.rpm
-rw-r--r--. 1 root root 2.3M Mar 20 12:17 selinux-policy-doc-3.14.4-48.fc31.noarch.rpm
-rw-r--r--. 1 root root 12M Mar 20 12:17 selinux-policy-minimum-3.14.4-48.fc31.noarch.rpm
-rw-r--r--. 1 root root 4.5M Mar 20 12:16 selinux-policy-mls-3.14.4-48.fc31.noarch.rpm
-rw-r--r--. 1 root root 111K Mar 20 12:16 selinux-policy-sandbox-3.14.4-48.fc31.noarch.rpm
-rw-r--r--. 1 root root 14M Mar 20 12:17 selinux-policy-targeted-3.14.4-48.fc31.noarch.rpm
5. Install SELinux packages from Fedora repo, if not already done so, and
update with the patched rpms above:
# rpm -Uhv rpmbuild/RPMS/noarch/selinux-policy-*
6. Enable SELinux Permissive mode for Targeted policy, if not already done so:
# cat /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=permissive
# SELINUXTYPE= can take one of these three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
7. Enable filesystem SELinux labeling at the next reboot:
# touch /.autorelabel
8. Reboot machine and it will label filesystems and load Targeted policy into the kernel;
9. Login and check that dmesg output doesn't mention that perf_event class is unknown to SELinux subsystem;
10. Check that SELinux is enabled and in Permissive mode
# getenforce
Permissive
11. Turn SELinux into Enforcing mode:
# setenforce 1
# getenforce
Enforcing
Opening access to perf_event_open() syscall on Fedora with SELinux
==================================================================
Access to performance monitoring and observability operations by Perf
can be limited for superuser or CAP_PERFMON or CAP_SYS_ADMIN privileged
processes. MAC policy settings (e.g. SELinux) can be loaded into the kernel
and prevent unauthorized access to perf_event_open() syscall. In such case
Perf tool provides a message similar to the one below:
# perf stat
Error:
Access to performance monitoring and observability operations is limited.
Enforced MAC policy settings (SELinux) can limit access to performance
monitoring and observability operations. Inspect system audit records for
more perf_event access control information and adjusting the policy.
Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open
access to performance monitoring and observability operations for users
without CAP_PERFMON or CAP_SYS_ADMIN Linux capability.
perf_event_paranoid setting is -1:
-1: Allow use of (almost) all events by all users
Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
>= 0: Disallow raw and ftrace function tracepoint access
>= 1: Disallow CPU event access
>= 2: Disallow kernel profiling
To make the adjusted perf_event_paranoid setting permanent preserve it
in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)
To make sure that access is limited by MAC policy settings inspect system
audit records using journalctl command or /var/log/audit/audit.log so the
output would contain AVC denied records related to perf_event:
# journalctl --reverse --no-pager | grep perf_event
python3[1318099]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t.
If you believe that perf should be allowed open access on perf_event labeled unconfined_t by default.
setroubleshoot[1318099]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t. For complete SELinux messages run: sealert -l 4595ce5b-e58f-462c-9d86-3bc2074935de
audit[1318098]: AVC avc: denied { open } for pid=1318098 comm="perf" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=perf_event permissive=0
In order to open access to perf_event_open() syscall MAC policy settings can
require to be extended. On SELinux system this can be done by loading a special
policy module extending base policy settings. Perf related policy module can
be generated using the system audit records about blocking perf_event access.
Run the command below to generate my-perf.te policy extension file with
perf_event related rules:
# ausearch -c 'perf' --raw | audit2allow -M my-perf && cat my-perf.te
module my-perf 1.0;
require {
type unconfined_t;
class perf_event { cpu kernel open read tracepoint write };
}
#============= unconfined_t ==============
allow unconfined_t self:perf_event { cpu kernel open read tracepoint write };
Now compile, pack and load my-perf.pp extension module into the kernel:
# checkmodule -M -m -o my-perf.mod my-perf.te
# semodule_package -o my-perf.pp -m my-perf.mod
# semodule -X 300 -i my-perf.pp
After all those taken steps above access to perf_event_open() syscall should
now be allowed by the policy settings. Check access running Perf like this:
# perf stat
^C
Performance counter stats for 'system wide':
36,387.41 msec cpu-clock # 7.999 CPUs utilized
2,629 context-switches # 0.072 K/sec
57 cpu-migrations # 0.002 K/sec
1 page-faults # 0.000 K/sec
263,721,559 cycles # 0.007 GHz
175,746,713 instructions # 0.67 insn per cycle
19,628,798 branches # 0.539 M/sec
1,259,201 branch-misses # 6.42% of all branches
4.549061439 seconds time elapsed
The generated perf-event.pp related policy extension module can be removed
from the kernel using this command:
# semodule -X 300 -r my-perf
Alternatively the module can be temporarily disabled and enabled back using
these two commands:
# semodule -d my-perf
# semodule -e my-perf
If something went wrong
=======================
To turn SELinux into Permissive mode:
# setenforce 0
To fully disable SELinux during kernel boot [3] set kernel command line parameter selinux=0
To remove SELinux labeling from local filesystems:
# find / -mount -print0 | xargs -0 setfattr -h -x security.selinux
To fully turn SELinux off a machine set SELINUX=disabled at /etc/selinux/config file and reboot;
Links
=====
[1] https://download-ib01.fedoraproject.org/pub/fedora/linux/updates/31/Everything/SRPMS/Packages/s/selinux-policy-3.14.4-49.fc31.src.rpm
[2] https://docs.fedoraproject.org/en-US/Fedora/11/html/Security-Enhanced_Linux/sect-Security-Enhanced_Linux-Working_with_SELinux-Enabling_and_Disabling_SELinux.html
[3] https://danwalsh.livejournal.com/10972.html

View File

@ -23,12 +23,28 @@ include $(srctree)/tools/scripts/Makefile.arch
$(call detected_var,SRCARCH)
NO_PERF_REGS := 1
NO_SYSCALL_TABLE := 1
ifneq ($(NO_SYSCALL_TABLE),1)
NO_SYSCALL_TABLE := 1
ifeq ($(SRCARCH),x86)
ifeq (${IS_64_BIT}, 1)
NO_SYSCALL_TABLE := 0
endif
else
ifeq ($(SRCARCH),$(filter $(SRCARCH),powerpc arm64 s390))
NO_SYSCALL_TABLE := 0
endif
endif
ifneq ($(NO_SYSCALL_TABLE),1)
CFLAGS += -DHAVE_SYSCALL_TABLE_SUPPORT
endif
endif
# Additional ARCH settings for ppc
ifeq ($(SRCARCH),powerpc)
NO_PERF_REGS := 0
NO_SYSCALL_TABLE := 0
CFLAGS += -I$(OUTPUT)arch/powerpc/include/generated
LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
endif
@ -37,7 +53,6 @@ endif
ifeq ($(SRCARCH),x86)
$(call detected,CONFIG_X86)
ifeq (${IS_64_BIT}, 1)
NO_SYSCALL_TABLE := 0
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -I$(OUTPUT)arch/x86/include/generated
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
LIBUNWIND_LIBS = -lunwind-x86_64 -lunwind -llzma
@ -55,7 +70,6 @@ endif
ifeq ($(SRCARCH),arm64)
NO_PERF_REGS := 0
NO_SYSCALL_TABLE := 0
CFLAGS += -I$(OUTPUT)arch/arm64/include/generated
LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
endif
@ -70,7 +84,6 @@ endif
ifeq ($(ARCH),s390)
NO_PERF_REGS := 0
NO_SYSCALL_TABLE := 0
CFLAGS += -fPIC -I$(OUTPUT)arch/s390/include/generated
endif
@ -78,10 +91,6 @@ ifeq ($(NO_PERF_REGS),0)
$(call detected,CONFIG_PERF_REGS)
endif
ifneq ($(NO_SYSCALL_TABLE),1)
CFLAGS += -DHAVE_SYSCALL_TABLE_SUPPORT
endif
# So far there's only x86 and arm libdw unwind support merged in perf.
# Disable it on all other architectures in case libdw unwind
# support is detected in system. Add supported architectures
@ -346,7 +355,7 @@ ifndef NO_BIONIC
endif
ifeq ($(feature-eventfd), 1)
CFLAGS += -DHAVE_EVENTFD
CFLAGS += -DHAVE_EVENTFD_SUPPORT
endif
ifeq ($(feature-get_current_dir_name), 1)
@ -651,6 +660,7 @@ ifeq ($(NO_SYSCALL_TABLE),0)
$(call detected,CONFIG_TRACE)
else
ifndef NO_LIBAUDIT
$(call feature_check,libaudit)
ifneq ($(feature-libaudit), 1)
msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev);
NO_LIBAUDIT := 1
@ -1012,6 +1022,19 @@ ifdef LIBCLANGLLVM
endif
endif
ifdef LIBPFM4
$(call feature_check,libpfm4)
ifeq ($(feature-libpfm4), 1)
CFLAGS += -DHAVE_LIBPFM
EXTLIBS += -lpfm
ASCIIDOC_EXTRA = -aHAVE_LIBPFM=1
$(call detected,CONFIG_LIBPFM4)
else
msg := $(warning libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev);
NO_LIBPFM4 := 1
endif
endif
# Among the variables below, these:
# perfexecdir
# perf_include_dir

View File

@ -118,6 +118,12 @@ include ../scripts/utilities.mak
#
# Define LIBBPF_DYNAMIC to enable libbpf dynamic linking.
#
# Define NO_SYSCALL_TABLE=1 to disable the use of syscall id to/from name tables
# generated from the kernel .tbl or unistd.h files and use, if available, libaudit
# for doing the conversions to/from strings/id.
#
# Define LIBPFM4 to enable libpfm4 events extension.
#
# As per kernel Makefile, avoid funny character set dependencies
unexport LC_ALL
@ -278,6 +284,7 @@ strip-libs = $(filter-out -l%,$(1))
ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT)
PLUGINS_PATH=$(OUTPUT)
BPF_PATH=$(OUTPUT)
SUBCMD_PATH=$(OUTPUT)
LIBPERF_PATH=$(OUTPUT)
@ -288,6 +295,7 @@ else
endif
else
TE_PATH=$(TRACE_EVENT_DIR)
PLUGINS_PATH=$(TRACE_EVENT_DIR)plugins/
API_PATH=$(LIB_DIR)
BPF_PATH=$(BPF_DIR)
SUBCMD_PATH=$(SUBCMD_DIR)
@ -297,7 +305,7 @@ endif
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
export LIBTRACEEVENT
LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)plugins/libtraceevent-dynamic-list
LIBTRACEEVENT_DYNAMIC_LIST = $(PLUGINS_PATH)libtraceevent-dynamic-list
#
# The static build has no dynsym table, so this does not work for
@ -756,10 +764,10 @@ $(LIBTRACEEVENT): FORCE
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a
libtraceevent_plugins: FORCE
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR)plugins $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins
$(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)plugins/libtraceevent-dynamic-list
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR)plugins $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent-dynamic-list
$(LIBTRACEEVENT)-clean:
$(call QUIET_CLEAN, libtraceevent)

View File

@ -216,7 +216,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
struct evsel *evsel)
{
char msg[BUFSIZ], path[PATH_MAX], *sink;
struct perf_evsel_config_term *term;
struct evsel_config_term *term;
int ret = -EINVAL;
u32 hash;
@ -224,7 +224,7 @@ static int cs_etm_set_sink_attr(struct perf_pmu *pmu,
return 0;
list_for_each_entry(term, &evsel->config_terms, list) {
if (term->type != PERF_EVSEL__CONFIG_TERM_DRV_CFG)
if (term->type != EVSEL__CONFIG_TERM_DRV_CFG)
continue;
sink = term->val.str;
@ -265,7 +265,8 @@ static int cs_etm_recording_options(struct auxtrace_record *itr,
ptr->evlist = evlist;
ptr->snapshot_mode = opts->auxtrace_snapshot_mode;
if (perf_can_record_switch_events())
if (!record_opts__no_switch_events(opts) &&
perf_can_record_switch_events())
opts->record_switch_events = true;
evlist__for_each_entry(evlist, evsel) {

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
#include "../../util/unwind-libdw.h"
#include "../../util/perf_regs.h"
#include "../../util/event.h"
#include "../../../util/unwind-libdw.h"
#include "../../../util/perf_regs.h"
#include "../../../util/event.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{

View File

@ -2,6 +2,7 @@ perf-y += header.o
perf-y += kvm-stat.o
perf-y += perf_regs.o
perf-y += mem-events.o
perf-y += sym-handling.o
perf-$(CONFIG_DWARF) += dwarf-regs.o
perf-$(CONFIG_DWARF) += skip-callchain-idx.o

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
#include <linux/kernel.h>
#include "../../util/unwind-libdw.h"
#include "../../util/perf_regs.h"
#include "../../util/event.h"
#include "../../../util/unwind-libdw.h"
#include "../../../util/perf_regs.h"
#include "../../../util/event.h"
/* See backends/ppc_initreg.c and backends/ppc_regs.c in elfutils. */
static const int special_regs[3][2] = {

View File

@ -55,6 +55,14 @@ int test__arch_unwind_sample(struct perf_sample *sample,
return -1;
}
#ifdef MEMORY_SANITIZER
/*
* Assignments to buf in the assembly function perf_regs_load aren't
* seen by memory sanitizer. Zero the memory to convince memory
* sanitizer the memory is initialized.
*/
memset(buf, 0, sizeof(u64) * PERF_REGS_MAX);
#endif
perf_regs_load(buf);
regs->abi = PERF_SAMPLE_REGS_ABI;
regs->regs = buf;

View File

@ -59,7 +59,8 @@ struct intel_pt_recording {
size_t priv_size;
};
static int intel_pt_parse_terms_with_default(struct list_head *formats,
static int intel_pt_parse_terms_with_default(const char *pmu_name,
struct list_head *formats,
const char *str,
u64 *config)
{
@ -78,7 +79,8 @@ static int intel_pt_parse_terms_with_default(struct list_head *formats,
goto out_free;
attr.config = *config;
err = perf_pmu__config_terms(formats, &attr, terms, true, NULL);
err = perf_pmu__config_terms(pmu_name, formats, &attr, terms, true,
NULL);
if (err)
goto out_free;
@ -88,11 +90,12 @@ out_free:
return err;
}
static int intel_pt_parse_terms(struct list_head *formats, const char *str,
u64 *config)
static int intel_pt_parse_terms(const char *pmu_name, struct list_head *formats,
const char *str, u64 *config)
{
*config = 0;
return intel_pt_parse_terms_with_default(formats, str, config);
return intel_pt_parse_terms_with_default(pmu_name, formats, str,
config);
}
static u64 intel_pt_masked_bits(u64 mask, u64 bits)
@ -229,7 +232,8 @@ static u64 intel_pt_default_config(struct perf_pmu *intel_pt_pmu)
pr_debug2("%s default config: %s\n", intel_pt_pmu->name, buf);
intel_pt_parse_terms(&intel_pt_pmu->format, buf, &config);
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format, buf,
&config);
return config;
}
@ -337,13 +341,16 @@ static int intel_pt_info_fill(struct auxtrace_record *itr,
if (priv_size != ptr->priv_size)
return -EINVAL;
intel_pt_parse_terms(&intel_pt_pmu->format, "tsc", &tsc_bit);
intel_pt_parse_terms(&intel_pt_pmu->format, "noretcomp",
&noretcomp_bit);
intel_pt_parse_terms(&intel_pt_pmu->format, "mtc", &mtc_bit);
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
"tsc", &tsc_bit);
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
"noretcomp", &noretcomp_bit);
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
"mtc", &mtc_bit);
mtc_freq_bits = perf_pmu__format_bits(&intel_pt_pmu->format,
"mtc_period");
intel_pt_parse_terms(&intel_pt_pmu->format, "cyc", &cyc_bit);
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
"cyc", &cyc_bit);
intel_pt_tsc_ctc_ratio(&tsc_ctc_ratio_n, &tsc_ctc_ratio_d);
@ -556,10 +563,9 @@ static int intel_pt_validate_config(struct perf_pmu *intel_pt_pmu,
static void intel_pt_config_sample_mode(struct perf_pmu *intel_pt_pmu,
struct evsel *evsel)
{
struct perf_evsel_config_term *term;
u64 user_bits = 0, bits;
struct evsel_config_term *term = evsel__get_config_term(evsel, CFG_CHG);
term = perf_evsel__get_config_term(evsel, CFG_CHG);
if (term)
user_bits = term->val.cfg_chg;
@ -769,7 +775,8 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
}
}
intel_pt_parse_terms(&intel_pt_pmu->format, "tsc", &tsc_bit);
intel_pt_parse_terms(intel_pt_pmu->name, &intel_pt_pmu->format,
"tsc", &tsc_bit);
if (opts->full_auxtrace && (intel_pt_evsel->core.attr.config & tsc_bit))
have_timing_info = true;
@ -780,7 +787,8 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
* Per-cpu recording needs sched_switch events to distinguish different
* threads.
*/
if (have_timing_info && !perf_cpu_map__empty(cpus)) {
if (have_timing_info && !perf_cpu_map__empty(cpus) &&
!record_opts__no_switch_events(opts)) {
if (perf_can_record_switch_events()) {
bool cpu_wide = !target__none(&opts->target) &&
!target__has_task(&opts->target);
@ -875,7 +883,8 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
* per-cpu with no sched_switch (except workload-only).
*/
if (!ptr->have_sched_switch && !perf_cpu_map__empty(cpus) &&
!target__none(&opts->target))
!target__none(&opts->target) &&
!intel_pt_evsel->core.attr.exclude_user)
ui__warning("Intel Processor Trace decoding will not be possible except for kernel tracing!\n");
return 0;

View File

@ -1,8 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include <elfutils/libdwfl.h>
#include "../../util/unwind-libdw.h"
#include "../../util/perf_regs.h"
#include "../../util/event.h"
#include "../../../util/unwind-libdw.h"
#include "../../../util/perf_regs.h"
#include "../../../util/event.h"
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
{

View File

@ -5,7 +5,7 @@
* Benchmark the various operations allowed for epoll_ctl(2).
* The idea is to concurrently stress a single epoll instance
*/
#ifdef HAVE_EVENTFD
#ifdef HAVE_EVENTFD_SUPPORT
/* For the CLR_() macros */
#include <string.h>
#include <pthread.h>
@ -412,4 +412,4 @@ int bench_epoll_ctl(int argc, const char **argv)
errmem:
err(EXIT_FAILURE, "calloc");
}
#endif // HAVE_EVENTFD
#endif // HAVE_EVENTFD_SUPPORT

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#ifdef HAVE_EVENTFD
#ifdef HAVE_EVENTFD_SUPPORT
/*
* Copyright (C) 2018 Davidlohr Bueso.
*
@ -540,4 +540,4 @@ int bench_epoll_wait(int argc, const char **argv)
errmem:
err(EXIT_FAILURE, "calloc");
}
#endif // HAVE_EVENTFD
#endif // HAVE_EVENTFD_SUPPORT

View File

@ -40,7 +40,7 @@ struct sender_context {
unsigned int num_fds;
int ready_out;
int wakefd;
int out_fds[0];
int out_fds[];
};
struct receiver_context {

View File

@ -432,7 +432,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
hists__collapse_resort(hists, NULL);
/* Don't sort callchain */
evsel__reset_sample_bit(pos, CALLCHAIN);
perf_evsel__output_resort(pos, NULL);
evsel__output_resort(pos, NULL);
if (symbol_conf.event_group && !evsel__is_group_leader(pos))
continue;

View File

@ -67,14 +67,14 @@ static struct bench futex_benchmarks[] = {
{ NULL, NULL, NULL }
};
#ifdef HAVE_EVENTFD
#ifdef HAVE_EVENTFD_SUPPORT
static struct bench epoll_benchmarks[] = {
{ "wait", "Benchmark epoll concurrent epoll_waits", bench_epoll_wait },
{ "ctl", "Benchmark epoll concurrent epoll_ctls", bench_epoll_ctl },
{ "all", "Run all futex benchmarks", NULL },
{ NULL, NULL, NULL }
};
#endif // HAVE_EVENTFD
#endif // HAVE_EVENTFD_SUPPORT
static struct bench internals_benchmarks[] = {
{ "synthesize", "Benchmark perf event synthesis", bench_synthesize },
@ -95,7 +95,7 @@ static struct collection collections[] = {
{ "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
#endif
{"futex", "Futex stressing benchmarks", futex_benchmarks },
#ifdef HAVE_EVENTFD
#ifdef HAVE_EVENTFD_SUPPORT
{"epoll", "Epoll stressing benchmarks", epoll_benchmarks },
#endif
{ "internals", "Perf-internals benchmarks", internals_benchmarks },

View File

@ -2887,8 +2887,15 @@ static int parse_record_events(const struct option *opt,
{
bool *event_set = (bool *) opt->value;
if (!strcmp(str, "list")) {
perf_mem_events__list();
exit(0);
}
if (perf_mem_events__parse(str))
exit(-1);
*event_set = true;
return perf_mem_events__parse(str);
return 0;
}

View File

@ -34,7 +34,7 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
return PTR_ERR(session);
evlist__for_each_entry(session->evlist, pos) {
perf_evsel__fprintf(pos, details, stdout);
evsel__fprintf(pos, details, stdout);
if (pos->core.attr.type == PERF_TYPE_TRACEPOINT)
has_tracepoint = true;

View File

@ -45,6 +45,7 @@ struct filter_entry {
char name[];
};
static volatile int workload_exec_errno;
static bool done;
static void sig_handler(int sig __maybe_unused)
@ -63,7 +64,7 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
siginfo_t *info __maybe_unused,
void *ucontext __maybe_unused)
{
/* workload_exec_errno = info->si_value.sival_int; */
workload_exec_errno = info->si_value.sival_int;
done = true;
}
@ -383,6 +384,14 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char **argv)
write_tracing_file("tracing_on", "0");
if (workload_exec_errno) {
const char *emsg = str_error_r(workload_exec_errno, buf, sizeof(buf));
/* flush stdout first so below error msg appears at the end. */
fflush(stdout);
pr_err("workload failed: %s\n", emsg);
goto out_close_fd;
}
/* read remaining buffer contents */
while (true) {
int n = read(trace_fd, buf, sizeof(buf));
@ -397,7 +406,7 @@ out_close_fd:
out_reset:
reset_tracing_files(ftrace);
out:
return done ? 0 : -1;
return (done && !workload_exec_errno) ? 0 : -1;
}
static int perf_ftrace_config(const char *var, const char *value, void *cb)
@ -494,7 +503,7 @@ int cmd_ftrace(int argc, const char **argv)
argc = parse_options(argc, argv, ftrace_options, ftrace_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && target__none(&ftrace.target))
usage_with_options(ftrace_usage, ftrace_options);
ftrace.target.system_wide = true;
ret = target__validate(&ftrace.target);
if (ret) {

View File

@ -51,7 +51,7 @@ struct perf_inject {
struct event_entry {
struct list_head node;
u32 tid;
union perf_event event[0];
union perf_event event[];
};
static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)

View File

@ -42,7 +42,7 @@ int cmd_list(int argc, const char **argv)
OPT_END()
};
const char * const list_usage[] = {
"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|event_glob]",
"perf list [<options>] [hw|sw|cache|tracepoint|pmu|sdt|metric|metricgroup|event_glob]",
NULL
};

View File

@ -38,26 +38,16 @@ static int parse_record_events(const struct option *opt,
const char *str, int unset __maybe_unused)
{
struct perf_mem *mem = *(struct perf_mem **)opt->value;
int j;
if (strcmp(str, "list")) {
if (!perf_mem_events__parse(str)) {
mem->operation = 0;
return 0;
}
if (!strcmp(str, "list")) {
perf_mem_events__list();
exit(0);
}
if (perf_mem_events__parse(str))
exit(-1);
}
for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
struct perf_mem_event *e = &perf_mem_events[j];
fprintf(stderr, "%-13s%-*s%s\n",
e->tag,
verbose > 0 ? 25 : 0,
verbose > 0 ? perf_mem_events__name(j) : "",
e->supported ? ": available" : "");
}
exit(0);
mem->operation = 0;
return 0;
}
static const char * const __usage[] = {

View File

@ -364,6 +364,9 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
for (k = 0; k < pev->ntevs; k++) {
struct probe_trace_event *tev = &pev->tevs[k];
/* Skipped events have no event name */
if (!tev->event)
continue;
/* We use tev's name for showing new events */
show_perf_probe_event(tev->group, tev->event, pev,

View File

@ -45,6 +45,7 @@
#include "util/units.h"
#include "util/bpf-event.h"
#include "util/util.h"
#include "util/pfm.h"
#include "asm/bug.h"
#include "perf.h"
@ -56,6 +57,9 @@
#include <unistd.h>
#include <sched.h>
#include <signal.h>
#ifdef HAVE_EVENTFD_SUPPORT
#include <sys/eventfd.h>
#endif
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/types.h>
@ -538,6 +542,9 @@ static int record__pushfn(struct mmap *map, void *to, void *bf, size_t size)
static volatile int signr = -1;
static volatile int child_finished;
#ifdef HAVE_EVENTFD_SUPPORT
static int done_fd = -1;
#endif
static void sig_handler(int sig)
{
@ -547,6 +554,21 @@ static void sig_handler(int sig)
signr = sig;
done = 1;
#ifdef HAVE_EVENTFD_SUPPORT
{
u64 tmp = 1;
/*
* It is possible for this signal handler to run after done is checked
* in the main loop, but before the perf counter fds are polled. If this
* happens, the poll() will continue to wait even though done is set,
* and will only break out if either another signal is received, or the
* counters are ready for read. To ensure the poll() doesn't sleep when
* done is set, use an eventfd (done_fd) to wake up the poll().
*/
if (write(done_fd, &tmp, sizeof(tmp)) < 0)
pr_err("failed to signal wakeup fd, error: %m\n");
}
#endif // HAVE_EVENTFD_SUPPORT
}
static void sigsegv_handler(int sig)
@ -825,19 +847,28 @@ static int record__open(struct record *rec)
int rc = 0;
/*
* For initial_delay we need to add a dummy event so that we can track
* PERF_RECORD_MMAP while we wait for the initial delay to enable the
* real events, the ones asked by the user.
* For initial_delay or system wide, we need to add a dummy event so
* that we can track PERF_RECORD_MMAP to cover the delay of waiting or
* event synthesis.
*/
if (opts->initial_delay) {
if (opts->initial_delay || target__has_cpu(&opts->target)) {
if (perf_evlist__add_dummy(evlist))
return -ENOMEM;
/* Disable tracking of mmaps on lead event. */
pos = evlist__first(evlist);
pos->tracking = 0;
/* Set up dummy event. */
pos = evlist__last(evlist);
pos->tracking = 1;
pos->core.attr.enable_on_exec = 1;
/*
* Enable the dummy event when the process is forked for
* initial_delay, immediately for system wide.
*/
if (opts->initial_delay)
pos->core.attr.enable_on_exec = 1;
else
pos->immediate = 1;
}
perf_evlist__config(evlist, opts, &callchain_param);
@ -1538,6 +1569,20 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
pr_err("Compression initialization failed.\n");
return -1;
}
#ifdef HAVE_EVENTFD_SUPPORT
done_fd = eventfd(0, EFD_NONBLOCK);
if (done_fd < 0) {
pr_err("Failed to create wakeup eventfd, error: %m\n");
status = -1;
goto out_delete_session;
}
err = evlist__add_pollfd(rec->evlist, done_fd);
if (err < 0) {
pr_err("Failed to add wakeup eventfd to poll list\n");
status = err;
goto out_delete_session;
}
#endif // HAVE_EVENTFD_SUPPORT
session->header.env.comp_type = PERF_COMP_ZSTD;
session->header.env.comp_level = rec->opts.comp_level;
@ -1896,6 +1941,10 @@ out_child:
}
out_delete_session:
#ifdef HAVE_EVENTFD_SUPPORT
if (done_fd >= 0)
close(done_fd);
#endif
zstd_fini(&session->zstd_data);
perf_session__delete(session);
@ -2453,8 +2502,9 @@ static struct option __record_options[] = {
"Record namespaces events"),
OPT_BOOLEAN(0, "all-cgroups", &record.opts.record_cgroup,
"Record cgroup events"),
OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
"Record context switch events"),
OPT_BOOLEAN_SET(0, "switch-events", &record.opts.record_switch_events,
&record.opts.record_switch_events_set,
"Record context switch events"),
OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel,
"Configure all used events to run in kernel space.",
PARSE_OPT_EXCLUSIVE),
@ -2506,6 +2556,11 @@ static struct option __record_options[] = {
OPT_UINTEGER(0, "num-thread-synthesize",
&record.opts.nr_threads_synthesize,
"number of threads to run for event synthesis"),
#ifdef HAVE_LIBPFM
OPT_CALLBACK(0, "pfm-events", &record.evlist, "event",
"libpfm4 event selector. use 'perf list' to list available events",
parse_libpfm_events_option),
#endif
OPT_END()
};

View File

@ -47,7 +47,6 @@
#include "util/time-utils.h"
#include "util/auxtrace.h"
#include "util/units.h"
#include "util/branch.h"
#include "util/util.h" // perf_tip()
#include "ui/ui.h"
#include "ui/progress.h"
@ -402,16 +401,7 @@ static int report__setup_sample_type(struct report *rep)
}
}
if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
if ((sample_type & PERF_SAMPLE_REGS_USER) &&
(sample_type & PERF_SAMPLE_STACK_USER)) {
callchain_param.record_mode = CALLCHAIN_DWARF;
dwarf_callchain_users = true;
} else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
callchain_param.record_mode = CALLCHAIN_LBR;
else
callchain_param.record_mode = CALLCHAIN_FP;
}
callchain_param_setup(sample_type);
if (rep->stitch_lbr && (callchain_param.record_mode != CALLCHAIN_LBR)) {
ui__warning("Can't find LBR callchain. Switch off --stitch-lbr.\n"
@ -716,8 +706,7 @@ static void report__output_resort(struct report *rep)
ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
evlist__for_each_entry(rep->session->evlist, pos) {
perf_evsel__output_resort_cb(pos, &prog,
hists__resort_cb, rep);
evsel__output_resort_cb(pos, &prog, hists__resort_cb, rep);
}
ui_progress__finish();
@ -1090,6 +1079,26 @@ parse_percent_limit(const struct option *opt, const char *str,
return 0;
}
static int process_attr(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct evlist **pevlist)
{
u64 sample_type;
int err;
err = perf_event__process_attr(tool, event, pevlist);
if (err)
return err;
/*
* Check if we need to enable callchains based
* on events sample_type.
*/
sample_type = perf_evlist__combined_sample_type(*pevlist);
callchain_param_setup(sample_type);
return 0;
}
int cmd_report(int argc, const char **argv)
{
struct perf_session *session;
@ -1120,7 +1129,7 @@ int cmd_report(int argc, const char **argv)
.fork = perf_event__process_fork,
.lost = perf_event__process_lost,
.read = process_read_event,
.attr = perf_event__process_attr,
.attr = process_attr,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.id_index = perf_event__process_id_index,

View File

@ -167,6 +167,7 @@ static struct {
u64 fields;
u64 invalid_fields;
u64 user_set_fields;
u64 user_unset_fields;
} output[OUTPUT_TYPE_MAX] = {
[PERF_TYPE_HARDWARE] = {
@ -2085,6 +2086,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
struct perf_script *scr = container_of(tool, struct perf_script, tool);
struct evlist *evlist;
struct evsel *evsel, *pos;
u64 sample_type;
int err;
static struct evsel_script *es;
@ -2117,12 +2119,34 @@ static int process_attr(struct perf_tool *tool, union perf_event *event,
return 0;
}
set_print_ip_opts(&evsel->core.attr);
if (evsel->core.attr.sample_type)
if (evsel->core.attr.sample_type) {
err = perf_evsel__check_attr(evsel, scr->session);
if (err)
return err;
}
return err;
/*
* Check if we need to enable callchains based
* on events sample_type.
*/
sample_type = perf_evlist__combined_sample_type(evlist);
callchain_param_setup(sample_type);
/* Enable fields for callchain entries */
if (symbol_conf.use_callchain &&
(sample_type & PERF_SAMPLE_CALLCHAIN ||
sample_type & PERF_SAMPLE_BRANCH_STACK ||
(sample_type & PERF_SAMPLE_REGS_USER &&
sample_type & PERF_SAMPLE_STACK_USER))) {
int type = output_type(evsel->core.attr.type);
if (!(output[type].user_unset_fields & PERF_OUTPUT_IP))
output[type].fields |= PERF_OUTPUT_IP;
if (!(output[type].user_unset_fields & PERF_OUTPUT_SYM))
output[type].fields |= PERF_OUTPUT_SYM;
}
set_print_ip_opts(&evsel->core.attr);
return 0;
}
static int print_event_with_time(struct perf_tool *tool,
@ -2434,7 +2458,7 @@ static int __cmd_script(struct perf_script *script)
struct script_spec {
struct list_head node;
struct scripting_ops *ops;
char spec[0];
char spec[];
};
static LIST_HEAD(script_specs);
@ -2672,9 +2696,11 @@ parse:
if (change == REMOVE) {
output[j].fields &= ~all_output_options[i].field;
output[j].user_set_fields &= ~all_output_options[i].field;
output[j].user_unset_fields |= all_output_options[i].field;
} else {
output[j].fields |= all_output_options[i].field;
output[j].user_set_fields |= all_output_options[i].field;
output[j].user_unset_fields &= ~all_output_options[i].field;
}
output[j].user_set = true;
output[j].wildcard_set = true;
@ -3286,7 +3312,10 @@ static int parse_xed(const struct option *opt __maybe_unused,
const char *str __maybe_unused,
int unset __maybe_unused)
{
force_pager("xed -F insn: -A -64 | less");
if (isatty(1))
force_pager("xed -F insn: -A -64 | less");
else
force_pager("xed -F insn: -A -64");
return 0;
}

View File

@ -66,6 +66,7 @@
#include "util/time-utils.h"
#include "util/top.h"
#include "util/affinity.h"
#include "util/pfm.h"
#include "asm/bug.h"
#include <linux/time64.h>
@ -189,6 +190,59 @@ static struct perf_stat_config stat_config = {
.big_num = true,
};
static bool cpus_map_matched(struct evsel *a, struct evsel *b)
{
if (!a->core.cpus && !b->core.cpus)
return true;
if (!a->core.cpus || !b->core.cpus)
return false;
if (a->core.cpus->nr != b->core.cpus->nr)
return false;
for (int i = 0; i < a->core.cpus->nr; i++) {
if (a->core.cpus->map[i] != b->core.cpus->map[i])
return false;
}
return true;
}
static void evlist__check_cpu_maps(struct evlist *evlist)
{
struct evsel *evsel, *pos, *leader;
char buf[1024];
evlist__for_each_entry(evlist, evsel) {
leader = evsel->leader;
/* Check that leader matches cpus with each member. */
if (leader == evsel)
continue;
if (cpus_map_matched(leader, evsel))
continue;
/* If there's mismatch disable the group and warn user. */
WARN_ONCE(1, "WARNING: grouped events cpus do not match, disabling group:\n");
evsel__group_desc(leader, buf, sizeof(buf));
pr_warning(" %s\n", buf);
if (verbose) {
cpu_map__snprint(leader->core.cpus, buf, sizeof(buf));
pr_warning(" %s: %s\n", leader->name, buf);
cpu_map__snprint(evsel->core.cpus, buf, sizeof(buf));
pr_warning(" %s: %s\n", evsel->name, buf);
}
for_each_group_evsel(pos, leader) {
pos->leader = pos;
pos->core.nr_members = 0;
}
evsel->leader->core.nr_members = 0;
}
}
static inline void diff_timespec(struct timespec *r, struct timespec *a,
struct timespec *b)
{
@ -314,14 +368,14 @@ static int read_counter_cpu(struct evsel *counter, struct timespec *rs, int cpu)
return 0;
}
static void read_counters(struct timespec *rs)
static int read_affinity_counters(struct timespec *rs)
{
struct evsel *counter;
struct affinity affinity;
int i, ncpus, cpu;
if (affinity__setup(&affinity) < 0)
return;
return -1;
ncpus = perf_cpu_map__nr(evsel_list->core.all_cpus);
if (!target__has_cpu(&target) || target__has_per_thread(&target))
@ -341,6 +395,15 @@ static void read_counters(struct timespec *rs)
}
}
affinity__cleanup(&affinity);
return 0;
}
static void read_counters(struct timespec *rs)
{
struct evsel *counter;
if (!stat_config.summary && (read_affinity_counters(rs) < 0))
return;
evlist__for_each_entry(evsel_list, counter) {
if (counter->err)
@ -351,6 +414,46 @@ static void read_counters(struct timespec *rs)
}
}
static int runtime_stat_new(struct perf_stat_config *config, int nthreads)
{
int i;
config->stats = calloc(nthreads, sizeof(struct runtime_stat));
if (!config->stats)
return -1;
config->stats_num = nthreads;
for (i = 0; i < nthreads; i++)
runtime_stat__init(&config->stats[i]);
return 0;
}
static void runtime_stat_delete(struct perf_stat_config *config)
{
int i;
if (!config->stats)
return;
for (i = 0; i < config->stats_num; i++)
runtime_stat__exit(&config->stats[i]);
zfree(&config->stats);
}
static void runtime_stat_reset(struct perf_stat_config *config)
{
int i;
if (!config->stats)
return;
for (i = 0; i < config->stats_num; i++)
perf_stat__reset_shadow_per_stat(&config->stats[i]);
}
static void process_interval(void)
{
struct timespec ts, rs;
@ -359,6 +462,7 @@ static void process_interval(void)
diff_timespec(&rs, &ts, &ref_time);
perf_stat__reset_shadow_per_stat(&rt_stat);
runtime_stat_reset(&stat_config);
read_counters(&rs);
if (STAT_RECORD) {
@ -367,7 +471,7 @@ static void process_interval(void)
}
init_stats(&walltime_nsecs_stats);
update_stats(&walltime_nsecs_stats, stat_config.interval * 1000000);
update_stats(&walltime_nsecs_stats, stat_config.interval * 1000000ULL);
print_counters(&rs, 0, NULL);
}
@ -722,7 +826,21 @@ try_again_reset:
if (stat_config.walltime_run_table)
stat_config.walltime_run[run_idx] = t1 - t0;
update_stats(&walltime_nsecs_stats, t1 - t0);
if (interval) {
stat_config.interval = 0;
stat_config.summary = true;
init_stats(&walltime_nsecs_stats);
update_stats(&walltime_nsecs_stats, t1 - t0);
if (stat_config.aggr_mode == AGGR_GLOBAL)
perf_evlist__save_aggr_prev_raw_counts(evsel_list);
perf_evlist__copy_prev_raw_counts(evsel_list);
perf_evlist__reset_prev_raw_counts(evsel_list);
runtime_stat_reset(&stat_config);
perf_stat__reset_shadow_per_stat(&rt_stat);
} else
update_stats(&walltime_nsecs_stats, t1 - t0);
/*
* Closing a group leader splits the group, and as we only disable
@ -821,10 +939,16 @@ static void sig_atexit(void)
kill(getpid(), signr);
}
void perf_stat__set_big_num(int set)
{
stat_config.big_num = (set != 0);
}
static int stat__set_big_num(const struct option *opt __maybe_unused,
const char *s __maybe_unused, int unset)
{
big_num_opt = unset ? 0 : 1;
perf_stat__set_big_num(!unset);
return 0;
}
@ -840,7 +964,10 @@ static int parse_metric_groups(const struct option *opt,
const char *str,
int unset __maybe_unused)
{
return metricgroup__parse_groups(opt, str, &stat_config.metric_events);
return metricgroup__parse_groups(opt, str,
stat_config.metric_no_group,
stat_config.metric_no_merge,
&stat_config.metric_events);
}
static struct option stat_options[] = {
@ -918,6 +1045,10 @@ static struct option stat_options[] = {
"ms to wait before starting measurement after program start"),
OPT_CALLBACK_NOOPT(0, "metric-only", &stat_config.metric_only, NULL,
"Only print computed metrics. No raw values", enable_metric_only),
OPT_BOOLEAN(0, "metric-no-group", &stat_config.metric_no_group,
"don't group metric events, impacts multiplexing"),
OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge,
"don't try to share events between metrics in a group"),
OPT_BOOLEAN(0, "topdown", &topdown_run,
"measure topdown level 1 statistics"),
OPT_BOOLEAN(0, "smi-cost", &smi_cost,
@ -935,6 +1066,11 @@ static struct option stat_options[] = {
"Use with 'percore' event qualifier to show the event "
"counts of one hardware thread by sum up total hardware "
"threads of same physical core"),
#ifdef HAVE_LIBPFM
OPT_CALLBACK(0, "pfm-events", &evsel_list, "event",
"libpfm4 event selector. use 'perf list' to list available events",
parse_libpfm_events_option),
#endif
OPT_END()
};
@ -1442,6 +1578,8 @@ static int add_default_attributes(void)
struct option opt = { .value = &evsel_list };
return metricgroup__parse_groups(&opt, "transaction",
stat_config.metric_no_group,
stat_config.metric_no_merge,
&stat_config.metric_events);
}
@ -1737,35 +1875,6 @@ int process_cpu_map_event(struct perf_session *session,
return set_maps(st);
}
static int runtime_stat_new(struct perf_stat_config *config, int nthreads)
{
int i;
config->stats = calloc(nthreads, sizeof(struct runtime_stat));
if (!config->stats)
return -1;
config->stats_num = nthreads;
for (i = 0; i < nthreads; i++)
runtime_stat__init(&config->stats[i]);
return 0;
}
static void runtime_stat_delete(struct perf_stat_config *config)
{
int i;
if (!config->stats)
return;
for (i = 0; i < config->stats_num; i++)
runtime_stat__exit(&config->stats[i]);
zfree(&config->stats);
}
static const char * const stat_report_usage[] = {
"perf stat report [<options>]",
NULL,
@ -2057,6 +2166,8 @@ int cmd_stat(int argc, const char **argv)
goto out;
}
evlist__check_cpu_maps(evsel_list);
/*
* Initialize thread_map with comm names,
* so we could print it out on output.
@ -2147,7 +2258,7 @@ int cmd_stat(int argc, const char **argv)
}
}
if (!forever && status != -1 && !interval)
if (!forever && status != -1 && (!interval || stat_config.summary))
print_counters(NULL, argc, argv);
if (STAT_RECORD) {

View File

@ -128,7 +128,7 @@ struct sample_wrapper {
struct sample_wrapper *next;
u64 timestamp;
unsigned char data[0];
unsigned char data[];
};
#define TYPE_NONE 0

View File

@ -53,6 +53,7 @@
#include "util/debug.h"
#include "util/ordered-events.h"
#include "util/pfm.h"
#include <assert.h>
#include <elf.h>
@ -307,7 +308,7 @@ static void perf_top__resort_hists(struct perf_top *t)
}
evlist__for_each_entry(evlist, pos) {
perf_evsel__output_resort(pos, NULL);
evsel__output_resort(pos, NULL);
}
}
@ -949,7 +950,7 @@ static int perf_top__overwrite_check(struct perf_top *top)
{
struct record_opts *opts = &top->record_opts;
struct evlist *evlist = top->evlist;
struct perf_evsel_config_term *term;
struct evsel_config_term *term;
struct list_head *config_terms;
struct evsel *evsel;
int set, overwrite = -1;
@ -958,7 +959,7 @@ static int perf_top__overwrite_check(struct perf_top *top)
set = -1;
config_terms = &evsel->config_terms;
list_for_each_entry(term, config_terms, list) {
if (term->type == PERF_EVSEL__CONFIG_TERM_OVERWRITE)
if (term->type == EVSEL__CONFIG_TERM_OVERWRITE)
set = term->val.overwrite ? 1 : 0;
}
@ -1575,6 +1576,11 @@ int cmd_top(int argc, const char **argv)
"WARNING: should be used on grouped events."),
OPT_BOOLEAN(0, "stitch-lbr", &top.stitch_lbr,
"Enable LBR callgraph stitching approach"),
#ifdef HAVE_LIBPFM
OPT_CALLBACK(0, "pfm-events", &top.evlist, "event",
"libpfm4 event selector. use 'perf list' to list available events",
parse_libpfm_events_option),
#endif
OPTS_EVSWITCH(&top.evswitch),
OPT_END()
};

View File

@ -461,11 +461,11 @@ static int evsel__init_raw_syscall_tp(struct evsel *evsel, void *handler)
static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
{
struct evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
struct evsel *evsel = evsel__newtp("raw_syscalls", direction);
/* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
if (IS_ERR(evsel))
evsel = perf_evsel__newtp("syscalls", direction);
evsel = evsel__newtp("syscalls", direction);
if (IS_ERR(evsel))
return NULL;
@ -1748,12 +1748,26 @@ static int trace__read_syscall_info(struct trace *trace, int id)
struct syscall *sc;
const char *name = syscalltbl__name(trace->sctbl, id);
#ifdef HAVE_SYSCALL_TABLE_SUPPORT
if (trace->syscalls.table == NULL) {
trace->syscalls.table = calloc(trace->sctbl->syscalls.max_id + 1, sizeof(*sc));
if (trace->syscalls.table == NULL)
return -ENOMEM;
}
#else
if (id > trace->sctbl->syscalls.max_id || (id == 0 && trace->syscalls.table == NULL)) {
// When using libaudit we don't know beforehand what is the max syscall id
struct syscall *table = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
if (table == NULL)
return -ENOMEM;
memset(table + trace->sctbl->syscalls.max_id, 0, (id - trace->sctbl->syscalls.max_id) * sizeof(*sc));
trace->syscalls.table = table;
trace->sctbl->syscalls.max_id = id;
}
#endif
sc = trace->syscalls.table + id;
if (sc->nonexistent)
return 0;
@ -2077,8 +2091,20 @@ static struct syscall *trace__syscall_info(struct trace *trace,
err = -EINVAL;
if (id > trace->sctbl->syscalls.max_id)
#ifdef HAVE_SYSCALL_TABLE_SUPPORT
if (id > trace->sctbl->syscalls.max_id) {
#else
if (id >= trace->sctbl->syscalls.max_id) {
/*
* With libaudit we don't know beforehand what is the max_id,
* so we let trace__read_syscall_info() figure that out as we
* go on reading syscalls.
*/
err = trace__read_syscall_info(trace, id);
if (err)
#endif
goto out_cant_read;
}
if ((trace->syscalls.table == NULL || trace->syscalls.table[id].name == NULL) &&
(err = trace__read_syscall_info(trace, id)) != 0)
@ -3045,7 +3071,7 @@ static bool evlist__add_vfs_getname(struct evlist *evlist)
return found;
}
static struct evsel *perf_evsel__new_pgfault(u64 config)
static struct evsel *evsel__new_pgfault(u64 config)
{
struct evsel *evsel;
struct perf_event_attr attr = {
@ -3174,6 +3200,26 @@ out_enomem:
}
#ifdef HAVE_LIBBPF_SUPPORT
static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace, const char *name)
{
if (trace->bpf_obj == NULL)
return NULL;
return bpf_object__find_map_by_name(trace->bpf_obj, name);
}
static void trace__set_bpf_map_filtered_pids(struct trace *trace)
{
trace->filter_pids.map = trace__find_bpf_map_by_name(trace, "pids_filtered");
}
static void trace__set_bpf_map_syscalls(struct trace *trace)
{
trace->syscalls.map = trace__find_bpf_map_by_name(trace, "syscalls");
trace->syscalls.prog_array.sys_enter = trace__find_bpf_map_by_name(trace, "syscalls_sys_enter");
trace->syscalls.prog_array.sys_exit = trace__find_bpf_map_by_name(trace, "syscalls_sys_exit");
}
static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace, const char *name)
{
if (trace->bpf_obj == NULL)
@ -3512,6 +3558,20 @@ static void trace__delete_augmented_syscalls(struct trace *trace)
trace->bpf_obj = NULL;
}
#else // HAVE_LIBBPF_SUPPORT
static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace __maybe_unused,
const char *name __maybe_unused)
{
return NULL;
}
static void trace__set_bpf_map_filtered_pids(struct trace *trace __maybe_unused)
{
}
static void trace__set_bpf_map_syscalls(struct trace *trace __maybe_unused)
{
}
static int trace__set_ev_qualifier_bpf_filter(struct trace *trace __maybe_unused)
{
return 0;
@ -3841,7 +3901,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
}
if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
pgfault_maj = evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
if (pgfault_maj == NULL)
goto out_error_mem;
evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
@ -3849,7 +3909,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
}
if ((trace->trace_pgfaults & TRACE_PFMIN)) {
pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
pgfault_min = evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
if (pgfault_min == NULL)
goto out_error_mem;
evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
@ -4600,26 +4660,6 @@ static int trace__parse_cgroups(const struct option *opt, const char *str, int u
return 0;
}
static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace, const char *name)
{
if (trace->bpf_obj == NULL)
return NULL;
return bpf_object__find_map_by_name(trace->bpf_obj, name);
}
static void trace__set_bpf_map_filtered_pids(struct trace *trace)
{
trace->filter_pids.map = trace__find_bpf_map_by_name(trace, "pids_filtered");
}
static void trace__set_bpf_map_syscalls(struct trace *trace)
{
trace->syscalls.map = trace__find_bpf_map_by_name(trace, "syscalls");
trace->syscalls.prog_array.sys_enter = trace__find_bpf_map_by_name(trace, "syscalls_sys_enter");
trace->syscalls.prog_array.sys_exit = trace__find_bpf_map_by_name(trace, "syscalls_sys_exit");
}
static int trace__config(const char *var, const char *value, void *arg)
{
struct trace *trace = arg;

View File

@ -128,4 +128,8 @@ check arch/x86/lib/insn.c '-I "^#include [\"<]\(../include/\)*asm/in
# diff non-symmetric files
check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl
# check duplicated library files
check_2 tools/perf/util/hashmap.h tools/lib/bpf/hashmap.h
check_2 tools/perf/util/hashmap.c tools/lib/bpf/hashmap.c
cd tools/perf

View File

@ -32,34 +32,41 @@ static void print_error(jvmtiEnv *jvmti, const char *msg, jvmtiError ret)
#ifdef HAVE_JVMTI_CMLR
static jvmtiError
do_get_line_numbers(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
jvmti_line_info_t *tab, jint *nr)
do_get_line_number(jvmtiEnv *jvmti, void *pc, jmethodID m, jint bci,
jvmti_line_info_t *tab)
{
jint i, lines = 0;
jint nr_lines = 0;
jint i, nr_lines = 0;
jvmtiLineNumberEntry *loc_tab = NULL;
jvmtiError ret;
jint src_line = -1;
ret = (*jvmti)->GetLineNumberTable(jvmti, m, &nr_lines, &loc_tab);
if (ret != JVMTI_ERROR_NONE) {
if (ret == JVMTI_ERROR_ABSENT_INFORMATION || ret == JVMTI_ERROR_NATIVE_METHOD) {
/* No debug information for this method */
return ret;
} else if (ret != JVMTI_ERROR_NONE) {
print_error(jvmti, "GetLineNumberTable", ret);
return ret;
}
for (i = 0; i < nr_lines; i++) {
if (loc_tab[i].start_location < bci) {
tab[lines].pc = (unsigned long)pc;
tab[lines].line_number = loc_tab[i].line_number;
tab[lines].discrim = 0; /* not yet used */
tab[lines].methodID = m;
lines++;
} else {
break;
}
for (i = 0; i < nr_lines && loc_tab[i].start_location <= bci; i++) {
src_line = i;
}
if (src_line != -1) {
tab->pc = (unsigned long)pc;
tab->line_number = loc_tab[src_line].line_number;
tab->discrim = 0; /* not yet used */
tab->methodID = m;
ret = JVMTI_ERROR_NONE;
} else {
ret = JVMTI_ERROR_ABSENT_INFORMATION;
}
(*jvmti)->Deallocate(jvmti, (unsigned char *)loc_tab);
*nr = lines;
return JVMTI_ERROR_NONE;
return ret;
}
static jvmtiError
@ -67,9 +74,8 @@ get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **
{
const jvmtiCompiledMethodLoadRecordHeader *hdr;
jvmtiCompiledMethodLoadInlineRecord *rec;
jvmtiLineNumberEntry *lne = NULL;
PCStackInfo *c;
jint nr, ret;
jint ret;
int nr_total = 0;
int i, lines_total = 0;
@ -82,21 +88,7 @@ get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **
for (hdr = compile_info; hdr != NULL; hdr = hdr->next) {
if (hdr->kind == JVMTI_CMLR_INLINE_INFO) {
rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
for (i = 0; i < rec->numpcs; i++) {
c = rec->pcinfo + i;
nr = 0;
/*
* unfortunately, need a tab to get the number of lines!
*/
ret = (*jvmti)->GetLineNumberTable(jvmti, c->methods[0], &nr, &lne);
if (ret == JVMTI_ERROR_NONE) {
/* free what was allocated for nothing */
(*jvmti)->Deallocate(jvmti, (unsigned char *)lne);
nr_total += (int)nr;
} else {
print_error(jvmti, "GetLineNumberTable", ret);
}
}
nr_total += rec->numpcs;
}
}
@ -115,14 +107,17 @@ get_line_numbers(jvmtiEnv *jvmti, const void *compile_info, jvmti_line_info_t **
rec = (jvmtiCompiledMethodLoadInlineRecord *)hdr;
for (i = 0; i < rec->numpcs; i++) {
c = rec->pcinfo + i;
nr = 0;
ret = do_get_line_numbers(jvmti, c->pc,
c->methods[0],
c->bcis[0],
*tab + lines_total,
&nr);
/*
* c->methods is the stack of inlined method calls
* at c->pc. [0] is the leaf method. Caller frames
* are ignored at the moment.
*/
ret = do_get_line_number(jvmti, c->pc,
c->methods[0],
c->bcis[0],
*tab + lines_total);
if (ret == JVMTI_ERROR_NONE)
lines_total += nr;
lines_total++;
}
}
}
@ -246,8 +241,6 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
char *class_sign = NULL;
char *func_name = NULL;
char *func_sign = NULL;
char *file_name = NULL;
char fn[PATH_MAX];
uint64_t addr = (uint64_t)(uintptr_t)code_addr;
jvmtiError ret;
int nr_lines = 0; /* in line_tab[] */
@ -264,7 +257,9 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
if (has_line_numbers && map && map_length) {
ret = get_line_numbers(jvmti, compile_info, &line_tab, &nr_lines);
if (ret != JVMTI_ERROR_NONE) {
warnx("jvmti: cannot get line table for method");
if (ret != JVMTI_ERROR_NOT_FOUND) {
warnx("jvmti: cannot get line table for method");
}
nr_lines = 0;
} else if (nr_lines > 0) {
line_file_names = malloc(sizeof(char*) * nr_lines);
@ -282,12 +277,6 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
}
}
ret = (*jvmti)->GetSourceFileName(jvmti, decl_class, &file_name);
if (ret != JVMTI_ERROR_NONE) {
print_error(jvmti, "GetSourceFileName", ret);
goto error;
}
ret = (*jvmti)->GetClassSignature(jvmti, decl_class,
&class_sign, NULL);
if (ret != JVMTI_ERROR_NONE) {
@ -302,8 +291,6 @@ compiled_method_load_cb(jvmtiEnv *jvmti,
goto error;
}
copy_class_filename(class_sign, file_name, fn, PATH_MAX);
/*
* write source line info record if we have it
*/
@ -323,7 +310,6 @@ error:
(*jvmti)->Deallocate(jvmti, (unsigned char *)func_name);
(*jvmti)->Deallocate(jvmti, (unsigned char *)func_sign);
(*jvmti)->Deallocate(jvmti, (unsigned char *)class_sign);
(*jvmti)->Deallocate(jvmti, (unsigned char *)file_name);
free(line_tab);
while (line_file_names && (nr_lines > 0)) {
if (line_file_names[nr_lines - 1]) {

View File

@ -169,7 +169,7 @@
},
{
"BriefDescription": "Cycles GCT empty where dispatch was held",
"MetricExpr": "(PM_GCT_NOSLOT_DISP_HELD_MAP + PM_GCT_NOSLOT_DISP_HELD_SRQ + PM_GCT_NOSLOT_DISP_HELD_ISSQ + PM_GCT_NOSLOT_DISP_HELD_OTHER) / PM_RUN_INST_CMPL)",
"MetricExpr": "(PM_GCT_NOSLOT_DISP_HELD_MAP + PM_GCT_NOSLOT_DISP_HELD_SRQ + PM_GCT_NOSLOT_DISP_HELD_ISSQ + PM_GCT_NOSLOT_DISP_HELD_OTHER) / PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "gct_empty_disp_held_cpi"
},

View File

@ -207,6 +207,84 @@
"MetricGroup": "cpi_breakdown",
"MetricName": "fxu_stall_cpi"
},
{
"BriefDescription": "Instruction Completion Table empty for this thread due to branch mispred",
"MetricExpr": "PM_ICT_NOSLOT_BR_MPRED/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_br_mpred_cpi"
},
{
"BriefDescription": "Instruction Completion Table empty for this thread due to Icache Miss and branch mispred",
"MetricExpr": "PM_ICT_NOSLOT_BR_MPRED_ICMISS/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_br_mpred_icmiss_cpi"
},
{
"BriefDescription": "Instruction Completion Table other stalls",
"MetricExpr": "(PM_ICT_NOSLOT_CYC - PM_ICT_NOSLOT_IC_MISS - PM_ICT_NOSLOT_BR_MPRED_ICMISS - PM_ICT_NOSLOT_BR_MPRED - PM_ICT_NOSLOT_DISP_HELD)/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_cyc_other_cpi"
},
{
"BriefDescription": "Cycles in which the NTC instruciton is held at dispatch for any reason",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_disp_held_cpi"
},
{
"BriefDescription": "Instruction Completion Table empty for this thread due to dispatch holds because the History Buffer was full. Could be GPR/VSR/VMR/FPR/CR/XVF",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_HB_FULL/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_disp_held_hb_full_cpi"
},
{
"BriefDescription": "Instruction Completion Table empty for this thread due to dispatch hold on this thread due to Issue q full, BRQ full, XVCF Full, Count cache, Link, Tar full",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_ISSQ/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_disp_held_issq_cpi"
},
{
"BriefDescription": "ICT_NOSLOT_DISP_HELD_OTHER_CPI",
"MetricExpr": "(PM_ICT_NOSLOT_DISP_HELD - PM_ICT_NOSLOT_DISP_HELD_HB_FULL - PM_ICT_NOSLOT_DISP_HELD_SYNC - PM_ICT_NOSLOT_DISP_HELD_TBEGIN - PM_ICT_NOSLOT_DISP_HELD_ISSQ)/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_disp_held_other_cpi"
},
{
"BriefDescription": "Dispatch held due to a synchronizing instruction at dispatch",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_SYNC/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_disp_held_sync_cpi"
},
{
"BriefDescription": "the NTC instruction is being held at dispatch because it is a tbegin instruction and there is an older tbegin in the pipeline that must complete before the younger tbegin can dispatch",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_TBEGIN/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_disp_held_tbegin_cpi"
},
{
"BriefDescription": "ICT_NOSLOT_IC_L2_CPI",
"MetricExpr": "(PM_ICT_NOSLOT_IC_MISS - PM_ICT_NOSLOT_IC_L3 - PM_ICT_NOSLOT_IC_L3MISS)/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_ic_l2_cpi"
},
{
"BriefDescription": "Instruction Completion Table empty for this thread due to icache misses that were sourced from the local L3",
"MetricExpr": "PM_ICT_NOSLOT_IC_L3/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_ic_l3_cpi"
},
{
"BriefDescription": "Instruction Completion Table empty for this thread due to icache misses that were sourced from beyond the local L3. The source could be local/remote/distant memory or another core's cache",
"MetricExpr": "PM_ICT_NOSLOT_IC_L3MISS/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_ic_l3miss_cpi"
},
{
"BriefDescription": "Instruction Completion Table empty for this thread due to Icache Miss",
"MetricExpr": "PM_ICT_NOSLOT_IC_MISS/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "ict_noslot_ic_miss_cpi"
},
{
"MetricExpr": "(PM_NTC_ISSUE_HELD_DARQ_FULL + PM_NTC_ISSUE_HELD_ARB + PM_NTC_ISSUE_HELD_OTHER)/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
@ -313,7 +391,7 @@
"MetricName": "nested_tend_stall_cpi"
},
{
"BriefDescription": "Number of cycles the ICT has no itags assigned to this thread",
"BriefDescription": "Number of cycles the Instruction Completion Table has no itags assigned to this thread",
"MetricExpr": "PM_ICT_NOSLOT_CYC/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "nothing_dispatched_cpi"
@ -362,7 +440,7 @@
},
{
"BriefDescription": "Completion stall for other reasons",
"MetricExpr": "PM_CMPLU_STALL - PM_CMPLU_STALL_NTC_DISP_FIN - PM_CMPLU_STALL_NTC_FLUSH - PM_CMPLU_STALL_LSU - PM_CMPLU_STALL_EXEC_UNIT - PM_CMPLU_STALL_BRU)/PM_RUN_INST_CMPL",
"MetricExpr": "(PM_CMPLU_STALL - PM_CMPLU_STALL_NTC_DISP_FIN - PM_CMPLU_STALL_NTC_FLUSH - PM_CMPLU_STALL_LSU - PM_CMPLU_STALL_EXEC_UNIT - PM_CMPLU_STALL_BRU)/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "other_stall_cpi"
},
@ -425,7 +503,7 @@
"MetricName": "st_fwd_stall_cpi"
},
{
"BriefDescription": "Nothing completed and ICT not empty",
"BriefDescription": "Nothing completed and Instruction Completion Table not empty",
"MetricExpr": "PM_CMPLU_STALL/PM_RUN_INST_CMPL",
"MetricGroup": "cpi_breakdown",
"MetricName": "stall_cpi"
@ -1819,71 +1897,6 @@
"MetricExpr": "PM_FXU_IDLE / PM_CYC",
"MetricName": "fxu_all_idle"
},
{
"BriefDescription": "Ict empty for this thread due to branch mispred",
"MetricExpr": "PM_ICT_NOSLOT_BR_MPRED/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_br_mpred_cpi"
},
{
"BriefDescription": "Ict empty for this thread due to Icache Miss and branch mispred",
"MetricExpr": "PM_ICT_NOSLOT_BR_MPRED_ICMISS/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_br_mpred_icmiss_cpi"
},
{
"BriefDescription": "ICT other stalls",
"MetricExpr": "(PM_ICT_NOSLOT_CYC - PM_ICT_NOSLOT_IC_MISS - PM_ICT_NOSLOT_BR_MPRED_ICMISS - PM_ICT_NOSLOT_BR_MPRED - PM_ICT_NOSLOT_DISP_HELD)/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_cyc_other_cpi"
},
{
"BriefDescription": "Cycles in which the NTC instruciton is held at dispatch for any reason",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_disp_held_cpi"
},
{
"BriefDescription": "Ict empty for this thread due to dispatch holds because the History Buffer was full. Could be GPR/VSR/VMR/FPR/CR/XVF",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_HB_FULL/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_disp_held_hb_full_cpi"
},
{
"BriefDescription": "Ict empty for this thread due to dispatch hold on this thread due to Issue q full, BRQ full, XVCF Full, Count cache, Link, Tar full",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_ISSQ/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_disp_held_issq_cpi"
},
{
"BriefDescription": "ICT_NOSLOT_DISP_HELD_OTHER_CPI",
"MetricExpr": "(PM_ICT_NOSLOT_DISP_HELD - PM_ICT_NOSLOT_DISP_HELD_HB_FULL - PM_ICT_NOSLOT_DISP_HELD_SYNC - PM_ICT_NOSLOT_DISP_HELD_TBEGIN - PM_ICT_NOSLOT_DISP_HELD_ISSQ)/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_disp_held_other_cpi"
},
{
"BriefDescription": "Dispatch held due to a synchronizing instruction at dispatch",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_SYNC/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_disp_held_sync_cpi"
},
{
"BriefDescription": "the NTC instruction is being held at dispatch because it is a tbegin instruction and there is an older tbegin in the pipeline that must complete before the younger tbegin can dispatch",
"MetricExpr": "PM_ICT_NOSLOT_DISP_HELD_TBEGIN/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_disp_held_tbegin_cpi"
},
{
"BriefDescription": "ICT_NOSLOT_IC_L2_CPI",
"MetricExpr": "(PM_ICT_NOSLOT_IC_MISS - PM_ICT_NOSLOT_IC_L3 - PM_ICT_NOSLOT_IC_L3MISS)/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_ic_l2_cpi"
},
{
"BriefDescription": "Ict empty for this thread due to icache misses that were sourced from the local L3",
"MetricExpr": "PM_ICT_NOSLOT_IC_L3/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_ic_l3_cpi"
},
{
"BriefDescription": "Ict empty for this thread due to icache misses that were sourced from beyond the local L3. The source could be local/remote/distant memory or another core's cache",
"MetricExpr": "PM_ICT_NOSLOT_IC_L3MISS/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_ic_l3miss_cpi"
},
{
"BriefDescription": "Ict empty for this thread due to Icache Miss",
"MetricExpr": "PM_ICT_NOSLOT_IC_MISS/PM_RUN_INST_CMPL",
"MetricName": "ict_noslot_ic_miss_cpi"
},
{
"BriefDescription": "Rate of IERAT reloads from L2",
"MetricExpr": "PM_IPTEG_FROM_L2 * 100 / PM_RUN_INST_CMPL",

View File

@ -328,31 +328,31 @@
},
{
"BriefDescription": "Average latency of data read request to external memory (in nanoseconds). Accounts for demand loads and L1/L2 prefetches",
"MetricExpr": "1000000000 * ( cha@event\\=0x36\\\\\\,umask\\=0x21@ / cha@event\\=0x35\\\\\\,umask\\=0x21@ ) / ( cha_0@event\\=0x0@ / duration_time )",
"MetricExpr": "1000000000 * ( cha@event\\=0x36\\,umask\\=0x21@ / cha@event\\=0x35\\,umask\\=0x21@ ) / ( cha_0@event\\=0x0@ / duration_time )",
"MetricGroup": "Memory_Lat",
"MetricName": "DRAM_Read_Latency"
},
{
"BriefDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches",
"MetricExpr": "cha@event\\=0x36\\\\\\,umask\\=0x21@ / cha@event\\=0x36\\\\\\,umask\\=0x21\\\\\\,thresh\\=1@",
"MetricExpr": "cha@event\\=0x36\\,umask\\=0x21@ / cha@event\\=0x36\\,umask\\=0x21\\,thresh\\=1@",
"MetricGroup": "Memory_BW",
"MetricName": "DRAM_Parallel_Reads"
},
{
"BriefDescription": "Average latency of data read request to external 3D X-Point memory [in nanoseconds]. Accounts for demand loads and L1/L2 data-read prefetches",
"MetricExpr": "( 1000000000 * ( imc@event\\=0xe0\\\\\\,umask\\=0x1@ / imc@event\\=0xe3@ ) / imc_0@event\\=0x0@ ) if 1 if 0 == 1 else 0 else 0",
"MetricExpr": "( 1000000000 * ( imc@event\\=0xe0\\,umask\\=0x1@ / imc@event\\=0xe3@ ) / imc_0@event\\=0x0@ )",
"MetricGroup": "Memory_Lat",
"MetricName": "MEM_PMM_Read_Latency"
},
{
"BriefDescription": "Average 3DXP Memory Bandwidth Use for reads [GB / sec]",
"MetricExpr": "( ( 64 * imc@event\\=0xe3@ / 1000000000 ) / duration_time ) if 1 if 0 == 1 else 0 else 0",
"MetricExpr": "( ( 64 * imc@event\\=0xe3@ / 1000000000 ) / duration_time )",
"MetricGroup": "Memory_BW",
"MetricName": "PMM_Read_BW"
},
{
"BriefDescription": "Average 3DXP Memory Bandwidth Use for Writes [GB / sec]",
"MetricExpr": "( ( 64 * imc@event\\=0xe7@ / 1000000000 ) / duration_time ) if 1 if 0 == 1 else 0 else 0",
"MetricExpr": "( ( 64 * imc@event\\=0xe7@ / 1000000000 ) / duration_time )",
"MetricGroup": "Memory_BW",
"MetricName": "PMM_Write_BW"
},

View File

@ -328,13 +328,13 @@
},
{
"BriefDescription": "Average latency of data read request to external memory (in nanoseconds). Accounts for demand loads and L1/L2 prefetches",
"MetricExpr": "1000000000 * ( cha@event\\=0x36\\\\\\,umask\\=0x21@ / cha@event\\=0x35\\\\\\,umask\\=0x21@ ) / ( cha_0@event\\=0x0@ / duration_time )",
"MetricExpr": "1000000000 * ( cha@event\\=0x36\\,umask\\=0x21@ / cha@event\\=0x35\\,umask\\=0x21@ ) / ( cha_0@event\\=0x0@ / duration_time )",
"MetricGroup": "Memory_Lat",
"MetricName": "DRAM_Read_Latency"
},
{
"BriefDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches",
"MetricExpr": "cha@event\\=0x36\\\\\\,umask\\=0x21@ / cha@event\\=0x36\\\\\\,umask\\=0x21\\\\\\,thresh\\=1@",
"MetricExpr": "cha@event\\=0x36\\,umask\\=0x21@ / cha@event\\=0x36\\,umask\\=0x21\\,thresh\\=1@",
"MetricGroup": "Memory_BW",
"MetricName": "DRAM_Parallel_Reads"
},

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* SPDX-License-Identifier: MIT */
#ifndef __JSMN_H_
#define __JSMN_H_

View File

@ -57,6 +57,8 @@ perf-y += maps.o
perf-y += time-utils-test.o
perf-y += genelf.o
perf-y += api-io.o
perf-y += demangle-java-test.o
perf-y += pfm.o
$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
$(call rule_mkdir)

View File

@ -0,0 +1,50 @@
# Event added by system-wide or CPU perf-record to handle the race of
# processes starting while /proc is processed.
[event]
fd=1
group_fd=-1
cpu=*
pid=-1
flags=8
type=1
size=120
config=9
sample_period=4000
sample_type=455
read_format=4
# Event will be enabled right away.
disabled=0
inherit=1
pinned=0
exclusive=0
exclude_user=0
exclude_kernel=0
exclude_hv=0
exclude_idle=0
mmap=1
comm=1
freq=1
inherit_stat=0
enable_on_exec=0
task=1
watermark=0
precise_ip=0
mmap_data=0
sample_id_all=1
exclude_host=0
exclude_guest=0
exclude_callchain_kernel=0
exclude_callchain_user=0
mmap2=1
comm_exec=1
context_switch=0
write_backward=0
namespaces=0
use_clockid=0
wakeup_events=0
bp_type=0
config1=0
config2=0
branch_sample_type=0
sample_regs_user=0
sample_stack_user=0

View File

@ -9,6 +9,14 @@ cpu=0
# no enable on exec for CPU attached
enable_on_exec=0
# PERF_SAMPLE_IP | PERF_SAMPLE_TID PERF_SAMPLE_TIME | # PERF_SAMPLE_PERIOD
# PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
# PERF_SAMPLE_ID | PERF_SAMPLE_PERIOD
# + PERF_SAMPLE_CPU added by -C 0
sample_type=391
sample_type=455
# Dummy event handles mmaps, comm and task.
mmap=0
comm=0
task=0
[event:system-wide-dummy]

View File

@ -75,6 +75,13 @@ static struct test generic_tests[] = {
{
.desc = "PMU events",
.func = test__pmu_events,
.subtest = {
.skip_if_fail = false,
.get_nr = test__pmu_events_subtest_get_nr,
.get_desc = test__pmu_events_subtest_get_desc,
.skip_reason = test__pmu_events_subtest_skip_reason,
},
},
{
.desc = "DSO data read",
@ -309,6 +316,15 @@ static struct test generic_tests[] = {
.desc = "Test jit_write_elf",
.func = test__jit_write_elf,
},
{
.desc = "Test libpfm4 support",
.func = test__pfm,
.subtest = {
.skip_if_fail = true,
.get_nr = test__pfm_subtest_get_nr,
.get_desc = test__pfm_subtest_get_desc,
}
},
{
.desc = "Test api io",
.func = test__api_io,
@ -317,6 +333,10 @@ static struct test generic_tests[] = {
.desc = "maps__merge_in",
.func = test__maps__merge_in,
},
{
.desc = "Demangle Java",
.func = test__demangle_java,
},
{
.func = NULL,
},
@ -327,7 +347,7 @@ static struct test *tests[] = {
arch_tests,
};
static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[])
static bool perf_test__matches(const char *desc, int curr, int argc, const char *argv[])
{
int i;
@ -344,7 +364,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
continue;
}
if (strcasestr(test->desc, argv[i]))
if (strcasestr(desc, argv[i]))
return true;
}
@ -429,8 +449,15 @@ static int test_and_print(struct test *t, bool force_skip, int subtest)
case TEST_OK:
pr_info(" Ok\n");
break;
case TEST_SKIP:
color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
case TEST_SKIP: {
const char *skip_reason = NULL;
if (t->subtest.skip_reason)
skip_reason = t->subtest.skip_reason(subtest);
if (skip_reason)
color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (%s)\n", skip_reason);
else
color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
}
break;
case TEST_FAIL:
default:
@ -566,7 +593,7 @@ static int run_shell_tests(int argc, const char *argv[], int i, int width)
.priv = &st,
};
if (!perf_test__matches(&test, curr, argc, argv))
if (!perf_test__matches(test.desc, curr, argc, argv))
continue;
st.file = ent->d_name;
@ -594,9 +621,25 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
for_each_test(j, t) {
int curr = i++, err;
int subi;
if (!perf_test__matches(t, curr, argc, argv))
continue;
if (!perf_test__matches(t->desc, curr, argc, argv)) {
bool skip = true;
int subn;
if (!t->subtest.get_nr)
continue;
subn = t->subtest.get_nr();
for (subi = 0; subi < subn; subi++) {
if (perf_test__matches(t->subtest.get_desc(subi), curr, argc, argv))
skip = false;
}
if (skip)
continue;
}
if (t->is_supported && !t->is_supported()) {
pr_debug("%2d: %-*s: Disabled\n", i, width, t->desc);
@ -624,7 +667,6 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
*/
int subw = width > 2 ? width - 2 : width;
bool skip = false;
int subi;
if (subn <= 0) {
color_fprintf(stderr, PERF_COLOR_YELLOW,
@ -641,6 +683,9 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
}
for (subi = 0; subi < subn; subi++) {
if (!perf_test__matches(t->subtest.get_desc(subi), curr, argc, argv))
continue;
pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
t->subtest.get_desc(subi));
err = test_and_print(t, skip, subi);
@ -674,7 +719,7 @@ static int perf_test__list_shell(int argc, const char **argv, int i)
.desc = shell_test__description(bf, sizeof(bf), path, ent->d_name),
};
if (!perf_test__matches(&t, curr, argc, argv))
if (!perf_test__matches(t.desc, curr, argc, argv))
continue;
pr_info("%2d: %s\n", i, t.desc);
@ -693,7 +738,7 @@ static int perf_test__list(int argc, const char **argv)
for_each_test(j, t) {
int curr = i++;
if (!perf_test__matches(t, curr, argc, argv) ||
if (!perf_test__matches(t->desc, curr, argc, argv) ||
(t->is_supported && !t->is_supported()))
continue;

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "tests.h"
#include "session.h"
#include "debug.h"
#include "demangle-java.h"
int test__demangle_java(struct test *test __maybe_unused, int subtest __maybe_unused)
{
int ret = TEST_OK;
char *buf = NULL;
size_t i;
struct {
const char *mangled, *demangled;
} test_cases[] = {
{ "Ljava/lang/StringLatin1;equals([B[B)Z",
"boolean java.lang.StringLatin1.equals(byte[], byte[])" },
{ "Ljava/util/zip/ZipUtils;CENSIZ([BI)J",
"long java.util.zip.ZipUtils.CENSIZ(byte[], int)" },
{ "Ljava/util/regex/Pattern$BmpCharProperty;match(Ljava/util/regex/Matcher;ILjava/lang/CharSequence;)Z",
"boolean java.util.regex.Pattern$BmpCharProperty.match(java.util.regex.Matcher, int, java.lang.CharSequence)" },
{ "Ljava/lang/AbstractStringBuilder;appendChars(Ljava/lang/String;II)V",
"void java.lang.AbstractStringBuilder.appendChars(java.lang.String, int, int)" },
{ "Ljava/lang/Object;<init>()V",
"void java.lang.Object<init>()" },
};
for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) {
buf = java_demangle_sym(test_cases[i].mangled, 0);
if (strcmp(buf, test_cases[i].demangled)) {
pr_debug("FAILED: %s: %s != %s\n", test_cases[i].mangled,
buf, test_cases[i].demangled);
ret = TEST_FAIL;
}
free(buf);
}
return ret;
}

View File

@ -37,6 +37,7 @@ static int init_live_machine(struct machine *machine)
union perf_event event;
pid_t pid = getpid();
memset(&event, 0, sizeof(event));
return perf_event__synthesize_mmap_events(NULL, &event, pid, pid,
mmap_handler, machine, true);
}
@ -94,7 +95,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
return strcmp((const char *) symbol, funcs[idx]);
}
noinline int test_dwarf_unwind__thread(struct thread *thread)
__no_tail_call noinline int test_dwarf_unwind__thread(struct thread *thread)
{
struct perf_sample sample;
unsigned long cnt = 0;
@ -125,7 +126,7 @@ noinline int test_dwarf_unwind__thread(struct thread *thread)
static int global_unwind_retval = -INT_MAX;
noinline int test_dwarf_unwind__compare(void *p1, void *p2)
__no_tail_call noinline int test_dwarf_unwind__compare(void *p1, void *p2)
{
/* Any possible value should be 'thread' */
struct thread *thread = *(struct thread **)p1;
@ -144,7 +145,7 @@ noinline int test_dwarf_unwind__compare(void *p1, void *p2)
return p1 - p2;
}
noinline int test_dwarf_unwind__krava_3(struct thread *thread)
__no_tail_call noinline int test_dwarf_unwind__krava_3(struct thread *thread)
{
struct thread *array[2] = {thread, thread};
void *fp = &bsearch;
@ -163,12 +164,12 @@ noinline int test_dwarf_unwind__krava_3(struct thread *thread)
return global_unwind_retval;
}
noinline int test_dwarf_unwind__krava_2(struct thread *thread)
__no_tail_call noinline int test_dwarf_unwind__krava_2(struct thread *thread)
{
return test_dwarf_unwind__krava_3(thread);
}
noinline int test_dwarf_unwind__krava_1(struct thread *thread)
__no_tail_call noinline int test_dwarf_unwind__krava_1(struct thread *thread)
{
return test_dwarf_unwind__krava_2(thread);
}

View File

@ -100,12 +100,11 @@ int test__perf_evsel__roundtrip_name_test(struct test *test __maybe_unused, int
{
int err = 0, ret = 0;
err = perf_evsel__name_array_test(perf_evsel__hw_names);
err = perf_evsel__name_array_test(evsel__hw_names);
if (err)
ret = err;
err = __perf_evsel__name_array_test(perf_evsel__sw_names,
PERF_COUNT_SW_DUMMY + 1);
err = __perf_evsel__name_array_test(evsel__sw_names, PERF_COUNT_SW_DUMMY + 1);
if (err)
ret = err;

View File

@ -35,11 +35,11 @@ static int perf_evsel__test_field(struct evsel *evsel, const char *name,
int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtest __maybe_unused)
{
struct evsel *evsel = perf_evsel__newtp("sched", "sched_switch");
struct evsel *evsel = evsel__newtp("sched", "sched_switch");
int ret = 0;
if (IS_ERR(evsel)) {
pr_debug("perf_evsel__newtp failed with %ld\n", PTR_ERR(evsel));
pr_debug("evsel__newtp failed with %ld\n", PTR_ERR(evsel));
return -1;
}
@ -66,10 +66,10 @@ int test__perf_evsel__tp_sched_test(struct test *test __maybe_unused, int subtes
evsel__delete(evsel);
evsel = perf_evsel__newtp("sched", "sched_wakeup");
evsel = evsel__newtp("sched", "sched_wakeup");
if (IS_ERR(evsel)) {
pr_debug("perf_evsel__newtp failed with %ld\n", PTR_ERR(evsel));
pr_debug("evsel__newtp failed with %ld\n", PTR_ERR(evsel));
return -1;
}

View File

@ -19,15 +19,13 @@ static int test(struct expr_parse_ctx *ctx, const char *e, double val2)
int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused)
{
const char *p;
const char **other;
double val;
int i, ret;
double val, *val_ptr;
int ret;
struct expr_parse_ctx ctx;
int num_other;
expr__ctx_init(&ctx);
expr__add_id(&ctx, "FOO", 1);
expr__add_id(&ctx, "BAR", 2);
expr__add_id(&ctx, strdup("FOO"), 1);
expr__add_id(&ctx, strdup("BAR"), 2);
ret = test(&ctx, "1+1", 2);
ret |= test(&ctx, "FOO+BAR", 3);
@ -39,6 +37,8 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused)
ret |= test(&ctx, "min(1,2) + 1", 2);
ret |= test(&ctx, "max(1,2) + 1", 3);
ret |= test(&ctx, "1+1 if 3*4 else 0", 2);
ret |= test(&ctx, "1.1 + 2.1", 3.2);
ret |= test(&ctx, ".1 + 2.", 2.1);
if (ret)
return ret;
@ -51,25 +51,29 @@ int test__expr(struct test *t __maybe_unused, int subtest __maybe_unused)
ret = expr__parse(&val, &ctx, p, 1);
TEST_ASSERT_VAL("missing operand", ret == -1);
expr__ctx_clear(&ctx);
TEST_ASSERT_VAL("find other",
expr__find_other("FOO + BAR + BAZ + BOZO", "FOO", &other, &num_other, 1) == 0);
TEST_ASSERT_VAL("find other", num_other == 3);
TEST_ASSERT_VAL("find other", !strcmp(other[0], "BAR"));
TEST_ASSERT_VAL("find other", !strcmp(other[1], "BAZ"));
TEST_ASSERT_VAL("find other", !strcmp(other[2], "BOZO"));
TEST_ASSERT_VAL("find other", other[3] == NULL);
expr__find_other("FOO + BAR + BAZ + BOZO", "FOO",
&ctx, 1) == 0);
TEST_ASSERT_VAL("find other", hashmap__size(&ctx.ids) == 3);
TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "BAR",
(void **)&val_ptr));
TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "BAZ",
(void **)&val_ptr));
TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "BOZO",
(void **)&val_ptr));
expr__ctx_clear(&ctx);
TEST_ASSERT_VAL("find other",
expr__find_other("EVENT1\\,param\\=?@ + EVENT2\\,param\\=?@", NULL,
&other, &num_other, 3) == 0);
TEST_ASSERT_VAL("find other", num_other == 2);
TEST_ASSERT_VAL("find other", !strcmp(other[0], "EVENT1,param=3/"));
TEST_ASSERT_VAL("find other", !strcmp(other[1], "EVENT2,param=3/"));
TEST_ASSERT_VAL("find other", other[2] == NULL);
expr__find_other("EVENT1\\,param\\=?@ + EVENT2\\,param\\=?@",
NULL, &ctx, 3) == 0);
TEST_ASSERT_VAL("find other", hashmap__size(&ctx.ids) == 2);
TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "EVENT1,param=3/",
(void **)&val_ptr));
TEST_ASSERT_VAL("find other", hashmap__find(&ctx.ids, "EVENT2,param=3/",
(void **)&val_ptr));
for (i = 0; i < num_other; i++)
zfree(&other[i]);
free((void *)other);
expr__ctx_clear(&ctx);
return 0;
}

View File

@ -190,7 +190,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec
* function since TEST_ASSERT_VAL() returns in case of failure.
*/
hists__collapse_resort(hists, NULL);
perf_evsel__output_resort(hists_to_evsel(hists), NULL);
evsel__output_resort(hists_to_evsel(hists), NULL);
if (verbose > 2) {
pr_info("use callchain: %d, cumulate callchain: %d\n",

View File

@ -142,7 +142,7 @@ int test__hists_filter(struct test *test __maybe_unused, int subtest __maybe_unu
struct hists *hists = evsel__hists(evsel);
hists__collapse_resort(hists, NULL);
perf_evsel__output_resort(evsel, NULL);
evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("Normal histogram\n");

View File

@ -155,7 +155,7 @@ static int test1(struct evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
perf_evsel__output_resort(evsel, NULL);
evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@ -255,7 +255,7 @@ static int test2(struct evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
perf_evsel__output_resort(evsel, NULL);
evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@ -309,7 +309,7 @@ static int test3(struct evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
perf_evsel__output_resort(evsel, NULL);
evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@ -387,7 +387,7 @@ static int test4(struct evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
perf_evsel__output_resort(evsel, NULL);
evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@ -490,7 +490,7 @@ static int test5(struct evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
perf_evsel__output_resort(evsel, NULL);
evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);

View File

@ -84,10 +84,13 @@ make_no_libaudit := NO_LIBAUDIT=1
make_no_libbionic := NO_LIBBIONIC=1
make_no_auxtrace := NO_AUXTRACE=1
make_no_libbpf := NO_LIBBPF=1
make_no_libbpf_DEBUG := NO_LIBBPF=1 DEBUG=1
make_no_libcrypto := NO_LIBCRYPTO=1
make_with_babeltrace:= LIBBABELTRACE=1
make_no_sdt := NO_SDT=1
make_no_syscall_tbl := NO_SYSCALL_TABLE=1
make_with_clangllvm := LIBCLANGLLVM=1
make_with_libpfm4 := LIBPFM4=1
make_tags := tags
make_cscope := cscope
make_help := help
@ -112,7 +115,7 @@ make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1
make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1
make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1
make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 NO_JVMTI=1 NO_LIBZSTD=1
make_minimal += NO_LIBCAP=1
make_minimal += NO_LIBCAP=1 NO_SYSCALL_TABLE=1
# $(run) contains all available tests
run := make_pure
@ -144,8 +147,13 @@ run += make_no_libaudit
run += make_no_libbionic
run += make_no_auxtrace
run += make_no_libbpf
run += make_no_libbpf_DEBUG
run += make_no_libcrypto
run += make_no_sdt
run += make_no_syscall_tbl
run += make_with_babeltrace
run += make_with_clangllvm
run += make_with_libpfm4
run += make_help
run += make_doc
run += make_perf_o

View File

@ -79,9 +79,9 @@ int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unuse
char name[64];
snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
evsels[i] = perf_evsel__newtp("syscalls", name);
evsels[i] = evsel__newtp("syscalls", name);
if (IS_ERR(evsels[i])) {
pr_debug("perf_evsel__new(%s)\n", name);
pr_debug("evsel__new(%s)\n", name);
goto out_delete_evlist;
}

View File

@ -44,7 +44,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int
CPU_ZERO(&cpu_set);
evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
evsel = evsel__newtp("syscalls", "sys_enter_openat");
if (IS_ERR(evsel)) {
tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat");
pr_debug("%s\n", errbuf);
@ -90,8 +90,8 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int
* we use the auto allocation it will allocate just for 1 cpu,
* as we start by cpu 0.
*/
if (perf_evsel__alloc_counts(evsel, cpus->nr, 1) < 0) {
pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
if (evsel__alloc_counts(evsel, cpus->nr, 1) < 0) {
pr_debug("evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
goto out_close_fd;
}
@ -117,7 +117,7 @@ int test__openat_syscall_event_on_all_cpus(struct test *test __maybe_unused, int
}
}
perf_evsel__free_counts(evsel);
evsel__free_counts(evsel);
out_close_fd:
perf_evsel__close_fd(&evsel->core);
out_evsel_delete:

View File

@ -46,9 +46,9 @@ int test__syscall_openat_tp_fields(struct test *test __maybe_unused, int subtest
goto out;
}
evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
evsel = evsel__newtp("syscalls", "sys_enter_openat");
if (IS_ERR(evsel)) {
pr_debug("%s: perf_evsel__newtp\n", __func__);
pr_debug("%s: evsel__newtp\n", __func__);
goto out_delete_evlist;
}

View File

@ -27,7 +27,7 @@ int test__openat_syscall_event(struct test *test __maybe_unused, int subtest __m
return -1;
}
evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
evsel = evsel__newtp("syscalls", "sys_enter_openat");
if (IS_ERR(evsel)) {
tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat");
pr_debug("%s\n", errbuf);

203
tools/perf/tests/pfm.c Normal file
View File

@ -0,0 +1,203 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Test support for libpfm4 event encodings.
*
* Copyright 2020 Google LLC.
*/
#include "tests.h"
#include "util/debug.h"
#include "util/evlist.h"
#include "util/pfm.h"
#include <linux/kernel.h>
#ifdef HAVE_LIBPFM
static int test__pfm_events(void);
static int test__pfm_group(void);
#endif
static const struct {
int (*func)(void);
const char *desc;
} pfm_testcase_table[] = {
#ifdef HAVE_LIBPFM
{
.func = test__pfm_events,
.desc = "test of individual --pfm-events",
},
{
.func = test__pfm_group,
.desc = "test groups of --pfm-events",
},
#endif
};
#ifdef HAVE_LIBPFM
static int count_pfm_events(struct perf_evlist *evlist)
{
struct perf_evsel *evsel;
int count = 0;
perf_evlist__for_each_entry(evlist, evsel) {
count++;
}
return count;
}
static int test__pfm_events(void)
{
struct evlist *evlist;
struct option opt;
size_t i;
const struct {
const char *events;
int nr_events;
} table[] = {
{
.events = "",
.nr_events = 0,
},
{
.events = "instructions",
.nr_events = 1,
},
{
.events = "instructions,cycles",
.nr_events = 2,
},
{
.events = "stereolab",
.nr_events = 0,
},
{
.events = "instructions,instructions",
.nr_events = 2,
},
{
.events = "stereolab,instructions",
.nr_events = 0,
},
{
.events = "instructions,stereolab",
.nr_events = 1,
},
};
for (i = 0; i < ARRAY_SIZE(table); i++) {
evlist = evlist__new();
if (evlist == NULL)
return -ENOMEM;
opt.value = evlist;
parse_libpfm_events_option(&opt,
table[i].events,
0);
TEST_ASSERT_EQUAL(table[i].events,
count_pfm_events(&evlist->core),
table[i].nr_events);
TEST_ASSERT_EQUAL(table[i].events,
evlist->nr_groups,
0);
evlist__delete(evlist);
}
return 0;
}
static int test__pfm_group(void)
{
struct evlist *evlist;
struct option opt;
size_t i;
const struct {
const char *events;
int nr_events;
int nr_groups;
} table[] = {
{
.events = "{},",
.nr_events = 0,
.nr_groups = 0,
},
{
.events = "{instructions}",
.nr_events = 1,
.nr_groups = 1,
},
{
.events = "{instructions},{}",
.nr_events = 1,
.nr_groups = 1,
},
{
.events = "{},{instructions}",
.nr_events = 0,
.nr_groups = 0,
},
{
.events = "{instructions},{instructions}",
.nr_events = 2,
.nr_groups = 2,
},
{
.events = "{instructions,cycles},{instructions,cycles}",
.nr_events = 4,
.nr_groups = 2,
},
{
.events = "{stereolab}",
.nr_events = 0,
.nr_groups = 0,
},
{
.events =
"{instructions,cycles},{instructions,stereolab}",
.nr_events = 3,
.nr_groups = 1,
},
};
for (i = 0; i < ARRAY_SIZE(table); i++) {
evlist = evlist__new();
if (evlist == NULL)
return -ENOMEM;
opt.value = evlist;
parse_libpfm_events_option(&opt,
table[i].events,
0);
TEST_ASSERT_EQUAL(table[i].events,
count_pfm_events(&evlist->core),
table[i].nr_events);
TEST_ASSERT_EQUAL(table[i].events,
evlist->nr_groups,
table[i].nr_groups);
evlist__delete(evlist);
}
return 0;
}
#endif
const char *test__pfm_subtest_get_desc(int i)
{
if (i < 0 || i >= (int)ARRAY_SIZE(pfm_testcase_table))
return NULL;
return pfm_testcase_table[i].desc;
}
int test__pfm_subtest_get_nr(void)
{
return (int)ARRAY_SIZE(pfm_testcase_table);
}
int test__pfm(struct test *test __maybe_unused, int i __maybe_unused)
{
#ifdef HAVE_LIBPFM
if (i < 0 || i >= (int)ARRAY_SIZE(pfm_testcase_table))
return TEST_FAIL;
return pfm_testcase_table[i].func();
#else
return TEST_SKIP;
#endif
}

View File

@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include "math.h"
#include "parse-events.h"
#include "pmu.h"
#include "tests.h"
@ -8,6 +9,9 @@
#include <linux/zalloc.h>
#include "debug.h"
#include "../pmu-events/pmu-events.h"
#include "util/evlist.h"
#include "util/expr.h"
#include "util/parse-events.h"
struct perf_pmu_test_event {
struct pmu_event event;
@ -144,7 +148,7 @@ static struct pmu_events_map *__test_pmu_get_events_map(void)
}
/* Verify generated events from pmu-events.c is as expected */
static int __test_pmu_event_table(void)
static int test_pmu_event_table(void)
{
struct pmu_events_map *map = __test_pmu_get_events_map();
struct pmu_event *table;
@ -347,14 +351,11 @@ static int __test__pmu_event_aliases(char *pmu_name, int *count)
return res;
}
int test__pmu_events(struct test *test __maybe_unused,
int subtest __maybe_unused)
static int test_aliases(void)
{
struct perf_pmu *pmu = NULL;
if (__test_pmu_event_table())
return -1;
while ((pmu = perf_pmu__scan(pmu)) != NULL) {
int count = 0;
@ -377,3 +378,163 @@ int test__pmu_events(struct test *test __maybe_unused,
return 0;
}
static bool is_number(const char *str)
{
char *end_ptr;
double v;
errno = 0;
v = strtod(str, &end_ptr);
(void)v; // We're not interested in this value, only if it is valid
return errno == 0 && end_ptr != str;
}
static int check_parse_id(const char *id, bool same_cpu, struct pmu_event *pe)
{
struct parse_events_error error;
struct evlist *evlist;
int ret;
/* Numbers are always valid. */
if (is_number(id))
return 0;
evlist = evlist__new();
memset(&error, 0, sizeof(error));
ret = parse_events(evlist, id, &error);
if (ret && same_cpu) {
pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n",
pe->metric_name, id, pe->metric_expr);
pr_warning("Error string '%s' help '%s'\n", error.str,
error.help);
} else if (ret) {
pr_debug3("Parse event failed, but for an event that may not be supported by this CPU.\nid '%s' metric '%s' expr '%s'\n",
id, pe->metric_name, pe->metric_expr);
ret = 0;
}
evlist__delete(evlist);
free(error.str);
free(error.help);
free(error.first_str);
free(error.first_help);
return ret;
}
static void expr_failure(const char *msg,
const struct pmu_events_map *map,
const struct pmu_event *pe)
{
pr_debug("%s for map %s %s %s\n",
msg, map->cpuid, map->version, map->type);
pr_debug("On metric %s\n", pe->metric_name);
pr_debug("On expression %s\n", pe->metric_expr);
}
static int test_parsing(void)
{
struct pmu_events_map *cpus_map = perf_pmu__find_map(NULL);
struct pmu_events_map *map;
struct pmu_event *pe;
int i, j, k;
int ret = 0;
struct expr_parse_ctx ctx;
double result;
i = 0;
for (;;) {
map = &pmu_events_map[i++];
if (!map->table)
break;
j = 0;
for (;;) {
struct hashmap_entry *cur;
size_t bkt;
pe = &map->table[j++];
if (!pe->name && !pe->metric_group && !pe->metric_name)
break;
if (!pe->metric_expr)
continue;
expr__ctx_init(&ctx);
if (expr__find_other(pe->metric_expr, NULL, &ctx, 0)
< 0) {
expr_failure("Parse other failed", map, pe);
ret++;
continue;
}
/*
* Add all ids with a made up value. The value may
* trigger divide by zero when subtracted and so try to
* make them unique.
*/
k = 1;
hashmap__for_each_entry((&ctx.ids), cur, bkt)
expr__add_id(&ctx, strdup(cur->key), k++);
hashmap__for_each_entry((&ctx.ids), cur, bkt) {
if (check_parse_id(cur->key, map == cpus_map,
pe))
ret++;
}
if (expr__parse(&result, &ctx, pe->metric_expr, 0)) {
expr_failure("Parse failed", map, pe);
ret++;
}
expr__ctx_clear(&ctx);
}
}
/* TODO: fail when not ok */
return ret == 0 ? TEST_OK : TEST_SKIP;
}
static const struct {
int (*func)(void);
const char *desc;
} pmu_events_testcase_table[] = {
{
.func = test_pmu_event_table,
.desc = "PMU event table sanity",
},
{
.func = test_aliases,
.desc = "PMU event map aliases",
},
{
.func = test_parsing,
.desc = "Parsing of PMU event table metrics",
},
};
const char *test__pmu_events_subtest_get_desc(int subtest)
{
if (subtest < 0 ||
subtest >= (int)ARRAY_SIZE(pmu_events_testcase_table))
return NULL;
return pmu_events_testcase_table[subtest].desc;
}
const char *test__pmu_events_subtest_skip_reason(int subtest)
{
if (subtest < 0 ||
subtest >= (int)ARRAY_SIZE(pmu_events_testcase_table))
return NULL;
if (pmu_events_testcase_table[subtest].func != test_parsing)
return NULL;
return "some metrics failed";
}
int test__pmu_events_subtest_get_nr(void)
{
return (int)ARRAY_SIZE(pmu_events_testcase_table);
}
int test__pmu_events(struct test *test __maybe_unused, int subtest)
{
if (subtest < 0 ||
subtest >= (int)ARRAY_SIZE(pmu_events_testcase_table))
return TEST_FAIL;
return pmu_events_testcase_table[subtest].func();
}

View File

@ -156,8 +156,8 @@ int test__pmu(struct test *test __maybe_unused, int subtest __maybe_unused)
if (ret)
break;
ret = perf_pmu__config_terms(&formats, &attr, terms,
false, NULL);
ret = perf_pmu__config_terms("perf-pmu-test", &formats, &attr,
terms, false, NULL);
if (ret)
break;

View File

@ -56,7 +56,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
evsel = evsel__new(&attr);
if (evsel == NULL) {
pr_debug("perf_evsel__new\n");
pr_debug("evsel__new\n");
goto out_delete_evlist;
}
evlist__add(evlist, evsel);

View File

@ -34,6 +34,7 @@ struct test {
bool skip_if_fail;
int (*get_nr)(void);
const char *(*get_desc)(int subtest);
const char *(*skip_reason)(int subtest);
} subtest;
bool (*is_supported)(void);
void *priv;
@ -50,6 +51,9 @@ int test__perf_evsel__tp_sched_test(struct test *test, int subtest);
int test__syscall_openat_tp_fields(struct test *test, int subtest);
int test__pmu(struct test *test, int subtest);
int test__pmu_events(struct test *test, int subtest);
const char *test__pmu_events_subtest_get_desc(int subtest);
const char *test__pmu_events_subtest_skip_reason(int subtest);
int test__pmu_events_subtest_get_nr(void);
int test__attr(struct test *test, int subtest);
int test__dso_data(struct test *test, int subtest);
int test__dso_data_cache(struct test *test, int subtest);
@ -113,6 +117,10 @@ int test__maps__merge_in(struct test *t, int subtest);
int test__time_utils(struct test *t, int subtest);
int test__jit_write_elf(struct test *test, int subtest);
int test__api_io(struct test *test, int subtest);
int test__demangle_java(struct test *test, int subtest);
int test__pfm(struct test *test, int subtest);
const char *test__pfm_subtest_get_desc(int subtest);
int test__pfm_subtest_get_nr(void);
bool test__bp_signal_is_supported(void);
bool test__bp_account_is_supported(void);

View File

@ -57,7 +57,7 @@ process_arch()
local arch="$1"
local asm_errno=$(asm_errno_file "$arch")
$gcc $include_path -E -dM -x c $asm_errno \
$gcc $CFLAGS $include_path -E -dM -x c $asm_errno \
|grep -hE '^#define[[:blank:]]+(E[^[:blank:]]+)[[:blank:]]+([[:digit:]]+).*' \
|awk '{ print $2","$3; }' \
|sort -t, -k2 -nu \
@ -91,7 +91,7 @@ EoHEADER
# in tools/perf/arch
archlist=""
for arch in $(find $toolsdir/arch -maxdepth 1 -mindepth 1 -type d -printf "%f\n" | grep -v x86 | sort); do
test -d arch/$arch && archlist="$archlist $arch"
test -d $toolsdir/perf/arch/$arch && archlist="$archlist $arch"
done
for arch in x86 $archlist generic; do

View File

@ -106,7 +106,7 @@ perf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
perf-$(CONFIG_AUXTRACE) += intel-pt.o
perf-$(CONFIG_AUXTRACE) += intel-bts.o
perf-$(CONFIG_AUXTRACE) += arm-spe.o
perf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
perf-$(CONFIG_AUXTRACE) += arm-spe-decoder/
perf-$(CONFIG_AUXTRACE) += s390-cpumsf.o
ifdef CONFIG_LIBOPENCSD
@ -136,6 +136,10 @@ perf-$(CONFIG_LIBELF) += symbol-elf.o
perf-$(CONFIG_LIBELF) += probe-file.o
perf-$(CONFIG_LIBELF) += probe-event.o
ifndef CONFIG_LIBBPF
perf-y += hashmap.o
endif
ifndef CONFIG_LIBELF
perf-y += symbol-minimal.o
endif
@ -179,6 +183,8 @@ perf-$(CONFIG_LIBBPF) += bpf-event.o
perf-$(CONFIG_CXX) += c++/
perf-$(CONFIG_LIBPFM4) += pfm.o
CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
CFLAGS_llvm-utils.o += -DPERF_INCLUDE_DIR="BUILD_STR($(perf_include_dir_SQ))"

View File

@ -41,7 +41,6 @@
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <bpf/libbpf.h>
#include <subcmd/parse-options.h>
#include <subcmd/run-command.h>

View File

@ -144,7 +144,7 @@ struct annotation_line {
u32 idx;
int idx_asm;
int data_nr;
struct annotation_data data[0];
struct annotation_data data[];
};
struct disasm_line {
@ -227,7 +227,7 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel);
struct sym_hist {
u64 nr_samples;
u64 period;
struct sym_hist_entry addr[0];
struct sym_hist_entry addr[];
};
struct cyc_hist {

View File

@ -0,0 +1 @@
perf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o arm-spe-decoder.o

View File

@ -0,0 +1,219 @@
// SPDX-License-Identifier: GPL-2.0
/*
* arm_spe_decoder.c: ARM SPE support
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <linux/compiler.h>
#include <linux/zalloc.h>
#include "../auxtrace.h"
#include "../debug.h"
#include "../util.h"
#include "arm-spe-decoder.h"
#ifndef BIT
#define BIT(n) (1UL << (n))
#endif
static u64 arm_spe_calc_ip(int index, u64 payload)
{
u8 *addr = (u8 *)&payload;
int ns, el;
/* Instruction virtual address or Branch target address */
if (index == SPE_ADDR_PKT_HDR_INDEX_INS ||
index == SPE_ADDR_PKT_HDR_INDEX_BRANCH) {
ns = addr[7] & SPE_ADDR_PKT_NS;
el = (addr[7] & SPE_ADDR_PKT_EL_MASK) >> SPE_ADDR_PKT_EL_OFFSET;
/* Fill highest byte for EL1 or EL2 (VHE) mode */
if (ns && (el == SPE_ADDR_PKT_EL1 || el == SPE_ADDR_PKT_EL2))
addr[7] = 0xff;
/* Clean highest byte for other cases */
else
addr[7] = 0x0;
/* Data access virtual address */
} else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT) {
/* Fill highest byte if bits [48..55] is 0xff */
if (addr[6] == 0xff)
addr[7] = 0xff;
/* Otherwise, cleanup tags */
else
addr[7] = 0x0;
/* Data access physical address */
} else if (index == SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS) {
/* Cleanup byte 7 */
addr[7] = 0x0;
} else {
pr_err("unsupported address packet index: 0x%x\n", index);
}
return payload;
}
struct arm_spe_decoder *arm_spe_decoder_new(struct arm_spe_params *params)
{
struct arm_spe_decoder *decoder;
if (!params->get_trace)
return NULL;
decoder = zalloc(sizeof(struct arm_spe_decoder));
if (!decoder)
return NULL;
decoder->get_trace = params->get_trace;
decoder->data = params->data;
return decoder;
}
void arm_spe_decoder_free(struct arm_spe_decoder *decoder)
{
free(decoder);
}
static int arm_spe_get_data(struct arm_spe_decoder *decoder)
{
struct arm_spe_buffer buffer = { .buf = 0, };
int ret;
pr_debug("Getting more data\n");
ret = decoder->get_trace(&buffer, decoder->data);
if (ret < 0)
return ret;
decoder->buf = buffer.buf;
decoder->len = buffer.len;
if (!decoder->len)
pr_debug("No more data\n");
return decoder->len;
}
static int arm_spe_get_next_packet(struct arm_spe_decoder *decoder)
{
int ret;
do {
if (!decoder->len) {
ret = arm_spe_get_data(decoder);
/* Failed to read out trace data */
if (ret <= 0)
return ret;
}
ret = arm_spe_get_packet(decoder->buf, decoder->len,
&decoder->packet);
if (ret <= 0) {
/* Move forward for 1 byte */
decoder->buf += 1;
decoder->len -= 1;
return -EBADMSG;
}
decoder->buf += ret;
decoder->len -= ret;
} while (decoder->packet.type == ARM_SPE_PAD);
return 1;
}
static int arm_spe_read_record(struct arm_spe_decoder *decoder)
{
int err;
int idx;
u64 payload, ip;
memset(&decoder->record, 0x0, sizeof(decoder->record));
while (1) {
err = arm_spe_get_next_packet(decoder);
if (err <= 0)
return err;
idx = decoder->packet.index;
payload = decoder->packet.payload;
switch (decoder->packet.type) {
case ARM_SPE_TIMESTAMP:
decoder->record.timestamp = payload;
return 1;
case ARM_SPE_END:
return 1;
case ARM_SPE_ADDRESS:
ip = arm_spe_calc_ip(idx, payload);
if (idx == SPE_ADDR_PKT_HDR_INDEX_INS)
decoder->record.from_ip = ip;
else if (idx == SPE_ADDR_PKT_HDR_INDEX_BRANCH)
decoder->record.to_ip = ip;
break;
case ARM_SPE_COUNTER:
break;
case ARM_SPE_CONTEXT:
break;
case ARM_SPE_OP_TYPE:
break;
case ARM_SPE_EVENTS:
if (payload & BIT(EV_L1D_REFILL))
decoder->record.type |= ARM_SPE_L1D_MISS;
if (payload & BIT(EV_L1D_ACCESS))
decoder->record.type |= ARM_SPE_L1D_ACCESS;
if (payload & BIT(EV_TLB_WALK))
decoder->record.type |= ARM_SPE_TLB_MISS;
if (payload & BIT(EV_TLB_ACCESS))
decoder->record.type |= ARM_SPE_TLB_ACCESS;
if ((idx == 1 || idx == 2 || idx == 3) &&
(payload & BIT(EV_LLC_MISS)))
decoder->record.type |= ARM_SPE_LLC_MISS;
if ((idx == 1 || idx == 2 || idx == 3) &&
(payload & BIT(EV_LLC_ACCESS)))
decoder->record.type |= ARM_SPE_LLC_ACCESS;
if ((idx == 1 || idx == 2 || idx == 3) &&
(payload & BIT(EV_REMOTE_ACCESS)))
decoder->record.type |= ARM_SPE_REMOTE_ACCESS;
if (payload & BIT(EV_MISPRED))
decoder->record.type |= ARM_SPE_BRANCH_MISS;
break;
case ARM_SPE_DATA_SOURCE:
break;
case ARM_SPE_BAD:
break;
case ARM_SPE_PAD:
break;
default:
pr_err("Get packet error!\n");
return -1;
}
}
return 0;
}
int arm_spe_decode(struct arm_spe_decoder *decoder)
{
return arm_spe_read_record(decoder);
}

View File

@ -0,0 +1,82 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* arm_spe_decoder.h: Arm Statistical Profiling Extensions support
* Copyright (c) 2019-2020, Arm Ltd.
*/
#ifndef INCLUDE__ARM_SPE_DECODER_H__
#define INCLUDE__ARM_SPE_DECODER_H__
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "arm-spe-pkt-decoder.h"
enum arm_spe_events {
EV_EXCEPTION_GEN = 0,
EV_RETIRED = 1,
EV_L1D_ACCESS = 2,
EV_L1D_REFILL = 3,
EV_TLB_ACCESS = 4,
EV_TLB_WALK = 5,
EV_NOT_TAKEN = 6,
EV_MISPRED = 7,
EV_LLC_ACCESS = 8,
EV_LLC_MISS = 9,
EV_REMOTE_ACCESS = 10,
EV_ALIGNMENT = 11,
EV_PARTIAL_PREDICATE = 17,
EV_EMPTY_PREDICATE = 18,
};
enum arm_spe_sample_type {
ARM_SPE_L1D_ACCESS = 1 << 0,
ARM_SPE_L1D_MISS = 1 << 1,
ARM_SPE_LLC_ACCESS = 1 << 2,
ARM_SPE_LLC_MISS = 1 << 3,
ARM_SPE_TLB_ACCESS = 1 << 4,
ARM_SPE_TLB_MISS = 1 << 5,
ARM_SPE_BRANCH_MISS = 1 << 6,
ARM_SPE_REMOTE_ACCESS = 1 << 7,
};
struct arm_spe_record {
enum arm_spe_sample_type type;
int err;
u64 from_ip;
u64 to_ip;
u64 timestamp;
};
struct arm_spe_insn;
struct arm_spe_buffer {
const unsigned char *buf;
size_t len;
u64 offset;
u64 trace_nr;
};
struct arm_spe_params {
int (*get_trace)(struct arm_spe_buffer *buffer, void *data);
void *data;
};
struct arm_spe_decoder {
int (*get_trace)(struct arm_spe_buffer *buffer, void *data);
void *data;
struct arm_spe_record record;
const unsigned char *buf;
size_t len;
struct arm_spe_pkt packet;
};
struct arm_spe_decoder *arm_spe_decoder_new(struct arm_spe_params *params);
void arm_spe_decoder_free(struct arm_spe_decoder *decoder);
int arm_spe_decode(struct arm_spe_decoder *decoder);
#endif

View File

@ -15,6 +15,8 @@
#define ARM_SPE_NEED_MORE_BYTES -1
#define ARM_SPE_BAD_PACKET -2
#define ARM_SPE_PKT_MAX_SZ 16
enum arm_spe_pkt_type {
ARM_SPE_BAD,
ARM_SPE_PAD,
@ -34,6 +36,20 @@ struct arm_spe_pkt {
uint64_t payload;
};
#define SPE_ADDR_PKT_HDR_INDEX_INS (0x0)
#define SPE_ADDR_PKT_HDR_INDEX_BRANCH (0x1)
#define SPE_ADDR_PKT_HDR_INDEX_DATA_VIRT (0x2)
#define SPE_ADDR_PKT_HDR_INDEX_DATA_PHYS (0x3)
#define SPE_ADDR_PKT_NS BIT(7)
#define SPE_ADDR_PKT_CH BIT(6)
#define SPE_ADDR_PKT_EL_OFFSET (5)
#define SPE_ADDR_PKT_EL_MASK (0x3 << SPE_ADDR_PKT_EL_OFFSET)
#define SPE_ADDR_PKT_EL0 (0)
#define SPE_ADDR_PKT_EL1 (1)
#define SPE_ADDR_PKT_EL2 (2)
#define SPE_ADDR_PKT_EL3 (3)
const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
int arm_spe_get_packet(const unsigned char *buf, size_t len,

View File

@ -4,46 +4,85 @@
* Copyright (c) 2017-2018, Arm Ltd.
*/
#include <byteswap.h>
#include <endian.h>
#include <errno.h>
#include <byteswap.h>
#include <inttypes.h>
#include <unistd.h>
#include <stdlib.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
#include <linux/log2.h>
#include <linux/types.h>
#include <linux/zalloc.h>
#include <stdlib.h>
#include <unistd.h>
#include "auxtrace.h"
#include "color.h"
#include "debug.h"
#include "evlist.h"
#include "evsel.h"
#include "machine.h"
#include "session.h"
#include "debug.h"
#include "auxtrace.h"
#include "symbol.h"
#include "thread.h"
#include "thread-stack.h"
#include "tool.h"
#include "util/synthetic-events.h"
#include "arm-spe.h"
#include "arm-spe-pkt-decoder.h"
#include "arm-spe-decoder/arm-spe-decoder.h"
#include "arm-spe-decoder/arm-spe-pkt-decoder.h"
#define MAX_TIMESTAMP (~0ULL)
struct arm_spe {
struct auxtrace auxtrace;
struct auxtrace_queues queues;
struct auxtrace_heap heap;
struct itrace_synth_opts synth_opts;
u32 auxtrace_type;
struct perf_session *session;
struct machine *machine;
u32 pmu_type;
u8 timeless_decoding;
u8 data_queued;
u8 sample_flc;
u8 sample_llc;
u8 sample_tlb;
u8 sample_branch;
u8 sample_remote_access;
u64 l1d_miss_id;
u64 l1d_access_id;
u64 llc_miss_id;
u64 llc_access_id;
u64 tlb_miss_id;
u64 tlb_access_id;
u64 branch_miss_id;
u64 remote_access_id;
u64 kernel_start;
unsigned long num_events;
};
struct arm_spe_queue {
struct arm_spe *spe;
unsigned int queue_nr;
struct auxtrace_buffer *buffer;
bool on_heap;
bool done;
pid_t pid;
pid_t tid;
int cpu;
struct arm_spe *spe;
unsigned int queue_nr;
struct auxtrace_buffer *buffer;
struct auxtrace_buffer *old_buffer;
union perf_event *event_buf;
bool on_heap;
bool done;
pid_t pid;
pid_t tid;
int cpu;
struct arm_spe_decoder *decoder;
u64 time;
u64 timestamp;
struct thread *thread;
};
static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
@ -92,44 +131,520 @@ static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
arm_spe_dump(spe, buf, len);
}
static int arm_spe_process_event(struct perf_session *session __maybe_unused,
union perf_event *event __maybe_unused,
struct perf_sample *sample __maybe_unused,
struct perf_tool *tool __maybe_unused)
static int arm_spe_get_trace(struct arm_spe_buffer *b, void *data)
{
struct arm_spe_queue *speq = data;
struct auxtrace_buffer *buffer = speq->buffer;
struct auxtrace_buffer *old_buffer = speq->old_buffer;
struct auxtrace_queue *queue;
queue = &speq->spe->queues.queue_array[speq->queue_nr];
buffer = auxtrace_buffer__next(queue, buffer);
/* If no more data, drop the previous auxtrace_buffer and return */
if (!buffer) {
if (old_buffer)
auxtrace_buffer__drop_data(old_buffer);
b->len = 0;
return 0;
}
speq->buffer = buffer;
/* If the aux_buffer doesn't have data associated, try to load it */
if (!buffer->data) {
/* get the file desc associated with the perf data file */
int fd = perf_data__fd(speq->spe->session->data);
buffer->data = auxtrace_buffer__get_data(buffer, fd);
if (!buffer->data)
return -ENOMEM;
}
b->len = buffer->size;
b->buf = buffer->data;
if (b->len) {
if (old_buffer)
auxtrace_buffer__drop_data(old_buffer);
speq->old_buffer = buffer;
} else {
auxtrace_buffer__drop_data(buffer);
return arm_spe_get_trace(b, data);
}
return 0;
}
static struct arm_spe_queue *arm_spe__alloc_queue(struct arm_spe *spe,
unsigned int queue_nr)
{
struct arm_spe_params params = { .get_trace = 0, };
struct arm_spe_queue *speq;
speq = zalloc(sizeof(*speq));
if (!speq)
return NULL;
speq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
if (!speq->event_buf)
goto out_free;
speq->spe = spe;
speq->queue_nr = queue_nr;
speq->pid = -1;
speq->tid = -1;
speq->cpu = -1;
/* params set */
params.get_trace = arm_spe_get_trace;
params.data = speq;
/* create new decoder */
speq->decoder = arm_spe_decoder_new(&params);
if (!speq->decoder)
goto out_free;
return speq;
out_free:
zfree(&speq->event_buf);
free(speq);
return NULL;
}
static inline u8 arm_spe_cpumode(struct arm_spe *spe, u64 ip)
{
return ip >= spe->kernel_start ?
PERF_RECORD_MISC_KERNEL :
PERF_RECORD_MISC_USER;
}
static void arm_spe_prep_sample(struct arm_spe *spe,
struct arm_spe_queue *speq,
union perf_event *event,
struct perf_sample *sample)
{
struct arm_spe_record *record = &speq->decoder->record;
if (!spe->timeless_decoding)
sample->time = speq->timestamp;
sample->ip = record->from_ip;
sample->cpumode = arm_spe_cpumode(spe, sample->ip);
sample->pid = speq->pid;
sample->tid = speq->tid;
sample->addr = record->to_ip;
sample->period = 1;
sample->cpu = speq->cpu;
event->sample.header.type = PERF_RECORD_SAMPLE;
event->sample.header.misc = sample->cpumode;
event->sample.header.size = sizeof(struct perf_event_header);
}
static inline int
arm_spe_deliver_synth_event(struct arm_spe *spe,
struct arm_spe_queue *speq __maybe_unused,
union perf_event *event,
struct perf_sample *sample)
{
int ret;
ret = perf_session__deliver_synth_event(spe->session, event, sample);
if (ret)
pr_err("ARM SPE: failed to deliver event, error %d\n", ret);
return ret;
}
static int
arm_spe_synth_spe_events_sample(struct arm_spe_queue *speq,
u64 spe_events_id)
{
struct arm_spe *spe = speq->spe;
union perf_event *event = speq->event_buf;
struct perf_sample sample = { .ip = 0, };
arm_spe_prep_sample(spe, speq, event, &sample);
sample.id = spe_events_id;
sample.stream_id = spe_events_id;
return arm_spe_deliver_synth_event(spe, speq, event, &sample);
}
static int arm_spe_sample(struct arm_spe_queue *speq)
{
const struct arm_spe_record *record = &speq->decoder->record;
struct arm_spe *spe = speq->spe;
int err;
if (spe->sample_flc) {
if (record->type & ARM_SPE_L1D_MISS) {
err = arm_spe_synth_spe_events_sample(
speq, spe->l1d_miss_id);
if (err)
return err;
}
if (record->type & ARM_SPE_L1D_ACCESS) {
err = arm_spe_synth_spe_events_sample(
speq, spe->l1d_access_id);
if (err)
return err;
}
}
if (spe->sample_llc) {
if (record->type & ARM_SPE_LLC_MISS) {
err = arm_spe_synth_spe_events_sample(
speq, spe->llc_miss_id);
if (err)
return err;
}
if (record->type & ARM_SPE_LLC_ACCESS) {
err = arm_spe_synth_spe_events_sample(
speq, spe->llc_access_id);
if (err)
return err;
}
}
if (spe->sample_tlb) {
if (record->type & ARM_SPE_TLB_MISS) {
err = arm_spe_synth_spe_events_sample(
speq, spe->tlb_miss_id);
if (err)
return err;
}
if (record->type & ARM_SPE_TLB_ACCESS) {
err = arm_spe_synth_spe_events_sample(
speq, spe->tlb_access_id);
if (err)
return err;
}
}
if (spe->sample_branch && (record->type & ARM_SPE_BRANCH_MISS)) {
err = arm_spe_synth_spe_events_sample(speq,
spe->branch_miss_id);
if (err)
return err;
}
if (spe->sample_remote_access &&
(record->type & ARM_SPE_REMOTE_ACCESS)) {
err = arm_spe_synth_spe_events_sample(speq,
spe->remote_access_id);
if (err)
return err;
}
return 0;
}
static int arm_spe_run_decoder(struct arm_spe_queue *speq, u64 *timestamp)
{
struct arm_spe *spe = speq->spe;
int ret;
if (!spe->kernel_start)
spe->kernel_start = machine__kernel_start(spe->machine);
while (1) {
ret = arm_spe_decode(speq->decoder);
if (!ret) {
pr_debug("No data or all data has been processed.\n");
return 1;
}
/*
* Error is detected when decode SPE trace data, continue to
* the next trace data and find out more records.
*/
if (ret < 0)
continue;
ret = arm_spe_sample(speq);
if (ret)
return ret;
if (!spe->timeless_decoding && speq->timestamp >= *timestamp) {
*timestamp = speq->timestamp;
return 0;
}
}
return 0;
}
static int arm_spe__setup_queue(struct arm_spe *spe,
struct auxtrace_queue *queue,
unsigned int queue_nr)
{
struct arm_spe_queue *speq = queue->priv;
struct arm_spe_record *record;
if (list_empty(&queue->head) || speq)
return 0;
speq = arm_spe__alloc_queue(spe, queue_nr);
if (!speq)
return -ENOMEM;
queue->priv = speq;
if (queue->cpu != -1)
speq->cpu = queue->cpu;
if (!speq->on_heap) {
int ret;
if (spe->timeless_decoding)
return 0;
retry:
ret = arm_spe_decode(speq->decoder);
if (!ret)
return 0;
if (ret < 0)
goto retry;
record = &speq->decoder->record;
speq->timestamp = record->timestamp;
ret = auxtrace_heap__add(&spe->heap, queue_nr, speq->timestamp);
if (ret)
return ret;
speq->on_heap = true;
}
return 0;
}
static int arm_spe__setup_queues(struct arm_spe *spe)
{
unsigned int i;
int ret;
for (i = 0; i < spe->queues.nr_queues; i++) {
ret = arm_spe__setup_queue(spe, &spe->queues.queue_array[i], i);
if (ret)
return ret;
}
return 0;
}
static int arm_spe__update_queues(struct arm_spe *spe)
{
if (spe->queues.new_data) {
spe->queues.new_data = false;
return arm_spe__setup_queues(spe);
}
return 0;
}
static bool arm_spe__is_timeless_decoding(struct arm_spe *spe)
{
struct evsel *evsel;
struct evlist *evlist = spe->session->evlist;
bool timeless_decoding = true;
/*
* Circle through the list of event and complain if we find one
* with the time bit set.
*/
evlist__for_each_entry(evlist, evsel) {
if ((evsel->core.attr.sample_type & PERF_SAMPLE_TIME))
timeless_decoding = false;
}
return timeless_decoding;
}
static void arm_spe_set_pid_tid_cpu(struct arm_spe *spe,
struct auxtrace_queue *queue)
{
struct arm_spe_queue *speq = queue->priv;
pid_t tid;
tid = machine__get_current_tid(spe->machine, speq->cpu);
if (tid != -1) {
speq->tid = tid;
thread__zput(speq->thread);
} else
speq->tid = queue->tid;
if ((!speq->thread) && (speq->tid != -1)) {
speq->thread = machine__find_thread(spe->machine, -1,
speq->tid);
}
if (speq->thread) {
speq->pid = speq->thread->pid_;
if (queue->cpu == -1)
speq->cpu = speq->thread->cpu;
}
}
static int arm_spe_process_queues(struct arm_spe *spe, u64 timestamp)
{
unsigned int queue_nr;
u64 ts;
int ret;
while (1) {
struct auxtrace_queue *queue;
struct arm_spe_queue *speq;
if (!spe->heap.heap_cnt)
return 0;
if (spe->heap.heap_array[0].ordinal >= timestamp)
return 0;
queue_nr = spe->heap.heap_array[0].queue_nr;
queue = &spe->queues.queue_array[queue_nr];
speq = queue->priv;
auxtrace_heap__pop(&spe->heap);
if (spe->heap.heap_cnt) {
ts = spe->heap.heap_array[0].ordinal + 1;
if (ts > timestamp)
ts = timestamp;
} else {
ts = timestamp;
}
arm_spe_set_pid_tid_cpu(spe, queue);
ret = arm_spe_run_decoder(speq, &ts);
if (ret < 0) {
auxtrace_heap__add(&spe->heap, queue_nr, ts);
return ret;
}
if (!ret) {
ret = auxtrace_heap__add(&spe->heap, queue_nr, ts);
if (ret < 0)
return ret;
} else {
speq->on_heap = false;
}
}
return 0;
}
static int arm_spe_process_timeless_queues(struct arm_spe *spe, pid_t tid,
u64 time_)
{
struct auxtrace_queues *queues = &spe->queues;
unsigned int i;
u64 ts = 0;
for (i = 0; i < queues->nr_queues; i++) {
struct auxtrace_queue *queue = &spe->queues.queue_array[i];
struct arm_spe_queue *speq = queue->priv;
if (speq && (tid == -1 || speq->tid == tid)) {
speq->time = time_;
arm_spe_set_pid_tid_cpu(spe, queue);
arm_spe_run_decoder(speq, &ts);
}
}
return 0;
}
static int arm_spe_process_event(struct perf_session *session,
union perf_event *event,
struct perf_sample *sample,
struct perf_tool *tool)
{
int err = 0;
u64 timestamp;
struct arm_spe *spe = container_of(session->auxtrace,
struct arm_spe, auxtrace);
if (dump_trace)
return 0;
if (!tool->ordered_events) {
pr_err("SPE trace requires ordered events\n");
return -EINVAL;
}
if (sample->time && (sample->time != (u64) -1))
timestamp = sample->time;
else
timestamp = 0;
if (timestamp || spe->timeless_decoding) {
err = arm_spe__update_queues(spe);
if (err)
return err;
}
if (spe->timeless_decoding) {
if (event->header.type == PERF_RECORD_EXIT) {
err = arm_spe_process_timeless_queues(spe,
event->fork.tid,
sample->time);
}
} else if (timestamp) {
if (event->header.type == PERF_RECORD_EXIT) {
err = arm_spe_process_queues(spe, timestamp);
if (err)
return err;
}
}
return err;
}
static int arm_spe_process_auxtrace_event(struct perf_session *session,
union perf_event *event,
struct perf_tool *tool __maybe_unused)
{
struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
auxtrace);
struct auxtrace_buffer *buffer;
off_t data_offset;
int fd = perf_data__fd(session->data);
int err;
if (perf_data__is_pipe(session->data)) {
data_offset = 0;
} else {
data_offset = lseek(fd, 0, SEEK_CUR);
if (data_offset == -1)
return -errno;
}
if (!spe->data_queued) {
struct auxtrace_buffer *buffer;
off_t data_offset;
int fd = perf_data__fd(session->data);
int err;
err = auxtrace_queues__add_event(&spe->queues, session, event,
data_offset, &buffer);
if (err)
return err;
if (perf_data__is_pipe(session->data)) {
data_offset = 0;
} else {
data_offset = lseek(fd, 0, SEEK_CUR);
if (data_offset == -1)
return -errno;
}
/* Dump here now we have copied a piped trace out of the pipe */
if (dump_trace) {
if (auxtrace_buffer__get_data(buffer, fd)) {
arm_spe_dump_event(spe, buffer->data,
buffer->size);
auxtrace_buffer__put_data(buffer);
err = auxtrace_queues__add_event(&spe->queues, session, event,
data_offset, &buffer);
if (err)
return err;
/* Dump here now we have copied a piped trace out of the pipe */
if (dump_trace) {
if (auxtrace_buffer__get_data(buffer, fd)) {
arm_spe_dump_event(spe, buffer->data,
buffer->size);
auxtrace_buffer__put_data(buffer);
}
}
}
@ -139,7 +654,25 @@ static int arm_spe_process_auxtrace_event(struct perf_session *session,
static int arm_spe_flush(struct perf_session *session __maybe_unused,
struct perf_tool *tool __maybe_unused)
{
return 0;
struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
auxtrace);
int ret;
if (dump_trace)
return 0;
if (!tool->ordered_events)
return -EINVAL;
ret = arm_spe__update_queues(spe);
if (ret < 0)
return ret;
if (spe->timeless_decoding)
return arm_spe_process_timeless_queues(spe, -1,
MAX_TIMESTAMP - 1);
return arm_spe_process_queues(spe, MAX_TIMESTAMP);
}
static void arm_spe_free_queue(void *priv)
@ -148,6 +681,9 @@ static void arm_spe_free_queue(void *priv)
if (!speq)
return;
thread__zput(speq->thread);
arm_spe_decoder_free(speq->decoder);
zfree(&speq->event_buf);
free(speq);
}
@ -196,11 +732,189 @@ static void arm_spe_print_info(__u64 *arr)
fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
}
struct arm_spe_synth {
struct perf_tool dummy_tool;
struct perf_session *session;
};
static int arm_spe_event_synth(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct machine *machine __maybe_unused)
{
struct arm_spe_synth *arm_spe_synth =
container_of(tool, struct arm_spe_synth, dummy_tool);
return perf_session__deliver_synth_event(arm_spe_synth->session,
event, NULL);
}
static int arm_spe_synth_event(struct perf_session *session,
struct perf_event_attr *attr, u64 id)
{
struct arm_spe_synth arm_spe_synth;
memset(&arm_spe_synth, 0, sizeof(struct arm_spe_synth));
arm_spe_synth.session = session;
return perf_event__synthesize_attr(&arm_spe_synth.dummy_tool, attr, 1,
&id, arm_spe_event_synth);
}
static void arm_spe_set_event_name(struct evlist *evlist, u64 id,
const char *name)
{
struct evsel *evsel;
evlist__for_each_entry(evlist, evsel) {
if (evsel->core.id && evsel->core.id[0] == id) {
if (evsel->name)
zfree(&evsel->name);
evsel->name = strdup(name);
break;
}
}
}
static int
arm_spe_synth_events(struct arm_spe *spe, struct perf_session *session)
{
struct evlist *evlist = session->evlist;
struct evsel *evsel;
struct perf_event_attr attr;
bool found = false;
u64 id;
int err;
evlist__for_each_entry(evlist, evsel) {
if (evsel->core.attr.type == spe->pmu_type) {
found = true;
break;
}
}
if (!found) {
pr_debug("No selected events with SPE trace data\n");
return 0;
}
memset(&attr, 0, sizeof(struct perf_event_attr));
attr.size = sizeof(struct perf_event_attr);
attr.type = PERF_TYPE_HARDWARE;
attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK;
attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID |
PERF_SAMPLE_PERIOD;
if (spe->timeless_decoding)
attr.sample_type &= ~(u64)PERF_SAMPLE_TIME;
else
attr.sample_type |= PERF_SAMPLE_TIME;
attr.exclude_user = evsel->core.attr.exclude_user;
attr.exclude_kernel = evsel->core.attr.exclude_kernel;
attr.exclude_hv = evsel->core.attr.exclude_hv;
attr.exclude_host = evsel->core.attr.exclude_host;
attr.exclude_guest = evsel->core.attr.exclude_guest;
attr.sample_id_all = evsel->core.attr.sample_id_all;
attr.read_format = evsel->core.attr.read_format;
/* create new id val to be a fixed offset from evsel id */
id = evsel->core.id[0] + 1000000000;
if (!id)
id = 1;
if (spe->synth_opts.flc) {
spe->sample_flc = true;
/* Level 1 data cache miss */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->l1d_miss_id = id;
arm_spe_set_event_name(evlist, id, "l1d-miss");
id += 1;
/* Level 1 data cache access */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->l1d_access_id = id;
arm_spe_set_event_name(evlist, id, "l1d-access");
id += 1;
}
if (spe->synth_opts.llc) {
spe->sample_llc = true;
/* Last level cache miss */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->llc_miss_id = id;
arm_spe_set_event_name(evlist, id, "llc-miss");
id += 1;
/* Last level cache access */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->llc_access_id = id;
arm_spe_set_event_name(evlist, id, "llc-access");
id += 1;
}
if (spe->synth_opts.tlb) {
spe->sample_tlb = true;
/* TLB miss */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->tlb_miss_id = id;
arm_spe_set_event_name(evlist, id, "tlb-miss");
id += 1;
/* TLB access */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->tlb_access_id = id;
arm_spe_set_event_name(evlist, id, "tlb-access");
id += 1;
}
if (spe->synth_opts.branches) {
spe->sample_branch = true;
/* Branch miss */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->branch_miss_id = id;
arm_spe_set_event_name(evlist, id, "branch-miss");
id += 1;
}
if (spe->synth_opts.remote_access) {
spe->sample_remote_access = true;
/* Remote access */
err = arm_spe_synth_event(session, &attr, id);
if (err)
return err;
spe->remote_access_id = id;
arm_spe_set_event_name(evlist, id, "remote-access");
id += 1;
}
return 0;
}
int arm_spe_process_auxtrace_info(union perf_event *event,
struct perf_session *session)
{
struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info;
size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE;
size_t min_sz = sizeof(u64) * ARM_SPE_AUXTRACE_PRIV_MAX;
struct arm_spe *spe;
int err;
@ -221,6 +935,7 @@ int arm_spe_process_auxtrace_info(union perf_event *event,
spe->auxtrace_type = auxtrace_info->type;
spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
spe->timeless_decoding = arm_spe__is_timeless_decoding(spe);
spe->auxtrace.process_event = arm_spe_process_event;
spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event;
spe->auxtrace.flush_events = arm_spe_flush;
@ -231,8 +946,30 @@ int arm_spe_process_auxtrace_info(union perf_event *event,
arm_spe_print_info(&auxtrace_info->priv[0]);
if (dump_trace)
return 0;
if (session->itrace_synth_opts && session->itrace_synth_opts->set)
spe->synth_opts = *session->itrace_synth_opts;
else
itrace_synth_opts__set_default(&spe->synth_opts, false);
err = arm_spe_synth_events(spe, session);
if (err)
goto err_free_queues;
err = auxtrace_queues__process_index(&spe->queues, session);
if (err)
goto err_free_queues;
if (spe->queues.populated)
spe->data_queued = true;
return 0;
err_free_queues:
auxtrace_queues__free(&spe->queues);
session->auxtrace = NULL;
err_free:
free(spe);
return err;

View File

@ -55,7 +55,6 @@
#include "util/mmap.h"
#include <linux/ctype.h>
#include <linux/kernel.h>
#include "symbol/kallsyms.h"
#include <internal/lib.h>
@ -729,7 +728,7 @@ int auxtrace_parse_sample_options(struct auxtrace_record *itr,
struct evlist *evlist,
struct record_opts *opts, const char *str)
{
struct perf_evsel_config_term *term;
struct evsel_config_term *term;
struct evsel *aux_evsel;
bool has_aux_sample_size = false;
bool has_aux_leader = false;
@ -771,7 +770,7 @@ no_opt:
evlist__for_each_entry(evlist, evsel) {
if (evsel__is_aux_event(evsel))
aux_evsel = evsel;
term = perf_evsel__get_config_term(evsel, AUX_SAMPLE_SIZE);
term = evsel__get_config_term(evsel, AUX_SAMPLE_SIZE);
if (term) {
has_aux_sample_size = true;
evsel->core.attr.aux_sample_size = term->val.aux_sample_size;
@ -1331,6 +1330,11 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts,
synth_opts->pwr_events = true;
synth_opts->other_events = true;
synth_opts->errors = true;
synth_opts->flc = true;
synth_opts->llc = true;
synth_opts->tlb = true;
synth_opts->remote_access = true;
if (no_sample) {
synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS;
synth_opts->period = 1;
@ -1491,6 +1495,18 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str,
goto out_err;
p = endptr;
break;
case 'f':
synth_opts->flc = true;
break;
case 'm':
synth_opts->llc = true;
break;
case 't':
synth_opts->tlb = true;
break;
case 'a':
synth_opts->remote_access = true;
break;
case ' ':
case ',':
break;

View File

@ -63,6 +63,7 @@ enum itrace_period_type {
* because 'perf inject' will write it out
* @instructions: whether to synthesize 'instructions' events
* @branches: whether to synthesize 'branches' events
* (branch misses only for Arm SPE)
* @transactions: whether to synthesize events for transactions
* @ptwrites: whether to synthesize events for ptwrites
* @pwr_events: whether to synthesize power events
@ -78,6 +79,10 @@ enum itrace_period_type {
* @thread_stack: feed branches to the thread_stack
* @last_branch: add branch context to 'instruction' events
* @add_last_branch: add branch context to existing event records
* @flc: whether to synthesize first level cache events
* @llc: whether to synthesize last level cache events
* @tlb: whether to synthesize TLB events
* @remote_access: whether to synthesize remote access events
* @callchain_sz: maximum callchain size
* @last_branch_sz: branch context size
* @period: 'instructions' events period
@ -107,6 +112,10 @@ struct itrace_synth_opts {
bool thread_stack;
bool last_branch;
bool add_last_branch;
bool flc;
bool llc;
bool tlb;
bool remote_access;
unsigned int callchain_sz;
unsigned int last_branch_sz;
unsigned long long period;
@ -596,7 +605,7 @@ bool auxtrace__evsel_is_auxtrace(struct perf_session *session,
#define ITRACE_HELP \
" i: synthesize instructions events\n" \
" b: synthesize branches events\n" \
" b: synthesize branches events (branch misses for Arm SPE)\n" \
" c: synthesize branches events (calls only)\n" \
" r: synthesize branches events (returns only)\n" \
" x: synthesize transactions events\n" \
@ -604,6 +613,10 @@ bool auxtrace__evsel_is_auxtrace(struct perf_session *session,
" p: synthesize power events\n" \
" e: synthesize error events\n" \
" d: create a debug log\n" \
" f: synthesize first level cache events\n" \
" m: synthesize last level cache events\n" \
" t: synthesize TLB events\n" \
" a: synthesize remote access events\n" \
" g[len]: synthesize a call chain (use with i or x)\n" \
" l[len]: synthesize last branch entries (use with i or x)\n" \
" sNUMBER: skip initial number of events\n" \

View File

@ -1225,7 +1225,7 @@ bpf__obj_config_map(struct bpf_object *obj,
out:
free(map_name);
if (!err)
key_scan_pos += strlen(map_opt);
*key_scan_pos += strlen(map_opt);
return err;
}

View File

@ -46,7 +46,7 @@ struct branch_entry {
struct branch_stack {
u64 nr;
u64 hw_idx;
struct branch_entry entries[0];
struct branch_entry entries[];
};
/*

View File

@ -1599,3 +1599,17 @@ void callchain_cursor_reset(struct callchain_cursor *cursor)
for (node = cursor->first; node != NULL; node = node->next)
map__zput(node->ms.map);
}
void callchain_param_setup(u64 sample_type)
{
if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
if ((sample_type & PERF_SAMPLE_REGS_USER) &&
(sample_type & PERF_SAMPLE_STACK_USER)) {
callchain_param.record_mode = CALLCHAIN_DWARF;
dwarf_callchain_users = true;
} else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
callchain_param.record_mode = CALLCHAIN_LBR;
else
callchain_param.record_mode = CALLCHAIN_FP;
}
}

View File

@ -297,4 +297,5 @@ int callchain_branch_counts(struct callchain_root *root,
u64 *branch_count, u64 *predicted_count,
u64 *abort_count, u64 *cycles_count);
void callchain_param_setup(u64 sample_type);
#endif /* __PERF_CALLCHAIN_H */

View File

@ -65,7 +65,7 @@ static int perf_flag_probe(void)
return 1;
}
WARN_ONCE(err != EINVAL && err != EBUSY,
WARN_ONCE(err != EINVAL && err != EBUSY && err != EACCES,
"perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
err, str_error_r(err, sbuf, sizeof(sbuf)));
@ -83,7 +83,7 @@ static int perf_flag_probe(void)
if (fd >= 0)
close(fd);
if (WARN_ONCE(fd < 0 && err != EBUSY,
if (WARN_ONCE(fd < 0 && err != EBUSY && err != EACCES,
"perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
err, str_error_r(err, sbuf, sizeof(sbuf))))
return -1;

View File

@ -17,10 +17,10 @@
#include "util/event.h" /* proc_map_timeout */
#include "util/hist.h" /* perf_hist_config */
#include "util/llvm-utils.h" /* perf_llvm_config */
#include "util/stat.h" /* perf_stat__set_big_num */
#include "build-id.h"
#include "debug.h"
#include "config.h"
#include "debug.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
@ -452,6 +452,15 @@ static int perf_ui_config(const char *var, const char *value)
return 0;
}
static int perf_stat_config(const char *var, const char *value)
{
if (!strcmp(var, "stat.big-num"))
perf_stat__set_big_num(perf_config_bool(var, value));
/* Add other config variables here. */
return 0;
}
int perf_default_config(const char *var, const char *value,
void *dummy __maybe_unused)
{
@ -473,6 +482,9 @@ int perf_default_config(const char *var, const char *value,
if (strstarts(var, "buildid."))
return perf_buildid_config(var, value);
if (strstarts(var, "stat."))
return perf_stat_config(var, value);
/* Add other config variables here. */
return 0;
}

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "evsel.h"
#include "counts.h"
#include <linux/zalloc.h>
@ -42,24 +43,25 @@ void perf_counts__delete(struct perf_counts *counts)
}
}
static void perf_counts__reset(struct perf_counts *counts)
void perf_counts__reset(struct perf_counts *counts)
{
xyarray__reset(counts->loaded);
xyarray__reset(counts->values);
memset(&counts->aggr, 0, sizeof(struct perf_counts_values));
}
void perf_evsel__reset_counts(struct evsel *evsel)
void evsel__reset_counts(struct evsel *evsel)
{
perf_counts__reset(evsel->counts);
}
int perf_evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads)
int evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads)
{
evsel->counts = perf_counts__new(ncpus, nthreads);
return evsel->counts != NULL ? 0 : -ENOMEM;
}
void perf_evsel__free_counts(struct evsel *evsel)
void evsel__free_counts(struct evsel *evsel)
{
perf_counts__delete(evsel->counts);
evsel->counts = NULL;

View File

@ -37,9 +37,10 @@ perf_counts__set_loaded(struct perf_counts *counts, int cpu, int thread, bool lo
struct perf_counts *perf_counts__new(int ncpus, int nthreads);
void perf_counts__delete(struct perf_counts *counts);
void perf_counts__reset(struct perf_counts *counts);
void perf_evsel__reset_counts(struct evsel *evsel);
int perf_evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads);
void perf_evsel__free_counts(struct evsel *evsel);
void evsel__reset_counts(struct evsel *evsel);
int evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads);
void evsel__free_counts(struct evsel *evsel);
#endif /* __PERF_COUNTS_H */

View File

@ -22,7 +22,7 @@ struct numa_topology_node {
struct numa_topology {
u32 nr;
struct numa_topology_node nodes[0];
struct numa_topology_node nodes[];
};
struct cpu_topology *cpu_topology__new(void);

View File

@ -15,7 +15,7 @@ enum {
MODE_CLASS = 1,
MODE_FUNC = 2,
MODE_TYPE = 3,
MODE_CTYPE = 3, /* class arg */
MODE_CTYPE = 4, /* class arg */
};
#define BASE_ENT(c, n) [c - 'A']=n
@ -27,7 +27,7 @@ static const char *base_types['Z' - 'A' + 1] = {
BASE_ENT('I', "int" ),
BASE_ENT('J', "long" ),
BASE_ENT('S', "short" ),
BASE_ENT('Z', "bool" ),
BASE_ENT('Z', "boolean" ),
};
/*
@ -59,15 +59,16 @@ __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int
switch (*q) {
case 'L':
if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
if (mode == MODE_CTYPE) {
if (mode == MODE_PREFIX || mode == MODE_TYPE) {
if (mode == MODE_TYPE) {
if (narg)
rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
narg++;
}
rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
if (mode == MODE_PREFIX)
mode = MODE_CLASS;
else
mode = MODE_CTYPE;
} else
buf[rlen++] = *q;
break;
@ -120,7 +121,7 @@ __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int
if (mode != MODE_CLASS && mode != MODE_CTYPE)
goto error;
/* safe because at least one other char to process */
if (isalpha(*(q + 1)))
if (isalpha(*(q + 1)) && mode == MODE_CLASS)
rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
if (mode == MODE_CLASS)
mode = MODE_FUNC;

View File

@ -47,6 +47,7 @@ char dso__symtab_origin(const struct dso *dso)
[DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO] = 'D',
[DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f',
[DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u',
[DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO] = 'x',
[DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO] = 'o',
[DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
[DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
@ -129,6 +130,21 @@ int dso__read_binary_type_filename(const struct dso *dso,
snprintf(filename + len, size - len, "%s", dso->long_name);
break;
case DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO:
/*
* Ubuntu can mixup /usr/lib with /lib, putting debuginfo in
* /usr/lib/debug/lib when it is expected to be in
* /usr/lib/debug/usr/lib
*/
if (strlen(dso->long_name) < 9 ||
strncmp(dso->long_name, "/usr/lib/", 9)) {
ret = -1;
break;
}
len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
snprintf(filename + len, size - len, "%s", dso->long_name + 4);
break;
case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
{
const char *last_slash;

View File

@ -30,6 +30,7 @@ enum dso_binary_type {
DSO_BINARY_TYPE__BUILD_ID_CACHE_DEBUGINFO,
DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
DSO_BINARY_TYPE__GUEST_KMODULE,
@ -137,7 +138,7 @@ struct dso_cache {
struct rb_node rb_node;
u64 offset;
u64 size;
char data[0];
char data[];
};
struct auxtrace_cache;
@ -209,7 +210,7 @@ struct dso {
struct nsinfo *nsinfo;
struct dso_id id;
refcount_t refcnt;
char name[0];
char name[];
};
/* dso__for_each_symbol - iterate over the symbols of given type

View File

@ -79,7 +79,7 @@ struct sample_read {
struct ip_callchain {
u64 nr;
u64 ips[0];
u64 ips[];
};
struct branch_stack;

View File

@ -233,7 +233,7 @@ void perf_evlist__set_leader(struct evlist *evlist)
int __perf_evlist__add_default(struct evlist *evlist, bool precise)
{
struct evsel *evsel = perf_evsel__new_cycles(precise);
struct evsel *evsel = evsel__new_cycles(precise);
if (evsel == NULL)
return -ENOMEM;
@ -249,7 +249,7 @@ int perf_evlist__add_dummy(struct evlist *evlist)
.config = PERF_COUNT_SW_DUMMY,
.size = sizeof(attr), /* to capture ABI version */
};
struct evsel *evsel = perf_evsel__new_idx(&attr, evlist->core.nr_entries);
struct evsel *evsel = evsel__new_idx(&attr, evlist->core.nr_entries);
if (evsel == NULL)
return -ENOMEM;
@ -266,7 +266,7 @@ static int evlist__add_attrs(struct evlist *evlist,
size_t i;
for (i = 0; i < nr_attrs; i++) {
evsel = perf_evsel__new_idx(attrs + i, evlist->core.nr_entries + i);
evsel = evsel__new_idx(attrs + i, evlist->core.nr_entries + i);
if (evsel == NULL)
goto out_delete_partial_list;
list_add_tail(&evsel->core.node, &head);
@ -325,7 +325,7 @@ perf_evlist__find_tracepoint_by_name(struct evlist *evlist,
int perf_evlist__add_newtp(struct evlist *evlist,
const char *sys, const char *name, void *handler)
{
struct evsel *evsel = perf_evsel__newtp(sys, name);
struct evsel *evsel = evsel__newtp(sys, name);
if (IS_ERR(evsel))
return -1;
@ -380,22 +380,33 @@ void evlist__disable(struct evlist *evlist)
{
struct evsel *pos;
struct affinity affinity;
int cpu, i;
int cpu, i, imm = 0;
bool has_imm = false;
if (affinity__setup(&affinity) < 0)
return;
evlist__for_each_cpu(evlist, i, cpu) {
affinity__set(&affinity, cpu);
/* Disable 'immediate' events last */
for (imm = 0; imm <= 1; imm++) {
evlist__for_each_cpu(evlist, i, cpu) {
affinity__set(&affinity, cpu);
evlist__for_each_entry(evlist, pos) {
if (evsel__cpu_iter_skip(pos, cpu))
continue;
if (pos->disabled || !evsel__is_group_leader(pos) || !pos->core.fd)
continue;
evsel__disable_cpu(pos, pos->cpu_iter - 1);
evlist__for_each_entry(evlist, pos) {
if (evsel__cpu_iter_skip(pos, cpu))
continue;
if (pos->disabled || !evsel__is_group_leader(pos) || !pos->core.fd)
continue;
if (pos->immediate)
has_imm = true;
if (pos->immediate != imm)
continue;
evsel__disable_cpu(pos, pos->cpu_iter - 1);
}
}
if (!has_imm)
break;
}
affinity__cleanup(&affinity);
evlist__for_each_entry(evlist, pos) {
if (!evsel__is_group_leader(pos) || !pos->core.fd)

View File

@ -56,14 +56,14 @@ struct perf_missing_features perf_missing_features;
static clockid_t clockid;
static int perf_evsel__no_extra_init(struct evsel *evsel __maybe_unused)
static int evsel__no_extra_init(struct evsel *evsel __maybe_unused)
{
return 0;
}
void __weak test_attr__ready(void) { }
static void perf_evsel__no_extra_fini(struct evsel *evsel __maybe_unused)
static void evsel__no_extra_fini(struct evsel *evsel __maybe_unused)
{
}
@ -73,13 +73,12 @@ static struct {
void (*fini)(struct evsel *evsel);
} perf_evsel__object = {
.size = sizeof(struct evsel),
.init = perf_evsel__no_extra_init,
.fini = perf_evsel__no_extra_fini,
.init = evsel__no_extra_init,
.fini = evsel__no_extra_fini,
};
int perf_evsel__object_config(size_t object_size,
int (*init)(struct evsel *evsel),
void (*fini)(struct evsel *evsel))
int evsel__object_config(size_t object_size, int (*init)(struct evsel *evsel),
void (*fini)(struct evsel *evsel))
{
if (object_size == 0)
@ -255,11 +254,12 @@ void evsel__init(struct evsel *evsel,
evsel->metric_expr = NULL;
evsel->metric_name = NULL;
evsel->metric_events = NULL;
evsel->per_pkg_mask = NULL;
evsel->collect_stat = false;
evsel->pmu_name = NULL;
}
struct evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx)
struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx)
{
struct evsel *evsel = zalloc(perf_evsel__object.size);
@ -292,7 +292,7 @@ static bool perf_event_can_profile_kernel(void)
return perf_event_paranoid_check(1);
}
struct evsel *perf_evsel__new_cycles(bool precise)
struct evsel *evsel__new_cycles(bool precise)
{
struct perf_event_attr attr = {
.type = PERF_TYPE_HARDWARE,
@ -334,7 +334,7 @@ error_free:
/*
* Returns pointer with encoded error via <linux/err.h> interface.
*/
struct evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx)
struct evsel *evsel__newtp_idx(const char *sys, const char *name, int idx)
{
struct evsel *evsel = zalloc(perf_evsel__object.size);
int err = -ENOMEM;
@ -372,7 +372,7 @@ out_err:
return ERR_PTR(err);
}
const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
const char *evsel__hw_names[PERF_COUNT_HW_MAX] = {
"cycles",
"instructions",
"cache-references",
@ -387,8 +387,8 @@ const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
static const char *__evsel__hw_name(u64 config)
{
if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
return perf_evsel__hw_names[config];
if (config < PERF_COUNT_HW_MAX && evsel__hw_names[config])
return evsel__hw_names[config];
return "unknown-hardware";
}
@ -435,7 +435,7 @@ static int evsel__hw_name(struct evsel *evsel, char *bf, size_t size)
return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
}
const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
const char *evsel__sw_names[PERF_COUNT_SW_MAX] = {
"cpu-clock",
"task-clock",
"page-faults",
@ -450,8 +450,8 @@ const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = {
static const char *__evsel__sw_name(u64 config)
{
if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config])
return perf_evsel__sw_names[config];
if (config < PERF_COUNT_SW_MAX && evsel__sw_names[config])
return evsel__sw_names[config];
return "unknown-software";
}
@ -486,8 +486,7 @@ static int evsel__bp_name(struct evsel *evsel, char *bf, size_t size)
return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
}
const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
[PERF_EVSEL__MAX_ALIASES] = {
const char *evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX][EVSEL__MAX_ALIASES] = {
{ "L1-dcache", "l1-d", "l1d", "L1-data", },
{ "L1-icache", "l1-i", "l1i", "L1-instruction", },
{ "LLC", "L2", },
@ -497,15 +496,13 @@ const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
{ "node", },
};
const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_EVSEL__MAX_ALIASES] = {
const char *evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][EVSEL__MAX_ALIASES] = {
{ "load", "loads", "read", },
{ "store", "stores", "write", },
{ "prefetch", "prefetches", "speculative-read", "speculative-load", },
};
const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
[PERF_EVSEL__MAX_ALIASES] = {
const char *evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX][EVSEL__MAX_ALIASES] = {
{ "refs", "Reference", "ops", "access", },
{ "misses", "miss", },
};
@ -521,7 +518,7 @@ const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
* L1I : Read and prefetch only
* ITLB and BPU : Read-only
*/
static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
static unsigned long evsel__hw_cache_stat[C(MAX)] = {
[C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
[C(L1I)] = (CACHE_READ | CACHE_PREFETCH),
[C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH),
@ -533,7 +530,7 @@ static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = {
bool evsel__is_cache_op_valid(u8 type, u8 op)
{
if (perf_evsel__hw_cache_stat[type] & COP(op))
if (evsel__hw_cache_stat[type] & COP(op))
return true; /* valid */
else
return false; /* invalid */
@ -542,13 +539,13 @@ bool evsel__is_cache_op_valid(u8 type, u8 op)
int __evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size)
{
if (result) {
return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0],
perf_evsel__hw_cache_op[op][0],
perf_evsel__hw_cache_result[result][0]);
return scnprintf(bf, size, "%s-%s-%s", evsel__hw_cache[type][0],
evsel__hw_cache_op[op][0],
evsel__hw_cache_result[result][0]);
}
return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0],
perf_evsel__hw_cache_op[op][1]);
return scnprintf(bf, size, "%s-%s", evsel__hw_cache[type][0],
evsel__hw_cache_op[op][1]);
}
static int __evsel__hw_cache_name(u64 config, char *bf, size_t size)
@ -768,10 +765,10 @@ perf_evsel__reset_callgraph(struct evsel *evsel,
}
}
static void apply_config_terms(struct evsel *evsel,
struct record_opts *opts, bool track)
static void evsel__apply_config_terms(struct evsel *evsel,
struct record_opts *opts, bool track)
{
struct perf_evsel_config_term *term;
struct evsel_config_term *term;
struct list_head *config_terms = &evsel->config_terms;
struct perf_event_attr *attr = &evsel->core.attr;
/* callgraph default */
@ -784,30 +781,30 @@ static void apply_config_terms(struct evsel *evsel,
list_for_each_entry(term, config_terms, list) {
switch (term->type) {
case PERF_EVSEL__CONFIG_TERM_PERIOD:
case EVSEL__CONFIG_TERM_PERIOD:
if (!(term->weak && opts->user_interval != ULLONG_MAX)) {
attr->sample_period = term->val.period;
attr->freq = 0;
evsel__reset_sample_bit(evsel, PERIOD);
}
break;
case PERF_EVSEL__CONFIG_TERM_FREQ:
case EVSEL__CONFIG_TERM_FREQ:
if (!(term->weak && opts->user_freq != UINT_MAX)) {
attr->sample_freq = term->val.freq;
attr->freq = 1;
evsel__set_sample_bit(evsel, PERIOD);
}
break;
case PERF_EVSEL__CONFIG_TERM_TIME:
case EVSEL__CONFIG_TERM_TIME:
if (term->val.time)
evsel__set_sample_bit(evsel, TIME);
else
evsel__reset_sample_bit(evsel, TIME);
break;
case PERF_EVSEL__CONFIG_TERM_CALLGRAPH:
case EVSEL__CONFIG_TERM_CALLGRAPH:
callgraph_buf = term->val.str;
break;
case PERF_EVSEL__CONFIG_TERM_BRANCH:
case EVSEL__CONFIG_TERM_BRANCH:
if (term->val.str && strcmp(term->val.str, "no")) {
evsel__set_sample_bit(evsel, BRANCH_STACK);
parse_branch_str(term->val.str,
@ -815,16 +812,16 @@ static void apply_config_terms(struct evsel *evsel,
} else
evsel__reset_sample_bit(evsel, BRANCH_STACK);
break;
case PERF_EVSEL__CONFIG_TERM_STACK_USER:
case EVSEL__CONFIG_TERM_STACK_USER:
dump_size = term->val.stack_user;
break;
case PERF_EVSEL__CONFIG_TERM_MAX_STACK:
case EVSEL__CONFIG_TERM_MAX_STACK:
max_stack = term->val.max_stack;
break;
case PERF_EVSEL__CONFIG_TERM_MAX_EVENTS:
case EVSEL__CONFIG_TERM_MAX_EVENTS:
evsel->max_events = term->val.max_events;
break;
case PERF_EVSEL__CONFIG_TERM_INHERIT:
case EVSEL__CONFIG_TERM_INHERIT:
/*
* attr->inherit should has already been set by
* evsel__config. If user explicitly set
@ -833,20 +830,20 @@ static void apply_config_terms(struct evsel *evsel,
*/
attr->inherit = term->val.inherit ? 1 : 0;
break;
case PERF_EVSEL__CONFIG_TERM_OVERWRITE:
case EVSEL__CONFIG_TERM_OVERWRITE:
attr->write_backward = term->val.overwrite ? 1 : 0;
break;
case PERF_EVSEL__CONFIG_TERM_DRV_CFG:
case EVSEL__CONFIG_TERM_DRV_CFG:
break;
case PERF_EVSEL__CONFIG_TERM_PERCORE:
case EVSEL__CONFIG_TERM_PERCORE:
break;
case PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT:
case EVSEL__CONFIG_TERM_AUX_OUTPUT:
attr->aux_output = term->val.aux_output ? 1 : 0;
break;
case PERF_EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
/* Already applied by auxtrace */
break;
case PERF_EVSEL__CONFIG_TERM_CFG_CHG:
case EVSEL__CONFIG_TERM_CFG_CHG:
break;
default:
break;
@ -907,10 +904,9 @@ static bool is_dummy_event(struct evsel *evsel)
(evsel->core.attr.config == PERF_COUNT_SW_DUMMY);
}
struct perf_evsel_config_term *__perf_evsel__get_config_term(struct evsel *evsel,
enum evsel_term_type type)
struct evsel_config_term *__evsel__get_config_term(struct evsel *evsel, enum evsel_term_type type)
{
struct perf_evsel_config_term *term, *found_term = NULL;
struct evsel_config_term *term, *found_term = NULL;
list_for_each_entry(term, &evsel->config_terms, list) {
if (term->type == type)
@ -1145,7 +1141,7 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
* Apply event specific term settings,
* it overloads any global configuration.
*/
apply_config_terms(evsel, opts, track);
evsel__apply_config_terms(evsel, opts, track);
evsel->ignore_missing_thread = opts->ignore_missing_thread;
@ -1158,11 +1154,14 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
}
/*
* A dummy event never triggers any actual counter and therefore
* cannot be used with branch_stack.
*
* For initial_delay, a dummy event is added implicitly.
* The software event will trigger -EOPNOTSUPP error out,
* if BRANCH_STACK bit is set.
*/
if (opts->initial_delay && is_dummy_event(evsel))
if (is_dummy_event(evsel))
evsel__reset_sample_bit(evsel, BRANCH_STACK);
}
@ -1241,9 +1240,9 @@ int evsel__disable(struct evsel *evsel)
return err;
}
static void perf_evsel__free_config_terms(struct evsel *evsel)
static void evsel__free_config_terms(struct evsel *evsel)
{
struct perf_evsel_config_term *term, *h;
struct evsel_config_term *term, *h;
list_for_each_entry_safe(term, h, &evsel->config_terms, list) {
list_del_init(&term->list);
@ -1257,10 +1256,10 @@ void evsel__exit(struct evsel *evsel)
{
assert(list_empty(&evsel->core.node));
assert(evsel->evlist == NULL);
perf_evsel__free_counts(evsel);
evsel__free_counts(evsel);
perf_evsel__free_fd(&evsel->core);
perf_evsel__free_id(&evsel->core);
perf_evsel__free_config_terms(evsel);
evsel__free_config_terms(evsel);
cgroup__put(evsel->cgrp);
perf_cpu_map__put(evsel->core.cpus);
perf_cpu_map__put(evsel->core.own_cpus);
@ -1268,6 +1267,8 @@ void evsel__exit(struct evsel *evsel)
zfree(&evsel->group_name);
zfree(&evsel->name);
zfree(&evsel->pmu_name);
zfree(&evsel->per_pkg_mask);
zfree(&evsel->metric_events);
perf_evsel__object.fini(evsel);
}
@ -1425,7 +1426,7 @@ int __evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread, bool scale)
if (FD(evsel, cpu, thread) < 0)
return -EINVAL;
if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0)
if (evsel->counts == NULL && evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0)
return -ENOMEM;
if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) <= 0)
@ -2416,7 +2417,7 @@ bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize)
/* Is there already the separator in the name. */
if (strchr(name, '/') ||
strchr(name, ':'))
(strchr(name, ':') && !evsel->is_libpfm_event))
sep = "";
if (asprintf(&new_name, "%s%su", name, sep) < 0)
@ -2477,31 +2478,40 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target,
int err, char *msg, size_t size)
{
char sbuf[STRERR_BUFSIZE];
int printed = 0;
int printed = 0, enforced = 0;
switch (err) {
case EPERM:
case EACCES:
printed += scnprintf(msg + printed, size - printed,
"Access to performance monitoring and observability operations is limited.\n");
if (!sysfs__read_int("fs/selinux/enforce", &enforced)) {
if (enforced) {
printed += scnprintf(msg + printed, size - printed,
"Enforced MAC policy settings (SELinux) can limit access to performance\n"
"monitoring and observability operations. Inspect system audit records for\n"
"more perf_event access control information and adjusting the policy.\n");
}
}
if (err == EPERM)
printed = scnprintf(msg, size,
printed += scnprintf(msg, size,
"No permission to enable %s event.\n\n", evsel__name(evsel));
return scnprintf(msg + printed, size - printed,
"You may not have permission to collect %sstats.\n\n"
"Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n"
"which controls use of the performance events system by\n"
"unprivileged users (without CAP_PERFMON or CAP_SYS_ADMIN).\n\n"
"The current value is %d:\n\n"
"Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open\n"
"access to performance monitoring and observability operations for users\n"
"without CAP_PERFMON or CAP_SYS_ADMIN Linux capability.\n"
"perf_event_paranoid setting is %d:\n"
" -1: Allow use of (almost) all events by all users\n"
" Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK\n"
">= 0: Disallow ftrace function tracepoint by users without CAP_PERFMON or CAP_SYS_ADMIN\n"
" Disallow raw tracepoint access by users without CAP_SYS_PERFMON or CAP_SYS_ADMIN\n"
">= 1: Disallow CPU event access by users without CAP_PERFMON or CAP_SYS_ADMIN\n"
">= 2: Disallow kernel profiling by users without CAP_PERFMON or CAP_SYS_ADMIN\n\n"
"To make this setting permanent, edit /etc/sysctl.conf too, e.g.:\n\n"
" kernel.perf_event_paranoid = -1\n" ,
target->system_wide ? "system-wide " : "",
perf_event_paranoid());
">= 0: Disallow raw and ftrace function tracepoint access\n"
">= 1: Disallow CPU event access\n"
">= 2: Disallow kernel profiling\n"
"To make the adjusted perf_event_paranoid setting permanent preserve it\n"
"in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)",
perf_event_paranoid());
case ENOENT:
return scnprintf(msg, size, "The %s event is not supported.", evsel__name(evsel));
case EMFILE:

View File

@ -76,6 +76,7 @@ struct evsel {
bool ignore_missing_thread;
bool forced_leader;
bool use_uncore_alias;
bool is_libpfm_event;
/* parse modifier helper */
int exclude_GH;
int sample_read;
@ -154,31 +155,31 @@ void perf_counts_values__scale(struct perf_counts_values *count,
void evsel__compute_deltas(struct evsel *evsel, int cpu, int thread,
struct perf_counts_values *count);
int perf_evsel__object_config(size_t object_size,
int (*init)(struct evsel *evsel),
void (*fini)(struct evsel *evsel));
int evsel__object_config(size_t object_size,
int (*init)(struct evsel *evsel),
void (*fini)(struct evsel *evsel));
struct perf_pmu *evsel__find_pmu(struct evsel *evsel);
bool evsel__is_aux_event(struct evsel *evsel);
struct evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx);
struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx);
static inline struct evsel *evsel__new(struct perf_event_attr *attr)
{
return perf_evsel__new_idx(attr, 0);
return evsel__new_idx(attr, 0);
}
struct evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx);
struct evsel *evsel__newtp_idx(const char *sys, const char *name, int idx);
/*
* Returns pointer with encoded error via <linux/err.h> interface.
*/
static inline struct evsel *perf_evsel__newtp(const char *sys, const char *name)
static inline struct evsel *evsel__newtp(const char *sys, const char *name)
{
return perf_evsel__newtp_idx(sys, name, 0);
return evsel__newtp_idx(sys, name, 0);
}
struct evsel *perf_evsel__new_cycles(bool precise);
struct evsel *evsel__new_cycles(bool precise);
struct tep_event *event_format__new(const char *sys, const char *name);
@ -198,16 +199,13 @@ void evsel__calc_id_pos(struct evsel *evsel);
bool evsel__is_cache_op_valid(u8 type, u8 op);
#define PERF_EVSEL__MAX_ALIASES 8
#define EVSEL__MAX_ALIASES 8
extern const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
[PERF_EVSEL__MAX_ALIASES];
extern const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_EVSEL__MAX_ALIASES];
extern const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX]
[PERF_EVSEL__MAX_ALIASES];
extern const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX];
extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX];
extern const char *evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX][EVSEL__MAX_ALIASES];
extern const char *evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX][EVSEL__MAX_ALIASES];
extern const char *evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX][EVSEL__MAX_ALIASES];
extern const char *evsel__hw_names[PERF_COUNT_HW_MAX];
extern const char *evsel__sw_names[PERF_COUNT_SW_MAX];
int __evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size);
const char *evsel__name(struct evsel *evsel);

View File

@ -6,30 +6,30 @@
#include <stdbool.h>
/*
* The 'struct perf_evsel_config_term' is used to pass event
* The 'struct evsel_config_term' is used to pass event
* specific configuration data to evsel__config routine.
* It is allocated within event parsing and attached to
* perf_evsel::config_terms list head.
* evsel::config_terms list head.
*/
enum evsel_term_type {
PERF_EVSEL__CONFIG_TERM_PERIOD,
PERF_EVSEL__CONFIG_TERM_FREQ,
PERF_EVSEL__CONFIG_TERM_TIME,
PERF_EVSEL__CONFIG_TERM_CALLGRAPH,
PERF_EVSEL__CONFIG_TERM_STACK_USER,
PERF_EVSEL__CONFIG_TERM_INHERIT,
PERF_EVSEL__CONFIG_TERM_MAX_STACK,
PERF_EVSEL__CONFIG_TERM_MAX_EVENTS,
PERF_EVSEL__CONFIG_TERM_OVERWRITE,
PERF_EVSEL__CONFIG_TERM_DRV_CFG,
PERF_EVSEL__CONFIG_TERM_BRANCH,
PERF_EVSEL__CONFIG_TERM_PERCORE,
PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT,
PERF_EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
PERF_EVSEL__CONFIG_TERM_CFG_CHG,
EVSEL__CONFIG_TERM_PERIOD,
EVSEL__CONFIG_TERM_FREQ,
EVSEL__CONFIG_TERM_TIME,
EVSEL__CONFIG_TERM_CALLGRAPH,
EVSEL__CONFIG_TERM_STACK_USER,
EVSEL__CONFIG_TERM_INHERIT,
EVSEL__CONFIG_TERM_MAX_STACK,
EVSEL__CONFIG_TERM_MAX_EVENTS,
EVSEL__CONFIG_TERM_OVERWRITE,
EVSEL__CONFIG_TERM_DRV_CFG,
EVSEL__CONFIG_TERM_BRANCH,
EVSEL__CONFIG_TERM_PERCORE,
EVSEL__CONFIG_TERM_AUX_OUTPUT,
EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE,
EVSEL__CONFIG_TERM_CFG_CHG,
};
struct perf_evsel_config_term {
struct evsel_config_term {
struct list_head list;
enum evsel_term_type type;
bool free_str;
@ -53,10 +53,9 @@ struct perf_evsel_config_term {
struct evsel;
struct perf_evsel_config_term *__perf_evsel__get_config_term(struct evsel *evsel,
enum evsel_term_type type);
struct evsel_config_term *__evsel__get_config_term(struct evsel *evsel, enum evsel_term_type type);
#define perf_evsel__get_config_term(evsel, type) \
__perf_evsel__get_config_term(evsel, PERF_EVSEL__CONFIG_TERM_ ## type)
#define evsel__get_config_term(evsel, type) \
__evsel__get_config_term(evsel, EVSEL__CONFIG_TERM_ ## type)
#endif // __PERF_EVSEL_CONFIG_H

Some files were not shown because too many files have changed in this diff Show More