History

Merge tag 'perf-tools-for-v6.8-1-2024-01-09' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools

Pull perf tools updates from Arnaldo Carvalho de Melo: "Add Namhyung Kim as tools/perf/ co-maintainer, we're taking turns processing patches, switching roles from perf-tools to perf-tools-next at each Linux release. Data profiling: - Associate samples that identify loads and stores with data structures. This uses events available on Intel, AMD and others and DWARF info: # To get memory access samples in kernel for 1 second (on Intel) $ perf mem record -a -K --ldlat=4 -- sleep 1 # Similar for the AMD (but it requires 6.3+ kernel for BPF filters) $ perf mem record -a --filter 'mem_op == load || mem_op == store, ip > 0x8000000000000000' -- sleep 1 Then, amongst several modes of post processing, one can do things like: $ perf report -s type,typeoff --hierarchy --group --stdio ... # # Samples: 10K of events 'cpu/mem-loads,ldlat=4/P, cpu/mem-stores/P, dummy:u' # Event count (approx.): 602758064 # # Overhead Data Type / Data Type Offset # ........................... ............................ # 26.09% 3.28% 0.00% long unsigned int 26.09% 3.28% 0.00% long unsigned int +0 (no field) 18.48% 0.73% 0.00% struct page 10.83% 0.02% 0.00% struct page +8 (lru.next) 3.90% 0.28% 0.00% struct page +0 (flags) 3.45% 0.06% 0.00% struct page +24 (mapping) 0.25% 0.28% 0.00% struct page +48 (_mapcount.counter) 0.02% 0.06% 0.00% struct page +32 (index) 0.02% 0.00% 0.00% struct page +52 (_refcount.counter) 0.02% 0.01% 0.00% struct page +56 (memcg_data) 0.00% 0.01% 0.00% struct page +16 (lru.prev) 15.37% 17.54% 0.00% (stack operation) 15.37% 17.54% 0.00% (stack operation) +0 (no field) 11.71% 50.27% 0.00% (unknown) 11.71% 50.27% 0.00% (unknown) +0 (no field) $ perf annotate --data-type ... Annotate type: 'struct cfs_rq' in [kernel.kallsyms] (13 samples): ============================================================================ samples offset size field 13 0 640 struct cfs_rq { 2 0 16 struct load_weight load { 2 0 8 unsigned long weight; 0 8 4 u32 inv_weight; }; 0 16 8 unsigned long runnable_weight; 0 24 4 unsigned int nr_running; 1 28 4 unsigned int h_nr_running; ... $ perf annotate --data-type=page --group Annotate type: 'struct page' in [kernel.kallsyms] (480 samples): event[0] = cpu/mem-loads,ldlat=4/P event[1] = cpu/mem-stores/P event[2] = dummy:u =================================================================================== samples offset size field 447 33 0 0 64 struct page { 108 8 0 0 8 long unsigned int flags; 319 13 0 8 40 union { 319 13 0 8 40 struct { 236 2 0 8 16 union { 236 2 0 8 16 struct list_head lru { 236 1 0 8 8 struct list_head* next; 0 1 0 16 8 struct list_head* prev; }; 236 2 0 8 16 struct { 236 1 0 8 8 void* __filler; 0 1 0 16 4 unsigned int mlock_count; }; 236 2 0 8 16 struct list_head buddy_list { 236 1 0 8 8 struct list_head* next; 0 1 0 16 8 struct list_head* prev; }; 236 2 0 8 16 struct list_head pcp_list { 236 1 0 8 8 struct list_head* next; 0 1 0 16 8 struct list_head* prev; }; }; 82 4 0 24 8 struct address_space* mapping; 1 7 0 32 8 union { 1 7 0 32 8 long unsigned int index; 1 7 0 32 8 long unsigned int share; }; 0 0 0 40 8 long unsigned int private; }; This uses the existing annotate code, calling objdump to do the disassembly, with improvements to avoid having this take too long, but longer term a switch to a disassembler library, possibly reusing code in the kernel will be pursued. This is the initial implementation, please use it and report impressions and bugs. Make sure the kernel-debuginfo packages match the running kernel. The 'perf report' phase for non short perf.data files may take a while. There is a great article about it on LWN: https://lwn.net/Articles/955709/ - "Data-type profiling for perf" One last test I did while writing this text, on a AMD Ryzen 5950X, using a distro kernel, while doing a simple 'find /' on an otherwise idle system resulted in: # uname -r 6.6.9-100.fc38.x86_64 # perf -vv | grep BPF_ bpf: [ on ] # HAVE_LIBBPF_SUPPORT bpf_skeletons: [ on ] # HAVE_BPF_SKEL # rpm -qa | grep kernel-debuginfo kernel-debuginfo-common-x86_64-6.6.9-100.fc38.x86_64 kernel-debuginfo-6.6.9-100.fc38.x86_64 # # perf mem record -a --filter 'mem_op == load || mem_op == store, ip > 0x8000000000000000' ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 2.199 MB perf.data (2913 samples) ] # # ls -la perf.data -rw-------. 1 root root 2346486 Jan 9 18:36 perf.data # perf evlist ibs_op// dummy:u # perf evlist -v ibs_op//: type: 11, size: 136, config: 0, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ADDR|CPU|PERIOD|IDENTIFIER|DATA_SRC|WEIGHT, read_format: ID, disabled: 1, inherit: 1, freq: 1, sample_id_all: 1 dummy:u: type: 1 (PERF_TYPE_SOFTWARE), size: 136, config: 0x9 (PERF_COUNT_SW_DUMMY), { sample_period, sample_freq }: 1, sample_type: IP|TID|TIME|ADDR|CPU|IDENTIFIER|DATA_SRC|WEIGHT, read_format: ID, inherit: 1, exclude_kernel: 1, exclude_hv: 1, mmap: 1, comm: 1, task: 1, mmap_data: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1, ksymbol: 1, bpf_event: 1 # # perf report -s type,typeoff --hierarchy --group --stdio # Total Lost Samples: 0 # # Samples: 2K of events 'ibs_op//, dummy:u' # Event count (approx.): 1904553038 # # Overhead Data Type / Data Type Offset # ................... ............................ # 73.70% 0.00% (unknown) 73.70% 0.00% (unknown) +0 (no field) 3.01% 0.00% long unsigned int 3.00% 0.00% long unsigned int +0 (no field) 0.01% 0.00% long unsigned int +2 (no field) 2.73% 0.00% struct task_struct 1.71% 0.00% struct task_struct +52 (on_cpu) 0.38% 0.00% struct task_struct +2104 (rcu_read_unlock_special.b.blocked) 0.23% 0.00% struct task_struct +2100 (rcu_read_lock_nesting) 0.14% 0.00% struct task_struct +2384 () 0.06% 0.00% struct task_struct +3096 (signal) 0.05% 0.00% struct task_struct +3616 (cgroups) 0.05% 0.00% struct task_struct +2344 (active_mm) 0.02% 0.00% struct task_struct +46 (flags) 0.02% 0.00% struct task_struct +2096 (migration_disabled) 0.01% 0.00% struct task_struct +24 (__state) 0.01% 0.00% struct task_struct +3956 (mm_cid_active) 0.01% 0.00% struct task_struct +1048 (cpus_ptr) 0.01% 0.00% struct task_struct +184 (se.group_node.next) 0.01% 0.00% struct task_struct +20 (thread_info.cpu) 0.00% 0.00% struct task_struct +104 (on_rq) 0.00% 0.00% struct task_struct +2456 (pid) 1.36% 0.00% struct module 0.59% 0.00% struct module +952 (kallsyms) 0.42% 0.00% struct module +0 (state) 0.23% 0.00% struct module +8 (list.next) 0.12% 0.00% struct module +216 (syms) 0.95% 0.00% struct inode 0.41% 0.00% struct inode +40 (i_sb) 0.22% 0.00% struct inode +0 (i_mode) 0.06% 0.00% struct inode +76 (i_rdev) 0.06% 0.00% struct inode +56 (i_security) <SNIP> perf top/report: - Don't ignore job control, allowing control+Z + bg to work. - Add s390 raw data interpretation for PAI (Processor Activity Instrumentation) counters. perf archive: - Add new option '--all' to pack perf.data with DSOs. - Add new option '--unpack' to expand tarballs. Initialization speedups: - Lazily initialize zstd streams to save memory when not using it. - Lazily allocate/size mmap event copy. - Lazy load kernel symbols in 'perf record'. - Be lazier in allocating lost samples buffer in 'perf record'. - Don't synthesize BPF events when disabled via the command line (perf record --no-bpf-event). Assorted improvements: - Show note on AMD systems that the :p, :pp, :ppp and :P are all the same, as IBS (Instruction Based Sampling) is used and it is inherentely precise, not having levels of precision like in Intel systems. - When 'cycles' isn't available, fall back to the "task-clock" event when not system wide, not to 'cpu-clock'. - Add --debug-file option to redirect debug output, e.g.: $ perf --debug-file /tmp/perf.log record -v true - Shrink 'struct map' to under one cacheline by avoiding function pointers for selecting if addresses are identity or DSO relative, and using just a byte for some boolean struct members. - Resolve the arch specific strerrno just once to use in perf_env__arch_strerrno(). - Reduce memory for recording PERF_RECORD_LOST_SAMPLES event. Assorted fixes: - Fix the default 'perf top' usage on Intel hybrid systems, now it starts with a browser showing the number of samples for Efficiency (cpu_atom/cycles/P) and Performance (cpu_core/cycles/P). This behaviour is similar on ARM64, with its respective set of big.LITTLE processors. - Fix segfault on build_mem_topology() error path. - Fix 'perf mem' error on hybrid related to availability of mem event in a PMU. - Fix missing reference count gets (map, maps) in the db-export code. - Avoid recursively taking env->bpf_progs.lock in the 'perf_env' code. - Use the newly introduced maps__for_each_map() to add missing locking around iteration of 'struct map' entries. - Parse NOTE segments until the build id is found, don't stop on the first one, ELF files may have several such NOTE segments. - Remove 'egrep' usage, its deprecated, use 'grep -E' instead. - Warn first about missing libelf, not libbpf, that depends on libelf. - Use alternative to 'find ... -printf' as this isn't supported in busybox. - Address python 3.6 DeprecationWarning for string scapes. - Fix memory leak in uniq() in libsubcmd. - Fix man page formatting for 'perf lock' - Fix some spelling mistakes. perf tests: - Fail shell tests that needs some symbol in perf itself if it is stripped. These tests check if a symbol is resolved, if some hot function is indeed detected by profiling, etc. - The 'perf test sigtrap' test is currently failing on PREEMPT_RT, skip it if sleeping spinlocks are detected (using BTF) and point to the mailing list discussion about it. This test is also being skipped on several architectures (powerpc, s390x, arm and aarch64) due to other pending issues with intruction breakpoints. - Adjust test case perf record offcpu profiling tests for s390. - Fix 'Setup struct perf_event_attr' fails on s390 on z/VM guest, addressing issues caused by the fallback from cycles to task-clock done in this release. - Fix mask for VG register in the user-regs test. - Use shellcheck on 'perf test' shell scripts automatically to make sure changes don't introduce things it flags as problematic. - Add option to change objdump binary and allow it to be set via 'perf config'. - Add basic 'perf script', 'perf list --json" and 'perf diff' tests. - Basic branch counter support. - Make DSO tests a suite rather than individual. - Remove atomics from test_loop to avoid test failures. - Fix call chain match on powerpc for the record+probe_libc_inet_pton test. - Improve Intel hybrid tests. Vendor event files (JSON): powerpc: - Update datasource event name to fix duplicate events on IBM's Power10. - Add PVN for HX-C2000 CPU with Power8 Architecture. Intel: - Alderlake/rocketlake metric fixes. - Update emeraldrapids events to v1.02. - Update icelakex events to v1.23. - Update sapphirerapids events to v1.17. - Add skx, clx, icx and spr upi bandwidth metric. AMD: - Add Zen 4 memory controller events. RISC-V: - Add StarFive Dubhe-80 and Dubhe-90 JSON files. https://www.starfivetech.com/en/site/cpu-u - Add T-HEAD C9xx JSON file. https://github.com/riscv-software-src/opensbi/blob/master/docs/platform/thead-c9xx.md ARM64: - Remove UTF-8 characters from cmn.json, that were causing build failure in some distros. - Add core PMU events and metrics for Ampere One X. - Rename Ampere One's BPU_FLUSH_MEM_FAULT to GPC_FLUSH_MEM_FAULT libperf: - Rename several perf_cpu_map constructor names to clarify what they really do. - Ditto for some other methods, coping with some issues in their semantics, like perf_cpu_map__empty() -> perf_cpu_map__has_any_cpu_or_is_empty(). - Document perf_cpu_map__nr()'s behavior perf stat: - Exit if parse groups fails. - Combine the -A/--no-aggr and --no-merge options. - Fix help message for --metric-no-threshold option. Hardware tracing: ARM64 CoreSight: - Bump minimum OpenCSD version to ensure a bugfix is present. - Add 'T' itrace option for timestamp trace - Set start vm addr of exectable file to 0 and don't ignore first sample on the arm-cs-trace-disasm.py 'perf script'" * tag 'perf-tools-for-v6.8-1-2024-01-09' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools: (179 commits) MAINTAINERS: Add Namhyung as tools/perf/ co-maintainer perf test: test case 'Setup struct perf_event_attr' fails on s390 on z/vm perf db-export: Fix missing reference count get in call_path_from_sample() perf tests: Add perf script test libsubcmd: Fix memory leak in uniq() perf TUI: Don't ignore job control perf vendor events intel: Update sapphirerapids events to v1.17 perf vendor events intel: Update icelakex events to v1.23 perf vendor events intel: Update emeraldrapids events to v1.02 perf vendor events intel: Alderlake/rocketlake metric fixes perf x86 test: Add hybrid test for conflicting legacy/sysfs event perf x86 test: Update hybrid expectations perf vendor events amd: Add Zen 4 memory controller events perf stat: Fix hard coded LL miss units perf record: Reduce memory for recording PERF_RECORD_LOST_SAMPLES event perf env: Avoid recursively taking env->bpf_progs.lock perf annotate: Add --insn-stat option for debugging perf annotate: Add --type-stat option for debugging perf annotate: Support event group display perf annotate: Add --data-type option ...

Linus Torvalds committed 2 years ago

Commit 9d64bf42 parents 57f22c8 d988c9f249 files · +7843 −2141Browse files

Unified · Split

249 files
  1. MAINTAINERS +1 −1
  2. tools/build/Makefile.feature +1 −0
  3. tools/build/feature/Makefile +4 −0
  4. tools/build/feature/test-dwarf_getcfi.c +9 −0
  5. tools/build/feature/test-libopencsd.c +2 −2
  6. tools/include/uapi/linux/perf_event.h +13 −0
  7. tools/lib/api/fs/fs.c +29 −51
  8. tools/lib/api/io.h +9 −3
  9. tools/lib/perf/Documentation/examples/sampling.c +1 −1
  10. tools/lib/perf/Documentation/libperf-sampling.txt +1 −1
  11. tools/lib/perf/Documentation/libperf.txt +2 −2
  12. tools/lib/perf/cpumap.c +38 −27
  13. tools/lib/perf/evlist.c +3 −3
  14. tools/lib/perf/evsel.c +1 −1
  15. tools/lib/perf/include/internal/mmap.h +2 −1
  16. tools/lib/perf/include/perf/cpumap.h +35 −5
  17. tools/lib/perf/libperf.map +3 −3
  18. tools/lib/perf/mmap.c +17 −3
  19. tools/lib/perf/tests/test-cpumap.c +2 −2
  20. tools/lib/perf/tests/test-evlist.c +3 −3
  21. tools/lib/perf/tests/test-evsel.c +1 −1
  22. tools/lib/subcmd/help.c +14 −4
  23. tools/perf/.gitignore +4 −0
  24. tools/perf/Documentation/itrace.txt +1 −0
  25. tools/perf/Documentation/perf-annotate.txt +11 −0
  26. tools/perf/Documentation/perf-config.txt +2 −2
  27. tools/perf/Documentation/perf-list.txt +7 −5
  28. tools/perf/Documentation/perf-lock.txt +1 −1
  29. tools/perf/Documentation/perf-record.txt +4 −0
  30. tools/perf/Documentation/perf-report.txt +3 −0
  31. tools/perf/Documentation/perf-stat.txt +28 −24
  32. tools/perf/Documentation/perf.txt +3 −0
  33. tools/perf/Makefile.config +9 −4
  34. tools/perf/Makefile.perf +11 −2
  35. tools/perf/arch/arm/util/cs-etm.c +8 −8
  36. tools/perf/arch/arm64/util/arm-spe.c +2 −2
  37. tools/perf/arch/arm64/util/header.c +1 −1
  38. tools/perf/arch/loongarch/annotate/instructions.c +3 −3
  39. tools/perf/arch/x86/tests/hybrid.c +30 −7
  40. tools/perf/arch/x86/util/dwarf-regs.c +38 −0
  41. tools/perf/arch/x86/util/event.c +58 −45
  42. tools/perf/arch/x86/util/intel-bts.c +2 −2
  43. tools/perf/arch/x86/util/intel-pt.c +5 −5
  44. tools/perf/bench/epoll-ctl.c +1 −1
  45. tools/perf/bench/epoll-wait.c +1 −1
  46. tools/perf/bench/futex-hash.c +1 −1
  47. tools/perf/bench/futex-lock-pi.c +1 −1
  48. tools/perf/bench/futex-requeue.c +1 −1
  49. tools/perf/bench/futex-wake-parallel.c +1 −1
  50. tools/perf/bench/futex-wake.c +1 −1
  51. tools/perf/bench/sched-seccomp-notify.c +1 −1
  52. tools/perf/builtin-annotate.c +272 −28
  53. tools/perf/builtin-c2c.c +1 −1
  54. tools/perf/builtin-ftrace.c +1 −1
  55. tools/perf/builtin-inject.c +6 −0
  56. tools/perf/builtin-lock.c +3 −1
  57. tools/perf/builtin-record.c +45 −48
  58. tools/perf/builtin-report.c +74 −39
  59. tools/perf/builtin-stat.c +19 −14
  60. tools/perf/builtin-top.c +26 −26
  61. tools/perf/builtin-trace.c +2 −4
  62. tools/perf/perf-archive.sh +80 −6
  63. tools/perf/perf.c +30 −0
  64. tools/perf/pmu-events/arch/arm64/ampere/ampereone/core-imp-def.json +1 −1
  65. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/branch.json +125 −0
  66. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/bus.json +20 −0
  67. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json +206 −0
  68. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/core-imp-def.json +464 −0
  69. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/exception.json +47 −0
  70. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/instruction.json +128 −0
  71. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/intrinsic.json +14 −0
  72. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/memory.json +41 −0
  73. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json +442 −0
  74. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/mmu.json +170 −0
  75. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/pipeline.json +41 −0
  76. tools/perf/pmu-events/arch/arm64/ampere/ampereonex/spe.json +14 −0
  77. tools/perf/pmu-events/arch/arm64/arm/cmn/sys/cmn.json +1 −1
  78. tools/perf/pmu-events/arch/arm64/mapfile.csv +1 −0
  79. tools/perf/pmu-events/arch/powerpc/mapfile.csv +1 −2
  80. tools/perf/pmu-events/arch/powerpc/power10/datasource.json +14 −4
  81. tools/perf/pmu-events/arch/riscv/mapfile.csv +2 −0
  82. tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/common.json +172 −0
  83. tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/firmware.json +68 −0
  84. tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json +67 −0
  85. tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json +68 −0
  86. tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json +72 −0
  87. tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json +80 −0
  88. tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json +8 −7
  89. tools/perf/pmu-events/arch/x86/amdzen4/memory-controller.json +101 −0
  90. tools/perf/pmu-events/arch/x86/amdzen4/recommended.json +84 −0
  91. tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json +6 −0
  92. tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json +24 −3
  93. tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json +1 −17
  94. tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json +4 −4
  95. tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-io.json +30 −0
  96. tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json +6 −0
  97. tools/perf/pmu-events/arch/x86/icelakex/other.json +1 −1
  98. tools/perf/pmu-events/arch/x86/icelakex/pipeline.json +1 −1
  99. tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json +3 −3
  100. tools/perf/pmu-events/arch/x86/mapfile.csv +3 −3
  101. tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json +1 −1
  102. tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json +24 −3
  103. tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json +1 −1
  104. tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json +6 −0
  105. tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json +4 −4
  106. tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-io.json +30 −0
  107. tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json +6 −0
  108. tools/perf/pmu-events/jevents.py +3 −1
  109. tools/perf/scripts/python/arm-cs-trace-disasm.py +16 −14
  110. tools/perf/scripts/python/compaction-times.py +1 −1
  111. tools/perf/scripts/python/exported-sql-viewer.py +2 −2
  112. tools/perf/tests/Build +14 −0
  113. tools/perf/tests/attr.c +1 −1
  114. tools/perf/tests/attr/base-record +1 −1
  115. tools/perf/tests/attr/test-record-user-regs-no-sve-aarch64 +1 −1
  116. tools/perf/tests/attr/test-record-user-regs-sve-aarch64 +1 −1
  117. tools/perf/tests/builtin-test.c +15 −2
  118. tools/perf/tests/code-reading.c +25 −55
  119. tools/perf/tests/cpumap.c +1 −1
  120. tools/perf/tests/dso-data.c +12 −3
  121. tools/perf/tests/keep-tracking.c +1 −1
  122. tools/perf/tests/make +1 −1
  123. tools/perf/tests/maps.c +38 −23
  124. tools/perf/tests/mmap-basic.c +1 −1
  125. tools/perf/tests/openat-syscall-all-cpus.c +1 −1
  126. tools/perf/tests/parse-events.c +187 −73
  127. tools/perf/tests/perf-time-to-tsc.c +1 −1
  128. tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c +0 −1
  129. tools/perf/tests/shell/coresight/thread_loop/thread_loop.c +0 −1
  130. tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c +0 −1
  131. tools/perf/tests/shell/diff.sh +108 −0
  132. tools/perf/tests/shell/lib/perf_has_symbol.sh +21 −0
  133. tools/perf/tests/shell/lib/setup_python.sh +16 −0
  134. tools/perf/tests/shell/list.sh +19 −0
  135. tools/perf/tests/shell/pipe_test.sh +8 −1
  136. tools/perf/tests/shell/record+probe_libc_inet_pton.sh +4 −1
  137. tools/perf/tests/shell/record.sh +37 −1
  138. tools/perf/tests/shell/record_offcpu.sh +2 −2
  139. tools/perf/tests/shell/script.sh +66 −0
  140. tools/perf/tests/shell/stat+json_output.sh +3 −13
  141. tools/perf/tests/shell/stat_all_pmu.sh +1 −1
  142. tools/perf/tests/shell/stat_metrics_values.sh +4 −10
  143. tools/perf/tests/shell/test_arm_callgraph_fp.sh +6 −0
  144. tools/perf/tests/shell/test_brstack.sh +6 −0
  145. tools/perf/tests/shell/test_data_symbol.sh +14 −2
  146. tools/perf/tests/shell/test_perf_data_converter_json.sh +3 −10
  147. tools/perf/tests/sigtrap.c +84 −22
  148. tools/perf/tests/sw-clock.c +1 −1
  149. tools/perf/tests/switch-tracking.c +1 −1
  150. tools/perf/tests/task-exit.c +1 −1
  151. tools/perf/tests/tests.h +1 −0
  152. tools/perf/tests/topology.c +1 −1
  153. tools/perf/tests/vmlinux-kallsyms.c +98 −83
  154. tools/perf/tests/workloads/thloop.c +1 −3
  155. tools/perf/trace/beauty/arch_errno_names.sh +6 −4
  156. tools/perf/trace/beauty/beauty.h +0 −2
  157. tools/perf/trace/beauty/prctl_option.sh +2 −2
  158. tools/perf/trace/beauty/socket.sh +2 −2
  159. tools/perf/ui/browsers/annotate.c +48 −56
  160. tools/perf/ui/browsers/hists.c +14 −22
  161. tools/perf/ui/browsers/hists.h +0 −2
  162. tools/perf/ui/browsers/scripts.c +1 −0
  163. tools/perf/ui/gtk/annotate.c +2 −4
  164. tools/perf/ui/gtk/gtk.h +0 −2
  165. tools/perf/ui/tui/setup.c +22 −0
  166. tools/perf/util/Build +2 −0
  167. tools/perf/util/annotate-data.c +405 −0
  168. tools/perf/util/annotate-data.h +143 −0
  169. tools/perf/util/annotate.c +522 −165
  170. tools/perf/util/annotate.h +100 −44
  171. tools/perf/util/auxtrace.c +5 −2
  172. tools/perf/util/auxtrace.h +3 −0
  173. tools/perf/util/block-info.c +4 −6
  174. tools/perf/util/block-info.h +1 −2
  175. tools/perf/util/block-range.c +6 −1
  176. tools/perf/util/bpf-event.c +7 −4
  177. tools/perf/util/bpf-event.h +6 −6
  178. tools/perf/util/bpf_counter.c +1 −1
  179. tools/perf/util/bpf_lock_contention.c +1 −1
  180. tools/perf/util/compress.h +5 −2
  181. tools/perf/util/cpumap.c +1 −1
  182. tools/perf/util/cputopo.c +1 −1
  183. tools/perf/util/cs-etm.c +18 −3
  184. tools/perf/util/db-export.c +2 −2
  185. tools/perf/util/debug.c +15 −7
  186. tools/perf/util/debug.h +1 −0
  187. tools/perf/util/debuginfo.c +205 −0
  188. tools/perf/util/debuginfo.h +64 −0
  189. tools/perf/util/dso.c +4 −0
  190. tools/perf/util/dso.h +2 −0
  191. tools/perf/util/dwarf-aux.c +232 −17
  192. tools/perf/util/dwarf-aux.h +49 −2
  193. tools/perf/util/dwarf-regs.c +34 −0
  194. tools/perf/util/env.c +64 −18
  195. tools/perf/util/env.h +17 −0
  196. tools/perf/util/event.c +2 −2
  197. tools/perf/util/evlist.c +32 −2
  198. tools/perf/util/evlist.h +1 −0
  199. tools/perf/util/evsel.c +45 −10
  200. tools/perf/util/evsel.h +3 −1
  201. tools/perf/util/genelf.c +3 −3
  202. tools/perf/util/header.c +33 −10
  203. tools/perf/util/hisi-ptt.c +1 −0
  204. tools/perf/util/hist.h +11 −17
  205. tools/perf/util/include/dwarf-regs.h +19 −0
  206. tools/perf/util/machine.c +41 −34
  207. tools/perf/util/map.c +2 −18
  208. tools/perf/util/map.h +43 −40
  209. tools/perf/util/maps.c +445 −83
  210. tools/perf/util/maps.h +19 −29
  211. tools/perf/util/mem-events.c +14 −11
  212. tools/perf/util/mmap.c +2 −3
  213. tools/perf/util/mmap.h +0 −1
  214. tools/perf/util/parse-branch-options.c +1 −0
  215. tools/perf/util/parse-events.c +38 −14
  216. tools/perf/util/perf_api_probe.c +2 −2
  217. tools/perf/util/perf_event_attr_fprintf.c +1 −0
  218. tools/perf/util/pmu.c +6 −2
  219. tools/perf/util/pmu.h +2 −1
  220. tools/perf/util/probe-event.c +26 −14
  221. tools/perf/util/probe-finder.c +5 −196
  222. tools/perf/util/probe-finder.h +1 −18
  223. tools/perf/util/record.c +2 −2
  224. tools/perf/util/s390-cpumcf-kernel.h +2 −0
  225. tools/perf/util/s390-sample-raw.c +104 −10
  226. tools/perf/util/sample.h +1 −0
  227. tools/perf/util/scripting-engines/trace-event-perl.c +3 −0
  228. tools/perf/util/scripting-engines/trace-event-python.c +15 −2
  229. tools/perf/util/session.c +18 −2
  230. tools/perf/util/sort.c +207 −9
  231. tools/perf/util/sort.h +7 −0
  232. tools/perf/util/stat-display.c +1 −1
  233. tools/perf/util/stat-shadow.c +1 −1
  234. tools/perf/util/stat.c +2 −2
  235. tools/perf/util/stat.h +0 −1
  236. tools/perf/util/symbol-elf.c +2 −4
  237. tools/perf/util/symbol-minimal.c +6 −4
  238. tools/perf/util/symbol.c +29 −277
  239. tools/perf/util/symbol.h +0 −1
  240. tools/perf/util/symbol_conf.h +5 −1
  241. tools/perf/util/synthetic-events.c +67 −51
  242. tools/perf/util/thread.c +20 −22
  243. tools/perf/util/thread.h +14 −0
  244. tools/perf/util/top.c +4 −5
  245. tools/perf/util/top.h +0 −1
  246. tools/perf/util/unwind-libdw.c +17 −4
  247. tools/perf/util/unwind-libunwind-local.c +24 −10
  248. tools/perf/util/vdso.c +23 −12
  249. tools/perf/util/zstd.c +33 −30
MAINTAINERS+1−1
@@ -17140,10 +17140,10 @@ PERFORMANCE EVENTS SUBSYSTEM · 17139 unmodified lines
1714017140 M: Peter Zijlstra <peterz@infradead.org>
1714117141 M: Ingo Molnar <mingo@redhat.com>
1714217142 M: Arnaldo Carvalho de Melo <acme@kernel.org>
17143+M: Namhyung Kim <namhyung@kernel.org>
1714317144 R: Mark Rutland <mark.rutland@arm.com>
1714417145 R: Alexander Shishkin <alexander.shishkin@linux.intel.com>
1714517146 R: Jiri Olsa <jolsa@kernel.org>
17146−R: Namhyung Kim <namhyung@kernel.org>
1714717147 R: Ian Rogers <irogers@google.com>
1714817148 R: Adrian Hunter <adrian.hunter@intel.com>
1714917149 L: linux-perf-users@vger.kernel.org
tools/build/Makefile.feature+1−0
@@ -32,6 +32,7 @@ FEATURE_TESTS_BASIC := \ · 31 unmodified lines
3232 backtrace \
3333 dwarf \
3434 dwarf_getlocations \
35+ dwarf_getcfi \
3536 eventfd \
3637 fortify-source \
3738 get_current_dir_name \
tools/build/feature/Makefile+4−0
@@ -7,6 +7,7 @@ FILES= \ · 6 unmodified lines
77 test-bionic.bin \
88 test-dwarf.bin \
99 test-dwarf_getlocations.bin \
10+ test-dwarf_getcfi.bin \
1011 test-eventfd.bin \
1112 test-fortify-source.bin \
1213 test-get_current_dir_name.bin \
@@ -154,6 +155,9 @@ $(OUTPUT)test-dwarf.bin: · 141 unmodified lines
154155 $(OUTPUT)test-dwarf_getlocations.bin:
155156 $(BUILD) $(DWARFLIBS)
156157
158+$(OUTPUT)test-dwarf_getcfi.bin:
159+ $(BUILD) $(DWARFLIBS)
160+
157161 $(OUTPUT)test-libelf-getphdrnum.bin:
158162 $(BUILD) -lelf
159163
tools/build/feature/test-dwarf_getcfi.c+9−0
@@ -0,0 +1,9 @@
1+// SPDX-License-Identifier: GPL-2.0
2+#include <stdio.h>
3+#include <elfutils/libdw.h>
4+
5+int main(void)
6+{
7+ Dwarf *dwarf = NULL;
8+ return dwarf_getcfi(dwarf) == NULL;
9+}
tools/build/feature/test-libopencsd.c+2−2
@@ -4,9 +4,9 @@ · 3 unmodified lines
44 /*
55 * Check OpenCSD library version is sufficient to provide required features
66 */
7−#define OCSD_MIN_VER ((1 << 16) | (1 << 8) | (1))
7+#define OCSD_MIN_VER ((1 << 16) | (2 << 8) | (1))
88 #if !defined(OCSD_VER_NUM) || (OCSD_VER_NUM < OCSD_MIN_VER)
9−#error "OpenCSD >= 1.1.1 is required"
9+#error "OpenCSD >= 1.2.1 is required"
1010 #endif
1111
1212 int main(void)
tools/include/uapi/linux/perf_event.h+13−0
@@ -204,6 +204,8 @@ enum perf_branch_sample_type_shift { · 203 unmodified lines
204204
205205 PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT = 18, /* save privilege mode */
206206
207+ PERF_SAMPLE_BRANCH_COUNTERS_SHIFT = 19, /* save occurrences of events on a branch */
208+
207209 PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
208210 };
209211
@@ -235,6 +237,8 @@ enum perf_branch_sample_type { · 25 unmodified lines
235237
236238 PERF_SAMPLE_BRANCH_PRIV_SAVE = 1U << PERF_SAMPLE_BRANCH_PRIV_SAVE_SHIFT,
237239
240+ PERF_SAMPLE_BRANCH_COUNTERS = 1U << PERF_SAMPLE_BRANCH_COUNTERS_SHIFT,
241+
238242 PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
239243 };
240244
@@ -982,6 +986,12 @@ enum perf_event_type { · 741 unmodified lines
982986 * { u64 nr;
983987 * { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
984988 * { u64 from, to, flags } lbr[nr];
989+ * #
990+ * # The format of the counters is decided by the
991+ * # "branch_counter_nr" and "branch_counter_width",
992+ * # which are defined in the ABI.
993+ * #
994+ * { u64 counters; } cntr[nr] && PERF_SAMPLE_BRANCH_COUNTERS
985995 * } && PERF_SAMPLE_BRANCH_STACK
986996 *
987997 * { u64 abi; # enum perf_sample_regs_abi
@@ -1427,6 +1437,9 @@ struct perf_branch_entry { · 439 unmodified lines
14271437 reserved:31;
14281438 };
14291439
1440+/* Size of used info bits in struct perf_branch_entry */
1441+#define PERF_BRANCH_ENTRY_INFO_BITS_MAX 33
1442+
14301443 union perf_sample_weight {
14311444 __u64 full;
14321445 #if defined(__LITTLE_ENDIAN_BITFIELD)
tools/lib/api/fs/fs.c+29−51
@@ -16,6 +16,7 @@ · 15 unmodified lines
1616 #include <sys/mount.h>
1717
1818 #include "fs.h"
19+#include "../io.h"
1920 #include "debug-internal.h"
2021
2122 #define _STR(x) #x
@@ -344,53 +345,24 @@ int filename__read_ull(const char *filename, unsigned long long *value) · 322 unmodified lines
344345 return filename__read_ull_base(filename, value, 0);
345346 }
346347
347−#define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */
348−
349348 int filename__read_str(const char *filename, char **buf, size_t *sizep)
350349 {
351− size_t size = 0, alloc_size = 0;
352− void *bf = NULL, *nbf;
353− int fd, n, err = 0;
354− char sbuf[STRERR_BUFSIZE];
350+ struct io io;
351+ char bf[128];
352+ int err;
355353
356− fd = open(filename, O_RDONLY);
357− if (fd < 0)
354+ io.fd = open(filename, O_RDONLY);
355+ if (io.fd < 0)
358356 return -errno;
359−
360− do {
361− if (size == alloc_size) {
362− alloc_size += BUFSIZ;
363− nbf = realloc(bf, alloc_size);
364− if (!nbf) {
365− err = -ENOMEM;
366− break;
367− }
368−
369− bf = nbf;
370− }
371−
372− n = read(fd, bf + size, alloc_size - size);
373− if (n < 0) {
374− if (size) {
375− pr_warn("read failed %d: %s\n", errno,
376− strerror_r(errno, sbuf, sizeof(sbuf)));
377− err = 0;
378− } else
379− err = -errno;
380−
381− break;
382− }
383−
384− size += n;
385− } while (n > 0);
386−
387− if (!err) {
388− *sizep = size;
389− *buf = bf;
357+ io__init(&io, io.fd, bf, sizeof(bf));
358+ *buf = NULL;
359+ err = io__getdelim(&io, buf, sizep, /*delim=*/-1);
360+ if (err < 0) {
361+ free(*buf);
362+ *buf = NULL;
390363 } else
391− free(bf);
392−
393− close(fd);
364+ err = 0;
365+ close(io.fd);
394366 return err;
395367 }
396368
@@ -475,15 +447,22 @@ int sysfs__read_str(const char *entry, char **buf, size_t *sizep) · 78 unmodified lines
475447
476448 int sysfs__read_bool(const char *entry, bool *value)
477449 {
478− char *buf;
479− size_t size;
480− int ret;
450+ struct io io;
451+ char bf[16];
452+ int ret = 0;
453+ char path[PATH_MAX];
454+ const char *sysfs = sysfs__mountpoint();
455+
456+ if (!sysfs)
457+ return -1;
481458
482− ret = sysfs__read_str(entry, &buf, &size);
483− if (ret < 0)
484− return ret;
459+ snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
460+ io.fd = open(path, O_RDONLY);
461+ if (io.fd < 0)
462+ return -errno;
485463
486− switch (buf[0]) {
464+ io__init(&io, io.fd, bf, sizeof(bf));
465+ switch (io__get_char(&io)) {
487466 case '1':
488467 case 'y':
489468 case 'Y':
@@ -497,8 +476,7 @@ int sysfs__read_bool(const char *entry, bool *value) · 7 unmodified lines
497476 default:
498477 ret = -1;
499478 }
500−
501− free(buf);
479+ close(io.fd);
502480
503481 return ret;
504482 }
tools/lib/api/io.h+9−3
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include <stdlib.h>
1313 #include <string.h>
1414 #include <unistd.h>
15+#include <linux/types.h>
1516
1617 struct io {
1718 /* File descriptor being read/ */
@@ -140,8 +141,8 @@ static inline int io__get_dec(struct io *io, __u64 *dec) · 122 unmodified lines
140141 }
141142 }
142143
143−/* Read up to and including the first newline following the pattern of getline. */
144−static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out)
144+/* Read up to and including the first delim. */
145+static inline ssize_t io__getdelim(struct io *io, char **line_out, size_t *line_len_out, int delim)
145146 {
146147 char buf[128];
147148 int buf_pos = 0;
@@ -151,7 +152,7 @@ static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_l · 3 unmodified lines
151152
152153 /* TODO: reuse previously allocated memory. */
153154 free(*line_out);
154− while (ch != '\n') {
155+ while (ch != delim) {
155156 ch = io__get_char(io);
156157
157158 if (ch < 0)
@@ -184,4 +185,9 @@ err_out: · 26 unmodified lines
184185 return -ENOMEM;
185186 }
186187
188+static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out)
189+{
190+ return io__getdelim(io, line_out, line_len_out, /*delim=*/'\n');
191+}
192+
187193 #endif /* __API_IO__ */
tools/lib/perf/Documentation/examples/sampling.c+1−1
@@ -39,7 +39,7 @@ int main(int argc, char **argv) · 38 unmodified lines
3939
4040 libperf_init(libperf_print);
4141
42− cpus = perf_cpu_map__new(NULL);
42+ cpus = perf_cpu_map__new_online_cpus();
4343 if (!cpus) {
4444 fprintf(stderr, "failed to create cpus\n");
4545 return -1;
tools/lib/perf/Documentation/libperf-sampling.txt+1−1
@@ -97,7 +97,7 @@ In this case we will monitor all the available CPUs: · 96 unmodified lines
9797
9898 [source,c]
9999 --
100− 42 cpus = perf_cpu_map__new(NULL);
100+ 42 cpus = perf_cpu_map__new_online_cpus();
101101 43 if (!cpus) {
102102 44 fprintf(stderr, "failed to create cpus\n");
103103 45 return -1;
tools/lib/perf/Documentation/libperf.txt+2−2
@@ -37,7 +37,7 @@ SYNOPSIS · 36 unmodified lines
3737
3838 struct perf_cpu_map;
3939
40− struct perf_cpu_map *perf_cpu_map__dummy_new(void);
40+ struct perf_cpu_map *perf_cpu_map__new_any_cpu(void);
4141 struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
4242 struct perf_cpu_map *perf_cpu_map__read(FILE *file);
4343 struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
@@ -46,7 +46,7 @@ SYNOPSIS · 2 unmodified lines
4646 void perf_cpu_map__put(struct perf_cpu_map *map);
4747 int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
4848 int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
49− bool perf_cpu_map__empty(const struct perf_cpu_map *map);
49+ bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map);
5050 int perf_cpu_map__max(struct perf_cpu_map *map);
5151 bool perf_cpu_map__has(const struct perf_cpu_map *map, int cpu);
5252
tools/lib/perf/cpumap.c+38−27
@@ -9,6 +9,7 @@ · 8 unmodified lines
99 #include <unistd.h>
1010 #include <ctype.h>
1111 #include <limits.h>
12+#include "internal.h"
1213
1314 void perf_cpu_map__set_nr(struct perf_cpu_map *map, int nr_cpus)
1415 {
@@ -27,7 +28,7 @@ struct perf_cpu_map *perf_cpu_map__alloc(int nr_cpus) · 12 unmodified lines
2728 return result;
2829 }
2930
30−struct perf_cpu_map *perf_cpu_map__dummy_new(void)
31+struct perf_cpu_map *perf_cpu_map__new_any_cpu(void)
3132 {
3233 struct perf_cpu_map *cpus = perf_cpu_map__alloc(1);
3334
@@ -66,15 +67,21 @@ void perf_cpu_map__put(struct perf_cpu_map *map) · 32 unmodified lines
6667 }
6768 }
6869
69−static struct perf_cpu_map *cpu_map__default_new(void)
70+static struct perf_cpu_map *cpu_map__new_sysconf(void)
7071 {
7172 struct perf_cpu_map *cpus;
72− int nr_cpus;
73+ int nr_cpus, nr_cpus_conf;
7374
7475 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
7576 if (nr_cpus < 0)
7677 return NULL;
7778
79+ nr_cpus_conf = sysconf(_SC_NPROCESSORS_CONF);
80+ if (nr_cpus != nr_cpus_conf) {
81+ pr_warning("Number of online CPUs (%d) differs from the number configured (%d) the CPU map will only cover the first %d CPUs.",
82+ nr_cpus, nr_cpus_conf, nr_cpus);
83+ }
84+
7885 cpus = perf_cpu_map__alloc(nr_cpus);
7986 if (cpus != NULL) {
8087 int i;
@@ -86,9 +93,27 @@ static struct perf_cpu_map *cpu_map__default_new(void) · 5 unmodified lines
8693 return cpus;
8794 }
8895
89−struct perf_cpu_map *perf_cpu_map__default_new(void)
96+static struct perf_cpu_map *cpu_map__new_sysfs_online(void)
9097 {
91− return cpu_map__default_new();
98+ struct perf_cpu_map *cpus = NULL;
99+ FILE *onlnf;
100+
101+ onlnf = fopen("/sys/devices/system/cpu/online", "r");
102+ if (onlnf) {
103+ cpus = perf_cpu_map__read(onlnf);
104+ fclose(onlnf);
105+ }
106+ return cpus;
107+}
108+
109+struct perf_cpu_map *perf_cpu_map__new_online_cpus(void)
110+{
111+ struct perf_cpu_map *cpus = cpu_map__new_sysfs_online();
112+
113+ if (cpus)
114+ return cpus;
115+
116+ return cpu_map__new_sysconf();
92117 }
93118
94119
@@ -180,27 +205,11 @@ struct perf_cpu_map *perf_cpu_map__read(FILE *file) · 85 unmodified lines
180205
181206 if (nr_cpus > 0)
182207 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
183− else
184− cpus = cpu_map__default_new();
185208 out_free_tmp:
186209 free(tmp_cpus);
187210 return cpus;
188211 }
189212
190−static struct perf_cpu_map *cpu_map__read_all_cpu_map(void)
191−{
192− struct perf_cpu_map *cpus = NULL;
193− FILE *onlnf;
194−
195− onlnf = fopen("/sys/devices/system/cpu/online", "r");
196− if (!onlnf)
197− return cpu_map__default_new();
198−
199− cpus = perf_cpu_map__read(onlnf);
200− fclose(onlnf);
201− return cpus;
202−}
203−
204213 struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list)
205214 {
206215 struct perf_cpu_map *cpus = NULL;
@@ -211,7 +220,7 @@ struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list) · 4 unmodified lines
211220 int max_entries = 0;
212221
213222 if (!cpu_list)
214− return cpu_map__read_all_cpu_map();
223+ return perf_cpu_map__new_online_cpus();
215224
216225 /*
217226 * must handle the case of empty cpumap to cover
@@ -268,10 +277,12 @@ struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list) · 50 unmodified lines
268277
269278 if (nr_cpus > 0)
270279 cpus = cpu_map__trim_new(nr_cpus, tmp_cpus);
271− else if (*cpu_list != '\0')
272− cpus = cpu_map__default_new();
273− else
274− cpus = perf_cpu_map__dummy_new();
280+ else if (*cpu_list != '\0') {
281+ pr_warning("Unexpected characters at end of cpu list ('%s'), using online CPUs.",
282+ cpu_list);
283+ cpus = perf_cpu_map__new_online_cpus();
284+ } else
285+ cpus = perf_cpu_map__new_any_cpu();
275286 invalid:
276287 free(tmp_cpus);
277288 out:
@@ -300,7 +311,7 @@ int perf_cpu_map__nr(const struct perf_cpu_map *cpus) · 22 unmodified lines
300311 return cpus ? __perf_cpu_map__nr(cpus) : 1;
301312 }
302313
303−bool perf_cpu_map__empty(const struct perf_cpu_map *map)
314+bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map)
304315 {
305316 return map ? __perf_cpu_map__cpu(map, 0).cpu == -1 : true;
306317 }
tools/lib/perf/evlist.c+3−3
@@ -39,7 +39,7 @@ static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, · 38 unmodified lines
3939 if (evsel->system_wide) {
4040 /* System wide: set the cpu map of the evsel to all online CPUs. */
4141 perf_cpu_map__put(evsel->cpus);
42− evsel->cpus = perf_cpu_map__new(NULL);
42+ evsel->cpus = perf_cpu_map__new_online_cpus();
4343 } else if (evlist->has_user_cpus && evsel->is_pmu_core) {
4444 /*
4545 * User requested CPUs on a core PMU, ensure the requested CPUs
@@ -619,7 +619,7 @@ static int perf_evlist__nr_mmaps(struct perf_evlist *evlist) · 573 unmodified lines
619619
620620 /* One for each CPU */
621621 nr_mmaps = perf_cpu_map__nr(evlist->all_cpus);
622− if (perf_cpu_map__empty(evlist->all_cpus)) {
622+ if (perf_cpu_map__has_any_cpu_or_is_empty(evlist->all_cpus)) {
623623 /* Plus one for each thread */
624624 nr_mmaps += perf_thread_map__nr(evlist->threads);
625625 /* Minus the per-thread CPU (-1) */
@@ -653,7 +653,7 @@ int perf_evlist__mmap_ops(struct perf_evlist *evlist, · 27 unmodified lines
653653 if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0)
654654 return -ENOMEM;
655655
656− if (perf_cpu_map__empty(cpus))
656+ if (perf_cpu_map__has_any_cpu_or_is_empty(cpus))
657657 return mmap_per_thread(evlist, ops, mp);
658658
659659 return mmap_per_cpu(evlist, ops, mp);
tools/lib/perf/evsel.c+1−1
@@ -120,7 +120,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, · 119 unmodified lines
120120 static struct perf_cpu_map *empty_cpu_map;
121121
122122 if (empty_cpu_map == NULL) {
123− empty_cpu_map = perf_cpu_map__dummy_new();
123+ empty_cpu_map = perf_cpu_map__new_any_cpu();
124124 if (empty_cpu_map == NULL)
125125 return -ENOMEM;
126126 }
tools/lib/perf/include/internal/mmap.h+2−1
@@ -33,7 +33,8 @@ struct perf_mmap { · 32 unmodified lines
3333 bool overwrite;
3434 u64 flush;
3535 libperf_unmap_cb_t unmap_cb;
36− char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8);
36+ void *event_copy;
37+ size_t event_copy_sz;
3738 struct perf_mmap *next;
3839 };
3940
tools/lib/perf/include/perf/cpumap.h+35−5
@@ -19,10 +19,23 @@ struct perf_cache { · 18 unmodified lines
1919 struct perf_cpu_map;
2020
2121 /**
22− * perf_cpu_map__dummy_new - a map with a singular "any CPU"/dummy -1 value.
22+ * perf_cpu_map__new_any_cpu - a map with a singular "any CPU"/dummy -1 value.
23+ */
24+LIBPERF_API struct perf_cpu_map *perf_cpu_map__new_any_cpu(void);
25+/**
26+ * perf_cpu_map__new_online_cpus - a map read from
27+ * /sys/devices/system/cpu/online if
28+ * available. If reading wasn't possible a map
29+ * is created using the online processors
30+ * assuming the first 'n' processors are all
31+ * online.
32+ */
33+LIBPERF_API struct perf_cpu_map *perf_cpu_map__new_online_cpus(void);
34+/**
35+ * perf_cpu_map__new - create a map from the given cpu_list such as "0-7". If no
36+ * cpu_list argument is provided then
37+ * perf_cpu_map__new_online_cpus is returned.
2338 */
24−LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void);
25−LIBPERF_API struct perf_cpu_map *perf_cpu_map__default_new(void);
2639 LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list);
2740 LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file);
2841 LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map);
@@ -31,12 +44,23 @@ LIBPERF_API struct perf_cpu_map *perf_cpu_map__merge(struct perf_cpu_map *orig, · 2 unmodified lines
3144 LIBPERF_API struct perf_cpu_map *perf_cpu_map__intersect(struct perf_cpu_map *orig,
3245 struct perf_cpu_map *other);
3346 LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map);
47+/**
48+ * perf_cpu_map__cpu - get the CPU value at the given index. Returns -1 if index
49+ * is invalid.
50+ */
3451 LIBPERF_API struct perf_cpu perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx);
52+/**
53+ * perf_cpu_map__nr - for an empty map returns 1, as perf_cpu_map__cpu returns a
54+ * cpu of -1 for an invalid index, this makes an empty map
55+ * look like it contains the "any CPU"/dummy value. Otherwise
56+ * the result is the number CPUs in the map plus one if the
57+ * "any CPU"/dummy value is present.
58+ */
3559 LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus);
3660 /**
37− * perf_cpu_map__empty - is map either empty or the "any CPU"/dummy value.
61+ * perf_cpu_map__has_any_cpu_or_is_empty - is map either empty or has the "any CPU"/dummy value.
3862 */
39−LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map);
63+LIBPERF_API bool perf_cpu_map__has_any_cpu_or_is_empty(const struct perf_cpu_map *map);
4064 LIBPERF_API struct perf_cpu perf_cpu_map__max(const struct perf_cpu_map *map);
4165 LIBPERF_API bool perf_cpu_map__has(const struct perf_cpu_map *map, struct perf_cpu cpu);
4266 LIBPERF_API bool perf_cpu_map__equal(const struct perf_cpu_map *lhs,
@@ -51,6 +75,12 @@ LIBPERF_API bool perf_cpu_map__has_any_cpu(const struct perf_cpu_map *map); · 8 unmodified lines
5175 (idx) < perf_cpu_map__nr(cpus); \
5276 (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx))
5377
78+#define perf_cpu_map__for_each_cpu_skip_any(_cpu, idx, cpus) \
79+ for ((idx) = 0, (_cpu) = perf_cpu_map__cpu(cpus, idx); \
80+ (idx) < perf_cpu_map__nr(cpus); \
81+ (idx)++, (_cpu) = perf_cpu_map__cpu(cpus, idx)) \
82+ if ((_cpu).cpu != -1)
83+
5484 #define perf_cpu_map__for_each_idx(idx, cpus) \
5585 for ((idx) = 0; (idx) < perf_cpu_map__nr(cpus); (idx)++)
5686
tools/lib/perf/libperf.map+3−3
@@ -1,15 +1,15 @@
11 LIBPERF_0.0.1 {
22 global:
33 libperf_init;
4− perf_cpu_map__dummy_new;
5− perf_cpu_map__default_new;
4+ perf_cpu_map__new_any_cpu;
5+ perf_cpu_map__new_online_cpus;
66 perf_cpu_map__get;
77 perf_cpu_map__put;
88 perf_cpu_map__new;
99 perf_cpu_map__read;
1010 perf_cpu_map__nr;
1111 perf_cpu_map__cpu;
12− perf_cpu_map__empty;
12+ perf_cpu_map__has_any_cpu_or_is_empty;
1313 perf_cpu_map__max;
1414 perf_cpu_map__has;
1515 perf_thread_map__new_array;
tools/lib/perf/mmap.c+17−3
@@ -19,6 +19,7 @@ · 18 unmodified lines
1919 void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev,
2020 bool overwrite, libperf_unmap_cb_t unmap_cb)
2121 {
22+ /* Assume fields were zero initialized. */
2223 map->fd = -1;
2324 map->overwrite = overwrite;
2425 map->unmap_cb = unmap_cb;
@@ -51,13 +52,18 @@ int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp, · 26 unmodified lines
5152
5253 void perf_mmap__munmap(struct perf_mmap *map)
5354 {
54− if (map && map->base != NULL) {
55+ if (!map)
56+ return;
57+
58+ zfree(&map->event_copy);
59+ map->event_copy_sz = 0;
60+ if (map->base) {
5561 munmap(map->base, perf_mmap__mmap_len(map));
5662 map->base = NULL;
5763 map->fd = -1;
5864 refcount_set(&map->refcnt, 0);
5965 }
60− if (map && map->unmap_cb)
66+ if (map->unmap_cb)
6167 map->unmap_cb(map);
6268 }
6369
@@ -223,9 +229,17 @@ static union perf_event *perf_mmap__read(struct perf_mmap *map, · 159 unmodified lines
223229 */
224230 if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) {
225231 unsigned int offset = *startp;
226− unsigned int len = min(sizeof(*event), size), cpy;
232+ unsigned int len = size, cpy;
227233 void *dst = map->event_copy;
228234
235+ if (size > map->event_copy_sz) {
236+ dst = realloc(map->event_copy, size);
237+ if (!dst)
238+ return NULL;
239+ map->event_copy = dst;
240+ map->event_copy_sz = size;
241+ }
242+
229243 do {
230244 cpy = min(map->mask + 1 - (offset & map->mask), len);
231245 memcpy(dst, &data[offset & map->mask], cpy);
tools/lib/perf/tests/test-cpumap.c+2−2
@@ -21,7 +21,7 @@ int test_cpumap(int argc, char **argv) · 20 unmodified lines
2121
2222 libperf_init(libperf_print);
2323
24− cpus = perf_cpu_map__dummy_new();
24+ cpus = perf_cpu_map__new_any_cpu();
2525 if (!cpus)
2626 return -1;
2727
@@ -29,7 +29,7 @@ int test_cpumap(int argc, char **argv) · 1 unmodified line
2929 perf_cpu_map__put(cpus);
3030 perf_cpu_map__put(cpus);
3131
32− cpus = perf_cpu_map__default_new();
32+ cpus = perf_cpu_map__new_online_cpus();
3333 if (!cpus)
3434 return -1;
3535
tools/lib/perf/tests/test-evlist.c+3−3
@@ -46,7 +46,7 @@ static int test_stat_cpu(void) · 45 unmodified lines
4646 };
4747 int err, idx;
4848
49− cpus = perf_cpu_map__new(NULL);
49+ cpus = perf_cpu_map__new_online_cpus();
5050 __T("failed to create cpus", cpus);
5151
5252 evlist = perf_evlist__new();
@@ -261,7 +261,7 @@ static int test_mmap_thread(void) · 208 unmodified lines
261261 threads = perf_thread_map__new_dummy();
262262 __T("failed to create threads", threads);
263263
264− cpus = perf_cpu_map__dummy_new();
264+ cpus = perf_cpu_map__new_any_cpu();
265265 __T("failed to create cpus", cpus);
266266
267267 perf_thread_map__set_pid(threads, 0, pid);
@@ -350,7 +350,7 @@ static int test_mmap_cpus(void) · 82 unmodified lines
350350
351351 attr.config = id;
352352
353− cpus = perf_cpu_map__new(NULL);
353+ cpus = perf_cpu_map__new_online_cpus();
354354 __T("failed to create cpus", cpus);
355355
356356 evlist = perf_evlist__new();
tools/lib/perf/tests/test-evsel.c+1−1
@@ -27,7 +27,7 @@ static int test_stat_cpu(void) · 26 unmodified lines
2727 };
2828 int err, idx;
2929
30− cpus = perf_cpu_map__new(NULL);
30+ cpus = perf_cpu_map__new_online_cpus();
3131 __T("failed to create cpus", cpus);
3232
3333 evsel = perf_evsel__new(&attr);
tools/lib/subcmd/help.c+14−4
@@ -52,11 +52,21 @@ void uniq(struct cmdnames *cmds) · 51 unmodified lines
5252 if (!cmds->cnt)
5353 return;
5454
55− for (i = j = 1; i < cmds->cnt; i++)
56− if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
57− cmds->names[j++] = cmds->names[i];
58−
55+ for (i = 1; i < cmds->cnt; i++) {
56+ if (!strcmp(cmds->names[i]->name, cmds->names[i-1]->name))
57+ zfree(&cmds->names[i - 1]);
58+ }
59+ for (i = 0, j = 0; i < cmds->cnt; i++) {
60+ if (cmds->names[i]) {
61+ if (i == j)
62+ j++;
63+ else
64+ cmds->names[j++] = cmds->names[i];
65+ }
66+ }
5967 cmds->cnt = j;
68+ while (j < i)
69+ cmds->names[j++] = NULL;
6070 }
6171
6272 void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
tools/perf/.gitignore+4−0
@@ -39,6 +39,9 @@ trace/beauty/generated/ · 38 unmodified lines
3939 pmu-events/pmu-events.c
4040 pmu-events/jevents
4141 pmu-events/metric_test.log
42+tests/shell/*.shellcheck_log
43+tests/shell/coresight/*.shellcheck_log
44+tests/shell/lib/*.shellcheck_log
4245 feature/
4346 libapi/
4447 libbpf/
@@ -49,3 +52,4 @@ libtraceevent/ · 4 unmodified lines
4952 libtraceevent_plugins/
5053 fixdep
5154 Documentation/doc.dep
55+python_ext_build/
tools/perf/Documentation/itrace.txt+1−0
@@ -25,6 +25,7 @@ · 24 unmodified lines
2525 q quicker (less detailed) decoding
2626 A approximate IPC
2727 Z prefer to ignore timestamps (so-called "timeless" decoding)
28+ T use the timestamp trace as kernel time
2829
2930 The default is all events i.e. the same as --itrace=iybxwpe,
3031 except for perf script where it is --itrace=ce
tools/perf/Documentation/perf-annotate.txt+11−0
@@ -155,6 +155,17 @@ include::itrace.txt[] · 154 unmodified lines
155155 stdio or stdio2 (Default: 0). Note that this is about selection of
156156 functions to display, not about lines within the function.
157157
158+--data-type[=TYPE_NAME]::
159+ Display data type annotation instead of code. It infers data type of
160+ samples (if they are memory accessing instructions) using DWARF debug
161+ information. It can take an optional argument of data type name. In
162+ that case it'd show annotation for the type only, otherwise it'd show
163+ all data types it finds.
164+
165+--type-stat::
166+ Show stats for the data type annotation.
167+
168+
158169 SEE ALSO
159170 --------
160171 linkperf:perf-record[1], linkperf:perf-report[1]
tools/perf/Documentation/perf-config.txt+2−2
@@ -251,7 +251,8 @@ annotate.*:: · 250 unmodified lines
251251 addr2line binary to use for file names and line numbers.
252252
253253 annotate.objdump::
254− objdump binary to use for disassembly and annotations.
254+ objdump binary to use for disassembly and annotations,
255+ including in the 'perf test' command.
255256
256257 annotate.disassembler_style::
257258 Use this to change the default disassembler style to some other value
@@ -722,7 +723,6 @@ session-<NAME>.*:: · 464 unmodified lines
722723 Defines new record session for daemon. The value is record's
723724 command line without the 'record' keyword.
724725
725−
726726 SEE ALSO
727727 --------
728728 linkperf:perf[1]
tools/perf/Documentation/perf-list.txt+7−5
@@ -81,11 +81,13 @@ For Intel systems precise event sampling is implemented with PEBS · 80 unmodified lines
8181 which supports up to precise-level 2, and precise level 3 for
8282 some special cases
8383
84−On AMD systems it is implemented using IBS (up to precise-level 2).
85−The precise modifier works with event types 0x76 (cpu-cycles, CPU
86−clocks not halted) and 0xC1 (micro-ops retired). Both events map to
87−IBS execution sampling (IBS op) with the IBS Op Counter Control bit
88−(IbsOpCntCtl) set respectively (see the
84+On AMD systems it is implemented using IBS OP (up to precise-level 2).
85+Unlike Intel PEBS which provides levels of precision, AMD core pmu is
86+inherently non-precise and IBS is inherently precise. (i.e. ibs_op//,
87+ibs_op//p, ibs_op//pp and ibs_op//ppp are all same). The precise modifier
88+works with event types 0x76 (cpu-cycles, CPU clocks not halted) and 0xC1
89+(micro-ops retired). Both events map to IBS execution sampling (IBS op)
90+with the IBS Op Counter Control bit (IbsOpCntCtl) set respectively (see the
8991 Core Complex (CCX) -> Processor x86 Core -> Instruction Based Sampling (IBS)
9092 section of the [AMD Processor Programming Reference (PPR)] relevant to the
9193 family, model and stepping of the processor being used).
tools/perf/Documentation/perf-lock.txt+1−1
@@ -119,7 +119,7 @@ INFO OPTIONS · 118 unmodified lines
119119
120120
121121 CONTENTION OPTIONS
122−--------------
122+------------------
123123
124124 -k::
125125 --key=<value>::
tools/perf/Documentation/perf-record.txt+4−0
@@ -445,6 +445,10 @@ following filters are defined: · 444 unmodified lines
445445 4th-Gen Xeon+ server), the save branch type is unconditionally enabled
446446 when the taken branch stack sampling is enabled.
447447 - priv: save privilege state during sampling in case binary is not available later
448+ - counter: save occurrences of the event since the last branch entry. Currently, the
449+ feature is only supported by a newer CPU, e.g., Intel Sierra Forest and
450+ later platforms. An error out is expected if it's used on the unsupported
451+ kernel or CPUs.
448452
449453 +
450454 The option requires at least one branch type among any, any_call, any_ret, ind_call, cond.
tools/perf/Documentation/perf-report.txt+3−0
@@ -118,6 +118,9 @@ OPTIONS · 117 unmodified lines
118118 - retire_lat: On X86, this reports pipeline stall of this instruction compared
119119 to the previous instruction in cycles. And currently supported only on X86
120120 - simd: Flags describing a SIMD operation. "e" for empty Arm SVE predicate. "p" for partial Arm SVE predicate
121+ - type: Data type of sample memory access.
122+ - typeoff: Offset in the data type of sample memory access.
123+ - symoff: Offset in the symbol.
121124
122125 By default, comm, dso and symbol keys are used.
123126 (i.e. --sort comm,dso,symbol)
tools/perf/Documentation/perf-stat.txt+28−24
@@ -422,7 +422,34 @@ See perf list output for the possible metrics and metricgroups. · 421 unmodified lines
422422
423423 -A::
424424 --no-aggr::
425−Do not aggregate counts across all monitored CPUs.
425+--no-merge::
426+Do not aggregate/merge counts across monitored CPUs or PMUs.
427+
428+When multiple events are created from a single event specification,
429+stat will, by default, aggregate the event counts and show the result
430+in a single row. This option disables that behavior and shows the
431+individual events and counts.
432+
433+Multiple events are created from a single event specification when:
434+
435+1. PID monitoring isn't requested and the system has more than one
436+ CPU. For example, a system with 8 SMT threads will have one event
437+ opened on each thread and aggregation is performed across them.
438+
439+2. Prefix or glob wildcard matching is used for the PMU name. For
440+ example, multiple memory controller PMUs may exist typically with a
441+ suffix of _0, _1, etc. By default the event counts will all be
442+ combined if the PMU is specified without the suffix such as
443+ uncore_imc rather than uncore_imc_0.
444+
445+3. Aliases, which are listed immediately after the Kernel PMU events
446+ by perf list, are used.
447+
448+--hybrid-merge::
449+Merge core event counts from all core PMUs. In hybrid or big.LITTLE
450+systems by default each core PMU will report its count
451+separately. This option forces core PMU counts to be combined to give
452+a behavior closer to having a single CPU type in the system.
426453
427454 --topdown::
428455 Print top-down metrics supported by the CPU. This allows to determine
@@ -475,29 +502,6 @@ highlight 'tma_frontend_bound'. This metric may be drilled into with · 46 unmodified lines
475502
476503 Error out if the input is higher than the supported max level.
477504
478−--no-merge::
479−Do not merge results from same PMUs.
480−
481−When multiple events are created from a single event specification,
482−stat will, by default, aggregate the event counts and show the result
483−in a single row. This option disables that behavior and shows
484−the individual events and counts.
485−
486−Multiple events are created from a single event specification when:
487−1. Prefix or glob matching is used for the PMU name.
488−2. Aliases, which are listed immediately after the Kernel PMU events
489− by perf list, are used.
490−
491−--hybrid-merge::
492−Merge the hybrid event counts from all PMUs.
493−
494−For hybrid events, by default, the stat aggregates and reports the event
495−counts per PMU. But sometimes, it's also useful to aggregate event counts
496−from all PMUs. This option enables that behavior and reports the counts
497−without PMUs.
498−
499−For non-hybrid events, it should be no effect.
500−
501505 --smi-cost::
502506 Measure SMI cost if msr/aperf/ and msr/smi/ events are supported.
503507
tools/perf/Documentation/perf.txt+3−0
@@ -64,6 +64,9 @@ OPTIONS · 63 unmodified lines
6464 perf-event-open - Print perf_event_open() arguments and
6565 return value
6666
67+--debug-file::
68+ Write debug output to a specified file.
69+
6770 DESCRIPTION
6871 -----------
6972 Performance counters for Linux are a new kernel-based subsystem
tools/perf/Makefile.config+9−4
@@ -476,6 +476,11 @@ else · 475 unmodified lines
476476 else
477477 CFLAGS += -DHAVE_DWARF_GETLOCATIONS_SUPPORT
478478 endif # dwarf_getlocations
479+ ifneq ($(feature-dwarf_getcfi), 1)
480+ msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.142);
481+ else
482+ CFLAGS += -DHAVE_DWARF_CFI_SUPPORT
483+ endif # dwarf_getcfi
479484 endif # Dwarf support
480485 endif # libelf support
481486 endif # NO_LIBELF
@@ -680,15 +685,15 @@ ifndef BUILD_BPF_SKEL · 198 unmodified lines
680685 endif
681686
682687 ifeq ($(BUILD_BPF_SKEL),1)
683− ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),)
684− dummy := $(warning Warning: Disabled BPF skeletons as libbpf is required)
685− BUILD_BPF_SKEL := 0
686− else ifeq ($(filter -DHAVE_LIBELF_SUPPORT, $(CFLAGS)),)
688+ ifeq ($(filter -DHAVE_LIBELF_SUPPORT, $(CFLAGS)),)
687689 dummy := $(warning Warning: Disabled BPF skeletons as libelf is required by bpftool)
688690 BUILD_BPF_SKEL := 0
689691 else ifeq ($(filter -DHAVE_ZLIB_SUPPORT, $(CFLAGS)),)
690692 dummy := $(warning Warning: Disabled BPF skeletons as zlib is required by bpftool)
691693 BUILD_BPF_SKEL := 0
694+ else ifeq ($(filter -DHAVE_LIBBPF_SUPPORT, $(CFLAGS)),)
695+ dummy := $(warning Warning: Disabled BPF skeletons as libbpf is required)
696+ BUILD_BPF_SKEL := 0
692697 else ifeq ($(call get-executable,$(CLANG)),)
693698 dummy := $(warning Warning: Disabled BPF skeletons as clang ($(CLANG)) is missing)
694699 BUILD_BPF_SKEL := 0
tools/perf/Makefile.perf+11−2
@@ -134,6 +134,8 @@ include ../scripts/utilities.mak · 133 unmodified lines
134134 # x86 instruction decoder - new instructions test
135135 #
136136 # Define GEN_VMLINUX_H to generate vmlinux.h from the BTF.
137+#
138+# Define NO_SHELLCHECK if you do not want to run shellcheck during build
137139
138140 # As per kernel Makefile, avoid funny character set dependencies
139141 unexport LC_ALL
@@ -227,8 +229,15 @@ else · 87 unmodified lines
227229 force_fixdep := $(config)
228230 endif
229231
232+# Runs shellcheck on perf test shell scripts
233+ifeq ($(NO_SHELLCHECK),1)
234+ SHELLCHECK :=
235+else
236+ SHELLCHECK := $(shell which shellcheck 2> /dev/null)
237+endif
238+
230239 export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK
231−export HOSTCC HOSTLD HOSTAR HOSTCFLAGS
240+export HOSTCC HOSTLD HOSTAR HOSTCFLAGS SHELLCHECK
232241
233242 include $(srctree)/tools/build/Makefile.include
234243
@@ -1152,7 +1161,7 @@ bpf-skel-clean: · 917 unmodified lines
11521161
11531162 clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean $(LIBSYMBOL)-clean $(LIBPERF)-clean arm64-sysreg-defs-clean fixdep-clean python-clean bpf-skel-clean tests-coresight-targets-clean
11541163 $(call QUIET_CLEAN, core-objs) $(RM) $(LIBPERF_A) $(OUTPUT)perf-archive $(OUTPUT)perf-iostat $(LANG_BINDINGS)
1155− $(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
1164+ $(Q)find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete -o -name '*.shellcheck_log' -delete
11561165 $(Q)$(RM) $(OUTPUT).config-detected
11571166 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so
11581167 $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
tools/perf/arch/arm/util/cs-etm.c+8−8
@@ -199,7 +199,7 @@ static int cs_etm_validate_config(struct auxtrace_record *itr, · 198 unmodified lines
199199 {
200200 int i, err = -EINVAL;
201201 struct perf_cpu_map *event_cpus = evsel->evlist->core.user_requested_cpus;
202− struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
202+ struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus();
203203
204204 /* Set option of each CPU we have */
205205 for (i = 0; i < cpu__max_cpu().cpu; i++) {
@@ -211,7 +211,7 @@ static int cs_etm_validate_config(struct auxtrace_record *itr, · 5 unmodified lines
211211 * program can run on any CPUs in this case, thus don't skip
212212 * validation.
213213 */
214− if (!perf_cpu_map__empty(event_cpus) &&
214+ if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus) &&
215215 !perf_cpu_map__has(event_cpus, cpu))
216216 continue;
217217
@@ -435,7 +435,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, · 217 unmodified lines
435435 * Also the case of per-cpu mmaps, need the contextID in order to be notified
436436 * when a context switch happened.
437437 */
438− if (!perf_cpu_map__empty(cpus)) {
438+ if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) {
439439 evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
440440 "timestamp", 1);
441441 evsel__set_config_if_unset(cs_etm_pmu, cs_etm_evsel,
@@ -461,7 +461,7 @@ static int cs_etm_recording_options(struct auxtrace_record *itr, · 19 unmodified lines
461461 evsel->core.attr.sample_period = 1;
462462
463463 /* In per-cpu case, always need the time of mmap events etc */
464− if (!perf_cpu_map__empty(cpus))
464+ if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus))
465465 evsel__set_sample_bit(evsel, TIME);
466466
467467 err = cs_etm_validate_config(itr, cs_etm_evsel);
@@ -536,10 +536,10 @@ cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, · 68 unmodified lines
536536 int i;
537537 int etmv3 = 0, etmv4 = 0, ete = 0;
538538 struct perf_cpu_map *event_cpus = evlist->core.user_requested_cpus;
539− struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
539+ struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus();
540540
541541 /* cpu map is not empty, we have specific CPUs to work with */
542− if (!perf_cpu_map__empty(event_cpus)) {
542+ if (!perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) {
543543 for (i = 0; i < cpu__max_cpu().cpu; i++) {
544544 struct perf_cpu cpu = { .cpu = i, };
545545
@@ -802,7 +802,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, · 256 unmodified lines
802802 u64 nr_cpu, type;
803803 struct perf_cpu_map *cpu_map;
804804 struct perf_cpu_map *event_cpus = session->evlist->core.user_requested_cpus;
805− struct perf_cpu_map *online_cpus = perf_cpu_map__new(NULL);
805+ struct perf_cpu_map *online_cpus = perf_cpu_map__new_online_cpus();
806806 struct cs_etm_recording *ptr =
807807 container_of(itr, struct cs_etm_recording, itr);
808808 struct perf_pmu *cs_etm_pmu = ptr->cs_etm_pmu;
@@ -814,7 +814,7 @@ static int cs_etm_info_fill(struct auxtrace_record *itr, · 5 unmodified lines
814814 return -EINVAL;
815815
816816 /* If the cpu_map is empty all online CPUs are involved */
817− if (perf_cpu_map__empty(event_cpus)) {
817+ if (perf_cpu_map__has_any_cpu_or_is_empty(event_cpus)) {
818818 cpu_map = online_cpus;
819819 } else {
820820 /* Make sure all specified CPUs are online */
tools/perf/arch/arm64/util/arm-spe.c+2−2
@@ -232,7 +232,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, · 231 unmodified lines
232232 * In the case of per-cpu mmaps, sample CPU for AUX event;
233233 * also enable the timestamp tracing for samples correlation.
234234 */
235− if (!perf_cpu_map__empty(cpus)) {
235+ if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) {
236236 evsel__set_sample_bit(arm_spe_evsel, CPU);
237237 evsel__set_config_if_unset(arm_spe_pmu, arm_spe_evsel,
238238 "ts_enable", 1);
@@ -265,7 +265,7 @@ static int arm_spe_recording_options(struct auxtrace_record *itr, · 26 unmodified lines
265265 tracking_evsel->core.attr.sample_period = 1;
266266
267267 /* In per-cpu case, always need the time of mmap events etc */
268− if (!perf_cpu_map__empty(cpus)) {
268+ if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) {
269269 evsel__set_sample_bit(tracking_evsel, TIME);
270270 evsel__set_sample_bit(tracking_evsel, CPU);
271271
tools/perf/arch/arm64/util/header.c+1−1
@@ -57,7 +57,7 @@ static int _get_cpuid(char *buf, size_t sz, struct perf_cpu_map *cpus) · 56 unmodified lines
5757
5858 int get_cpuid(char *buf, size_t sz)
5959 {
60− struct perf_cpu_map *cpus = perf_cpu_map__new(NULL);
60+ struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus();
6161 int ret;
6262
6363 if (!cpus)
tools/perf/arch/loongarch/annotate/instructions.c+3−3
@@ -61,10 +61,10 @@ static int loongarch_jump__parse(struct arch *arch, struct ins_operands *ops, st · 60 unmodified lines
6161 const char *c = strchr(ops->raw, '#');
6262 u64 start, end;
6363
64− ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
65− ops->raw_func_start = strchr(ops->raw, '<');
64+ ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char);
65+ ops->jump.raw_func_start = strchr(ops->raw, '<');
6666
67− if (ops->raw_func_start && c > ops->raw_func_start)
67+ if (ops->jump.raw_func_start && c > ops->jump.raw_func_start)
6868 c = NULL;
6969
7070 if (c++ != NULL)
tools/perf/arch/x86/tests/hybrid.c+30−7
@@ -47,7 +47,7 @@ static int test__hybrid_hw_group_event(struct evlist *evlist) · 46 unmodified lines
4747 evsel = evsel__next(evsel);
4848 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
4949 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
50− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
50+ TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS));
5151 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
5252 return TEST_OK;
5353 }
@@ -102,7 +102,7 @@ static int test__hybrid_group_modifier1(struct evlist *evlist) · 48 unmodified lines
102102 evsel = evsel__next(evsel);
103103 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
104104 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
105− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
105+ TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_INSTRUCTIONS));
106106 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
107107 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
108108 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
@@ -163,6 +163,24 @@ static int test__checkevent_pmu(struct evlist *evlist) · 54 unmodified lines
163163 return TEST_OK;
164164 }
165165
166+static int test__hybrid_hw_group_event_2(struct evlist *evlist)
167+{
168+ struct evsel *evsel, *leader;
169+
170+ evsel = leader = evlist__first(evlist);
171+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries);
172+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
173+ TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW));
174+ TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
175+ TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
176+
177+ evsel = evsel__next(evsel);
178+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type);
179+ TEST_ASSERT_VAL("wrong config", evsel->core.attr.config == 0x3c);
180+ TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
181+ return TEST_OK;
182+}
183+
166184 struct evlist_test {
167185 const char *name;
168186 bool (*valid)(void);
@@ -171,27 +189,27 @@ struct evlist_test { · 2 unmodified lines
171189
172190 static const struct evlist_test test__hybrid_events[] = {
173191 {
174− .name = "cpu_core/cpu-cycles/",
192+ .name = "cpu_core/cycles/",
175193 .check = test__hybrid_hw_event_with_pmu,
176194 /* 0 */
177195 },
178196 {
179− .name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}",
197+ .name = "{cpu_core/cycles/,cpu_core/branches/}",
180198 .check = test__hybrid_hw_group_event,
181199 /* 1 */
182200 },
183201 {
184− .name = "{cpu-clock,cpu_core/cpu-cycles/}",
202+ .name = "{cpu-clock,cpu_core/cycles/}",
185203 .check = test__hybrid_sw_hw_group_event,
186204 /* 2 */
187205 },
188206 {
189− .name = "{cpu_core/cpu-cycles/,cpu-clock}",
207+ .name = "{cpu_core/cycles/,cpu-clock}",
190208 .check = test__hybrid_hw_sw_group_event,
191209 /* 3 */
192210 },
193211 {
194− .name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}",
212+ .name = "{cpu_core/cycles/k,cpu_core/branches/u}",
195213 .check = test__hybrid_group_modifier1,
196214 /* 4 */
197215 },
@@ -215,6 +233,11 @@ static const struct evlist_test test__hybrid_events[] = { · 17 unmodified lines
215233 .check = test__hybrid_cache_event,
216234 /* 8 */
217235 },
236+ {
237+ .name = "{cpu_core/cycles/,cpu_core/cpu-cycles/}",
238+ .check = test__hybrid_hw_group_event_2,
239+ /* 9 */
240+ },
218241 };
219242
220243 static int test_event(const struct evlist_test *e)
tools/perf/arch/x86/util/dwarf-regs.c+38−0
@@ -113,3 +113,41 @@ int regs_query_register_offset(const char *name) · 112 unmodified lines
113113 return roff->offset;
114114 return -EINVAL;
115115 }
116+
117+struct dwarf_regs_idx {
118+ const char *name;
119+ int idx;
120+};
121+
122+static const struct dwarf_regs_idx x86_regidx_table[] = {
123+ { "rax", 0 }, { "eax", 0 }, { "ax", 0 }, { "al", 0 },
124+ { "rdx", 1 }, { "edx", 1 }, { "dx", 1 }, { "dl", 1 },
125+ { "rcx", 2 }, { "ecx", 2 }, { "cx", 2 }, { "cl", 2 },
126+ { "rbx", 3 }, { "edx", 3 }, { "bx", 3 }, { "bl", 3 },
127+ { "rsi", 4 }, { "esi", 4 }, { "si", 4 }, { "sil", 4 },
128+ { "rdi", 5 }, { "edi", 5 }, { "di", 5 }, { "dil", 5 },
129+ { "rbp", 6 }, { "ebp", 6 }, { "bp", 6 }, { "bpl", 6 },
130+ { "rsp", 7 }, { "esp", 7 }, { "sp", 7 }, { "spl", 7 },
131+ { "r8", 8 }, { "r8d", 8 }, { "r8w", 8 }, { "r8b", 8 },
132+ { "r9", 9 }, { "r9d", 9 }, { "r9w", 9 }, { "r9b", 9 },
133+ { "r10", 10 }, { "r10d", 10 }, { "r10w", 10 }, { "r10b", 10 },
134+ { "r11", 11 }, { "r11d", 11 }, { "r11w", 11 }, { "r11b", 11 },
135+ { "r12", 12 }, { "r12d", 12 }, { "r12w", 12 }, { "r12b", 12 },
136+ { "r13", 13 }, { "r13d", 13 }, { "r13w", 13 }, { "r13b", 13 },
137+ { "r14", 14 }, { "r14d", 14 }, { "r14w", 14 }, { "r14b", 14 },
138+ { "r15", 15 }, { "r15d", 15 }, { "r15w", 15 }, { "r15b", 15 },
139+ { "rip", DWARF_REG_PC },
140+};
141+
142+int get_arch_regnum(const char *name)
143+{
144+ unsigned int i;
145+
146+ if (*name != '%')
147+ return -EINVAL;
148+
149+ for (i = 0; i < ARRAY_SIZE(x86_regidx_table); i++)
150+ if (!strcmp(x86_regidx_table[i].name, name + 1))
151+ return x86_regidx_table[i].idx;
152+ return -ENOENT;
153+}
tools/perf/arch/x86/util/event.c+58−45
@@ -14,66 +14,79 @@ · 13 unmodified lines
1414
1515 #if defined(__x86_64__)
1616
17−int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
18− perf_event__handler_t process,
19− struct machine *machine)
17+struct perf_event__synthesize_extra_kmaps_cb_args {
18+ struct perf_tool *tool;
19+ perf_event__handler_t process;
20+ struct machine *machine;
21+ union perf_event *event;
22+};
23+
24+static int perf_event__synthesize_extra_kmaps_cb(struct map *map, void *data)
2025 {
21− int rc = 0;
22− struct map_rb_node *pos;
23− struct maps *kmaps = machine__kernel_maps(machine);
24− union perf_event *event = zalloc(sizeof(event->mmap) +
25− machine->id_hdr_size);
26+ struct perf_event__synthesize_extra_kmaps_cb_args *args = data;
27+ union perf_event *event = args->event;
28+ struct kmap *kmap;
29+ size_t size;
2630
27− if (!event) {
28− pr_debug("Not enough memory synthesizing mmap event "
29− "for extra kernel maps\n");
30− return -1;
31− }
31+ if (!__map__is_extra_kernel_map(map))
32+ return 0;
3233
33− maps__for_each_entry(kmaps, pos) {
34− struct kmap *kmap;
35− size_t size;
36− struct map *map = pos->map;
34+ kmap = map__kmap(map);
3735
38− if (!__map__is_extra_kernel_map(map))
39− continue;
36+ size = sizeof(event->mmap) - sizeof(event->mmap.filename) +
37+ PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) +
38+ args->machine->id_hdr_size;
4039
41− kmap = map__kmap(map);
40+ memset(event, 0, size);
4241
43− size = sizeof(event->mmap) - sizeof(event->mmap.filename) +
44− PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) +
45− machine->id_hdr_size;
42+ event->mmap.header.type = PERF_RECORD_MMAP;
4643
47− memset(event, 0, size);
44+ /*
45+ * kernel uses 0 for user space maps, see kernel/perf_event.c
46+ * __perf_event_mmap
47+ */
48+ if (machine__is_host(args->machine))
49+ event->header.misc = PERF_RECORD_MISC_KERNEL;
50+ else
51+ event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
4852
49− event->mmap.header.type = PERF_RECORD_MMAP;
53+ event->mmap.header.size = size;
5054
51− /*
52− * kernel uses 0 for user space maps, see kernel/perf_event.c
53− * __perf_event_mmap
54− */
55− if (machine__is_host(machine))
56− event->header.misc = PERF_RECORD_MISC_KERNEL;
57− else
58− event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
55+ event->mmap.start = map__start(map);
56+ event->mmap.len = map__size(map);
57+ event->mmap.pgoff = map__pgoff(map);
58+ event->mmap.pid = args->machine->pid;
5959
60− event->mmap.header.size = size;
60+ strlcpy(event->mmap.filename, kmap->name, PATH_MAX);
6161
62− event->mmap.start = map__start(map);
63− event->mmap.len = map__size(map);
64− event->mmap.pgoff = map__pgoff(map);
65− event->mmap.pid = machine->pid;
62+ if (perf_tool__process_synth_event(args->tool, event, args->machine, args->process) != 0)
63+ return -1;
6664
67− strlcpy(event->mmap.filename, kmap->name, PATH_MAX);
65+ return 0;
66+}
6867
69− if (perf_tool__process_synth_event(tool, event, machine,
70− process) != 0) {
71− rc = -1;
72− break;
73− }
68+int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
69+ perf_event__handler_t process,
70+ struct machine *machine)
71+{
72+ int rc;
73+ struct maps *kmaps = machine__kernel_maps(machine);
74+ struct perf_event__synthesize_extra_kmaps_cb_args args = {
75+ .tool = tool,
76+ .process = process,
77+ .machine = machine,
78+ .event = zalloc(sizeof(args.event->mmap) + machine->id_hdr_size),
79+ };
80+
81+ if (!args.event) {
82+ pr_debug("Not enough memory synthesizing mmap event "
83+ "for extra kernel maps\n");
84+ return -1;
7485 }
7586
76− free(event);
87+ rc = maps__for_each_map(kmaps, perf_event__synthesize_extra_kmaps_cb, &args);
88+
89+ free(args.event);
7790 return rc;
7891 }
7992
tools/perf/arch/x86/util/intel-bts.c+2−2
@@ -143,7 +143,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, · 142 unmodified lines
143143 if (!opts->full_auxtrace)
144144 return 0;
145145
146− if (opts->full_auxtrace && !perf_cpu_map__empty(cpus)) {
146+ if (opts->full_auxtrace && !perf_cpu_map__has_any_cpu_or_is_empty(cpus)) {
147147 pr_err(INTEL_BTS_PMU_NAME " does not support per-cpu recording\n");
148148 return -EINVAL;
149149 }
@@ -224,7 +224,7 @@ static int intel_bts_recording_options(struct auxtrace_record *itr, · 74 unmodified lines
224224 * In the case of per-cpu mmaps, we need the CPU on the
225225 * AUX event.
226226 */
227− if (!perf_cpu_map__empty(cpus))
227+ if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus))
228228 evsel__set_sample_bit(intel_bts_evsel, CPU);
229229 }
230230
tools/perf/arch/x86/util/intel-pt.c+5−5
@@ -369,7 +369,7 @@ static int intel_pt_info_fill(struct auxtrace_record *itr, · 368 unmodified lines
369369 ui__warning("Intel Processor Trace: TSC not available\n");
370370 }
371371
372− per_cpu_mmaps = !perf_cpu_map__empty(session->evlist->core.user_requested_cpus);
372+ per_cpu_mmaps = !perf_cpu_map__has_any_cpu_or_is_empty(session->evlist->core.user_requested_cpus);
373373
374374 auxtrace_info->type = PERF_AUXTRACE_INTEL_PT;
375375 auxtrace_info->priv[INTEL_PT_PMU_TYPE] = intel_pt_pmu->type;
@@ -774,7 +774,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, · 398 unmodified lines
774774 * Per-cpu recording needs sched_switch events to distinguish different
775775 * threads.
776776 */
777− if (have_timing_info && !perf_cpu_map__empty(cpus) &&
777+ if (have_timing_info && !perf_cpu_map__has_any_cpu_or_is_empty(cpus) &&
778778 !record_opts__no_switch_events(opts)) {
779779 if (perf_can_record_switch_events()) {
780780 bool cpu_wide = !target__none(&opts->target) &&
@@ -832,7 +832,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, · 51 unmodified lines
832832 * In the case of per-cpu mmaps, we need the CPU on the
833833 * AUX event.
834834 */
835− if (!perf_cpu_map__empty(cpus))
835+ if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus))
836836 evsel__set_sample_bit(intel_pt_evsel, CPU);
837837 }
838838
@@ -858,7 +858,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, · 19 unmodified lines
858858 tracking_evsel->immediate = true;
859859
860860 /* In per-cpu case, always need the time of mmap events etc */
861− if (!perf_cpu_map__empty(cpus)) {
861+ if (!perf_cpu_map__has_any_cpu_or_is_empty(cpus)) {
862862 evsel__set_sample_bit(tracking_evsel, TIME);
863863 /* And the CPU for switch events */
864864 evsel__set_sample_bit(tracking_evsel, CPU);
@@ -870,7 +870,7 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, · 5 unmodified lines
870870 * Warn the user when we do not have enough information to decode i.e.
871871 * per-cpu with no sched_switch (except workload-only).
872872 */
873− if (!ptr->have_sched_switch && !perf_cpu_map__empty(cpus) &&
873+ if (!ptr->have_sched_switch && !perf_cpu_map__has_any_cpu_or_is_empty(cpus) &&
874874 !target__none(&opts->target) &&
875875 !intel_pt_evsel->core.attr.exclude_user)
876876 ui__warning("Intel Processor Trace decoding will not be possible except for kernel tracing!\n");
tools/perf/bench/epoll-ctl.c+1−1
@@ -330,7 +330,7 @@ int bench_epoll_ctl(int argc, const char **argv) · 329 unmodified lines
330330 act.sa_sigaction = toggle_done;
331331 sigaction(SIGINT, &act, NULL);
332332
333− cpu = perf_cpu_map__new(NULL);
333+ cpu = perf_cpu_map__new_online_cpus();
334334 if (!cpu)
335335 goto errmem;
336336
tools/perf/bench/epoll-wait.c+1−1
@@ -444,7 +444,7 @@ int bench_epoll_wait(int argc, const char **argv) · 443 unmodified lines
444444 act.sa_sigaction = toggle_done;
445445 sigaction(SIGINT, &act, NULL);
446446
447− cpu = perf_cpu_map__new(NULL);
447+ cpu = perf_cpu_map__new_online_cpus();
448448 if (!cpu)
449449 goto errmem;
450450
tools/perf/bench/futex-hash.c+1−1
@@ -138,7 +138,7 @@ int bench_futex_hash(int argc, const char **argv) · 137 unmodified lines
138138 exit(EXIT_FAILURE);
139139 }
140140
141− cpu = perf_cpu_map__new(NULL);
141+ cpu = perf_cpu_map__new_online_cpus();
142142 if (!cpu)
143143 goto errmem;
144144
tools/perf/bench/futex-lock-pi.c+1−1
@@ -172,7 +172,7 @@ int bench_futex_lock_pi(int argc, const char **argv) · 171 unmodified lines
172172 if (argc)
173173 goto err;
174174
175− cpu = perf_cpu_map__new(NULL);
175+ cpu = perf_cpu_map__new_online_cpus();
176176 if (!cpu)
177177 err(EXIT_FAILURE, "calloc");
178178
tools/perf/bench/futex-requeue.c+1−1
@@ -174,7 +174,7 @@ int bench_futex_requeue(int argc, const char **argv) · 173 unmodified lines
174174 if (argc)
175175 goto err;
176176
177− cpu = perf_cpu_map__new(NULL);
177+ cpu = perf_cpu_map__new_online_cpus();
178178 if (!cpu)
179179 err(EXIT_FAILURE, "cpu_map__new");
180180
tools/perf/bench/futex-wake-parallel.c+1−1
@@ -264,7 +264,7 @@ int bench_futex_wake_parallel(int argc, const char **argv) · 263 unmodified lines
264264 err(EXIT_FAILURE, "mlockall");
265265 }
266266
267− cpu = perf_cpu_map__new(NULL);
267+ cpu = perf_cpu_map__new_online_cpus();
268268 if (!cpu)
269269 err(EXIT_FAILURE, "calloc");
270270
tools/perf/bench/futex-wake.c+1−1
@@ -149,7 +149,7 @@ int bench_futex_wake(int argc, const char **argv) · 148 unmodified lines
149149 exit(EXIT_FAILURE);
150150 }
151151
152− cpu = perf_cpu_map__new(NULL);
152+ cpu = perf_cpu_map__new_online_cpus();
153153 if (!cpu)
154154 err(EXIT_FAILURE, "calloc");
155155
tools/perf/bench/sched-seccomp-notify.c+1−1
@@ -32,7 +32,7 @@ static bool sync_mode; · 31 unmodified lines
3232 static const struct option options[] = {
3333 OPT_U64('l', "loop", &loops, "Specify number of loops"),
3434 OPT_BOOLEAN('s', "sync-mode", &sync_mode,
35− "Enable the synchronious mode for seccomp notifications"),
35+ "Enable the synchronous mode for seccomp notifications"),
3636 OPT_END()
3737 };
3838
tools/perf/builtin-annotate.c+272−28
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include "util/evlist.h"
2121 #include "util/evsel.h"
2222 #include "util/annotate.h"
23+#include "util/annotate-data.h"
2324 #include "util/event.h"
2425 #include <subcmd/parse-options.h>
2526 #include "util/parse-events.h"
@@ -45,7 +46,6 @@ · 19 unmodified lines
4546 struct perf_annotate {
4647 struct perf_tool tool;
4748 struct perf_session *session;
48− struct annotation_options opts;
4949 #ifdef HAVE_SLANG_SUPPORT
5050 bool use_tui;
5151 #endif
@@ -56,9 +56,13 @@ struct perf_annotate { · 4 unmodified lines
5656 bool skip_missing;
5757 bool has_br_stack;
5858 bool group_set;
59+ bool data_type;
60+ bool type_stat;
61+ bool insn_stat;
5962 float min_percent;
6063 const char *sym_hist_filter;
6164 const char *cpu_list;
65+ const char *target_data_type;
6266 DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
6367 };
6468
@@ -94,6 +98,7 @@ static void process_basic_block(struct addr_map_symbol *start, · 29 unmodified lines
9498 struct annotation *notes = sym ? symbol__annotation(sym) : NULL;
9599 struct block_range_iter iter;
96100 struct block_range *entry;
101+ struct annotated_branch *branch;
97102
98103 /*
99104 * Sanity; NULL isn't executable and the CPU cannot execute backwards
@@ -105,6 +110,8 @@ static void process_basic_block(struct addr_map_symbol *start, · 5 unmodified lines
105110 if (!block_range_iter__valid(&iter))
106111 return;
107112
113+ branch = annotation__get_branch(notes);
114+
108115 /*
109116 * First block in range is a branch target.
110117 */
@@ -118,8 +125,8 @@ static void process_basic_block(struct addr_map_symbol *start, · 7 unmodified lines
118125 entry->coverage++;
119126 entry->sym = sym;
120127
121− if (notes)
122− notes->max_coverage = max(notes->max_coverage, entry->coverage);
128+ if (branch)
129+ branch->max_coverage = max(branch->max_coverage, entry->coverage);
123130
124131 } while (block_range_iter__next(&iter));
125132
@@ -315,9 +322,153 @@ static int hist_entry__tty_annotate(struct hist_entry *he, · 189 unmodified lines
315322 struct perf_annotate *ann)
316323 {
317324 if (!ann->use_stdio2)
318− return symbol__tty_annotate(&he->ms, evsel, &ann->opts);
325+ return symbol__tty_annotate(&he->ms, evsel);
326+
327+ return symbol__tty_annotate2(&he->ms, evsel);
328+}
329+
330+static void print_annotated_data_header(struct hist_entry *he, struct evsel *evsel)
331+{
332+ struct dso *dso = map__dso(he->ms.map);
333+ int nr_members = 1;
334+ int nr_samples = he->stat.nr_events;
335+
336+ if (evsel__is_group_event(evsel)) {
337+ struct hist_entry *pair;
338+
339+ list_for_each_entry(pair, &he->pairs.head, pairs.node)
340+ nr_samples += pair->stat.nr_events;
341+ }
342+
343+ printf("Annotate type: '%s' in %s (%d samples):\n",
344+ he->mem_type->self.type_name, dso->name, nr_samples);
345+
346+ if (evsel__is_group_event(evsel)) {
347+ struct evsel *pos;
348+ int i = 0;
349+
350+ for_each_group_evsel(pos, evsel)
351+ printf(" event[%d] = %s\n", i++, pos->name);
352+
353+ nr_members = evsel->core.nr_members;
354+ }
355+
356+ printf("============================================================================\n");
357+ printf("%*s %10s %10s %s\n", 11 * nr_members, "samples", "offset", "size", "field");
358+}
359+
360+static void print_annotated_data_type(struct annotated_data_type *mem_type,
361+ struct annotated_member *member,
362+ struct evsel *evsel, int indent)
363+{
364+ struct annotated_member *child;
365+ struct type_hist *h = mem_type->histograms[evsel->core.idx];
366+ int i, nr_events = 1, samples = 0;
367+
368+ for (i = 0; i < member->size; i++)
369+ samples += h->addr[member->offset + i].nr_samples;
370+ printf(" %10d", samples);
319371
320− return symbol__tty_annotate2(&he->ms, evsel, &ann->opts);
372+ if (evsel__is_group_event(evsel)) {
373+ struct evsel *pos;
374+
375+ for_each_group_member(pos, evsel) {
376+ h = mem_type->histograms[pos->core.idx];
377+
378+ samples = 0;
379+ for (i = 0; i < member->size; i++)
380+ samples += h->addr[member->offset + i].nr_samples;
381+ printf(" %10d", samples);
382+ }
383+ nr_events = evsel->core.nr_members;
384+ }
385+
386+ printf(" %10d %10d %*s%s\t%s",
387+ member->offset, member->size, indent, "", member->type_name,
388+ member->var_name ?: "");
389+
390+ if (!list_empty(&member->children))
391+ printf(" {\n");
392+
393+ list_for_each_entry(child, &member->children, node)
394+ print_annotated_data_type(mem_type, child, evsel, indent + 4);
395+
396+ if (!list_empty(&member->children))
397+ printf("%*s}", 11 * nr_events + 24 + indent, "");
398+ printf(";\n");
399+}
400+
401+static void print_annotate_data_stat(struct annotated_data_stat *s)
402+{
403+#define PRINT_STAT(fld) if (s->fld) printf("%10d : %s\n", s->fld, #fld)
404+
405+ int bad = s->no_sym +
406+ s->no_insn +
407+ s->no_insn_ops +
408+ s->no_mem_ops +
409+ s->no_reg +
410+ s->no_dbginfo +
411+ s->no_cuinfo +
412+ s->no_var +
413+ s->no_typeinfo +
414+ s->invalid_size +
415+ s->bad_offset;
416+ int ok = s->total - bad;
417+
418+ printf("Annotate data type stats:\n");
419+ printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n",
420+ s->total, ok, 100.0 * ok / (s->total ?: 1), bad, 100.0 * bad / (s->total ?: 1));
421+ printf("-----------------------------------------------------------\n");
422+ PRINT_STAT(no_sym);
423+ PRINT_STAT(no_insn);
424+ PRINT_STAT(no_insn_ops);
425+ PRINT_STAT(no_mem_ops);
426+ PRINT_STAT(no_reg);
427+ PRINT_STAT(no_dbginfo);
428+ PRINT_STAT(no_cuinfo);
429+ PRINT_STAT(no_var);
430+ PRINT_STAT(no_typeinfo);
431+ PRINT_STAT(invalid_size);
432+ PRINT_STAT(bad_offset);
433+ printf("\n");
434+
435+#undef PRINT_STAT
436+}
437+
438+static void print_annotate_item_stat(struct list_head *head, const char *title)
439+{
440+ struct annotated_item_stat *istat, *pos, *iter;
441+ int total_good, total_bad, total;
442+ int sum1, sum2;
443+ LIST_HEAD(tmp);
444+
445+ /* sort the list by count */
446+ list_splice_init(head, &tmp);
447+ total_good = total_bad = 0;
448+
449+ list_for_each_entry_safe(istat, pos, &tmp, list) {
450+ total_good += istat->good;
451+ total_bad += istat->bad;
452+ sum1 = istat->good + istat->bad;
453+
454+ list_for_each_entry(iter, head, list) {
455+ sum2 = iter->good + iter->bad;
456+ if (sum1 > sum2)
457+ break;
458+ }
459+ list_move_tail(&istat->list, &iter->list);
460+ }
461+ total = total_good + total_bad;
462+
463+ printf("Annotate %s stats\n", title);
464+ printf("total %d, ok %d (%.1f%%), bad %d (%.1f%%)\n\n", total,
465+ total_good, 100.0 * total_good / (total ?: 1),
466+ total_bad, 100.0 * total_bad / (total ?: 1));
467+ printf(" %-10s: %5s %5s\n", "Name", "Good", "Bad");
468+ printf("-----------------------------------------------------------\n");
469+ list_for_each_entry(istat, head, list)
470+ printf(" %-10s: %5d %5d\n", istat->name, istat->good, istat->bad);
471+ printf("\n");
321472 }
322473
323474 static void hists__find_annotations(struct hists *hists,
@@ -327,6 +478,11 @@ static void hists__find_annotations(struct hists *hists, · 3 unmodified lines
327478 struct rb_node *nd = rb_first_cached(&hists->entries), *next;
328479 int key = K_RIGHT;
329480
481+ if (ann->type_stat)
482+ print_annotate_data_stat(&ann_data_stat);
483+ if (ann->insn_stat)
484+ print_annotate_item_stat(&ann_insn_stat, "Instruction");
485+
330486 while (nd) {
331487 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
332488 struct annotation *notes;
@@ -359,11 +515,38 @@ find_next: · 26 unmodified lines
359515 continue;
360516 }
361517
518+ if (ann->data_type) {
519+ /* skip unknown type */
520+ if (he->mem_type->histograms == NULL)
521+ goto find_next;
522+
523+ if (ann->target_data_type) {
524+ const char *type_name = he->mem_type->self.type_name;
525+
526+ /* skip 'struct ' prefix in the type name */
527+ if (strncmp(ann->target_data_type, "struct ", 7) &&
528+ !strncmp(type_name, "struct ", 7))
529+ type_name += 7;
530+
531+ /* skip 'union ' prefix in the type name */
532+ if (strncmp(ann->target_data_type, "union ", 6) &&
533+ !strncmp(type_name, "union ", 6))
534+ type_name += 6;
535+
536+ if (strcmp(ann->target_data_type, type_name))
537+ goto find_next;
538+ }
539+
540+ print_annotated_data_header(he, evsel);
541+ print_annotated_data_type(he->mem_type, &he->mem_type->self, evsel, 0);
542+ printf("\n");
543+ goto find_next;
544+ }
545+
362546 if (use_browser == 2) {
363547 int ret;
364548 int (*annotate)(struct hist_entry *he,
365549 struct evsel *evsel,
366− struct annotation_options *options,
367550 struct hist_browser_timer *hbt);
368551
369552 annotate = dlsym(perf_gtk_handle,
@@ -373,14 +556,14 @@ find_next: · 3 unmodified lines
373556 return;
374557 }
375558
376− ret = annotate(he, evsel, &ann->opts, NULL);
559+ ret = annotate(he, evsel, NULL);
377560 if (!ret || !ann->skip_missing)
378561 return;
379562
380563 /* skip missing symbols */
381564 nd = rb_next(nd);
382565 } else if (use_browser == 1) {
383− key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts);
566+ key = hist_entry__tui_annotate(he, evsel, NULL);
384567
385568 switch (key) {
386569 case -1:
@@ -422,9 +605,9 @@ static int __cmd_annotate(struct perf_annotate *ann) · 35 unmodified lines
422605 goto out;
423606 }
424607
425− if (!ann->opts.objdump_path) {
608+ if (!annotate_opts.objdump_path) {
426609 ret = perf_env__lookup_objdump(&session->header.env,
427− &ann->opts.objdump_path);
610+ &annotate_opts.objdump_path);
428611 if (ret)
429612 goto out;
430613 }
@@ -457,8 +640,20 @@ static int __cmd_annotate(struct perf_annotate *ann) · 26 unmodified lines
457640 evsel__reset_sample_bit(pos, CALLCHAIN);
458641 evsel__output_resort(pos, NULL);
459642
460− if (symbol_conf.event_group && !evsel__is_group_leader(pos))
643+ /*
644+ * An event group needs to display other events too.
645+ * Let's delay printing until other events are processed.
646+ */
647+ if (symbol_conf.event_group) {
648+ if (!evsel__is_group_leader(pos)) {
649+ struct hists *leader_hists;
650+
651+ leader_hists = evsel__hists(evsel__leader(pos));
652+ hists__match(leader_hists, hists);
653+ hists__link(leader_hists, hists);
654+ }
461655 continue;
656+ }
462657
463658 hists__find_annotations(hists, pos, ann);
464659 }
@@ -469,6 +664,20 @@ static int __cmd_annotate(struct perf_annotate *ann) · 4 unmodified lines
469664 goto out;
470665 }
471666
667+ /* Display group events together */
668+ evlist__for_each_entry(session->evlist, pos) {
669+ struct hists *hists = evsel__hists(pos);
670+ u32 nr_samples = hists->stats.nr_samples;
671+
672+ if (nr_samples == 0)
673+ continue;
674+
675+ if (!symbol_conf.event_group || !evsel__is_group_leader(pos))
676+ continue;
677+
678+ hists__find_annotations(hists, pos, ann);
679+ }
680+
472681 if (use_browser == 2) {
473682 void (*show_annotations)(void);
474683
@@ -495,6 +704,17 @@ static int parse_percent_limit(const struct option *opt, const char *str, · 20 unmodified lines
495704 return 0;
496705 }
497706
707+static int parse_data_type(const struct option *opt, const char *str, int unset)
708+{
709+ struct perf_annotate *ann = opt->value;
710+
711+ ann->data_type = !unset;
712+ if (str)
713+ ann->target_data_type = strdup(str);
714+
715+ return 0;
716+}
717+
498718 static const char * const annotate_usage[] = {
499719 "perf annotate [<options>]",
500720 NULL
@@ -558,9 +778,9 @@ int cmd_annotate(int argc, const char **argv) · 57 unmodified lines
558778 "file", "vmlinux pathname"),
559779 OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
560780 "load module symbols - WARNING: use only with -k and LIVE kernel"),
561− OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines,
781+ OPT_BOOLEAN('l', "print-line", &annotate_opts.print_lines,
562782 "print matching source lines (may be slow)"),
563− OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path,
783+ OPT_BOOLEAN('P', "full-paths", &annotate_opts.full_path,
564784 "Don't shorten the displayed pathnames"),
565785 OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
566786 "Skip symbols that cannot be annotated"),
@@ -571,15 +791,15 @@ int cmd_annotate(int argc, const char **argv) · 4 unmodified lines
571791 OPT_CALLBACK(0, "symfs", NULL, "directory",
572792 "Look for files with symbols relative to this directory",
573793 symbol__config_symfs),
574− OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src,
794+ OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src,
575795 "Interleave source code with assembly code (default)"),
576− OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw,
796+ OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw,
577797 "Display raw encoding of assembly instructions (default)"),
578798 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
579799 "Specify disassembler style (e.g. -M intel for intel syntax)"),
580− OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix",
800+ OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix",
581801 "Add prefix to source file path names in programs (with --prefix-strip)"),
582− OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N",
802+ OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N",
583803 "Strip first N entries of source file path name in programs (with --prefix)"),
584804 OPT_STRING(0, "objdump", &objdump_path, "path",
585805 "objdump binary to use for disassembly and annotations"),
@@ -598,7 +818,7 @@ int cmd_annotate(int argc, const char **argv) · 12 unmodified lines
598818 OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode",
599819 "'always' (default), 'never' or 'auto' only applicable to --stdio mode",
600820 stdio__config_color, "always"),
601− OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period",
821+ OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period",
602822 "Set percent type local/global-period/hits",
603823 annotate_parse_percent_type),
604824 OPT_CALLBACK(0, "percent-limit", &annotate, "percent",
@@ -606,7 +826,13 @@ int cmd_annotate(int argc, const char **argv) · 1 unmodified line
606826 OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts",
607827 "Instruction Tracing options\n" ITRACE_HELP,
608828 itrace_parse_synth_opts),
609−
829+ OPT_CALLBACK_OPTARG(0, "data-type", &annotate, NULL, "name",
830+ "Show data type annotate for the memory accesses",
831+ parse_data_type),
832+ OPT_BOOLEAN(0, "type-stat", &annotate.type_stat,
833+ "Show stats for the data type annotation"),
834+ OPT_BOOLEAN(0, "insn-stat", &annotate.insn_stat,
835+ "Show instruction stats for the data type annotation"),
610836 OPT_END()
611837 };
612838 int ret;
@@ -614,13 +840,13 @@ int cmd_annotate(int argc, const char **argv) · 1 unmodified line
614840 set_option_flag(options, 0, "show-total-period", PARSE_OPT_EXCLUSIVE);
615841 set_option_flag(options, 0, "show-nr-samples", PARSE_OPT_EXCLUSIVE);
616842
617− annotation_options__init(&annotate.opts);
843+ annotation_options__init();
618844
619845 ret = hists__init();
620846 if (ret < 0)
621847 return ret;
622848
623− annotation_config__init(&annotate.opts);
849+ annotation_config__init();
624850
625851 argc = parse_options(argc, argv, options, annotate_usage, 0);
626852 if (argc) {
@@ -635,13 +861,13 @@ int cmd_annotate(int argc, const char **argv) · 8 unmodified lines
635861 }
636862
637863 if (disassembler_style) {
638− annotate.opts.disassembler_style = strdup(disassembler_style);
639− if (!annotate.opts.disassembler_style)
864+ annotate_opts.disassembler_style = strdup(disassembler_style);
865+ if (!annotate_opts.disassembler_style)
640866 return -ENOMEM;
641867 }
642868 if (objdump_path) {
643− annotate.opts.objdump_path = strdup(objdump_path);
644− if (!annotate.opts.objdump_path)
869+ annotate_opts.objdump_path = strdup(objdump_path);
870+ if (!annotate_opts.objdump_path)
645871 return -ENOMEM;
646872 }
647873 if (addr2line_path) {
@@ -650,7 +876,7 @@ int cmd_annotate(int argc, const char **argv) · 2 unmodified lines
650876 return -ENOMEM;
651877 }
652878
653− if (annotate_check_args(&annotate.opts) < 0)
879+ if (annotate_check_args() < 0)
654880 return -EINVAL;
655881
656882 #ifdef HAVE_GTK2_SUPPORT
@@ -660,6 +886,13 @@ int cmd_annotate(int argc, const char **argv) · 3 unmodified lines
660886 }
661887 #endif
662888
889+#ifndef HAVE_DWARF_GETLOCATIONS_SUPPORT
890+ if (annotate.data_type) {
891+ pr_err("Error: Data type profiling is disabled due to missing DWARF support\n");
892+ return -ENOTSUP;
893+ }
894+#endif
895+
663896 ret = symbol__validate_sym_arguments();
664897 if (ret)
665898 return ret;
@@ -702,6 +935,14 @@ int cmd_annotate(int argc, const char **argv) · 36 unmodified lines
702935 use_browser = 2;
703936 #endif
704937
938+ /* FIXME: only support stdio for now */
939+ if (annotate.data_type) {
940+ use_browser = 0;
941+ annotate_opts.annotate_src = false;
942+ symbol_conf.annotate_data_member = true;
943+ symbol_conf.annotate_data_sample = true;
944+ }
945+
705946 setup_browser(true);
706947
707948 /*
@@ -709,7 +950,10 @@ int cmd_annotate(int argc, const char **argv) · 1 unmodified line
709950 * symbol, we do not care about the processes in annotate,
710951 * set sort order to avoid repeated output.
711952 */
712− sort_order = "dso,symbol";
953+ if (annotate.data_type)
954+ sort_order = "dso,type";
955+ else
956+ sort_order = "dso,symbol";
713957
714958 /*
715959 * Set SORT_MODE__BRANCH so that annotate display IPC/Cycle
@@ -731,7 +975,7 @@ out_delete: · 15 unmodified lines
731975 #ifndef NDEBUG
732976 perf_session__delete(annotate.session);
733977 #endif
734− annotation_options__exit(&annotate.opts);
978+ annotation_options__exit();
735979
736980 return ret;
737981 }
tools/perf/builtin-c2c.c+1−1
@@ -2320,7 +2320,7 @@ static int setup_nodes(struct perf_session *session) · 2319 unmodified lines
23202320 nodes[node] = set;
23212321
23222322 /* empty node, skip */
2323− if (perf_cpu_map__empty(map))
2323+ if (perf_cpu_map__has_any_cpu_or_is_empty(map))
23242324 continue;
23252325
23262326 perf_cpu_map__for_each_cpu(cpu, idx, map) {
tools/perf/builtin-ftrace.c+1−1
@@ -333,7 +333,7 @@ static int set_tracing_func_irqinfo(struct perf_ftrace *ftrace) · 332 unmodified lines
333333
334334 static int reset_tracing_cpu(void)
335335 {
336− struct perf_cpu_map *cpumap = perf_cpu_map__new(NULL);
336+ struct perf_cpu_map *cpumap = perf_cpu_map__new_online_cpus();
337337 int ret;
338338
339339 ret = set_tracing_cpumask(cpumap);
tools/perf/builtin-inject.c+6−0
@@ -2265,6 +2265,12 @@ int cmd_inject(int argc, const char **argv) · 2264 unmodified lines
22652265 "perf inject [<options>]",
22662266 NULL
22672267 };
2268+
2269+ if (!inject.itrace_synth_opts.set) {
2270+ /* Disable eager loading of kernel symbols that adds overhead to perf inject. */
2271+ symbol_conf.lazy_load_kernel_maps = true;
2272+ }
2273+
22682274 #ifndef HAVE_JITDUMP
22692275 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
22702276 #endif
tools/perf/builtin-lock.c+3−1
@@ -2285,8 +2285,10 @@ setup_args: · 2284 unmodified lines
22852285 else
22862286 ev_name = strdup(contention_tracepoints[j].name);
22872287
2288− if (!ev_name)
2288+ if (!ev_name) {
2289+ free(rec_argv);
22892290 return -ENOMEM;
2291+ }
22902292
22912293 rec_argv[i++] = "-e";
22922294 rec_argv[i++] = ev_name;
tools/perf/builtin-record.c+45−48
@@ -270,7 +270,7 @@ static int record__write(struct record *rec, struct mmap *map __maybe_unused, · 269 unmodified lines
270270
271271 static int record__aio_enabled(struct record *rec);
272272 static int record__comp_enabled(struct record *rec);
273−static size_t zstd_compress(struct perf_session *session, struct mmap *map,
273+static ssize_t zstd_compress(struct perf_session *session, struct mmap *map,
274274 void *dst, size_t dst_size, void *src, size_t src_size);
275275
276276 #ifdef HAVE_AIO_SUPPORT
@@ -405,9 +405,13 @@ static int record__aio_pushfn(struct mmap *map, void *to, void *buf, size_t size · 128 unmodified lines
405405 */
406406
407407 if (record__comp_enabled(aio->rec)) {
408− size = zstd_compress(aio->rec->session, NULL, aio->data + aio->size,
409− mmap__mmap_len(map) - aio->size,
410− buf, size);
408+ ssize_t compressed = zstd_compress(aio->rec->session, NULL, aio->data + aio->size,
409+ mmap__mmap_len(map) - aio->size,
410+ buf, size);
411+ if (compressed < 0)
412+ return (int)compressed;
413+
414+ size = compressed;
411415 } else {
412416 memcpy(aio->data + aio->size, buf, size);
413417 }
@@ -633,7 +637,13 @@ static int record__pushfn(struct mmap *map, void *to, void *bf, size_t size) · 219 unmodified lines
633637 struct record *rec = to;
634638
635639 if (record__comp_enabled(rec)) {
636− size = zstd_compress(rec->session, map, map->data, mmap__mmap_len(map), bf, size);
640+ ssize_t compressed = zstd_compress(rec->session, map, map->data,
641+ mmap__mmap_len(map), bf, size);
642+
643+ if (compressed < 0)
644+ return (int)compressed;
645+
646+ size = compressed;
637647 bf = map->data;
638648 }
639649
@@ -1350,7 +1360,7 @@ static int record__open(struct record *rec) · 710 unmodified lines
13501360 evlist__for_each_entry(evlist, pos) {
13511361 try_again:
13521362 if (evsel__open(pos, pos->core.cpus, pos->core.threads) < 0) {
1353− if (evsel__fallback(pos, errno, msg, sizeof(msg))) {
1363+ if (evsel__fallback(pos, &opts->target, errno, msg, sizeof(msg))) {
13541364 if (verbose > 0)
13551365 ui__warning("%s\n", msg);
13561366 goto try_again;
@@ -1527,10 +1537,10 @@ static size_t process_comp_header(void *record, size_t increment) · 170 unmodified lines
15271537 return size;
15281538 }
15291539
1530−static size_t zstd_compress(struct perf_session *session, struct mmap *map,
1540+static ssize_t zstd_compress(struct perf_session *session, struct mmap *map,
15311541 void *dst, size_t dst_size, void *src, size_t src_size)
15321542 {
1533− size_t compressed;
1543+ ssize_t compressed;
15341544 size_t max_record_size = PERF_SAMPLE_MAX_SIZE - sizeof(struct perf_record_compressed) - 1;
15351545 struct zstd_data *zstd_data = &session->zstd_data;
15361546
@@ -1539,6 +1549,8 @@ static size_t zstd_compress(struct perf_session *session, struct mmap *map, · 2 unmodified lines
15391549
15401550 compressed = zstd_compress_stream_to_records(zstd_data, dst, dst_size, src, src_size,
15411551 max_record_size, process_comp_header);
1552+ if (compressed < 0)
1553+ return compressed;
15421554
15431555 if (map && map->file) {
15441556 thread->bytes_transferred += src_size;
@@ -1912,21 +1924,13 @@ static void __record__save_lost_samples(struct record *rec, struct evsel *evsel, · 367 unmodified lines
19121924 static void record__read_lost_samples(struct record *rec)
19131925 {
19141926 struct perf_session *session = rec->session;
1915− struct perf_record_lost_samples *lost;
1927+ struct perf_record_lost_samples *lost = NULL;
19161928 struct evsel *evsel;
19171929
19181930 /* there was an error during record__open */
19191931 if (session->evlist == NULL)
19201932 return;
19211933
1922− lost = zalloc(PERF_SAMPLE_MAX_SIZE);
1923− if (lost == NULL) {
1924− pr_debug("Memory allocation failed\n");
1925− return;
1926− }
1927−
1928− lost->header.type = PERF_RECORD_LOST_SAMPLES;
1929−
19301934 evlist__for_each_entry(session->evlist, evsel) {
19311935 struct xyarray *xy = evsel->core.sample_id;
19321936 u64 lost_count;
@@ -1949,6 +1953,15 @@ static void record__read_lost_samples(struct record *rec) · 16 unmodified lines
19491953 }
19501954
19511955 if (count.lost) {
1956+ if (!lost) {
1957+ lost = zalloc(sizeof(*lost) +
1958+ session->machines.host.id_hdr_size);
1959+ if (!lost) {
1960+ pr_debug("Memory allocation failed\n");
1961+ return;
1962+ }
1963+ lost->header.type = PERF_RECORD_LOST_SAMPLES;
1964+ }
19521965 __record__save_lost_samples(rec, evsel, lost,
19531966 x, y, count.lost, 0);
19541967 }
@@ -1956,9 +1969,19 @@ static void record__read_lost_samples(struct record *rec) · 1 unmodified line
19561969 }
19571970
19581971 lost_count = perf_bpf_filter__lost_count(evsel);
1959− if (lost_count)
1972+ if (lost_count) {
1973+ if (!lost) {
1974+ lost = zalloc(sizeof(*lost) +
1975+ session->machines.host.id_hdr_size);
1976+ if (!lost) {
1977+ pr_debug("Memory allocation failed\n");
1978+ return;
1979+ }
1980+ lost->header.type = PERF_RECORD_LOST_SAMPLES;
1981+ }
19601982 __record__save_lost_samples(rec, evsel, lost, 0, 0, lost_count,
19611983 PERF_RECORD_MISC_LOST_SAMPLES_BPF);
1984+ }
19621985 }
19631986 out:
19641987 free(lost);
@@ -2216,32 +2239,6 @@ static void hit_auxtrace_snapshot_trigger(struct record *rec) · 251 unmodified lines
22162239 }
22172240 }
22182241
2219−static void record__uniquify_name(struct record *rec)
2220−{
2221− struct evsel *pos;
2222− struct evlist *evlist = rec->evlist;
2223− char *new_name;
2224− int ret;
2225−
2226− if (perf_pmus__num_core_pmus() == 1)
2227− return;
2228−
2229− evlist__for_each_entry(evlist, pos) {
2230− if (!evsel__is_hybrid(pos))
2231− continue;
2232−
2233− if (strchr(pos->name, '/'))
2234− continue;
2235−
2236− ret = asprintf(&new_name, "%s/%s/",
2237− pos->pmu_name, pos->name);
2238− if (ret) {
2239− free(pos->name);
2240− pos->name = new_name;
2241− }
2242− }
2243−}
2244−
22452242 static int record__terminate_thread(struct record_thread *thread_data)
22462243 {
22472244 int err;
@@ -2475,7 +2472,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) · 227 unmodified lines
24752472 if (data->is_pipe && rec->evlist->core.nr_entries == 1)
24762473 rec->opts.sample_id = true;
24772474
2478− record__uniquify_name(rec);
2475+ evlist__uniquify_name(rec->evlist);
24792476
24802477 /* Debug message used by test scripts */
24812478 pr_debug3("perf record opening and mmapping events\n");
@@ -3580,9 +3577,7 @@ static int record__mmap_cpu_mask_init(struct mmap_cpu_mask *mask, struct perf_cp · 1098 unmodified lines
35803577 if (cpu_map__is_dummy(cpus))
35813578 return 0;
35823579
3583− perf_cpu_map__for_each_cpu(cpu, idx, cpus) {
3584− if (cpu.cpu == -1)
3585− continue;
3580+ perf_cpu_map__for_each_cpu_skip_any(cpu, idx, cpus) {
35863581 /* Return ENODEV is input cpu is greater than max cpu */
35873582 if ((unsigned long)cpu.cpu > mask->nbits)
35883583 return -ENODEV;
@@ -3989,6 +3984,8 @@ int cmd_record(int argc, const char **argv) · 400 unmodified lines
39893984 # undef set_nobuild
39903985 #endif
39913986
3987+ /* Disable eager loading of kernel symbols that adds overhead to perf record. */
3988+ symbol_conf.lazy_load_kernel_maps = true;
39923989 rec->opts.affinity = PERF_AFFINITY_SYS;
39933990
39943991 rec->evlist = evlist__new();
tools/perf/builtin-report.c+74−39
@@ -96,9 +96,9 @@ struct report { · 95 unmodified lines
9696 bool stitch_lbr;
9797 bool disable_order;
9898 bool skip_empty;
99+ bool data_type;
99100 int max_stack;
100101 struct perf_read_values show_threads_values;
101− struct annotation_options annotation_opts;
102102 const char *pretty_printing_style;
103103 const char *cpu_list;
104104 const char *symbol_filter_str;
@@ -171,7 +171,7 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, · 66 unmodified lines
171171 struct mem_info *mi;
172172 struct branch_info *bi;
173173
174− if (!ui__has_annotation() && !rep->symbol_ipc)
174+ if (!ui__has_annotation() && !rep->symbol_ipc && !rep->data_type)
175175 return 0;
176176
177177 if (sort__mode == SORT_MODE__BRANCH) {
@@ -541,8 +541,7 @@ static int evlist__tui_block_hists_browse(struct evlist *evlist, struct report * · 363 unmodified lines
541541 evlist__for_each_entry(evlist, pos) {
542542 ret = report__browse_block_hists(&rep->block_reports[i++].hist,
543543 rep->min_percent, pos,
544− &rep->session->header.env,
545− &rep->annotation_opts);
544+ &rep->session->header.env);
546545 if (ret != 0)
547546 return ret;
548547 }
@@ -574,8 +573,7 @@ static int evlist__tty_browse_hists(struct evlist *evlist, struct report *rep, c · 25 unmodified lines
574573
575574 if (rep->total_cycles_mode) {
576575 report__browse_block_hists(&rep->block_reports[i++].hist,
577− rep->min_percent, pos,
578− NULL, NULL);
576+ rep->min_percent, pos, NULL);
579577 continue;
580578 }
581579
@@ -670,7 +668,7 @@ static int report__browse_hists(struct report *rep) · 88 unmodified lines
670668 }
671669
672670 ret = evlist__tui_browse_hists(evlist, help, NULL, rep->min_percent,
673− &session->header.env, true, &rep->annotation_opts);
671+ &session->header.env, true);
674672 /*
675673 * Usually "ret" is the last pressed key, and we only
676674 * care if the key notifies us to switch data file.
@@ -745,7 +743,7 @@ static int hists__resort_cb(struct hist_entry *he, void *arg) · 68 unmodified lines
745743 if (rep->symbol_ipc && sym && !sym->annotate2) {
746744 struct evsel *evsel = hists_to_evsel(he->hists);
747745
748− symbol__annotate2(&he->ms, evsel, &rep->annotation_opts, NULL);
746+ symbol__annotate2(&he->ms, evsel, NULL);
749747 }
750748
751749 return 0;
@@ -859,27 +857,47 @@ static struct task *tasks_list(struct task *task, struct machine *machine) · 107 unmodified lines
859857 return tasks_list(parent_task, machine);
860858 }
861859
862−static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)
860+struct maps__fprintf_task_args {
861+ int indent;
862+ FILE *fp;
863+ size_t printed;
864+};
865+
866+static int maps__fprintf_task_cb(struct map *map, void *data)
863867 {
864− size_t printed = 0;
865− struct map_rb_node *rb_node;
868+ struct maps__fprintf_task_args *args = data;
869+ const struct dso *dso = map__dso(map);
870+ u32 prot = map__prot(map);
871+ int ret;
866872
867− maps__for_each_entry(maps, rb_node) {
868− struct map *map = rb_node->map;
869− const struct dso *dso = map__dso(map);
870− u32 prot = map__prot(map);
873+ ret = fprintf(args->fp,
874+ "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n",
875+ args->indent, "", map__start(map), map__end(map),
876+ prot & PROT_READ ? 'r' : '-',
877+ prot & PROT_WRITE ? 'w' : '-',
878+ prot & PROT_EXEC ? 'x' : '-',
879+ map__flags(map) ? 's' : 'p',
880+ map__pgoff(map),
881+ dso->id.ino, dso->name);
871882
872− printed += fprintf(fp, "%*s %" PRIx64 "-%" PRIx64 " %c%c%c%c %08" PRIx64 " %" PRIu64 " %s\n",
873− indent, "", map__start(map), map__end(map),
874− prot & PROT_READ ? 'r' : '-',
875− prot & PROT_WRITE ? 'w' : '-',
876− prot & PROT_EXEC ? 'x' : '-',
877− map__flags(map) ? 's' : 'p',
878− map__pgoff(map),
879− dso->id.ino, dso->name);
880− }
883+ if (ret < 0)
884+ return ret;
885+
886+ args->printed += ret;
887+ return 0;
888+}
889+
890+static size_t maps__fprintf_task(struct maps *maps, int indent, FILE *fp)
891+{
892+ struct maps__fprintf_task_args args = {
893+ .indent = indent,
894+ .fp = fp,
895+ .printed = 0,
896+ };
881897
882− return printed;
898+ maps__for_each_map(maps, maps__fprintf_task_cb, &args);
899+
900+ return args.printed;
883901 }
884902
885903 static void task__print_level(struct task *task, FILE *fp, int level)
@@ -1341,15 +1359,15 @@ int cmd_report(int argc, const char **argv) · 455 unmodified lines
13411359 "list of cpus to profile"),
13421360 OPT_BOOLEAN('I', "show-info", &report.show_full_info,
13431361 "Display extended information about perf.data file"),
1344− OPT_BOOLEAN(0, "source", &report.annotation_opts.annotate_src,
1362+ OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src,
13451363 "Interleave source code with assembly code (default)"),
1346− OPT_BOOLEAN(0, "asm-raw", &report.annotation_opts.show_asm_raw,
1364+ OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw,
13471365 "Display raw encoding of assembly instructions (default)"),
13481366 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
13491367 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1350− OPT_STRING(0, "prefix", &report.annotation_opts.prefix, "prefix",
1368+ OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix",
13511369 "Add prefix to source file path names in programs (with --prefix-strip)"),
1352− OPT_STRING(0, "prefix-strip", &report.annotation_opts.prefix_strip, "N",
1370+ OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N",
13531371 "Strip first N entries of source file path name in programs (with --prefix)"),
13541372 OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
13551373 "Show a column with the sum of periods"),
@@ -1401,7 +1419,7 @@ int cmd_report(int argc, const char **argv) · 45 unmodified lines
14011419 "Time span of interest (start,stop)"),
14021420 OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name,
14031421 "Show inline function"),
1404− OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period",
1422+ OPT_CALLBACK(0, "percent-type", &annotate_opts, "local-period",
14051423 "Set percent type local/global-period/hits",
14061424 annotate_parse_percent_type),
14071425 OPT_BOOLEAN(0, "ns", &symbol_conf.nanosecs, "Show times in nanosecs"),
@@ -1426,7 +1444,14 @@ int cmd_report(int argc, const char **argv) · 18 unmodified lines
14261444 if (ret < 0)
14271445 goto exit;
14281446
1429− annotation_options__init(&report.annotation_opts);
1447+ /*
1448+ * tasks_mode require access to exited threads to list those that are in
1449+ * the data file. Off-cpu events are synthesized after other events and
1450+ * reference exited threads.
1451+ */
1452+ symbol_conf.keep_exited_threads = true;
1453+
1454+ annotation_options__init();
14301455
14311456 ret = perf_config(report__config, &report);
14321457 if (ret)
@@ -1445,13 +1470,13 @@ int cmd_report(int argc, const char **argv) · 12 unmodified lines
14451470 }
14461471
14471472 if (disassembler_style) {
1448− report.annotation_opts.disassembler_style = strdup(disassembler_style);
1449− if (!report.annotation_opts.disassembler_style)
1473+ annotate_opts.disassembler_style = strdup(disassembler_style);
1474+ if (!annotate_opts.disassembler_style)
14501475 return -ENOMEM;
14511476 }
14521477 if (objdump_path) {
1453− report.annotation_opts.objdump_path = strdup(objdump_path);
1454− if (!report.annotation_opts.objdump_path)
1478+ annotate_opts.objdump_path = strdup(objdump_path);
1479+ if (!annotate_opts.objdump_path)
14551480 return -ENOMEM;
14561481 }
14571482 if (addr2line_path) {
@@ -1460,7 +1485,7 @@ int cmd_report(int argc, const char **argv) · 2 unmodified lines
14601485 return -ENOMEM;
14611486 }
14621487
1463− if (annotate_check_args(&report.annotation_opts) < 0) {
1488+ if (annotate_check_args() < 0) {
14641489 ret = -EINVAL;
14651490 goto exit;
14661491 }
@@ -1615,6 +1640,16 @@ repeat: · 148 unmodified lines
16151640 sort_order = NULL;
16161641 }
16171642
1643+ if (sort_order && strstr(sort_order, "type")) {
1644+ report.data_type = true;
1645+ annotate_opts.annotate_src = false;
1646+
1647+#ifndef HAVE_DWARF_GETLOCATIONS_SUPPORT
1648+ pr_err("Error: Data type profiling is disabled due to missing DWARF support\n");
1649+ goto error;
1650+#endif
1651+ }
1652+
16181653 if (strcmp(input_name, "-") != 0)
16191654 setup_browser(true);
16201655 else
@@ -1673,7 +1708,7 @@ repeat: · 52 unmodified lines
16731708 * so don't allocate extra space that won't be used in the stdio
16741709 * implementation.
16751710 */
1676− if (ui__has_annotation() || report.symbol_ipc ||
1711+ if (ui__has_annotation() || report.symbol_ipc || report.data_type ||
16771712 report.total_cycles_mode) {
16781713 ret = symbol__annotation_init();
16791714 if (ret < 0)
@@ -1692,7 +1727,7 @@ repeat: · 12 unmodified lines
16921727 */
16931728 symbol_conf.priv_size += sizeof(u32);
16941729 }
1695− annotation_config__init(&report.annotation_opts);
1730+ annotation_config__init();
16961731 }
16971732
16981733 if (symbol__init(&session->header.env) < 0)
@@ -1746,7 +1781,7 @@ error: · 47 unmodified lines
17461781 zstd_fini(&(session->zstd_data));
17471782 perf_session__delete(session);
17481783 exit:
1749− annotation_options__exit(&report.annotation_opts);
1784+ annotation_options__exit();
17501785 free(sort_order_help);
17511786 free(field_order_help);
17521787 return ret;
tools/perf/builtin-stat.c+19−14
@@ -653,7 +653,7 @@ static enum counter_recovery stat_handle_error(struct evsel *counter) · 652 unmodified lines
653653 if ((evsel__leader(counter) != counter) ||
654654 !(counter->core.leader->nr_members > 1))
655655 return COUNTER_SKIP;
656− } else if (evsel__fallback(counter, errno, msg, sizeof(msg))) {
656+ } else if (evsel__fallback(counter, &target, errno, msg, sizeof(msg))) {
657657 if (verbose > 0)
658658 ui__warning("%s\n", msg);
659659 return COUNTER_RETRY;
@@ -1204,8 +1204,9 @@ static struct option stat_options[] = { · 544 unmodified lines
12041204 OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
12051205 "list of cpus to monitor in system-wide"),
12061206 OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
1207− "disable CPU count aggregation", AGGR_NONE),
1208− OPT_BOOLEAN(0, "no-merge", &stat_config.no_merge, "Do not merge identical named events"),
1207+ "disable aggregation across CPUs or PMUs", AGGR_NONE),
1208+ OPT_SET_UINT(0, "no-merge", &stat_config.aggr_mode,
1209+ "disable aggregation the same as -A or -no-aggr", AGGR_NONE),
12091210 OPT_BOOLEAN(0, "hybrid-merge", &stat_config.hybrid_merge,
12101211 "Merge identical named hybrid events"),
12111212 OPT_STRING('x', "field-separator", &stat_config.csv_sep, "separator",
@@ -1255,7 +1256,7 @@ static struct option stat_options[] = { · 43 unmodified lines
12551256 OPT_BOOLEAN(0, "metric-no-merge", &stat_config.metric_no_merge,
12561257 "don't try to share events between metrics in a group"),
12571258 OPT_BOOLEAN(0, "metric-no-threshold", &stat_config.metric_no_threshold,
1258− "don't try to share events between metrics in a group "),
1259+ "disable adding events for the metric threshold calculation"),
12591260 OPT_BOOLEAN(0, "topdown", &topdown_run,
12601261 "measure top-down statistics"),
12611262 OPT_UINTEGER(0, "td-level", &stat_config.topdown_level,
@@ -1316,7 +1317,7 @@ static int cpu__get_cache_id_from_map(struct perf_cpu cpu, char *map) · 54 unmodified lines
13161317 * be the first online CPU in the cache domain else use the
13171318 * first online CPU of the cache domain as the ID.
13181319 */
1319− if (perf_cpu_map__empty(cpu_map))
1320+ if (perf_cpu_map__has_any_cpu_or_is_empty(cpu_map))
13201321 id = cpu.cpu;
13211322 else
13221323 id = perf_cpu_map__cpu(cpu_map, 0).cpu;
@@ -1622,7 +1623,7 @@ static int perf_stat_init_aggr_mode(void) · 299 unmodified lines
16221623 * taking the highest cpu number to be the size of
16231624 * the aggregation translate cpumap.
16241625 */
1625− if (!perf_cpu_map__empty(evsel_list->core.user_requested_cpus))
1626+ if (!perf_cpu_map__has_any_cpu_or_is_empty(evsel_list->core.user_requested_cpus))
16261627 nr = perf_cpu_map__max(evsel_list->core.user_requested_cpus).cpu;
16271628 else
16281629 nr = 0;
@@ -2289,7 +2290,7 @@ int process_stat_config_event(struct perf_session *session, · 660 unmodified lines
22892290
22902291 perf_event__read_stat_config(&stat_config, &event->stat_config);
22912292
2292− if (perf_cpu_map__empty(st->cpus)) {
2293+ if (perf_cpu_map__has_any_cpu_or_is_empty(st->cpus)) {
22932294 if (st->aggr_mode != AGGR_UNSET)
22942295 pr_warning("warning: processing task data, aggregation mode not set\n");
22952296 } else if (st->aggr_mode != AGGR_UNSET) {
@@ -2695,15 +2696,19 @@ int cmd_stat(int argc, const char **argv) · 399 unmodified lines
26952696 */
26962697 if (metrics) {
26972698 const char *pmu = parse_events_option_args.pmu_filter ?: "all";
2699+ int ret = metricgroup__parse_groups(evsel_list, pmu, metrics,
2700+ stat_config.metric_no_group,
2701+ stat_config.metric_no_merge,
2702+ stat_config.metric_no_threshold,
2703+ stat_config.user_requested_cpu_list,
2704+ stat_config.system_wide,
2705+ &stat_config.metric_events);
26982706
2699− metricgroup__parse_groups(evsel_list, pmu, metrics,
2700− stat_config.metric_no_group,
2701− stat_config.metric_no_merge,
2702− stat_config.metric_no_threshold,
2703− stat_config.user_requested_cpu_list,
2704− stat_config.system_wide,
2705− &stat_config.metric_events);
27062707 zfree(&metrics);
2708+ if (ret) {
2709+ status = ret;
2710+ goto out;
2711+ }
27072712 }
27082713
27092714 if (add_default_attributes())
tools/perf/builtin-top.c+26−26
@@ -147,7 +147,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) · 146 unmodified lines
147147 return err;
148148 }
149149
150− err = symbol__annotate(&he->ms, evsel, &top->annotation_opts, NULL);
150+ err = symbol__annotate(&he->ms, evsel, NULL);
151151 if (err == 0) {
152152 top->sym_filter_entry = he;
153153 } else {
@@ -261,9 +261,9 @@ static void perf_top__show_details(struct perf_top *top) · 107 unmodified lines
261261 goto out_unlock;
262262
263263 printf("Showing %s for %s\n", evsel__name(top->sym_evsel), symbol->name);
264− printf(" Events Pcnt (>=%d%%)\n", top->annotation_opts.min_pcnt);
264+ printf(" Events Pcnt (>=%d%%)\n", annotate_opts.min_pcnt);
265265
266− more = symbol__annotate_printf(&he->ms, top->sym_evsel, &top->annotation_opts);
266+ more = symbol__annotate_printf(&he->ms, top->sym_evsel);
267267
268268 if (top->evlist->enabled) {
269269 if (top->zero)
@@ -450,7 +450,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) · 180 unmodified lines
450450
451451 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
452452
453− fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->annotation_opts.min_pcnt);
453+ fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", annotate_opts.min_pcnt);
454454 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
455455 fprintf(stdout, "\t[S] stop annotation.\n");
456456
@@ -553,7 +553,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) · 96 unmodified lines
553553 prompt_integer(&top->count_filter, "Enter display event count filter");
554554 break;
555555 case 'F':
556− prompt_percent(&top->annotation_opts.min_pcnt,
556+ prompt_percent(&annotate_opts.min_pcnt,
557557 "Enter details display event filter (percent)");
558558 break;
559559 case 'K':
@@ -646,8 +646,7 @@ repeat: · 86 unmodified lines
646646 }
647647
648648 ret = evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
649− &top->session->header.env, !top->record_opts.overwrite,
650− &top->annotation_opts);
649+ &top->session->header.env, !top->record_opts.overwrite);
651650 if (ret == K_RELOAD) {
652651 top->zero = true;
653652 goto repeat;
@@ -1027,8 +1026,8 @@ static int perf_top__start_counters(struct perf_top *top) · 373 unmodified lines
10271026
10281027 evlist__for_each_entry(evlist, counter) {
10291028 try_again:
1030− if (evsel__open(counter, top->evlist->core.user_requested_cpus,
1031− top->evlist->core.threads) < 0) {
1029+ if (evsel__open(counter, counter->core.cpus,
1030+ counter->core.threads) < 0) {
10321031
10331032 /*
10341033 * Specially handle overwrite fall back.
@@ -1044,7 +1043,7 @@ try_again: · 9 unmodified lines
10441043 perf_top_overwrite_fallback(top, counter))
10451044 goto try_again;
10461045
1047− if (evsel__fallback(counter, errno, msg, sizeof(msg))) {
1046+ if (evsel__fallback(counter, &opts->target, errno, msg, sizeof(msg))) {
10481047 if (verbose > 0)
10491048 ui__warning("%s\n", msg);
10501049 goto try_again;
@@ -1241,9 +1240,9 @@ static int __cmd_top(struct perf_top *top) · 190 unmodified lines
12411240 pthread_t thread, thread_process;
12421241 int ret;
12431242
1244− if (!top->annotation_opts.objdump_path) {
1243+ if (!annotate_opts.objdump_path) {
12451244 ret = perf_env__lookup_objdump(&top->session->header.env,
1246− &top->annotation_opts.objdump_path);
1245+ &annotate_opts.objdump_path);
12471246 if (ret)
12481247 return ret;
12491248 }
@@ -1299,6 +1298,7 @@ static int __cmd_top(struct perf_top *top) · 49 unmodified lines
12991298 }
13001299 }
13011300
1301+ evlist__uniquify_name(top->evlist);
13021302 ret = perf_top__start_counters(top);
13031303 if (ret)
13041304 return ret;
@@ -1536,9 +1536,9 @@ int cmd_top(int argc, const char **argv) · 231 unmodified lines
15361536 "only consider symbols in these comms"),
15371537 OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
15381538 "only consider these symbols"),
1539− OPT_BOOLEAN(0, "source", &top.annotation_opts.annotate_src,
1539+ OPT_BOOLEAN(0, "source", &annotate_opts.annotate_src,
15401540 "Interleave source code with assembly code (default)"),
1541− OPT_BOOLEAN(0, "asm-raw", &top.annotation_opts.show_asm_raw,
1541+ OPT_BOOLEAN(0, "asm-raw", &annotate_opts.show_asm_raw,
15421542 "Display raw encoding of assembly instructions (default)"),
15431543 OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
15441544 "Enable kernel symbol demangling"),
@@ -1549,9 +1549,9 @@ int cmd_top(int argc, const char **argv) · 4 unmodified lines
15491549 "addr2line binary to use for line numbers"),
15501550 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
15511551 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1552− OPT_STRING(0, "prefix", &top.annotation_opts.prefix, "prefix",
1552+ OPT_STRING(0, "prefix", &annotate_opts.prefix, "prefix",
15531553 "Add prefix to source file path names in programs (with --prefix-strip)"),
1554− OPT_STRING(0, "prefix-strip", &top.annotation_opts.prefix_strip, "N",
1554+ OPT_STRING(0, "prefix-strip", &annotate_opts.prefix_strip, "N",
15551555 "Strip first N entries of source file path name in programs (with --prefix)"),
15561556 OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
15571557 OPT_CALLBACK(0, "percent-limit", &top, "percent",
@@ -1609,10 +1609,10 @@ int cmd_top(int argc, const char **argv) · 51 unmodified lines
16091609 if (status < 0)
16101610 return status;
16111611
1612− annotation_options__init(&top.annotation_opts);
1612+ annotation_options__init();
16131613
1614− top.annotation_opts.min_pcnt = 5;
1615− top.annotation_opts.context = 4;
1614+ annotate_opts.min_pcnt = 5;
1615+ annotate_opts.context = 4;
16161616
16171617 top.evlist = evlist__new();
16181618 if (top.evlist == NULL)
@@ -1642,13 +1642,13 @@ int cmd_top(int argc, const char **argv) · 23 unmodified lines
16421642 usage_with_options(top_usage, options);
16431643
16441644 if (disassembler_style) {
1645− top.annotation_opts.disassembler_style = strdup(disassembler_style);
1646− if (!top.annotation_opts.disassembler_style)
1645+ annotate_opts.disassembler_style = strdup(disassembler_style);
1646+ if (!annotate_opts.disassembler_style)
16471647 return -ENOMEM;
16481648 }
16491649 if (objdump_path) {
1650− top.annotation_opts.objdump_path = strdup(objdump_path);
1651− if (!top.annotation_opts.objdump_path)
1650+ annotate_opts.objdump_path = strdup(objdump_path);
1651+ if (!annotate_opts.objdump_path)
16521652 return -ENOMEM;
16531653 }
16541654 if (addr2line_path) {
@@ -1661,7 +1661,7 @@ int cmd_top(int argc, const char **argv) · 6 unmodified lines
16611661 if (status)
16621662 goto out_delete_evlist;
16631663
1664− if (annotate_check_args(&top.annotation_opts) < 0)
1664+ if (annotate_check_args() < 0)
16651665 goto out_delete_evlist;
16661666
16671667 if (!top.evlist->core.nr_entries) {
@@ -1787,7 +1787,7 @@ int cmd_top(int argc, const char **argv) · 119 unmodified lines
17871787 if (status < 0)
17881788 goto out_delete_evlist;
17891789
1790− annotation_config__init(&top.annotation_opts);
1790+ annotation_config__init();
17911791
17921792 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
17931793 status = symbol__init(NULL);
@@ -1840,7 +1840,7 @@ int cmd_top(int argc, const char **argv) · 46 unmodified lines
18401840 out_delete_evlist:
18411841 evlist__delete(top.evlist);
18421842 perf_session__delete(top.session);
1843− annotation_options__exit(&top.annotation_opts);
1843+ annotation_options__exit();
18441844
18451845 return status;
18461846 }
tools/perf/builtin-trace.c+2−4
@@ -2470,9 +2470,8 @@ static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sam · 2469 unmodified lines
24702470 static const char *errno_to_name(struct evsel *evsel, int err)
24712471 {
24722472 struct perf_env *env = evsel__env(evsel);
2473− const char *arch_name = perf_env__arch(env);
24742473
2475− return arch_syscalls__strerrno(arch_name, err);
2474+ return perf_env__arch_strerrno(env, err);
24762475 }
24772476
24782477 static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
@@ -4264,12 +4263,11 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, · 1785 unmodified lines
42644263 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
42654264
42664265 if (trace->errno_summary && stats->nr_failures) {
4267− const char *arch_name = perf_env__arch(trace->host->env);
42684266 int e;
42694267
42704268 for (e = 0; e < stats->max_errno; ++e) {
42714269 if (stats->errnos[e] != 0)
4272− fprintf(fp, "\t\t\t\t%s: %d\n", arch_syscalls__strerrno(arch_name, e + 1), stats->errnos[e]);
4270+ fprintf(fp, "\t\t\t\t%s: %d\n", perf_env__arch_strerrno(trace->host->env, e + 1), stats->errnos[e]);
42734271 }
42744272 }
42754273 }
tools/perf/perf-archive.sh+80−6
@@ -4,8 +4,73 @@ · 3 unmodified lines
44 # Arnaldo Carvalho de Melo <acme@redhat.com>
55
66 PERF_DATA=perf.data
7−if [ $# -ne 0 ] ; then
8− PERF_DATA=$1
7+PERF_SYMBOLS=perf.symbols
8+PERF_ALL=perf.all
9+ALL=0
10+UNPACK=0
11+
12+while [ $# -gt 0 ] ; do
13+ if [ $1 == "--all" ]; then
14+ ALL=1
15+ shift
16+ elif [ $1 == "--unpack" ]; then
17+ UNPACK=1
18+ shift
19+ else
20+ PERF_DATA=$1
21+ UNPACK_TAR=$1
22+ shift
23+ fi
24+done
25+
26+if [ $UNPACK -eq 1 ]; then
27+ if [ ! -z "$UNPACK_TAR" ]; then # tar given as an argument
28+ if [ ! -e "$UNPACK_TAR" ]; then
29+ echo "Provided file $UNPACK_TAR does not exist"
30+ exit 1
31+ fi
32+ TARGET="$UNPACK_TAR"
33+ else # search for perf tar in the current directory
34+ TARGET=`find . -regex "\./perf.*\.tar\.bz2"`
35+ TARGET_NUM=`echo -n "$TARGET" | grep -c '^'`
36+
37+ if [ -z "$TARGET" -o $TARGET_NUM -gt 1 ]; then
38+ echo -e "Error: $TARGET_NUM files found for unpacking:\n$TARGET"
39+ echo "Provide the requested file as an argument"
40+ exit 1
41+ else
42+ echo "Found target file for unpacking: $TARGET"
43+ fi
44+ fi
45+
46+ if [[ "$TARGET" =~ (\./)?$PERF_ALL.*.tar.bz2 ]]; then # perf tar generated by --all option
47+ TAR_CONTENTS=`tar tvf "$TARGET" | tr -s " " | cut -d " " -f 6`
48+ VALID_TAR=`echo "$TAR_CONTENTS" | grep "$PERF_SYMBOLS.tar.bz2" | wc -l` # check if it contains a sub-tar perf.symbols
49+ if [ $VALID_TAR -ne 1 ]; then
50+ echo "Error: $TARGET file is not valid (contains zero or multiple sub-tar files with debug symbols)"
51+ exit 1
52+ fi
53+
54+ INTERSECT=`comm -12 <(ls) <(echo "$TAR_CONTENTS") | tr "\n" " "` # check for overwriting
55+ if [ ! -z "$INTERSECT" ]; then # prompt if file(s) already exist in the current directory
56+ echo "File(s) ${INTERSECT::-1} already exist in the current directory."
57+ while true; do
58+ read -p 'Do you wish to overwrite them? ' yn
59+ case $yn in
60+ [Yy]* ) break;;
61+ [Nn]* ) exit 1;;
62+ * ) echo "Please answer yes or no.";;
63+ esac
64+ done
65+ fi
66+
67+ # unzip the perf.data file in the current working directory and debug symbols in ~/.debug directory
68+ tar xvf $TARGET && tar xvf $PERF_SYMBOLS.tar.bz2 -C ~/.debug
69+
70+ else # perf tar generated by perf archive (contains only debug symbols)
71+ tar xvf $TARGET -C ~/.debug
72+ fi
73+ exit 0
974 fi
1075
1176 #
@@ -39,9 +104,18 @@ while read build_id ; do · 27 unmodified lines
39104 echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST
40105 done
41106
42−tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
43−rm $MANIFEST $BUILDIDS || true
107+if [ $ALL -eq 1 ]; then # pack perf.data file together with tar containing debug symbols
108+ HOSTNAME=$(hostname)
109+ DATE=$(date '+%Y%m%d-%H%M%S')
110+ tar cjf $PERF_SYMBOLS.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
111+ tar cjf $PERF_ALL-$HOSTNAME-$DATE.tar.bz2 $PERF_DATA $PERF_SYMBOLS.tar.bz2
112+ rm $PERF_SYMBOLS.tar.bz2 $MANIFEST $BUILDIDS || true
113+else # pack only the debug symbols
114+ tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
115+ rm $MANIFEST $BUILDIDS || true
116+fi
117+
44118 echo -e "Now please run:\n"
45−echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
46−echo "wherever you need to run 'perf report' on."
119+echo -e "$ perf archive --unpack\n"
120+echo "or unpack the tar manually wherever you need to run 'perf report' on."
47121 exit 0
tools/perf/perf.c+30−0
@@ -39,6 +39,7 @@ · 38 unmodified lines
3939 #include <linux/zalloc.h>
4040
4141 static int use_pager = -1;
42+static FILE *debug_fp = NULL;
4243
4344 struct cmd_struct {
4445 const char *cmd;
@@ -162,6 +163,19 @@ static void commit_pager_choice(void) · 117 unmodified lines
162163 }
163164 }
164165
166+static int set_debug_file(const char *path)
167+{
168+ debug_fp = fopen(path, "w");
169+ if (!debug_fp) {
170+ fprintf(stderr, "Open debug file '%s' failed: %s\n",
171+ path, strerror(errno));
172+ return -1;
173+ }
174+
175+ debug_set_file(debug_fp);
176+ return 0;
177+}
178+
165179 struct option options[] = {
166180 OPT_ARGUMENT("help", "help"),
167181 OPT_ARGUMENT("version", "version"),
@@ -174,6 +188,7 @@ struct option options[] = { · 6 unmodified lines
174188 OPT_ARGUMENT("list-cmds", "list-cmds"),
175189 OPT_ARGUMENT("list-opts", "list-opts"),
176190 OPT_ARGUMENT("debug", "debug"),
191+ OPT_ARGUMENT("debug-file", "debug-file"),
177192 OPT_END()
178193 };
179194
@@ -287,6 +302,18 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) · 107 unmodified lines
287302
288303 (*argv)++;
289304 (*argc)--;
305+ } else if (!strcmp(cmd, "--debug-file")) {
306+ if (*argc < 2) {
307+ fprintf(stderr, "No path given for --debug-file.\n");
308+ usage(perf_usage_string);
309+ }
310+
311+ if (set_debug_file((*argv)[1]))
312+ usage(perf_usage_string);
313+
314+ (*argv)++;
315+ (*argc)--;
316+
290317 } else {
291318 fprintf(stderr, "Unknown option: %s\n", cmd);
292319 usage(perf_usage_string);
@@ -547,5 +574,8 @@ int main(int argc, const char **argv) · 254 unmodified lines
547574 fprintf(stderr, "Failed to run command '%s': %s\n",
548575 cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
549576 out:
577+ if (debug_fp)
578+ fclose(debug_fp);
579+
550580 return 1;
551581 }
tools/perf/pmu-events/arch/arm64/ampere/ampereone/core-imp-def.json+1−1
@@ -110,7 +110,7 @@ · 109 unmodified lines
110110 {
111111 "PublicDescription": "Flushes due to memory hazards",
112112 "EventCode": "0x121",
113− "EventName": "BPU_FLUSH_MEM_FAULT",
113+ "EventName": "GPC_FLUSH_MEM_FAULT",
114114 "BriefDescription": "Flushes due to memory hazards"
115115 },
116116 {
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/branch.json+125−0
@@ -0,0 +1,125 @@
1+[
2+ {
3+ "ArchStdEvent": "BR_IMMED_SPEC"
4+ },
5+ {
6+ "ArchStdEvent": "BR_RETURN_SPEC"
7+ },
8+ {
9+ "ArchStdEvent": "BR_INDIRECT_SPEC"
10+ },
11+ {
12+ "ArchStdEvent": "BR_MIS_PRED"
13+ },
14+ {
15+ "ArchStdEvent": "BR_PRED"
16+ },
17+ {
18+ "PublicDescription": "Instruction architecturally executed, branch not taken",
19+ "EventCode": "0x8107",
20+ "EventName": "BR_SKIP_RETIRED",
21+ "BriefDescription": "Instruction architecturally executed, branch not taken"
22+ },
23+ {
24+ "PublicDescription": "Instruction architecturally executed, immediate branch taken",
25+ "EventCode": "0x8108",
26+ "EventName": "BR_IMMED_TAKEN_RETIRED",
27+ "BriefDescription": "Instruction architecturally executed, immediate branch taken"
28+ },
29+ {
30+ "PublicDescription": "Instruction architecturally executed, indirect branch excluding return retired",
31+ "EventCode": "0x810c",
32+ "EventName": "BR_INDNR_TAKEN_RETIRED",
33+ "BriefDescription": "Instruction architecturally executed, indirect branch excluding return retired"
34+ },
35+ {
36+ "PublicDescription": "Instruction architecturally executed, predicted immediate branch",
37+ "EventCode": "0x8110",
38+ "EventName": "BR_IMMED_PRED_RETIRED",
39+ "BriefDescription": "Instruction architecturally executed, predicted immediate branch"
40+ },
41+ {
42+ "PublicDescription": "Instruction architecturally executed, mispredicted immediate branch",
43+ "EventCode": "0x8111",
44+ "EventName": "BR_IMMED_MIS_PRED_RETIRED",
45+ "BriefDescription": "Instruction architecturally executed, mispredicted immediate branch"
46+ },
47+ {
48+ "PublicDescription": "Instruction architecturally executed, predicted indirect branch",
49+ "EventCode": "0x8112",
50+ "EventName": "BR_IND_PRED_RETIRED",
51+ "BriefDescription": "Instruction architecturally executed, predicted indirect branch"
52+ },
53+ {
54+ "PublicDescription": "Instruction architecturally executed, mispredicted indirect branch",
55+ "EventCode": "0x8113",
56+ "EventName": "BR_IND_MIS_PRED_RETIRED",
57+ "BriefDescription": "Instruction architecturally executed, mispredicted indirect branch"
58+ },
59+ {
60+ "PublicDescription": "Instruction architecturally executed, predicted procedure return",
61+ "EventCode": "0x8114",
62+ "EventName": "BR_RETURN_PRED_RETIRED",
63+ "BriefDescription": "Instruction architecturally executed, predicted procedure return"
64+ },
65+ {
66+ "PublicDescription": "Instruction architecturally executed, mispredicted procedure return",
67+ "EventCode": "0x8115",
68+ "EventName": "BR_RETURN_MIS_PRED_RETIRED",
69+ "BriefDescription": "Instruction architecturally executed, mispredicted procedure return"
70+ },
71+ {
72+ "PublicDescription": "Instruction architecturally executed, predicted indirect branch excluding return",
73+ "EventCode": "0x8116",
74+ "EventName": "BR_INDNR_PRED_RETIRED",
75+ "BriefDescription": "Instruction architecturally executed, predicted indirect branch excluding return"
76+ },
77+ {
78+ "PublicDescription": "Instruction architecturally executed, mispredicted indirect branch excluding return",
79+ "EventCode": "0x8117",
80+ "EventName": "BR_INDNR_MIS_PRED_RETIRED",
81+ "BriefDescription": "Instruction architecturally executed, mispredicted indirect branch excluding return"
82+ },
83+ {
84+ "PublicDescription": "Instruction architecturally executed, predicted branch, taken",
85+ "EventCode": "0x8118",
86+ "EventName": "BR_TAKEN_PRED_RETIRED",
87+ "BriefDescription": "Instruction architecturally executed, predicted branch, taken"
88+ },
89+ {
90+ "PublicDescription": "Instruction architecturally executed, mispredicted branch, taken",
91+ "EventCode": "0x8119",
92+ "EventName": "BR_TAKEN_MIS_PRED_RETIRED",
93+ "BriefDescription": "Instruction architecturally executed, mispredicted branch, taken"
94+ },
95+ {
96+ "PublicDescription": "Instruction architecturally executed, predicted branch, not taken",
97+ "EventCode": "0x811a",
98+ "EventName": "BR_SKIP_PRED_RETIRED",
99+ "BriefDescription": "Instruction architecturally executed, predicted branch, not taken"
100+ },
101+ {
102+ "PublicDescription": "Instruction architecturally executed, mispredicted branch, not taken",
103+ "EventCode": "0x811b",
104+ "EventName": "BR_SKIP_MIS_PRED_RETIRED",
105+ "BriefDescription": "Instruction architecturally executed, mispredicted branch, not taken"
106+ },
107+ {
108+ "PublicDescription": "Instruction architecturally executed, predicted branch",
109+ "EventCode": "0x811c",
110+ "EventName": "BR_PRED_RETIRED",
111+ "BriefDescription": "Instruction architecturally executed, predicted branch"
112+ },
113+ {
114+ "PublicDescription": "Instruction architecturally executed, indirect branch",
115+ "EventCode": "0x811d",
116+ "EventName": "BR_IND_RETIRED",
117+ "BriefDescription": "Instruction architecturally executed, indirect branch"
118+ },
119+ {
120+ "PublicDescription": "Branch Record captured.",
121+ "EventCode": "0x811f",
122+ "EventName": "BRB_FILTRATE",
123+ "BriefDescription": "Branch Record captured."
124+ }
125+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/bus.json+20−0
@@ -0,0 +1,20 @@
1+[
2+ {
3+ "ArchStdEvent": "CPU_CYCLES"
4+ },
5+ {
6+ "ArchStdEvent": "BUS_CYCLES"
7+ },
8+ {
9+ "ArchStdEvent": "BUS_ACCESS_RD"
10+ },
11+ {
12+ "ArchStdEvent": "BUS_ACCESS_WR"
13+ },
14+ {
15+ "ArchStdEvent": "BUS_ACCESS"
16+ },
17+ {
18+ "ArchStdEvent": "CNT_CYCLES"
19+ }
20+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/cache.json+206−0
@@ -0,0 +1,206 @@
1+[
2+ {
3+ "ArchStdEvent": "L1D_CACHE_RD"
4+ },
5+ {
6+ "ArchStdEvent": "L1D_CACHE_WR"
7+ },
8+ {
9+ "ArchStdEvent": "L1D_CACHE_REFILL_RD"
10+ },
11+ {
12+ "ArchStdEvent": "L1D_CACHE_INVAL"
13+ },
14+ {
15+ "ArchStdEvent": "L1D_TLB_REFILL_RD"
16+ },
17+ {
18+ "ArchStdEvent": "L1D_TLB_REFILL_WR"
19+ },
20+ {
21+ "ArchStdEvent": "L2D_CACHE_RD"
22+ },
23+ {
24+ "ArchStdEvent": "L2D_CACHE_WR"
25+ },
26+ {
27+ "ArchStdEvent": "L2D_CACHE_REFILL_RD"
28+ },
29+ {
30+ "ArchStdEvent": "L2D_CACHE_REFILL_WR"
31+ },
32+ {
33+ "ArchStdEvent": "L2D_CACHE_WB_VICTIM"
34+ },
35+ {
36+ "ArchStdEvent": "L2D_CACHE_WB_CLEAN"
37+ },
38+ {
39+ "ArchStdEvent": "L2D_CACHE_INVAL"
40+ },
41+ {
42+ "ArchStdEvent": "L1I_CACHE_REFILL"
43+ },
44+ {
45+ "ArchStdEvent": "L1I_TLB_REFILL"
46+ },
47+ {
48+ "ArchStdEvent": "L1D_CACHE_REFILL"
49+ },
50+ {
51+ "ArchStdEvent": "L1D_CACHE"
52+ },
53+ {
54+ "ArchStdEvent": "L1D_TLB_REFILL"
55+ },
56+ {
57+ "ArchStdEvent": "L1I_CACHE"
58+ },
59+ {
60+ "ArchStdEvent": "L2D_CACHE"
61+ },
62+ {
63+ "ArchStdEvent": "L2D_CACHE_REFILL"
64+ },
65+ {
66+ "ArchStdEvent": "L2D_CACHE_WB"
67+ },
68+ {
69+ "ArchStdEvent": "L1D_TLB"
70+ },
71+ {
72+ "ArchStdEvent": "L1I_TLB"
73+ },
74+ {
75+ "ArchStdEvent": "L2D_TLB_REFILL"
76+ },
77+ {
78+ "ArchStdEvent": "L2I_TLB_REFILL"
79+ },
80+ {
81+ "ArchStdEvent": "L2D_TLB"
82+ },
83+ {
84+ "ArchStdEvent": "L2I_TLB"
85+ },
86+ {
87+ "ArchStdEvent": "DTLB_WALK"
88+ },
89+ {
90+ "ArchStdEvent": "ITLB_WALK"
91+ },
92+ {
93+ "ArchStdEvent": "L1D_CACHE_REFILL_WR"
94+ },
95+ {
96+ "ArchStdEvent": "L1D_CACHE_LMISS_RD"
97+ },
98+ {
99+ "ArchStdEvent": "L1I_CACHE_LMISS"
100+ },
101+ {
102+ "ArchStdEvent": "L2D_CACHE_LMISS_RD"
103+ },
104+ {
105+ "PublicDescription": "Level 1 data or unified cache demand access",
106+ "EventCode": "0x8140",
107+ "EventName": "L1D_CACHE_RW",
108+ "BriefDescription": "Level 1 data or unified cache demand access"
109+ },
110+ {
111+ "PublicDescription": "Level 1 data or unified cache preload or prefetch",
112+ "EventCode": "0x8142",
113+ "EventName": "L1D_CACHE_PRFM",
114+ "BriefDescription": "Level 1 data or unified cache preload or prefetch"
115+ },
116+ {
117+ "PublicDescription": "Level 1 data or unified cache refill, preload or prefetch",
118+ "EventCode": "0x8146",
119+ "EventName": "L1D_CACHE_REFILL_PRFM",
120+ "BriefDescription": "Level 1 data or unified cache refill, preload or prefetch"
121+ },
122+ {
123+ "ArchStdEvent": "L1D_TLB_RD"
124+ },
125+ {
126+ "ArchStdEvent": "L1D_TLB_WR"
127+ },
128+ {
129+ "ArchStdEvent": "L2D_TLB_REFILL_RD"
130+ },
131+ {
132+ "ArchStdEvent": "L2D_TLB_REFILL_WR"
133+ },
134+ {
135+ "ArchStdEvent": "L2D_TLB_RD"
136+ },
137+ {
138+ "ArchStdEvent": "L2D_TLB_WR"
139+ },
140+ {
141+ "PublicDescription": "L1D TLB miss",
142+ "EventCode": "0xD600",
143+ "EventName": "L1D_TLB_MISS",
144+ "BriefDescription": "L1D TLB miss"
145+ },
146+ {
147+ "PublicDescription": "Level 1 prefetcher, load prefetch requests generated",
148+ "EventCode": "0xd606",
149+ "EventName": "L1_PREFETCH_LD_GEN",
150+ "BriefDescription": "Level 1 prefetcher, load prefetch requests generated"
151+ },
152+ {
153+ "PublicDescription": "Level 1 prefetcher, load prefetch fills into the level 1 cache",
154+ "EventCode": "0xd607",
155+ "EventName": "L1_PREFETCH_LD_FILL",
156+ "BriefDescription": "Level 1 prefetcher, load prefetch fills into the level 1 cache"
157+ },
158+ {
159+ "PublicDescription": "Level 1 prefetcher, load prefetch to level 2 generated",
160+ "EventCode": "0xd608",
161+ "EventName": "L1_PREFETCH_L2_REQ",
162+ "BriefDescription": "Level 1 prefetcher, load prefetch to level 2 generated"
163+ },
164+ {
165+ "PublicDescription": "L1 prefetcher, distance was reset",
166+ "EventCode": "0xd609",
167+ "EventName": "L1_PREFETCH_DIST_RST",
168+ "BriefDescription": "L1 prefetcher, distance was reset"
169+ },
170+ {
171+ "PublicDescription": "L1 prefetcher, distance was increased",
172+ "EventCode": "0xd60a",
173+ "EventName": "L1_PREFETCH_DIST_INC",
174+ "BriefDescription": "L1 prefetcher, distance was increased"
175+ },
176+ {
177+ "PublicDescription": "Level 1 prefetcher, table entry is trained",
178+ "EventCode": "0xd60b",
179+ "EventName": "L1_PREFETCH_ENTRY_TRAINED",
180+ "BriefDescription": "Level 1 prefetcher, table entry is trained"
181+ },
182+ {
183+ "PublicDescription": "L1 data cache refill - Read or Write",
184+ "EventCode": "0xd60e",
185+ "EventName": "L1D_CACHE_REFILL_RW",
186+ "BriefDescription": "L1 data cache refill - Read or Write"
187+ },
188+ {
189+ "PublicDescription": "Level 2 cache refill from instruction-side miss, including IMMU refills",
190+ "EventCode": "0xD701",
191+ "EventName": "L2C_INST_REFILL",
192+ "BriefDescription": "Level 2 cache refill from instruction-side miss, including IMMU refills"
193+ },
194+ {
195+ "PublicDescription": "Level 2 cache refill from data-side miss, including DMMU refills",
196+ "EventCode": "0xD702",
197+ "EventName": "L2C_DATA_REFILL",
198+ "BriefDescription": "Level 2 cache refill from data-side miss, including DMMU refills"
199+ },
200+ {
201+ "PublicDescription": "Level 2 cache prefetcher, load prefetch requests generated",
202+ "EventCode": "0xD703",
203+ "EventName": "L2_PREFETCH_REQ",
204+ "BriefDescription": "Level 2 cache prefetcher, load prefetch requests generated"
205+ }
206+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/core-imp-def.json+464−0
@@ -0,0 +1,464 @@
1+[
2+ {
3+ "PublicDescription": "Level 2 prefetch requests, refilled to L2 cache",
4+ "EventCode": "0x10A",
5+ "EventName": "L2_PREFETCH_REFILL",
6+ "BriefDescription": "Level 2 prefetch requests, refilled to L2 cache"
7+ },
8+ {
9+ "PublicDescription": "Level 2 prefetch requests, late",
10+ "EventCode": "0x10B",
11+ "EventName": "L2_PREFETCH_UPGRADE",
12+ "BriefDescription": "Level 2 prefetch requests, late"
13+ },
14+ {
15+ "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB",
16+ "EventCode": "0x110",
17+ "EventName": "BPU_HIT_BTB",
18+ "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB"
19+ },
20+ {
21+ "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB",
22+ "EventCode": "0x111",
23+ "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB",
24+ "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB"
25+ },
26+ {
27+ "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor",
28+ "EventCode": "0x112",
29+ "EventName": "BPU_HIT_INDIRECT_PREDICTOR",
30+ "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor"
31+ },
32+ {
33+ "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor",
34+ "EventCode": "0x113",
35+ "EventName": "BPU_HIT_RSB",
36+ "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor"
37+ },
38+ {
39+ "PublicDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB",
40+ "EventCode": "0x114",
41+ "EventName": "BPU_UNCONDITIONAL_BRANCH_MISS_BTB",
42+ "BriefDescription": "Predictable unconditional branch speculatively executed that did not hit any level of BTB"
43+ },
44+ {
45+ "PublicDescription": "Predictable branch speculatively executed, unpredicted",
46+ "EventCode": "0x115",
47+ "EventName": "BPU_BRANCH_NO_HIT",
48+ "BriefDescription": "Predictable branch speculatively executed, unpredicted"
49+ },
50+ {
51+ "PublicDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict",
52+ "EventCode": "0x116",
53+ "EventName": "BPU_HIT_BTB_AND_MISPREDICT",
54+ "BriefDescription": "Predictable branch speculatively executed that hit any level of BTB that mispredict"
55+ },
56+ {
57+ "PublicDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict",
58+ "EventCode": "0x117",
59+ "EventName": "BPU_CONDITIONAL_BRANCH_HIT_BTB_AND_MISPREDICT",
60+ "BriefDescription": "Predictable conditional branch speculatively executed that hit any level of BTB that (direction) mispredict"
61+ },
62+ {
63+ "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict",
64+ "EventCode": "0x118",
65+ "EventName": "BPU_INDIRECT_BRANCH_HIT_BTB_AND_MISPREDICT",
66+ "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the indirect predictor that mispredict"
67+ },
68+ {
69+ "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict",
70+ "EventCode": "0x119",
71+ "EventName": "BPU_HIT_RSB_AND_MISPREDICT",
72+ "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the return predictor that mispredict"
73+ },
74+ {
75+ "PublicDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict",
76+ "EventCode": "0x11a",
77+ "EventName": "BPU_MISS_RSB_AND_MISPREDICT",
78+ "BriefDescription": "Predictable taken branch speculatively executed that hit any level of BTB that access the overflow/underflow return predictor that mispredict"
79+ },
80+ {
81+ "PublicDescription": "Predictable branch speculatively executed, unpredicted, that mispredict",
82+ "EventCode": "0x11b",
83+ "EventName": "BPU_NO_PREDICTION_MISPREDICT",
84+ "BriefDescription": "Predictable branch speculatively executed, unpredicted, that mispredict"
85+ },
86+ {
87+ "PublicDescription": "Preditable branch update the BTB region buffer entry",
88+ "EventCode": "0x11c",
89+ "EventName": "BPU_BTB_UPDATE",
90+ "BriefDescription": "Preditable branch update the BTB region buffer entry"
91+ },
92+ {
93+ "PublicDescription": "Count predict pipe stalls due to speculative return address predictor full",
94+ "EventCode": "0x11d",
95+ "EventName": "BPU_RSB_FULL_STALL",
96+ "BriefDescription": "Count predict pipe stalls due to speculative return address predictor full"
97+ },
98+ {
99+ "PublicDescription": "Macro-ops speculatively decoded",
100+ "EventCode": "0x11f",
101+ "EventName": "ICF_INST_SPEC_DECODE",
102+ "BriefDescription": "Macro-ops speculatively decoded"
103+ },
104+ {
105+ "PublicDescription": "Flushes",
106+ "EventCode": "0x120",
107+ "EventName": "GPC_FLUSH",
108+ "BriefDescription": "Flushes"
109+ },
110+ {
111+ "PublicDescription": "Flushes due to memory hazards",
112+ "EventCode": "0x121",
113+ "EventName": "GPC_FLUSH_MEM_FAULT",
114+ "BriefDescription": "Flushes due to memory hazards"
115+ },
116+ {
117+ "PublicDescription": "ETM extout bit 0",
118+ "EventCode": "0x141",
119+ "EventName": "MSC_ETM_EXTOUT0",
120+ "BriefDescription": "ETM extout bit 0"
121+ },
122+ {
123+ "PublicDescription": "ETM extout bit 1",
124+ "EventCode": "0x142",
125+ "EventName": "MSC_ETM_EXTOUT1",
126+ "BriefDescription": "ETM extout bit 1"
127+ },
128+ {
129+ "PublicDescription": "ETM extout bit 2",
130+ "EventCode": "0x143",
131+ "EventName": "MSC_ETM_EXTOUT2",
132+ "BriefDescription": "ETM extout bit 2"
133+ },
134+ {
135+ "PublicDescription": "ETM extout bit 3",
136+ "EventCode": "0x144",
137+ "EventName": "MSC_ETM_EXTOUT3",
138+ "BriefDescription": "ETM extout bit 3"
139+ },
140+ {
141+ "PublicDescription": "Bus request sn",
142+ "EventCode": "0x156",
143+ "EventName": "L2C_SNOOP",
144+ "BriefDescription": "Bus request sn"
145+ },
146+ {
147+ "PublicDescription": "L2 TXDAT LCRD blocked",
148+ "EventCode": "0x169",
149+ "EventName": "L2C_DAT_CRD_STALL",
150+ "BriefDescription": "L2 TXDAT LCRD blocked"
151+ },
152+ {
153+ "PublicDescription": "L2 TXRSP LCRD blocked",
154+ "EventCode": "0x16a",
155+ "EventName": "L2C_RSP_CRD_STALL",
156+ "BriefDescription": "L2 TXRSP LCRD blocked"
157+ },
158+ {
159+ "PublicDescription": "L2 TXREQ LCRD blocked",
160+ "EventCode": "0x16b",
161+ "EventName": "L2C_REQ_CRD_STALL",
162+ "BriefDescription": "L2 TXREQ LCRD blocked"
163+ },
164+ {
165+ "PublicDescription": "Early mispredict",
166+ "EventCode": "0xD100",
167+ "EventName": "ICF_EARLY_MIS_PRED",
168+ "BriefDescription": "Early mispredict"
169+ },
170+ {
171+ "PublicDescription": "FEQ full cycles",
172+ "EventCode": "0xD101",
173+ "EventName": "ICF_FEQ_FULL",
174+ "BriefDescription": "FEQ full cycles"
175+ },
176+ {
177+ "PublicDescription": "Instruction FIFO Full",
178+ "EventCode": "0xD102",
179+ "EventName": "ICF_INST_FIFO_FULL",
180+ "BriefDescription": "Instruction FIFO Full"
181+ },
182+ {
183+ "PublicDescription": "L1I TLB miss",
184+ "EventCode": "0xD103",
185+ "EventName": "L1I_TLB_MISS",
186+ "BriefDescription": "L1I TLB miss"
187+ },
188+ {
189+ "PublicDescription": "ICF sent 0 instructions to IDR this cycle",
190+ "EventCode": "0xD104",
191+ "EventName": "ICF_STALL",
192+ "BriefDescription": "ICF sent 0 instructions to IDR this cycle"
193+ },
194+ {
195+ "PublicDescription": "PC FIFO Full",
196+ "EventCode": "0xD105",
197+ "EventName": "ICF_PC_FIFO_FULL",
198+ "BriefDescription": "PC FIFO Full"
199+ },
200+ {
201+ "PublicDescription": "Stall due to BOB ID",
202+ "EventCode": "0xD200",
203+ "EventName": "IDR_STALL_BOB_ID",
204+ "BriefDescription": "Stall due to BOB ID"
205+ },
206+ {
207+ "PublicDescription": "Dispatch stall due to LOB entries",
208+ "EventCode": "0xD201",
209+ "EventName": "IDR_STALL_LOB_ID",
210+ "BriefDescription": "Dispatch stall due to LOB entries"
211+ },
212+ {
213+ "PublicDescription": "Dispatch stall due to SOB entries",
214+ "EventCode": "0xD202",
215+ "EventName": "IDR_STALL_SOB_ID",
216+ "BriefDescription": "Dispatch stall due to SOB entries"
217+ },
218+ {
219+ "PublicDescription": "Dispatch stall due to IXU scheduler entries",
220+ "EventCode": "0xD203",
221+ "EventName": "IDR_STALL_IXU_SCHED",
222+ "BriefDescription": "Dispatch stall due to IXU scheduler entries"
223+ },
224+ {
225+ "PublicDescription": "Dispatch stall due to FSU scheduler entries",
226+ "EventCode": "0xD204",
227+ "EventName": "IDR_STALL_FSU_SCHED",
228+ "BriefDescription": "Dispatch stall due to FSU scheduler entries"
229+ },
230+ {
231+ "PublicDescription": "Dispatch stall due to ROB entries",
232+ "EventCode": "0xD205",
233+ "EventName": "IDR_STALL_ROB_ID",
234+ "BriefDescription": "Dispatch stall due to ROB entries"
235+ },
236+ {
237+ "PublicDescription": "Dispatch stall due to flush",
238+ "EventCode": "0xD206",
239+ "EventName": "IDR_STALL_FLUSH",
240+ "BriefDescription": "Dispatch stall due to flush"
241+ },
242+ {
243+ "PublicDescription": "Dispatch stall due to WFI",
244+ "EventCode": "0xD207",
245+ "EventName": "IDR_STALL_WFI",
246+ "BriefDescription": "Dispatch stall due to WFI"
247+ },
248+ {
249+ "PublicDescription": "Number of SWOB drains triggered by timeout",
250+ "EventCode": "0xD208",
251+ "EventName": "IDR_STALL_SWOB_TIMEOUT",
252+ "BriefDescription": "Number of SWOB drains triggered by timeout"
253+ },
254+ {
255+ "PublicDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain",
256+ "EventCode": "0xD209",
257+ "EventName": "IDR_STALL_SWOB_RAW",
258+ "BriefDescription": "Number of SWOB drains triggered by system register or special-purpose register read-after-write or specific special-purpose register writes that cause SWOB drain"
259+ },
260+ {
261+ "PublicDescription": "Number of SWOB drains triggered by system register write when SWOB full",
262+ "EventCode": "0xD20A",
263+ "EventName": "IDR_STALL_SWOB_FULL",
264+ "BriefDescription": "Number of SWOB drains triggered by system register write when SWOB full"
265+ },
266+ {
267+ "PublicDescription": "Dispatch stall due to L1 instruction cache miss",
268+ "EventCode": "0xD20B",
269+ "EventName": "STALL_FRONTEND_CACHE",
270+ "BriefDescription": "Dispatch stall due to L1 instruction cache miss"
271+ },
272+ {
273+ "PublicDescription": "Dispatch stall due to L1 data cache miss",
274+ "EventCode": "0xD20D",
275+ "EventName": "STALL_BACKEND_CACHE",
276+ "BriefDescription": "Dispatch stall due to L1 data cache miss"
277+ },
278+ {
279+ "PublicDescription": "Dispatch stall due to lack of any core resource",
280+ "EventCode": "0xD20F",
281+ "EventName": "STALL_BACKEND_RESOURCE",
282+ "BriefDescription": "Dispatch stall due to lack of any core resource"
283+ },
284+ {
285+ "PublicDescription": "Instructions issued by the scheduler",
286+ "EventCode": "0xD300",
287+ "EventName": "IXU_NUM_UOPS_ISSUED",
288+ "BriefDescription": "Instructions issued by the scheduler"
289+ },
290+ {
291+ "PublicDescription": "Any uop issued was canceled for any reason",
292+ "EventCode": "0xD301",
293+ "EventName": "IXU_ISSUE_CANCEL",
294+ "BriefDescription": "Any uop issued was canceled for any reason"
295+ },
296+ {
297+ "PublicDescription": "A load wakeup to the scheduler has been canceled",
298+ "EventCode": "0xD302",
299+ "EventName": "IXU_LOAD_CANCEL",
300+ "BriefDescription": "A load wakeup to the scheduler has been canceled"
301+ },
302+ {
303+ "PublicDescription": "The scheduler had to cancel one slow Uop due to resource conflict",
304+ "EventCode": "0xD303",
305+ "EventName": "IXU_SLOW_CANCEL",
306+ "BriefDescription": "The scheduler had to cancel one slow Uop due to resource conflict"
307+ },
308+ {
309+ "PublicDescription": "Uops issued by the scheduler on IXA",
310+ "EventCode": "0xD304",
311+ "EventName": "IXU_IXA_ISSUED",
312+ "BriefDescription": "Uops issued by the scheduler on IXA"
313+ },
314+ {
315+ "PublicDescription": "Uops issued by the scheduler on IXA Par 0",
316+ "EventCode": "0xD305",
317+ "EventName": "IXU_IXA_PAR0_ISSUED",
318+ "BriefDescription": "Uops issued by the scheduler on IXA Par 0"
319+ },
320+ {
321+ "PublicDescription": "Uops issued by the scheduler on IXA Par 1",
322+ "EventCode": "0xD306",
323+ "EventName": "IXU_IXA_PAR1_ISSUED",
324+ "BriefDescription": "Uops issued by the scheduler on IXA Par 1"
325+ },
326+ {
327+ "PublicDescription": "Uops issued by the scheduler on IXB",
328+ "EventCode": "0xD307",
329+ "EventName": "IXU_IXB_ISSUED",
330+ "BriefDescription": "Uops issued by the scheduler on IXB"
331+ },
332+ {
333+ "PublicDescription": "Uops issued by the scheduler on IXB Par 0",
334+ "EventCode": "0xD308",
335+ "EventName": "IXU_IXB_PAR0_ISSUED",
336+ "BriefDescription": "Uops issued by the scheduler on IXB Par 0"
337+ },
338+ {
339+ "PublicDescription": "Uops issued by the scheduler on IXB Par 1",
340+ "EventCode": "0xD309",
341+ "EventName": "IXU_IXB_PAR1_ISSUED",
342+ "BriefDescription": "Uops issued by the scheduler on IXB Par 1"
343+ },
344+ {
345+ "PublicDescription": "Uops issued by the scheduler on IXC",
346+ "EventCode": "0xD30A",
347+ "EventName": "IXU_IXC_ISSUED",
348+ "BriefDescription": "Uops issued by the scheduler on IXC"
349+ },
350+ {
351+ "PublicDescription": "Uops issued by the scheduler on IXC Par 0",
352+ "EventCode": "0xD30B",
353+ "EventName": "IXU_IXC_PAR0_ISSUED",
354+ "BriefDescription": "Uops issued by the scheduler on IXC Par 0"
355+ },
356+ {
357+ "PublicDescription": "Uops issued by the scheduler on IXC Par 1",
358+ "EventCode": "0xD30C",
359+ "EventName": "IXU_IXC_PAR1_ISSUED",
360+ "BriefDescription": "Uops issued by the scheduler on IXC Par 1"
361+ },
362+ {
363+ "PublicDescription": "Uops issued by the scheduler on IXD",
364+ "EventCode": "0xD30D",
365+ "EventName": "IXU_IXD_ISSUED",
366+ "BriefDescription": "Uops issued by the scheduler on IXD"
367+ },
368+ {
369+ "PublicDescription": "Uops issued by the scheduler on IXD Par 0",
370+ "EventCode": "0xD30E",
371+ "EventName": "IXU_IXD_PAR0_ISSUED",
372+ "BriefDescription": "Uops issued by the scheduler on IXD Par 0"
373+ },
374+ {
375+ "PublicDescription": "Uops issued by the scheduler on IXD Par 1",
376+ "EventCode": "0xD30F",
377+ "EventName": "IXU_IXD_PAR1_ISSUED",
378+ "BriefDescription": "Uops issued by the scheduler on IXD Par 1"
379+ },
380+ {
381+ "PublicDescription": "Uops issued by the FSU scheduler",
382+ "EventCode": "0xD400",
383+ "EventName": "FSU_ISSUED",
384+ "BriefDescription": "Uops issued by the FSU scheduler"
385+ },
386+ {
387+ "PublicDescription": "Uops issued by the scheduler on FSX",
388+ "EventCode": "0xD401",
389+ "EventName": "FSU_FSX_ISSUED",
390+ "BriefDescription": "Uops issued by the scheduler on FSX"
391+ },
392+ {
393+ "PublicDescription": "Uops issued by the scheduler on FSY",
394+ "EventCode": "0xD402",
395+ "EventName": "FSU_FSY_ISSUED",
396+ "BriefDescription": "Uops issued by the scheduler on FSY"
397+ },
398+ {
399+ "PublicDescription": "Uops issued by the scheduler on FSZ",
400+ "EventCode": "0xD403",
401+ "EventName": "FSU_FSZ_ISSUED",
402+ "BriefDescription": "Uops issued by the scheduler on FSZ"
403+ },
404+ {
405+ "PublicDescription": "Uops canceled (load cancels)",
406+ "EventCode": "0xD404",
407+ "EventName": "FSU_CANCEL",
408+ "BriefDescription": "Uops canceled (load cancels)"
409+ },
410+ {
411+ "PublicDescription": "Count scheduler stalls due to divide/sqrt",
412+ "EventCode": "0xD405",
413+ "EventName": "FSU_DIV_SQRT_STALL",
414+ "BriefDescription": "Count scheduler stalls due to divide/sqrt"
415+ },
416+ {
417+ "PublicDescription": "Number of SWOB drains",
418+ "EventCode": "0xD500",
419+ "EventName": "GPC_SWOB_DRAIN",
420+ "BriefDescription": "Number of SWOB drains"
421+ },
422+ {
423+ "PublicDescription": "GPC detected a Breakpoint instruction match",
424+ "EventCode": "0xD501",
425+ "EventName": "BREAKPOINT_MATCH",
426+ "BriefDescription": "GPC detected a Breakpoint instruction match"
427+ },
428+ {
429+ "PublicDescription": "Core progress monitor triggered",
430+ "EventCode": "0xd502",
431+ "EventName": "GPC_CPM_TRIGGER",
432+ "BriefDescription": "Core progress monitor triggered"
433+ },
434+ {
435+ "PublicDescription": "Fill buffer full",
436+ "EventCode": "0xD601",
437+ "EventName": "OFB_FULL",
438+ "BriefDescription": "Fill buffer full"
439+ },
440+ {
441+ "PublicDescription": "Load satisified from store forwarded data",
442+ "EventCode": "0xD605",
443+ "EventName": "LD_FROM_ST_FWD",
444+ "BriefDescription": "Load satisified from store forwarded data"
445+ },
446+ {
447+ "PublicDescription": "Store retirement pipe stall",
448+ "EventCode": "0xD60C",
449+ "EventName": "LSU_ST_RETIRE_STALL",
450+ "BriefDescription": "Store retirement pipe stall"
451+ },
452+ {
453+ "PublicDescription": "LSU detected a Watchpoint data match",
454+ "EventCode": "0xD60D",
455+ "EventName": "WATCHPOINT_MATCH",
456+ "BriefDescription": "LSU detected a Watchpoint data match"
457+ },
458+ {
459+ "PublicDescription": "Counts cycles that MSC is telling GPC to stall commit due to ETM ISTALL feature",
460+ "EventCode": "0xda00",
461+ "EventName": "MSC_ETM_COMMIT_STALL",
462+ "BriefDescription": "Counts cycles that MSC is telling GPC to stall commit due to ETM ISTALL feature"
463+ }
464+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/exception.json+47−0
@@ -0,0 +1,47 @@
1+[
2+ {
3+ "ArchStdEvent": "EXC_UNDEF"
4+ },
5+ {
6+ "ArchStdEvent": "EXC_SVC"
7+ },
8+ {
9+ "ArchStdEvent": "EXC_PABORT"
10+ },
11+ {
12+ "ArchStdEvent": "EXC_DABORT"
13+ },
14+ {
15+ "ArchStdEvent": "EXC_IRQ"
16+ },
17+ {
18+ "ArchStdEvent": "EXC_FIQ"
19+ },
20+ {
21+ "ArchStdEvent": "EXC_HVC"
22+ },
23+ {
24+ "ArchStdEvent": "EXC_TRAP_PABORT"
25+ },
26+ {
27+ "ArchStdEvent": "EXC_TRAP_DABORT"
28+ },
29+ {
30+ "ArchStdEvent": "EXC_TRAP_OTHER"
31+ },
32+ {
33+ "ArchStdEvent": "EXC_TRAP_IRQ"
34+ },
35+ {
36+ "ArchStdEvent": "EXC_TRAP_FIQ"
37+ },
38+ {
39+ "ArchStdEvent": "EXC_TAKEN"
40+ },
41+ {
42+ "ArchStdEvent": "EXC_RETURN"
43+ },
44+ {
45+ "ArchStdEvent": "EXC_SMC"
46+ }
47+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/instruction.json+128−0
@@ -0,0 +1,128 @@
1+[
2+ {
3+ "ArchStdEvent": "SW_INCR"
4+ },
5+ {
6+ "ArchStdEvent": "ST_RETIRED"
7+ },
8+ {
9+ "ArchStdEvent": "LD_SPEC"
10+ },
11+ {
12+ "ArchStdEvent": "ST_SPEC"
13+ },
14+ {
15+ "ArchStdEvent": "LDST_SPEC"
16+ },
17+ {
18+ "ArchStdEvent": "DP_SPEC"
19+ },
20+ {
21+ "ArchStdEvent": "ASE_SPEC"
22+ },
23+ {
24+ "ArchStdEvent": "VFP_SPEC"
25+ },
26+ {
27+ "ArchStdEvent": "PC_WRITE_SPEC"
28+ },
29+ {
30+ "ArchStdEvent": "BR_IMMED_RETIRED"
31+ },
32+ {
33+ "ArchStdEvent": "BR_RETURN_RETIRED"
34+ },
35+ {
36+ "ArchStdEvent": "CRYPTO_SPEC"
37+ },
38+ {
39+ "ArchStdEvent": "ISB_SPEC"
40+ },
41+ {
42+ "ArchStdEvent": "DSB_SPEC"
43+ },
44+ {
45+ "ArchStdEvent": "DMB_SPEC"
46+ },
47+ {
48+ "ArchStdEvent": "RC_LD_SPEC"
49+ },
50+ {
51+ "ArchStdEvent": "RC_ST_SPEC"
52+ },
53+ {
54+ "ArchStdEvent": "INST_RETIRED"
55+ },
56+ {
57+ "ArchStdEvent": "CID_WRITE_RETIRED"
58+ },
59+ {
60+ "ArchStdEvent": "PC_WRITE_RETIRED"
61+ },
62+ {
63+ "ArchStdEvent": "INST_SPEC"
64+ },
65+ {
66+ "ArchStdEvent": "TTBR_WRITE_RETIRED"
67+ },
68+ {
69+ "ArchStdEvent": "BR_RETIRED"
70+ },
71+ {
72+ "ArchStdEvent": "BR_MIS_PRED_RETIRED"
73+ },
74+ {
75+ "ArchStdEvent": "OP_RETIRED"
76+ },
77+ {
78+ "ArchStdEvent": "OP_SPEC"
79+ },
80+ {
81+ "PublicDescription": "Operation speculatively executed - ASE Scalar",
82+ "EventCode": "0xd210",
83+ "EventName": "ASE_SCALAR_SPEC",
84+ "BriefDescription": "Operation speculatively executed - ASE Scalar"
85+ },
86+ {
87+ "PublicDescription": "Operation speculatively executed - ASE Vector",
88+ "EventCode": "0xd211",
89+ "EventName": "ASE_VECTOR_SPEC",
90+ "BriefDescription": "Operation speculatively executed - ASE Vector"
91+ },
92+ {
93+ "PublicDescription": "Barrier speculatively executed, CSDB",
94+ "EventCode": "0x7f",
95+ "EventName": "CSDB_SPEC",
96+ "BriefDescription": "Barrier speculatively executed, CSDB"
97+ },
98+ {
99+ "PublicDescription": "Prefetch sent to L2.",
100+ "EventCode": "0xd106",
101+ "EventName": "ICF_PREFETCH_DISPATCH",
102+ "BriefDescription": "Prefetch sent to L2."
103+ },
104+ {
105+ "PublicDescription": "Prefetch response received but was dropped since we don't support inflight upgrades.",
106+ "EventCode": "0xd107",
107+ "EventName": "ICF_PREFETCH_DROPPED_NO_UPGRADE",
108+ "BriefDescription": "Prefetch response received but was dropped since we don't support inflight upgrades."
109+ },
110+ {
111+ "PublicDescription": "Prefetch request missed TLB.",
112+ "EventCode": "0xd108",
113+ "EventName": "ICF_PREFETCH_DROPPED_TLB_MISS",
114+ "BriefDescription": "Prefetch request missed TLB."
115+ },
116+ {
117+ "PublicDescription": "Prefetch request dropped since duplicate was found in TLB.",
118+ "EventCode": "0xd109",
119+ "EventName": "ICF_PREFETCH_DROPPED_DUPLICATE",
120+ "BriefDescription": "Prefetch request dropped since duplicate was found in TLB."
121+ },
122+ {
123+ "PublicDescription": "Prefetch request dropped since it was found in cache.",
124+ "EventCode": "0xd10a",
125+ "EventName": "ICF_PREFETCH_DROPPED_CACHE_HIT",
126+ "BriefDescription": "Prefetch request dropped since it was found in cache."
127+ }
128+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/intrinsic.json+14−0
@@ -0,0 +1,14 @@
1+[
2+ {
3+ "ArchStdEvent": "LDREX_SPEC"
4+ },
5+ {
6+ "ArchStdEvent": "STREX_PASS_SPEC"
7+ },
8+ {
9+ "ArchStdEvent": "STREX_FAIL_SPEC"
10+ },
11+ {
12+ "ArchStdEvent": "STREX_SPEC"
13+ }
14+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/memory.json+41−0
@@ -0,0 +1,41 @@
1+[
2+ {
3+ "ArchStdEvent": "LD_RETIRED"
4+ },
5+ {
6+ "ArchStdEvent": "MEM_ACCESS_RD"
7+ },
8+ {
9+ "ArchStdEvent": "MEM_ACCESS_WR"
10+ },
11+ {
12+ "ArchStdEvent": "LD_ALIGN_LAT"
13+ },
14+ {
15+ "ArchStdEvent": "ST_ALIGN_LAT"
16+ },
17+ {
18+ "ArchStdEvent": "MEM_ACCESS"
19+ },
20+ {
21+ "ArchStdEvent": "MEMORY_ERROR"
22+ },
23+ {
24+ "ArchStdEvent": "LDST_ALIGN_LAT"
25+ },
26+ {
27+ "ArchStdEvent": "MEM_ACCESS_CHECKED"
28+ },
29+ {
30+ "ArchStdEvent": "MEM_ACCESS_CHECKED_RD"
31+ },
32+ {
33+ "ArchStdEvent": "MEM_ACCESS_CHECKED_WR"
34+ },
35+ {
36+ "PublicDescription": "Flushes due to memory hazards",
37+ "EventCode": "0x121",
38+ "EventName": "BPU_FLUSH_MEM_FAULT",
39+ "BriefDescription": "Flushes due to memory hazards"
40+ }
41+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/metrics.json+442−0
@@ -0,0 +1,442 @@
1+[
2+ {
3+ "MetricName": "branch_miss_pred_rate",
4+ "MetricExpr": "BR_MIS_PRED / BR_PRED",
5+ "BriefDescription": "Branch predictor misprediction rate. May not count branches that are never resolved because they are in the misprediction shadow of an earlier branch",
6+ "MetricGroup": "branch",
7+ "ScaleUnit": "100%"
8+ },
9+ {
10+ "MetricName": "bus_utilization",
11+ "MetricExpr": "BUS_ACCESS / (BUS_CYCLES * 1)",
12+ "BriefDescription": "Core-to-uncore bus utilization",
13+ "MetricGroup": "Bus",
14+ "ScaleUnit": "100percent of bus cycles"
15+ },
16+ {
17+ "MetricName": "l1d_cache_miss_ratio",
18+ "MetricExpr": "L1D_CACHE_REFILL / L1D_CACHE",
19+ "BriefDescription": "This metric measures the ratio of level 1 data cache accesses missed to the total number of level 1 data cache accesses. This gives an indication of the effectiveness of the level 1 data cache.",
20+ "MetricGroup": "Miss_Ratio;L1D_Cache_Effectiveness",
21+ "ScaleUnit": "1per cache access"
22+ },
23+ {
24+ "MetricName": "l1i_cache_miss_ratio",
25+ "MetricExpr": "L1I_CACHE_REFILL / L1I_CACHE",
26+ "BriefDescription": "This metric measures the ratio of level 1 instruction cache accesses missed to the total number of level 1 instruction cache accesses. This gives an indication of the effectiveness of the level 1 instruction cache.",
27+ "MetricGroup": "Miss_Ratio;L1I_Cache_Effectiveness",
28+ "ScaleUnit": "1per cache access"
29+ },
30+ {
31+ "MetricName": "Miss_Ratio;l1d_cache_read_miss",
32+ "MetricExpr": "L1D_CACHE_LMISS_RD / L1D_CACHE_RD",
33+ "BriefDescription": "L1D cache read miss rate",
34+ "MetricGroup": "Cache",
35+ "ScaleUnit": "1per cache read access"
36+ },
37+ {
38+ "MetricName": "l2_cache_miss_ratio",
39+ "MetricExpr": "L2D_CACHE_REFILL / L2D_CACHE",
40+ "BriefDescription": "This metric measures the ratio of level 2 cache accesses missed to the total number of level 2 cache accesses. This gives an indication of the effectiveness of the level 2 cache, which is a unified cache that stores both data and instruction. Note that cache accesses in this cache are either data memory access or instruction fetch as this is a unified cache.",
41+ "MetricGroup": "Miss_Ratio;L2_Cache_Effectiveness",
42+ "ScaleUnit": "1per cache access"
43+ },
44+ {
45+ "MetricName": "l1i_cache_read_miss_rate",
46+ "MetricExpr": "L1I_CACHE_LMISS / L1I_CACHE",
47+ "BriefDescription": "L1I cache read miss rate",
48+ "MetricGroup": "Cache",
49+ "ScaleUnit": "1per cache access"
50+ },
51+ {
52+ "MetricName": "l2d_cache_read_miss_rate",
53+ "MetricExpr": "L2D_CACHE_LMISS_RD / L2D_CACHE_RD",
54+ "BriefDescription": "L2 cache read miss rate",
55+ "MetricGroup": "Cache",
56+ "ScaleUnit": "1per cache read access"
57+ },
58+ {
59+ "MetricName": "l1d_cache_miss_mpki",
60+ "MetricExpr": "(L1D_CACHE_LMISS_RD * 1e3) / INST_RETIRED",
61+ "BriefDescription": "Misses per thousand instructions (data)",
62+ "MetricGroup": "Cache",
63+ "ScaleUnit": "1MPKI"
64+ },
65+ {
66+ "MetricName": "l1i_cache_miss_mpki",
67+ "MetricExpr": "(L1I_CACHE_LMISS * 1e3) / INST_RETIRED",
68+ "BriefDescription": "Misses per thousand instructions (instruction)",
69+ "MetricGroup": "Cache",
70+ "ScaleUnit": "1MPKI"
71+ },
72+ {
73+ "MetricName": "simd_percentage",
74+ "MetricExpr": "ASE_SPEC / INST_SPEC",
75+ "BriefDescription": "This metric measures advanced SIMD operations as a percentage of total operations speculatively executed.",
76+ "MetricGroup": "Operation_Mix",
77+ "ScaleUnit": "100percent of operations"
78+ },
79+ {
80+ "MetricName": "crypto_percentage",
81+ "MetricExpr": "CRYPTO_SPEC / INST_SPEC",
82+ "BriefDescription": "This metric measures crypto operations as a percentage of operations speculatively executed.",
83+ "MetricGroup": "Operation_Mix",
84+ "ScaleUnit": "100percent of operations"
85+ },
86+ {
87+ "MetricName": "gflops",
88+ "MetricExpr": "VFP_SPEC / (duration_time * 1e9)",
89+ "BriefDescription": "Giga-floating point operations per second",
90+ "MetricGroup": "InstructionMix"
91+ },
92+ {
93+ "MetricName": "integer_dp_percentage",
94+ "MetricExpr": "DP_SPEC / INST_SPEC",
95+ "BriefDescription": "This metric measures scalar integer operations as a percentage of operations speculatively executed.",
96+ "MetricGroup": "Operation_Mix",
97+ "ScaleUnit": "100percent of operations"
98+ },
99+ {
100+ "MetricName": "ipc",
101+ "MetricExpr": "INST_RETIRED / CPU_CYCLES",
102+ "BriefDescription": "This metric measures the number of instructions retired per cycle.",
103+ "MetricGroup": "General",
104+ "ScaleUnit": "1per cycle"
105+ },
106+ {
107+ "MetricName": "load_percentage",
108+ "MetricExpr": "LD_SPEC / INST_SPEC",
109+ "BriefDescription": "This metric measures load operations as a percentage of operations speculatively executed.",
110+ "MetricGroup": "Operation_Mix",
111+ "ScaleUnit": "100percent of operations"
112+ },
113+ {
114+ "MetricName": "load_store_spec_rate",
115+ "MetricExpr": "LDST_SPEC / INST_SPEC",
116+ "BriefDescription": "The rate of load or store instructions speculatively executed to overall instructions speclatively executed",
117+ "MetricGroup": "Operation_Mix",
118+ "ScaleUnit": "100percent of operations"
119+ },
120+ {
121+ "MetricName": "retired_mips",
122+ "MetricExpr": "INST_RETIRED / (duration_time * 1e6)",
123+ "BriefDescription": "Millions of instructions per second",
124+ "MetricGroup": "InstructionMix"
125+ },
126+ {
127+ "MetricName": "spec_utilization_mips",
128+ "MetricExpr": "INST_SPEC / (duration_time * 1e6)",
129+ "BriefDescription": "Millions of instructions per second",
130+ "MetricGroup": "PEutilization"
131+ },
132+ {
133+ "MetricName": "pc_write_spec_rate",
134+ "MetricExpr": "PC_WRITE_SPEC / INST_SPEC",
135+ "BriefDescription": "The rate of software change of the PC speculatively executed to overall instructions speclatively executed",
136+ "MetricGroup": "Operation_Mix",
137+ "ScaleUnit": "100percent of operations"
138+ },
139+ {
140+ "MetricName": "store_percentage",
141+ "MetricExpr": "ST_SPEC / INST_SPEC",
142+ "BriefDescription": "This metric measures store operations as a percentage of operations speculatively executed.",
143+ "MetricGroup": "Operation_Mix",
144+ "ScaleUnit": "100percent of operations"
145+ },
146+ {
147+ "MetricName": "scalar_fp_percentage",
148+ "MetricExpr": "VFP_SPEC / INST_SPEC",
149+ "BriefDescription": "This metric measures scalar floating point operations as a percentage of operations speculatively executed.",
150+ "MetricGroup": "Operation_Mix",
151+ "ScaleUnit": "100percent of operations"
152+ },
153+ {
154+ "MetricName": "retired_rate",
155+ "MetricExpr": "OP_RETIRED / OP_SPEC",
156+ "BriefDescription": "Of all the micro-operations issued, what percentage are retired(committed)",
157+ "MetricGroup": "General",
158+ "ScaleUnit": "100%"
159+ },
160+ {
161+ "MetricName": "wasted",
162+ "MetricExpr": "1 - (OP_RETIRED / (CPU_CYCLES * #slots))",
163+ "BriefDescription": "Of all the micro-operations issued, what proportion are lost",
164+ "MetricGroup": "General",
165+ "ScaleUnit": "100%"
166+ },
167+ {
168+ "MetricName": "wasted_rate",
169+ "MetricExpr": "1 - OP_RETIRED / OP_SPEC",
170+ "BriefDescription": "Of all the micro-operations issued, what percentage are not retired(committed)",
171+ "MetricGroup": "General",
172+ "ScaleUnit": "100%"
173+ },
174+ {
175+ "MetricName": "stall_backend_cache_rate",
176+ "MetricExpr": "STALL_BACKEND_CACHE / CPU_CYCLES",
177+ "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and cache miss",
178+ "MetricGroup": "Stall",
179+ "ScaleUnit": "100percent of cycles"
180+ },
181+ {
182+ "MetricName": "stall_backend_resource_rate",
183+ "MetricExpr": "STALL_BACKEND_RESOURCE / CPU_CYCLES",
184+ "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and resource full",
185+ "MetricGroup": "Stall",
186+ "ScaleUnit": "100percent of cycles"
187+ },
188+ {
189+ "MetricName": "stall_backend_tlb_rate",
190+ "MetricExpr": "STALL_BACKEND_TLB / CPU_CYCLES",
191+ "BriefDescription": "Proportion of cycles stalled and no operations issued to backend and TLB miss",
192+ "MetricGroup": "Stall",
193+ "ScaleUnit": "100percent of cycles"
194+ },
195+ {
196+ "MetricName": "stall_frontend_cache_rate",
197+ "MetricExpr": "STALL_FRONTEND_CACHE / CPU_CYCLES",
198+ "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and cache miss",
199+ "MetricGroup": "Stall",
200+ "ScaleUnit": "100percent of cycles"
201+ },
202+ {
203+ "MetricName": "stall_frontend_tlb_rate",
204+ "MetricExpr": "STALL_FRONTEND_TLB / CPU_CYCLES",
205+ "BriefDescription": "Proportion of cycles stalled and no ops delivered from frontend and TLB miss",
206+ "MetricGroup": "Stall",
207+ "ScaleUnit": "100percent of cycles"
208+ },
209+ {
210+ "MetricName": "dtlb_walk_ratio",
211+ "MetricExpr": "DTLB_WALK / L1D_TLB",
212+ "BriefDescription": "This metric measures the ratio of data TLB Walks to the total number of data TLB accesses. This gives an indication of the effectiveness of the data TLB accesses.",
213+ "MetricGroup": "Miss_Ratio;DTLB_Effectiveness",
214+ "ScaleUnit": "1per TLB access"
215+ },
216+ {
217+ "MetricName": "itlb_walk_ratio",
218+ "MetricExpr": "ITLB_WALK / L1I_TLB",
219+ "BriefDescription": "This metric measures the ratio of instruction TLB Walks to the total number of instruction TLB accesses. This gives an indication of the effectiveness of the instruction TLB accesses.",
220+ "MetricGroup": "Miss_Ratio;ITLB_Effectiveness",
221+ "ScaleUnit": "1per TLB access"
222+ },
223+ {
224+ "ArchStdEvent": "backend_bound"
225+ },
226+ {
227+ "ArchStdEvent": "frontend_bound",
228+ "MetricExpr": "100 - (retired_fraction + slots_lost_misspeculation_fraction + backend_bound)"
229+ },
230+ {
231+ "MetricName": "slots_lost_misspeculation_fraction",
232+ "MetricExpr": "(OP_SPEC - OP_RETIRED) / (CPU_CYCLES * #slots)",
233+ "BriefDescription": "Fraction of slots lost due to misspeculation",
234+ "DefaultMetricgroupName": "TopdownL1",
235+ "MetricGroup": "Default;TopdownL1",
236+ "ScaleUnit": "100percent of slots"
237+ },
238+ {
239+ "MetricName": "retired_fraction",
240+ "MetricExpr": "OP_RETIRED / (CPU_CYCLES * #slots)",
241+ "BriefDescription": "Fraction of slots retiring, useful work",
242+ "DefaultMetricgroupName": "TopdownL1",
243+ "MetricGroup": "Default;TopdownL1",
244+ "ScaleUnit": "100percent of slots"
245+ },
246+ {
247+ "MetricName": "backend_core",
248+ "MetricExpr": "(backend_bound / 100) - backend_memory",
249+ "BriefDescription": "Fraction of slots the CPU was stalled due to backend non-memory subsystem issues",
250+ "MetricGroup": "TopdownL2",
251+ "ScaleUnit": "100%"
252+ },
253+ {
254+ "MetricName": "backend_memory",
255+ "MetricExpr": "(STALL_BACKEND_TLB + STALL_BACKEND_CACHE) / CPU_CYCLES",
256+ "BriefDescription": "Fraction of slots the CPU was stalled due to backend memory subsystem issues (cache/tlb miss)",
257+ "MetricGroup": "TopdownL2",
258+ "ScaleUnit": "100%"
259+ },
260+ {
261+ "MetricName": "branch_mispredict",
262+ "MetricExpr": "(BR_MIS_PRED_RETIRED / GPC_FLUSH) * slots_lost_misspeculation_fraction",
263+ "BriefDescription": "Fraction of slots lost due to branch misprediciton",
264+ "MetricGroup": "TopdownL2",
265+ "ScaleUnit": "1percent of slots"
266+ },
267+ {
268+ "MetricName": "frontend_bandwidth",
269+ "MetricExpr": "frontend_bound - frontend_latency",
270+ "BriefDescription": "Fraction of slots the CPU did not dispatch at full bandwidth - able to dispatch partial slots only (1, 2, or 3 uops)",
271+ "MetricGroup": "TopdownL2",
272+ "ScaleUnit": "1percent of slots"
273+ },
274+ {
275+ "MetricName": "frontend_latency",
276+ "MetricExpr": "(STALL_FRONTEND - ((STALL_SLOT_FRONTEND - ((frontend_bound / 100) * CPU_CYCLES * #slots)) / #slots)) / CPU_CYCLES",
277+ "BriefDescription": "Fraction of slots the CPU was stalled due to frontend latency issues (cache/tlb miss); nothing to dispatch",
278+ "MetricGroup": "TopdownL2",
279+ "ScaleUnit": "100percent of slots"
280+ },
281+ {
282+ "MetricName": "other_miss_pred",
283+ "MetricExpr": "slots_lost_misspeculation_fraction - branch_mispredict",
284+ "BriefDescription": "Fraction of slots lost due to other/non-branch misprediction misspeculation",
285+ "MetricGroup": "TopdownL2",
286+ "ScaleUnit": "1percent of slots"
287+ },
288+ {
289+ "MetricName": "pipe_utilization",
290+ "MetricExpr": "100 * ((IXU_NUM_UOPS_ISSUED + FSU_ISSUED) / (CPU_CYCLES * 6))",
291+ "BriefDescription": "Fraction of execute slots utilized",
292+ "MetricGroup": "TopdownL2",
293+ "ScaleUnit": "1percent of slots"
294+ },
295+ {
296+ "MetricName": "d_cache_l2_miss_rate",
297+ "MetricExpr": "STALL_BACKEND_MEM / CPU_CYCLES",
298+ "BriefDescription": "Fraction of cycles the CPU was stalled due to data L2 cache miss",
299+ "MetricGroup": "TopdownL3",
300+ "ScaleUnit": "100percent of cycles"
301+ },
302+ {
303+ "MetricName": "d_cache_miss_rate",
304+ "MetricExpr": "STALL_BACKEND_CACHE / CPU_CYCLES",
305+ "BriefDescription": "Fraction of cycles the CPU was stalled due to data cache miss",
306+ "MetricGroup": "TopdownL3",
307+ "ScaleUnit": "100percent of cycles"
308+ },
309+ {
310+ "MetricName": "d_tlb_miss_rate",
311+ "MetricExpr": "STALL_BACKEND_TLB / CPU_CYCLES",
312+ "BriefDescription": "Fraction of cycles the CPU was stalled due to data TLB miss",
313+ "MetricGroup": "TopdownL3",
314+ "ScaleUnit": "100percent of cycles"
315+ },
316+ {
317+ "MetricName": "fsu_pipe_utilization",
318+ "MetricExpr": "FSU_ISSUED / (CPU_CYCLES * 2)",
319+ "BriefDescription": "Fraction of FSU execute slots utilized",
320+ "MetricGroup": "TopdownL3",
321+ "ScaleUnit": "100percent of slots"
322+ },
323+ {
324+ "MetricName": "i_cache_miss_rate",
325+ "MetricExpr": "STALL_FRONTEND_CACHE / CPU_CYCLES",
326+ "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction cache miss",
327+ "MetricGroup": "TopdownL3",
328+ "ScaleUnit": "100percent of slots"
329+ },
330+ {
331+ "MetricName": "i_tlb_miss_rate",
332+ "MetricExpr": "STALL_FRONTEND_TLB / CPU_CYCLES",
333+ "BriefDescription": "Fraction of cycles the CPU was stalled due to instruction TLB miss",
334+ "MetricGroup": "TopdownL3",
335+ "ScaleUnit": "100percent of slots"
336+ },
337+ {
338+ "MetricName": "ixu_pipe_utilization",
339+ "MetricExpr": "IXU_NUM_UOPS_ISSUED / (CPU_CYCLES * #slots)",
340+ "BriefDescription": "Fraction of IXU execute slots utilized",
341+ "MetricGroup": "TopdownL3",
342+ "ScaleUnit": "100percent of slots"
343+ },
344+ {
345+ "MetricName": "stall_recovery_rate",
346+ "MetricExpr": "IDR_STALL_FLUSH / CPU_CYCLES",
347+ "BriefDescription": "Fraction of cycles the CPU was stalled due to flush recovery",
348+ "MetricGroup": "TopdownL3",
349+ "ScaleUnit": "100percent of slots"
350+ },
351+ {
352+ "MetricName": "stall_fsu_sched_rate",
353+ "MetricExpr": "IDR_STALL_FSU_SCHED / CPU_CYCLES",
354+ "BriefDescription": "Fraction of cycles the CPU was stalled and FSU was full",
355+ "MetricGroup": "TopdownL4",
356+ "ScaleUnit": "100percent of cycles"
357+ },
358+ {
359+ "MetricName": "stall_ixu_sched_rate",
360+ "MetricExpr": "IDR_STALL_IXU_SCHED / CPU_CYCLES",
361+ "BriefDescription": "Fraction of cycles the CPU was stalled and IXU was full",
362+ "MetricGroup": "TopdownL4",
363+ "ScaleUnit": "100percent of cycles"
364+ },
365+ {
366+ "MetricName": "stall_lob_id_rate",
367+ "MetricExpr": "IDR_STALL_LOB_ID / CPU_CYCLES",
368+ "BriefDescription": "Fraction of cycles the CPU was stalled and LOB was full",
369+ "MetricGroup": "TopdownL4",
370+ "ScaleUnit": "100percent of cycles"
371+ },
372+ {
373+ "MetricName": "stall_rob_id_rate",
374+ "MetricExpr": "IDR_STALL_ROB_ID / CPU_CYCLES",
375+ "BriefDescription": "Fraction of cycles the CPU was stalled and ROB was full",
376+ "MetricGroup": "TopdownL4",
377+ "ScaleUnit": "100percent of cycles"
378+ },
379+ {
380+ "MetricName": "stall_sob_id_rate",
381+ "MetricExpr": "IDR_STALL_SOB_ID / CPU_CYCLES",
382+ "BriefDescription": "Fraction of cycles the CPU was stalled and SOB was full",
383+ "MetricGroup": "TopdownL4",
384+ "ScaleUnit": "100percent of cycles"
385+ },
386+ {
387+ "MetricName": "l1d_cache_access_demand",
388+ "MetricExpr": "L1D_CACHE_RW / L1D_CACHE",
389+ "BriefDescription": "L1D cache access - demand",
390+ "MetricGroup": "Cache",
391+ "ScaleUnit": "100percent of cache acceses"
392+ },
393+ {
394+ "MetricName": "l1d_cache_access_prefetces",
395+ "MetricExpr": "L1D_CACHE_PRFM / L1D_CACHE",
396+ "BriefDescription": "L1D cache access - prefetch",
397+ "MetricGroup": "Cache",
398+ "ScaleUnit": "100percent of cache acceses"
399+ },
400+ {
401+ "MetricName": "l1d_cache_demand_misses",
402+ "MetricExpr": "L1D_CACHE_REFILL_RW / L1D_CACHE",
403+ "BriefDescription": "L1D cache demand misses",
404+ "MetricGroup": "Cache",
405+ "ScaleUnit": "100percent of cache acceses"
406+ },
407+ {
408+ "MetricName": "l1d_cache_demand_misses_read",
409+ "MetricExpr": "L1D_CACHE_REFILL_RD / L1D_CACHE",
410+ "BriefDescription": "L1D cache demand misses - read",
411+ "MetricGroup": "Cache",
412+ "ScaleUnit": "100percent of cache acceses"
413+ },
414+ {
415+ "MetricName": "l1d_cache_demand_misses_write",
416+ "MetricExpr": "L1D_CACHE_REFILL_WR / L1D_CACHE",
417+ "BriefDescription": "L1D cache demand misses - write",
418+ "MetricGroup": "Cache",
419+ "ScaleUnit": "100percent of cache acceses"
420+ },
421+ {
422+ "MetricName": "l1d_cache_prefetch_misses",
423+ "MetricExpr": "L1D_CACHE_REFILL_PRFM / L1D_CACHE",
424+ "BriefDescription": "L1D cache prefetch misses",
425+ "MetricGroup": "Cache",
426+ "ScaleUnit": "100percent of cache acceses"
427+ },
428+ {
429+ "MetricName": "ase_scalar_mix",
430+ "MetricExpr": "ASE_SCALAR_SPEC / OP_SPEC",
431+ "BriefDescription": "Proportion of advanced SIMD data processing operations (excluding DP_SPEC/LD_SPEC) scalar operations",
432+ "MetricGroup": "Instructions",
433+ "ScaleUnit": "100percent of cache acceses"
434+ },
435+ {
436+ "MetricName": "ase_vector_mix",
437+ "MetricExpr": "ASE_VECTOR_SPEC / OP_SPEC",
438+ "BriefDescription": "Proportion of advanced SIMD data processing operations (excluding DP_SPEC/LD_SPEC) vector operations",
439+ "MetricGroup": "Instructions",
440+ "ScaleUnit": "100percent of cache acceses"
441+ }
442+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/mmu.json+170−0
@@ -0,0 +1,170 @@
1+[
2+ {
3+ "PublicDescription": "Level 2 data translation buffer allocation",
4+ "EventCode": "0xD800",
5+ "EventName": "MMU_D_OTB_ALLOC",
6+ "BriefDescription": "Level 2 data translation buffer allocation"
7+ },
8+ {
9+ "PublicDescription": "Data TLB translation cache hit on S1L2 walk cache entry",
10+ "EventCode": "0xd801",
11+ "EventName": "MMU_D_TRANS_CACHE_HIT_S1L2_WALK",
12+ "BriefDescription": "Data TLB translation cache hit on S1L2 walk cache entry"
13+ },
14+ {
15+ "PublicDescription": "Data TLB translation cache hit on S1L1 walk cache entry",
16+ "EventCode": "0xd802",
17+ "EventName": "MMU_D_TRANS_CACHE_HIT_S1L1_WALK",
18+ "BriefDescription": "Data TLB translation cache hit on S1L1 walk cache entry"
19+ },
20+ {
21+ "PublicDescription": "Data TLB translation cache hit on S1L0 walk cache entry",
22+ "EventCode": "0xd803",
23+ "EventName": "MMU_D_TRANS_CACHE_HIT_S1L0_WALK",
24+ "BriefDescription": "Data TLB translation cache hit on S1L0 walk cache entry"
25+ },
26+ {
27+ "PublicDescription": "Data TLB translation cache hit on S2L2 walk cache entry",
28+ "EventCode": "0xd804",
29+ "EventName": "MMU_D_TRANS_CACHE_HIT_S2L2_WALK",
30+ "BriefDescription": "Data TLB translation cache hit on S2L2 walk cache entry"
31+ },
32+ {
33+ "PublicDescrition": "Data TLB translation cache hit on S2L1 walk cache entry",
34+ "EventCode": "0xd805",
35+ "EventName": "MMU_D_TRANS_CACHE_HIT_S2L1_WALK",
36+ "BriefDescription": "Data TLB translation cache hit on S2L1 walk cache entry"
37+ },
38+ {
39+ "PublicDescrition": "Data TLB translation cache hit on S2L0 walk cache entry",
40+ "EventCode": "0xd806",
41+ "EventName": "MMU_D_TRANS_CACHE_HIT_S2L0_WALK",
42+ "BriefDescription": "Data TLB translation cache hit on S2L0 walk cache entry"
43+ },
44+ {
45+ "PublicDescrition": "Data-side S1 page walk cache lookup",
46+ "EventCode": "0xd807",
47+ "EventName": "MMU_D_S1_WALK_CACHE_LOOKUP",
48+ "BriefDescription": "Data-side S1 page walk cache lookup"
49+ },
50+ {
51+ "PublicDescrition": "Data-side S1 page walk cache refill",
52+ "EventCode": "0xd808",
53+ "EventName": "MMU_D_S1_WALK_CACHE_REFILL",
54+ "BriefDescription": "Data-side S1 page walk cache refill"
55+ },
56+ {
57+ "PublicDescrition": "Data-side S2 page walk cache lookup",
58+ "EventCode": "0xd809",
59+ "EventName": "MMU_D_S2_WALK_CACHE_LOOKUP",
60+ "BriefDescription": "Data-side S2 page walk cache lookup"
61+ },
62+ {
63+ "PublicDescrition": "Data-side S2 page walk cache refill",
64+ "EventCode": "0xd80a",
65+ "EventName": "MMU_D_S2_WALK_CACHE_REFILL",
66+ "BriefDescription": "Data-side S2 page walk cache refill"
67+ },
68+ {
69+ "PublicDescription": "Data-side S1 table walk fault",
70+ "EventCode": "0xD80B",
71+ "EventName": "MMU_D_S1_WALK_FAULT",
72+ "BriefDescription": "Data-side S1 table walk fault"
73+ },
74+ {
75+ "PublicDescription": "Data-side S2 table walk fault",
76+ "EventCode": "0xD80C",
77+ "EventName": "MMU_D_S2_WALK_FAULT",
78+ "BriefDescription": "Data-side S2 table walk fault"
79+ },
80+ {
81+ "PublicDescription": "Data-side table walk steps or descriptor fetches",
82+ "EventCode": "0xD80D",
83+ "EventName": "MMU_D_WALK_STEPS",
84+ "BriefDescription": "Data-side table walk steps or descriptor fetches"
85+ },
86+ {
87+ "PublicDescription": "Level 2 instruction translation buffer allocation",
88+ "EventCode": "0xD900",
89+ "EventName": "MMU_I_OTB_ALLOC",
90+ "BriefDescription": "Level 2 instruction translation buffer allocation"
91+ },
92+ {
93+ "PublicDescrition": "Instruction TLB translation cache hit on S1L2 walk cache entry",
94+ "EventCode": "0xd901",
95+ "EventName": "MMU_I_TRANS_CACHE_HIT_S1L2_WALK",
96+ "BriefDescription": "Instruction TLB translation cache hit on S1L2 walk cache entry"
97+ },
98+ {
99+ "PublicDescrition": "Instruction TLB translation cache hit on S1L1 walk cache entry",
100+ "EventCode": "0xd902",
101+ "EventName": "MMU_I_TRANS_CACHE_HIT_S1L1_WALK",
102+ "BriefDescription": "Instruction TLB translation cache hit on S1L1 walk cache entry"
103+ },
104+ {
105+ "PublicDescrition": "Instruction TLB translation cache hit on S1L0 walk cache entry",
106+ "EventCode": "0xd903",
107+ "EventName": "MMU_I_TRANS_CACHE_HIT_S1L0_WALK",
108+ "BriefDescription": "Instruction TLB translation cache hit on S1L0 walk cache entry"
109+ },
110+ {
111+ "PublicDescrition": "Instruction TLB translation cache hit on S2L2 walk cache entry",
112+ "EventCode": "0xd904",
113+ "EventName": "MMU_I_TRANS_CACHE_HIT_S2L2_WALK",
114+ "BriefDescription": "Instruction TLB translation cache hit on S2L2 walk cache entry"
115+ },
116+ {
117+ "PublicDescrition": "Instruction TLB translation cache hit on S2L1 walk cache entry",
118+ "EventCode": "0xd905",
119+ "EventName": "MMU_I_TRANS_CACHE_HIT_S2L1_WALK",
120+ "BriefDescription": "Instruction TLB translation cache hit on S2L1 walk cache entry"
121+ },
122+ {
123+ "PublicDescrition": "Instruction TLB translation cache hit on S2L0 walk cache entry",
124+ "EventCode": "0xd906",
125+ "EventName": "MMU_I_TRANS_CACHE_HIT_S2L0_WALK",
126+ "BriefDescription": "Instruction TLB translation cache hit on S2L0 walk cache entry"
127+ },
128+ {
129+ "PublicDescrition": "Instruction-side S1 page walk cache lookup",
130+ "EventCode": "0xd907",
131+ "EventName": "MMU_I_S1_WALK_CACHE_LOOKUP",
132+ "BriefDescription": "Instruction-side S1 page walk cache lookup"
133+ },
134+ {
135+ "PublicDescrition": "Instruction-side S1 page walk cache refill",
136+ "EventCode": "0xd908",
137+ "EventName": "MMU_I_S1_WALK_CACHE_REFILL",
138+ "BriefDescription": "Instruction-side S1 page walk cache refill"
139+ },
140+ {
141+ "PublicDescrition": "Instruction-side S2 page walk cache lookup",
142+ "EventCode": "0xd909",
143+ "EventName": "MMU_I_S2_WALK_CACHE_LOOKUP",
144+ "BriefDescription": "Instruction-side S2 page walk cache lookup"
145+ },
146+ {
147+ "PublicDescrition": "Instruction-side S2 page walk cache refill",
148+ "EventCode": "0xd90a",
149+ "EventName": "MMU_I_S2_WALK_CACHE_REFILL",
150+ "BriefDescription": "Instruction-side S2 page walk cache refill"
151+ },
152+ {
153+ "PublicDescription": "Instruction-side S1 table walk fault",
154+ "EventCode": "0xD90B",
155+ "EventName": "MMU_I_S1_WALK_FAULT",
156+ "BriefDescription": "Instruction-side S1 table walk fault"
157+ },
158+ {
159+ "PublicDescription": "Instruction-side S2 table walk fault",
160+ "EventCode": "0xD90C",
161+ "EventName": "MMU_I_S2_WALK_FAULT",
162+ "BriefDescription": "Instruction-side S2 table walk fault"
163+ },
164+ {
165+ "PublicDescription": "Instruction-side table walk steps or descriptor fetches",
166+ "EventCode": "0xD90D",
167+ "EventName": "MMU_I_WALK_STEPS",
168+ "BriefDescription": "Instruction-side table walk steps or descriptor fetches"
169+ }
170+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/pipeline.json+41−0
@@ -0,0 +1,41 @@
1+[
2+ {
3+ "ArchStdEvent": "STALL_FRONTEND",
4+ "Errata": "Errata AC03_CPU_29",
5+ "BriefDescription": "Impacted by errata, use metrics instead -"
6+ },
7+ {
8+ "ArchStdEvent": "STALL_BACKEND"
9+ },
10+ {
11+ "ArchStdEvent": "STALL",
12+ "Errata": "Errata AC03_CPU_29",
13+ "BriefDescription": "Impacted by errata, use metrics instead -"
14+ },
15+ {
16+ "ArchStdEvent": "STALL_SLOT_BACKEND"
17+ },
18+ {
19+ "ArchStdEvent": "STALL_SLOT_FRONTEND",
20+ "Errata": "Errata AC03_CPU_29",
21+ "BriefDescription": "Impacted by errata, use metrics instead -"
22+ },
23+ {
24+ "ArchStdEvent": "STALL_SLOT"
25+ },
26+ {
27+ "ArchStdEvent": "STALL_BACKEND_MEM"
28+ },
29+ {
30+ "PublicDescription": "Frontend stall cycles, TLB",
31+ "EventCode": "0x815c",
32+ "EventName": "STALL_FRONTEND_TLB",
33+ "BriefDescription": "Frontend stall cycles, TLB"
34+ },
35+ {
36+ "PublicDescription": "Backend stall cycles, TLB",
37+ "EventCode": "0x8167",
38+ "EventName": "STALL_BACKEND_TLB",
39+ "BriefDescription": "Backend stall cycles, TLB"
40+ }
41+]
tools/perf/pmu-events/arch/arm64/ampere/ampereonex/spe.json+14−0
@@ -0,0 +1,14 @@
1+[
2+ {
3+ "ArchStdEvent": "SAMPLE_POP"
4+ },
5+ {
6+ "ArchStdEvent": "SAMPLE_FEED"
7+ },
8+ {
9+ "ArchStdEvent": "SAMPLE_FILTRATE"
10+ },
11+ {
12+ "ArchStdEvent": "SAMPLE_COLLISION"
13+ }
14+]
tools/perf/pmu-events/arch/arm64/arm/cmn/sys/cmn.json+1−1
@@ -107,7 +107,7 @@ · 106 unmodified lines
107107 "EventName": "hnf_qos_hh_retry",
108108 "EventidCode": "0xe",
109109 "NodeType": "0x5",
110− "BriefDescription": "Counts number of times a HighHigh priority request is protocolretried at the HN‑F.",
110+ "BriefDescription": "Counts number of times a HighHigh priority request is protocolretried at the HN-F.",
111111 "Unit": "arm_cmn",
112112 "Compat": "(434|436|43c|43a).*"
113113 },
tools/perf/pmu-events/arch/arm64/mapfile.csv+1−0
@@ -42,3 +42,4 @@ · 41 unmodified lines
4242 0x00000000480fd010,v1,hisilicon/hip08,core
4343 0x00000000500f0000,v1,ampere/emag,core
4444 0x00000000c00fac30,v1,ampere/ampereone,core
45+0x00000000c00fac40,v1,ampere/ampereonex,core
tools/perf/pmu-events/arch/powerpc/mapfile.csv+1−2
@@ -11,8 +11,7 @@ · 10 unmodified lines
1111 #
1212 # Multiple PVRs could map to a single JSON file.
1313 #
14−
15−# Power8 entries
1614 0x004[bcd][[:xdigit:]]{4},1,power8,core
15+0x0066[[:xdigit:]]{4},1,power8,core
1716 0x004e[[:xdigit:]]{4},1,power9,core
1817 0x0080[[:xdigit:]]{4},1,power10,core
tools/perf/pmu-events/arch/powerpc/power10/datasource.json+14−4
@@ -99,6 +99,11 @@ · 98 unmodified lines
9999 "EventName": "PM_INST_FROM_L2MISS",
100100 "BriefDescription": "The processor's instruction cache was reloaded from a source beyond the local core's L2 due to a demand miss."
101101 },
102+ {
103+ "EventCode": "0x0003C0000000C040",
104+ "EventName": "PM_DATA_FROM_L2MISS_DSRC",
105+ "BriefDescription": "The processor's L1 data cache was reloaded from a source beyond the local core's L2 due to a demand miss."
106+ },
102107 {
103108 "EventCode": "0x000380000010C040",
104109 "EventName": "PM_INST_FROM_L2MISS_ALL",
@@ -161,9 +166,14 @@ · 56 unmodified lines
161166 },
162167 {
163168 "EventCode": "0x000780000000C040",
164− "EventName": "PM_INST_FROM_L3MISS",
169+ "EventName": "PM_INST_FROM_L3MISS_DSRC",
165170 "BriefDescription": "The processor's instruction cache was reloaded from beyond the local core's L3 due to a demand miss."
166171 },
172+ {
173+ "EventCode": "0x0007C0000000C040",
174+ "EventName": "PM_DATA_FROM_L3MISS_DSRC",
175+ "BriefDescription": "The processor's L1 data cache was reloaded from beyond the local core's L3 due to a demand miss."
176+ },
167177 {
168178 "EventCode": "0x000780000010C040",
169179 "EventName": "PM_INST_FROM_L3MISS_ALL",
@@ -981,7 +991,7 @@ · 811 unmodified lines
981991 },
982992 {
983993 "EventCode": "0x0003C0000000C142",
984− "EventName": "PM_MRK_DATA_FROM_L2MISS",
994+ "EventName": "PM_MRK_DATA_FROM_L2MISS_DSRC",
985995 "BriefDescription": "The processor's L1 data cache was reloaded from a source beyond the local core's L2 due to a demand miss for a marked instruction."
986996 },
987997 {
@@ -1046,12 +1056,12 @@ · 58 unmodified lines
10461056 },
10471057 {
10481058 "EventCode": "0x000780000000C142",
1049− "EventName": "PM_MRK_INST_FROM_L3MISS",
1059+ "EventName": "PM_MRK_INST_FROM_L3MISS_DSRC",
10501060 "BriefDescription": "The processor's instruction cache was reloaded from beyond the local core's L3 due to a demand miss for a marked instruction."
10511061 },
10521062 {
10531063 "EventCode": "0x0007C0000000C142",
1054− "EventName": "PM_MRK_DATA_FROM_L3MISS",
1064+ "EventName": "PM_MRK_DATA_FROM_L3MISS_DSRC",
10551065 "BriefDescription": "The processor's L1 data cache was reloaded from beyond the local core's L3 due to a demand miss for a marked instruction."
10561066 },
10571067 {
tools/perf/pmu-events/arch/riscv/mapfile.csv+2−0
@@ -15,3 +15,5 @@ · 14 unmodified lines
1515 #
1616 #MVENDORID-MARCHID-MIMPID,Version,Filename,EventType
1717 0x489-0x8000000000000007-0x[[:xdigit:]]+,v1,sifive/u74,core
18+0x5b7-0x0-0x0,v1,thead/c900-legacy,core
19+0x67e-0x80000000db0000[89]0-0x[[:xdigit:]]+,v1,starfive/dubhe-80,core
tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/common.json+172−0
@@ -0,0 +1,172 @@
1+[
2+ {
3+ "EventName": "ACCESS_MMU_STLB",
4+ "EventCode": "0x1",
5+ "BriefDescription": "access MMU STLB"
6+ },
7+ {
8+ "EventName": "MISS_MMU_STLB",
9+ "EventCode": "0x2",
10+ "BriefDescription": "miss MMU STLB"
11+ },
12+ {
13+ "EventName": "ACCESS_MMU_PTE_C",
14+ "EventCode": "0x3",
15+ "BriefDescription": "access MMU PTE-Cache"
16+ },
17+ {
18+ "EventName": "MISS_MMU_PTE_C",
19+ "EventCode": "0x4",
20+ "BriefDescription": "miss MMU PTE-Cache"
21+ },
22+ {
23+ "EventName": "ROB_FLUSH",
24+ "EventCode": "0x5",
25+ "BriefDescription": "ROB flush (all kinds of exceptions)"
26+ },
27+ {
28+ "EventName": "BTB_PREDICTION_MISS",
29+ "EventCode": "0x6",
30+ "BriefDescription": "BTB prediction miss"
31+ },
32+ {
33+ "EventName": "ITLB_MISS",
34+ "EventCode": "0x7",
35+ "BriefDescription": "ITLB miss"
36+ },
37+ {
38+ "EventName": "SYNC_DEL_FETCH_G",
39+ "EventCode": "0x8",
40+ "BriefDescription": "SYNC delivery a fetch-group"
41+ },
42+ {
43+ "EventName": "ICACHE_MISS",
44+ "EventCode": "0x9",
45+ "BriefDescription": "ICache miss"
46+ },
47+ {
48+ "EventName": "BPU_BR_RETIRE",
49+ "EventCode": "0xA",
50+ "BriefDescription": "condition branch instruction retire"
51+ },
52+ {
53+ "EventName": "BPU_BR_MISS",
54+ "EventCode": "0xB",
55+ "BriefDescription": "condition branch instruction miss"
56+ },
57+ {
58+ "EventName": "RET_INS_RETIRE",
59+ "EventCode": "0xC",
60+ "BriefDescription": "return instruction retire"
61+ },
62+ {
63+ "EventName": "RET_INS_MISS",
64+ "EventCode": "0xD",
65+ "BriefDescription": "return instruction miss"
66+ },
67+ {
68+ "EventName": "INDIRECT_JR_MISS",
69+ "EventCode": "0xE",
70+ "BriefDescription": "indirect JR instruction miss (inlcude without target)"
71+ },
72+ {
73+ "EventName": "IBUF_VAL_ID_NORDY",
74+ "EventCode": "0xF",
75+ "BriefDescription": "IBUF valid while ID not ready"
76+ },
77+ {
78+ "EventName": "IBUF_NOVAL_ID_RDY",
79+ "EventCode": "0x10",
80+ "BriefDescription": "IBUF not valid while ID ready"
81+ },
82+ {
83+ "EventName": "REN_INT_PHY_REG_NORDY",
84+ "EventCode": "0x11",
85+ "BriefDescription": "REN integer physical register file is not ready"
86+ },
87+ {
88+ "EventName": "REN_FP_PHY_REG_NORDY",
89+ "EventCode": "0x12",
90+ "BriefDescription": "REN floating point physical register file is not ready"
91+ },
92+ {
93+ "EventName": "REN_CP_NORDY",
94+ "EventCode": "0x13",
95+ "BriefDescription": "REN checkpoint is not ready"
96+ },
97+ {
98+ "EventName": "DEC_VAL_ROB_NORDY",
99+ "EventCode": "0x14",
100+ "BriefDescription": "DEC is valid and ROB is not ready"
101+ },
102+ {
103+ "EventName": "OOD_FLUSH_LS_DEP",
104+ "EventCode": "0x15",
105+ "BriefDescription": "out of order flush due to load/store dependency"
106+ },
107+ {
108+ "EventName": "BRU_RET_IJR_INS",
109+ "EventCode": "0x16",
110+ "BriefDescription": "BRU retire an IJR instruction"
111+ },
112+ {
113+ "EventName": "ACCESS_DTLB",
114+ "EventCode": "0x17",
115+ "BriefDescription": "access DTLB"
116+ },
117+ {
118+ "EventName": "MISS_DTLB",
119+ "EventCode": "0x18",
120+ "BriefDescription": "miss DTLB"
121+ },
122+ {
123+ "EventName": "LOAD_INS_DCACHE",
124+ "EventCode": "0x19",
125+ "BriefDescription": "load instruction access DCache"
126+ },
127+ {
128+ "EventName": "LOAD_INS_MISS_DCACHE",
129+ "EventCode": "0x1A",
130+ "BriefDescription": "load instruction miss DCache"
131+ },
132+ {
133+ "EventName": "STORE_INS_DCACHE",
134+ "EventCode": "0x1B",
135+ "BriefDescription": "store/amo instruction access DCache"
136+ },
137+ {
138+ "EventName": "STORE_INS_MISS_DCACHE",
139+ "EventCode": "0x1C",
140+ "BriefDescription": "store/amo instruction miss DCache"
141+ },
142+ {
143+ "EventName": "LOAD_SCACHE",
144+ "EventCode": "0x1D",
145+ "BriefDescription": "load access SCache"
146+ },
147+ {
148+ "EventName": "STORE_SCACHE",
149+ "EventCode": "0x1E",
150+ "BriefDescription": "store access SCache"
151+ },
152+ {
153+ "EventName": "LOAD_MISS_SCACHE",
154+ "EventCode": "0x1F",
155+ "BriefDescription": "load miss SCache"
156+ },
157+ {
158+ "EventName": "STORE_MISS_SCACHE",
159+ "EventCode": "0x20",
160+ "BriefDescription": "store miss SCache"
161+ },
162+ {
163+ "EventName": "L2C_PF_REQ",
164+ "EventCode": "0x21",
165+ "BriefDescription": "L2C data-prefetcher request"
166+ },
167+ {
168+ "EventName": "L2C_PF_HIT",
169+ "EventCode": "0x22",
170+ "BriefDescription": "L2C data-prefetcher hit"
171+ }
172+]
tools/perf/pmu-events/arch/riscv/starfive/dubhe-80/firmware.json+68−0
@@ -0,0 +1,68 @@
1+[
2+ {
3+ "ArchStdEvent": "FW_MISALIGNED_LOAD"
4+ },
5+ {
6+ "ArchStdEvent": "FW_MISALIGNED_STORE"
7+ },
8+ {
9+ "ArchStdEvent": "FW_ACCESS_LOAD"
10+ },
11+ {
12+ "ArchStdEvent": "FW_ACCESS_STORE"
13+ },
14+ {
15+ "ArchStdEvent": "FW_ILLEGAL_INSN"
16+ },
17+ {
18+ "ArchStdEvent": "FW_SET_TIMER"
19+ },
20+ {
21+ "ArchStdEvent": "FW_IPI_SENT"
22+ },
23+ {
24+ "ArchStdEvent": "FW_IPI_RECEIVED"
25+ },
26+ {
27+ "ArchStdEvent": "FW_FENCE_I_SENT"
28+ },
29+ {
30+ "ArchStdEvent": "FW_FENCE_I_RECEIVED"
31+ },
32+ {
33+ "ArchStdEvent": "FW_SFENCE_VMA_SENT"
34+ },
35+ {
36+ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED"
37+ },
38+ {
39+ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED"
40+ },
41+ {
42+ "ArchStdEvent": "FW_SFENCE_VMA_ASID_RECEIVED"
43+ },
44+ {
45+ "ArchStdEvent": "FW_HFENCE_GVMA_SENT"
46+ },
47+ {
48+ "ArchStdEvent": "FW_HFENCE_GVMA_RECEIVED"
49+ },
50+ {
51+ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_SENT"
52+ },
53+ {
54+ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_RECEIVED"
55+ },
56+ {
57+ "ArchStdEvent": "FW_HFENCE_VVMA_SENT"
58+ },
59+ {
60+ "ArchStdEvent": "FW_HFENCE_VVMA_RECEIVED"
61+ },
62+ {
63+ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_SENT"
64+ },
65+ {
66+ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_RECEIVED"
67+ }
68+]
tools/perf/pmu-events/arch/riscv/thead/c900-legacy/cache.json+67−0
@@ -0,0 +1,67 @@
1+[
2+ {
3+ "EventName": "L1_ICACHE_ACCESS",
4+ "EventCode": "0x00000001",
5+ "BriefDescription": "L1 instruction cache access"
6+ },
7+ {
8+ "EventName": "L1_ICACHE_MISS",
9+ "EventCode": "0x00000002",
10+ "BriefDescription": "L1 instruction cache miss"
11+ },
12+ {
13+ "EventName": "ITLB_MISS",
14+ "EventCode": "0x00000003",
15+ "BriefDescription": "I-UTLB miss"
16+ },
17+ {
18+ "EventName": "DTLB_MISS",
19+ "EventCode": "0x00000004",
20+ "BriefDescription": "D-UTLB miss"
21+ },
22+ {
23+ "EventName": "JTLB_MISS",
24+ "EventCode": "0x00000005",
25+ "BriefDescription": "JTLB miss"
26+ },
27+ {
28+ "EventName": "L1_DCACHE_READ_ACCESS",
29+ "EventCode": "0x0000000c",
30+ "BriefDescription": "L1 data cache read access"
31+ },
32+ {
33+ "EventName": "L1_DCACHE_READ_MISS",
34+ "EventCode": "0x0000000d",
35+ "BriefDescription": "L1 data cache read miss"
36+ },
37+ {
38+ "EventName": "L1_DCACHE_WRITE_ACCESS",
39+ "EventCode": "0x0000000e",
40+ "BriefDescription": "L1 data cache write access"
41+ },
42+ {
43+ "EventName": "L1_DCACHE_WRITE_MISS",
44+ "EventCode": "0x0000000f",
45+ "BriefDescription": "L1 data cache write miss"
46+ },
47+ {
48+ "EventName": "LL_CACHE_READ_ACCESS",
49+ "EventCode": "0x00000010",
50+ "BriefDescription": "LL Cache read access"
51+ },
52+ {
53+ "EventName": "LL_CACHE_READ_MISS",
54+ "EventCode": "0x00000011",
55+ "BriefDescription": "LL Cache read miss"
56+ },
57+ {
58+ "EventName": "LL_CACHE_WRITE_ACCESS",
59+ "EventCode": "0x00000012",
60+ "BriefDescription": "LL Cache write access"
61+ },
62+ {
63+ "EventName": "LL_CACHE_WRITE_MISS",
64+ "EventCode": "0x00000013",
65+ "BriefDescription": "LL Cache write miss"
66+ }
67+]
tools/perf/pmu-events/arch/riscv/thead/c900-legacy/firmware.json+68−0
@@ -0,0 +1,68 @@
1+[
2+ {
3+ "ArchStdEvent": "FW_MISALIGNED_LOAD"
4+ },
5+ {
6+ "ArchStdEvent": "FW_MISALIGNED_STORE"
7+ },
8+ {
9+ "ArchStdEvent": "FW_ACCESS_LOAD"
10+ },
11+ {
12+ "ArchStdEvent": "FW_ACCESS_STORE"
13+ },
14+ {
15+ "ArchStdEvent": "FW_ILLEGAL_INSN"
16+ },
17+ {
18+ "ArchStdEvent": "FW_SET_TIMER"
19+ },
20+ {
21+ "ArchStdEvent": "FW_IPI_SENT"
22+ },
23+ {
24+ "ArchStdEvent": "FW_IPI_RECEIVED"
25+ },
26+ {
27+ "ArchStdEvent": "FW_FENCE_I_SENT"
28+ },
29+ {
30+ "ArchStdEvent": "FW_FENCE_I_RECEIVED"
31+ },
32+ {
33+ "ArchStdEvent": "FW_SFENCE_VMA_SENT"
34+ },
35+ {
36+ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED"
37+ },
38+ {
39+ "ArchStdEvent": "FW_SFENCE_VMA_RECEIVED"
40+ },
41+ {
42+ "ArchStdEvent": "FW_SFENCE_VMA_ASID_RECEIVED"
43+ },
44+ {
45+ "ArchStdEvent": "FW_HFENCE_GVMA_SENT"
46+ },
47+ {
48+ "ArchStdEvent": "FW_HFENCE_GVMA_RECEIVED"
49+ },
50+ {
51+ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_SENT"
52+ },
53+ {
54+ "ArchStdEvent": "FW_HFENCE_GVMA_VMID_RECEIVED"
55+ },
56+ {
57+ "ArchStdEvent": "FW_HFENCE_VVMA_SENT"
58+ },
59+ {
60+ "ArchStdEvent": "FW_HFENCE_VVMA_RECEIVED"
61+ },
62+ {
63+ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_SENT"
64+ },
65+ {
66+ "ArchStdEvent": "FW_HFENCE_VVMA_ASID_RECEIVED"
67+ }
68+]
tools/perf/pmu-events/arch/riscv/thead/c900-legacy/instruction.json+72−0
@@ -0,0 +1,72 @@
1+[
2+ {
3+ "EventName": "INST_BRANCH_MISPREDICT",
4+ "EventCode": "0x00000006",
5+ "BriefDescription": "Mispredicted branch instructions"
6+ },
7+ {
8+ "EventName": "INST_BRANCH",
9+ "EventCode": "0x00000007",
10+ "BriefDescription": "Retired branch instructions"
11+ },
12+ {
13+ "EventName": "INST_JMP_MISPREDICT",
14+ "EventCode": "0x00000008",
15+ "BriefDescription": "Indirect branch mispredict"
16+ },
17+ {
18+ "EventName": "INST_JMP",
19+ "EventCode": "0x00000009",
20+ "BriefDescription": "Retired jmp instructions"
21+ },
22+ {
23+ "EventName": "INST_STORE",
24+ "EventCode": "0x0000000b",
25+ "BriefDescription": "Retired store instructions"
26+ },
27+ {
28+ "EventName": "INST_ALU",
29+ "EventCode": "0x0000001d",
30+ "BriefDescription": "Retired ALU instructions"
31+ },
32+ {
33+ "EventName": "INST_LDST",
34+ "EventCode": "0x0000001e",
35+ "BriefDescription": "Retired Load/Store instructions"
36+ },
37+ {
38+ "EventName": "INST_VECTOR",
39+ "EventCode": "0x0000001f",
40+ "BriefDescription": "Retired Vector instructions"
41+ },
42+ {
43+ "EventName": "INST_CSR",
44+ "EventCode": "0x00000020",
45+ "BriefDescription": "Retired CSR instructions"
46+ },
47+ {
48+ "EventName": "INST_SYNC",
49+ "EventCode": "0x00000021",
50+ "BriefDescription": "Retired sync instructions (AMO/LR/SC instructions)"
51+ },
52+ {
53+ "EventName": "INST_UNALIGNED_ACCESS",
54+ "EventCode": "0x00000022",
55+ "BriefDescription": "Retired Store/Load instructions with unaligned memory access"
56+ },
57+ {
58+ "EventName": "INST_ECALL",
59+ "EventCode": "0x00000025",
60+ "BriefDescription": "Retired ecall instructions"
61+ },
62+ {
63+ "EventName": "INST_LONG_JP",
64+ "EventCode": "0x00000026",
65+ "BriefDescription": "Retired long jump instructions"
66+ },
67+ {
68+ "EventName": "INST_FP",
69+ "EventCode": "0x0000002a",
70+ "BriefDescription": "Retired FPU instructions"
71+ }
72+]
tools/perf/pmu-events/arch/riscv/thead/c900-legacy/microarch.json+80−0
@@ -0,0 +1,80 @@
1+[
2+ {
3+ "EventName": "LSU_SPEC_FAIL",
4+ "EventCode": "0x0000000a",
5+ "BriefDescription": "LSU speculation fail"
6+ },
7+ {
8+ "EventName": "IDU_RF_PIPE_FAIL",
9+ "EventCode": "0x00000014",
10+ "BriefDescription": "Instruction decode unit launch pipeline failed in RF state"
11+ },
12+ {
13+ "EventName": "IDU_RF_REG_FAIL",
14+ "EventCode": "0x00000015",
15+ "BriefDescription": "Instruction decode unit launch register file fail in RF state"
16+ },
17+ {
18+ "EventName": "IDU_RF_INSTRUCTION",
19+ "EventCode": "0x00000016",
20+ "BriefDescription": "retired instruction count of Instruction decode unit in RF (Register File) stage"
21+ },
22+ {
23+ "EventName": "LSU_4K_STALL",
24+ "EventCode": "0x00000017",
25+ "BriefDescription": "LSU stall times for long distance data access (Over 4K)",
26+ "PublicDescription": "This stall occurs when translate virtual address with page offset over 4k"
27+ },
28+ {
29+ "EventName": "LSU_OTHER_STALL",
30+ "EventCode": "0x00000018",
31+ "BriefDescription": "LSU stall times for other reasons (except the 4k stall)"
32+ },
33+ {
34+ "EventName": "LSU_SQ_OTHER_DIS",
35+ "EventCode": "0x00000019",
36+ "BriefDescription": "LSU store queue discard others"
37+ },
38+ {
39+ "EventName": "LSU_SQ_DATA_DISCARD",
40+ "EventCode": "0x0000001a",
41+ "BriefDescription": "LSU store queue discard data (uops)"
42+ },
43+ {
44+ "EventName": "BRANCH_DIRECTION_MISPREDICTION",
45+ "EventCode": "0x0000001b",
46+ "BriefDescription": "Branch misprediction in BTB"
47+ },
48+ {
49+ "EventName": "BRANCH_DIRECTION_PREDICTION",
50+ "EventCode": "0x0000001c",
51+ "BriefDescription": "All branch prediction in BTB",
52+ "PublicDescription": "This event including both successful prediction and failed prediction in BTB"
53+ },
54+ {
55+ "EventName": "INTERRUPT_ACK_COUNT",
56+ "EventCode": "0x00000023",
57+ "BriefDescription": "acknowledged interrupt count"
58+ },
59+ {
60+ "EventName": "INTERRUPT_OFF_CYCLE",
61+ "EventCode": "0x00000024",
62+ "BriefDescription": "PLIC arbitration time when the interrupt is not responded",
63+ "PublicDescription": "The arbitration time is recorded while meeting any of the following:\n- CPU is M-mode and MIE == 0\n- CPU is S-mode and delegation and SIE == 0\n"
64+ },
65+ {
66+ "EventName": "IFU_STALLED_CYCLE",
67+ "EventCode": "0x00000027",
68+ "BriefDescription": "Number of stall cycles of the instruction fetch unit (IFU)."
69+ },
70+ {
71+ "EventName": "IDU_STALLED_CYCLE",
72+ "EventCode": "0x00000028",
73+ "BriefDescription": "hpcp_backend_stall Number of stall cycles of the instruction decoding unit (IDU) and next-level pipeline unit."
74+ },
75+ {
76+ "EventName": "SYNC_STALL",
77+ "EventCode": "0x00000029",
78+ "BriefDescription": "Sync instruction stall cycle fence/fence.i/sync/sfence"
79+ }
80+]
tools/perf/pmu-events/arch/x86/alderlake/adl-metrics.json+8−7
@@ -69,12 +69,6 @@ · 68 unmodified lines
6969 "MetricName": "C9_Pkg_Residency",
7070 "ScaleUnit": "100%"
7171 },
72− {
73− "BriefDescription": "Uncore frequency per die [GHZ]",
74− "MetricExpr": "tma_info_system_socket_clks / #num_dies / duration_time / 1e9",
75− "MetricGroup": "SoC",
76− "MetricName": "UNCORE_FREQ"
77− },
7872 {
7973 "BriefDescription": "Percentage of cycles spent in System Management Interrupts.",
8074 "MetricExpr": "((msr@aperf@ - cycles) / msr@aperf@ if msr@smi@ > 0 else 0)",
@@ -809,6 +803,13 @@ · 728 unmodified lines
809803 "ScaleUnit": "100%",
810804 "Unit": "cpu_atom"
811805 },
806+ {
807+ "BriefDescription": "Uncore frequency per die [GHZ]",
808+ "MetricExpr": "tma_info_system_socket_clks / #num_dies / duration_time / 1e9",
809+ "MetricGroup": "SoC",
810+ "MetricName": "UNCORE_FREQ",
811+ "Unit": "cpu_core"
812+ },
812813 {
813814 "BriefDescription": "This metric represents Core fraction of cycles CPU dispatched uops on execution ports for ALU operations.",
814815 "MetricExpr": "(cpu_core@UOPS_DISPATCHED.PORT_0@ + cpu_core@UOPS_DISPATCHED.PORT_1@ + cpu_core@UOPS_DISPATCHED.PORT_5_11@ + cpu_core@UOPS_DISPATCHED.PORT_6@) / (5 * tma_info_core_core_clks)",
@@ -1838,7 +1839,7 @@ · 1023 unmodified lines
18381839 },
18391840 {
18401841 "BriefDescription": "Average number of parallel data read requests to external memory",
1841− "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / cpu_core@UNC_ARB_DAT_OCCUPANCY.RD\\,cmask\\=1@",
1842+ "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / UNC_ARB_DAT_OCCUPANCY.RD@cmask\\=1@",
18421843 "MetricGroup": "Mem;MemoryBW;SoC",
18431844 "MetricName": "tma_info_system_mem_parallel_reads",
18441845 "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches",
tools/perf/pmu-events/arch/x86/amdzen4/memory-controller.json+101−0
@@ -0,0 +1,101 @@
1+[
2+ {
3+ "EventName": "umc_mem_clk",
4+ "PublicDescription": "Number of memory clock cycles.",
5+ "EventCode": "0x00",
6+ "PerPkg": "1",
7+ "Unit": "UMCPMC"
8+ },
9+ {
10+ "EventName": "umc_act_cmd.all",
11+ "PublicDescription": "Number of ACTIVATE commands sent.",
12+ "EventCode": "0x05",
13+ "PerPkg": "1",
14+ "Unit": "UMCPMC"
15+ },
16+ {
17+ "EventName": "umc_act_cmd.rd",
18+ "PublicDescription": "Number of ACTIVATE commands sent for reads.",
19+ "EventCode": "0x05",
20+ "RdWrMask": "0x1",
21+ "PerPkg": "1",
22+ "Unit": "UMCPMC"
23+ },
24+ {
25+ "EventName": "umc_act_cmd.wr",
26+ "PublicDescription": "Number of ACTIVATE commands sent for writes.",
27+ "EventCode": "0x05",
28+ "RdWrMask": "0x2",
29+ "PerPkg": "1",
30+ "Unit": "UMCPMC"
31+ },
32+ {
33+ "EventName": "umc_pchg_cmd.all",
34+ "PublicDescription": "Number of PRECHARGE commands sent.",
35+ "EventCode": "0x06",
36+ "PerPkg": "1",
37+ "Unit": "UMCPMC"
38+ },
39+ {
40+ "EventName": "umc_pchg_cmd.rd",
41+ "PublicDescription": "Number of PRECHARGE commands sent for reads.",
42+ "EventCode": "0x06",
43+ "RdWrMask": "0x1",
44+ "PerPkg": "1",
45+ "Unit": "UMCPMC"
46+ },
47+ {
48+ "EventName": "umc_pchg_cmd.wr",
49+ "PublicDescription": "Number of PRECHARGE commands sent for writes.",
50+ "EventCode": "0x06",
51+ "RdWrMask": "0x2",
52+ "PerPkg": "1",
53+ "Unit": "UMCPMC"
54+ },
55+ {
56+ "EventName": "umc_cas_cmd.all",
57+ "PublicDescription": "Number of CAS commands sent.",
58+ "EventCode": "0x0a",
59+ "PerPkg": "1",
60+ "Unit": "UMCPMC"
61+ },
62+ {
63+ "EventName": "umc_cas_cmd.rd",
64+ "PublicDescription": "Number of CAS commands sent for reads.",
65+ "EventCode": "0x0a",
66+ "RdWrMask": "0x1",
67+ "PerPkg": "1",
68+ "Unit": "UMCPMC"
69+ },
70+ {
71+ "EventName": "umc_cas_cmd.wr",
72+ "PublicDescription": "Number of CAS commands sent for writes.",
73+ "EventCode": "0x0a",
74+ "RdWrMask": "0x2",
75+ "PerPkg": "1",
76+ "Unit": "UMCPMC"
77+ },
78+ {
79+ "EventName": "umc_data_slot_clks.all",
80+ "PublicDescription": "Number of clocks used by the data bus.",
81+ "EventCode": "0x14",
82+ "PerPkg": "1",
83+ "Unit": "UMCPMC"
84+ },
85+ {
86+ "EventName": "umc_data_slot_clks.rd",
87+ "PublicDescription": "Number of clocks used by the data bus for reads.",
88+ "EventCode": "0x14",
89+ "RdWrMask": "0x1",
90+ "PerPkg": "1",
91+ "Unit": "UMCPMC"
92+ },
93+ {
94+ "EventName": "umc_data_slot_clks.wr",
95+ "PublicDescription": "Number of clocks used by the data bus for writes.",
96+ "EventCode": "0x14",
97+ "RdWrMask": "0x2",
98+ "PerPkg": "1",
99+ "Unit": "UMCPMC"
100+ }
101+]
tools/perf/pmu-events/arch/x86/amdzen4/recommended.json+84−0
@@ -330,5 +330,89 @@ · 329 unmodified lines
330330 "MetricGroup": "data_fabric",
331331 "PerPkg": "1",
332332 "ScaleUnit": "6.103515625e-5MiB"
333+ },
334+ {
335+ "MetricName": "umc_data_bus_utilization",
336+ "BriefDescription": "Memory controller data bus utilization.",
337+ "MetricExpr": "d_ratio(umc_data_slot_clks.all / 2, umc_mem_clk)",
338+ "MetricGroup": "memory_controller",
339+ "PerPkg": "1",
340+ "ScaleUnit": "100%"
341+ },
342+ {
343+ "MetricName": "umc_cas_cmd_rate",
344+ "BriefDescription": "Memory controller CAS command rate.",
345+ "MetricExpr": "d_ratio(umc_cas_cmd.all * 1000, umc_mem_clk)",
346+ "MetricGroup": "memory_controller",
347+ "PerPkg": "1"
348+ },
349+ {
350+ "MetricName": "umc_cas_cmd_read_ratio",
351+ "BriefDescription": "Ratio of memory controller CAS commands for reads.",
352+ "MetricExpr": "d_ratio(umc_cas_cmd.rd, umc_cas_cmd.all)",
353+ "MetricGroup": "memory_controller",
354+ "PerPkg": "1",
355+ "ScaleUnit": "100%"
356+ },
357+ {
358+ "MetricName": "umc_cas_cmd_write_ratio",
359+ "BriefDescription": "Ratio of memory controller CAS commands for writes.",
360+ "MetricExpr": "d_ratio(umc_cas_cmd.wr, umc_cas_cmd.all)",
361+ "MetricGroup": "memory_controller",
362+ "PerPkg": "1",
363+ "ScaleUnit": "100%"
364+ },
365+ {
366+ "MetricName": "umc_mem_read_bandwidth",
367+ "BriefDescription": "Estimated memory read bandwidth.",
368+ "MetricExpr": "(umc_cas_cmd.rd * 64) / 1e6 / duration_time",
369+ "MetricGroup": "memory_controller",
370+ "PerPkg": "1",
371+ "ScaleUnit": "1MB/s"
372+ },
373+ {
374+ "MetricName": "umc_mem_write_bandwidth",
375+ "BriefDescription": "Estimated memory write bandwidth.",
376+ "MetricExpr": "(umc_cas_cmd.wr * 64) / 1e6 / duration_time",
377+ "MetricGroup": "memory_controller",
378+ "PerPkg": "1",
379+ "ScaleUnit": "1MB/s"
380+ },
381+ {
382+ "MetricName": "umc_mem_bandwidth",
383+ "BriefDescription": "Estimated combined memory bandwidth.",
384+ "MetricExpr": "(umc_cas_cmd.all * 64) / 1e6 / duration_time",
385+ "MetricGroup": "memory_controller",
386+ "PerPkg": "1",
387+ "ScaleUnit": "1MB/s"
388+ },
389+ {
390+ "MetricName": "umc_cas_cmd_read_ratio",
391+ "BriefDescription": "Ratio of memory controller CAS commands for reads.",
392+ "MetricExpr": "d_ratio(umc_cas_cmd.rd, umc_cas_cmd.all)",
393+ "MetricGroup": "memory_controller",
394+ "PerPkg": "1",
395+ "ScaleUnit": "100%"
396+ },
397+ {
398+ "MetricName": "umc_cas_cmd_rate",
399+ "BriefDescription": "Memory controller CAS command rate.",
400+ "MetricExpr": "d_ratio(umc_cas_cmd.all * 1000, umc_mem_clk)",
401+ "MetricGroup": "memory_controller",
402+ "PerPkg": "1"
403+ },
404+ {
405+ "MetricName": "umc_activate_cmd_rate",
406+ "BriefDescription": "Memory controller ACTIVATE command rate.",
407+ "MetricExpr": "d_ratio(umc_act_cmd.all * 1000, umc_mem_clk)",
408+ "MetricGroup": "memory_controller",
409+ "PerPkg": "1"
410+ },
411+ {
412+ "MetricName": "umc_precharge_cmd_rate",
413+ "BriefDescription": "Memory controller PRECHARGE command rate.",
414+ "MetricExpr": "d_ratio(umc_pchg_cmd.all * 1000, umc_mem_clk)",
415+ "MetricGroup": "memory_controller",
416+ "PerPkg": "1"
333417 }
334418 ]
tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json+6−0
@@ -1862,6 +1862,12 @@ · 1861 unmodified lines
18621862 "MetricName": "uncore_frequency",
18631863 "ScaleUnit": "1GHz"
18641864 },
1865+ {
1866+ "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)",
1867+ "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
1868+ "MetricName": "upi_data_receive_bw",
1869+ "ScaleUnit": "1MB/s"
1870+ },
18651871 {
18661872 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
18671873 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
tools/perf/pmu-events/arch/x86/emeraldrapids/floating-point.json+24−3
@@ -23,26 +23,47 @@ · 22 unmodified lines
2323 "UMask": "0x10"
2424 },
2525 {
26− "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0",
26+ "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0]",
2727 "EventCode": "0xb3",
2828 "EventName": "FP_ARITH_DISPATCHED.PORT_0",
2929 "SampleAfterValue": "2000003",
3030 "UMask": "0x1"
3131 },
3232 {
33− "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1",
33+ "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1]",
3434 "EventCode": "0xb3",
3535 "EventName": "FP_ARITH_DISPATCHED.PORT_1",
3636 "SampleAfterValue": "2000003",
3737 "UMask": "0x2"
3838 },
3939 {
40− "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5",
40+ "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2]",
4141 "EventCode": "0xb3",
4242 "EventName": "FP_ARITH_DISPATCHED.PORT_5",
4343 "SampleAfterValue": "2000003",
4444 "UMask": "0x4"
4545 },
46+ {
47+ "BriefDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0]",
48+ "EventCode": "0xb3",
49+ "EventName": "FP_ARITH_DISPATCHED.V0",
50+ "SampleAfterValue": "2000003",
51+ "UMask": "0x1"
52+ },
53+ {
54+ "BriefDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1]",
55+ "EventCode": "0xb3",
56+ "EventName": "FP_ARITH_DISPATCHED.V1",
57+ "SampleAfterValue": "2000003",
58+ "UMask": "0x2"
59+ },
60+ {
61+ "BriefDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5]",
62+ "EventCode": "0xb3",
63+ "EventName": "FP_ARITH_DISPATCHED.V2",
64+ "SampleAfterValue": "2000003",
65+ "UMask": "0x4"
66+ },
4667 {
4768 "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
4869 "EventCode": "0xc7",
tools/perf/pmu-events/arch/x86/emeraldrapids/pipeline.json+1−17
@@ -1,20 +1,4 @@
11 [
2− {
3− "BriefDescription": "AMX retired arithmetic BF16 operations.",
4− "EventCode": "0xce",
5− "EventName": "AMX_OPS_RETIRED.BF16",
6− "PublicDescription": "Number of AMX-based retired arithmetic bfloat16 (BF16) floating-point operations. Counts TDPBF16PS FP instructions. SW to use operation multiplier of 4",
7− "SampleAfterValue": "1000003",
8− "UMask": "0x2"
9− },
10− {
11− "BriefDescription": "AMX retired arithmetic integer 8-bit operations.",
12− "EventCode": "0xce",
13− "EventName": "AMX_OPS_RETIRED.INT8",
14− "PublicDescription": "Number of AMX-based retired arithmetic integer operations of 8-bit width source operands. Counts TDPB[SS,UU,US,SU]D instructions. SW should use operation multiplier of 8.",
15− "SampleAfterValue": "1000003",
16− "UMask": "0x1"
17− },
182 {
193 "BriefDescription": "This event is deprecated. Refer to new event ARITH.DIV_ACTIVE",
204 "CounterMask": "1",
@@ -505,7 +489,7 @@ · 484 unmodified lines
505489 "UMask": "0x1"
506490 },
507491 {
508− "BriefDescription": "INT_MISC.UNKNOWN_BRANCH_CYCLES",
492+ "BriefDescription": "Bubble cycles of BAClear (Unknown Branch).",
509493 "EventCode": "0xad",
510494 "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES",
511495 "MSRIndex": "0x3F7",
tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-interconnect.json+4−4
@@ -4825,11 +4825,11 @@ · 4824 unmodified lines
48254825 "Unit": "M3UPI"
48264826 },
48274827 {
4828− "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bouncable)",
4828+ "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bounceable)",
48294829 "EventCode": "0x47",
48304830 "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC",
48314831 "PerPkg": "1",
4832− "PublicDescription": "AD Bouncable : Number of allocations into the CRS Egress",
4832+ "PublicDescription": "AD Bounceable : Number of allocations into the CRS Egress",
48334833 "UMask": "0x1",
48344834 "Unit": "MDF"
48354835 },
@@ -4861,11 +4861,11 @@ · 25 unmodified lines
48614861 "Unit": "MDF"
48624862 },
48634863 {
4864− "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bouncable)",
4864+ "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bounceable)",
48654865 "EventCode": "0x47",
48664866 "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC",
48674867 "PerPkg": "1",
4868− "PublicDescription": "BL Bouncable : Number of allocations into the CRS Egress",
4868+ "PublicDescription": "BL Bounceable : Number of allocations into the CRS Egress",
48694869 "UMask": "0x4",
48704870 "Unit": "MDF"
48714871 },
tools/perf/pmu-events/arch/x86/emeraldrapids/uncore-io.json+30−0
@@ -1185,6 +1185,36 @@ · 1184 unmodified lines
11851185 "UMask": "0x70ff010",
11861186 "Unit": "IIO"
11871187 },
1188+ {
1189+ "BriefDescription": ": IOTLB Hits to a 1G Page",
1190+ "EventCode": "0x40",
1191+ "EventName": "UNC_IIO_IOMMU0.1G_HITS",
1192+ "PerPkg": "1",
1193+ "PortMask": "0x0000",
1194+ "PublicDescription": ": IOTLB Hits to a 1G Page : Counts if a transaction to a 1G page, on its first lookup, hits the IOTLB.",
1195+ "UMask": "0x10",
1196+ "Unit": "IIO"
1197+ },
1198+ {
1199+ "BriefDescription": ": IOTLB Hits to a 2M Page",
1200+ "EventCode": "0x40",
1201+ "EventName": "UNC_IIO_IOMMU0.2M_HITS",
1202+ "PerPkg": "1",
1203+ "PortMask": "0x0000",
1204+ "PublicDescription": ": IOTLB Hits to a 2M Page : Counts if a transaction to a 2M page, on its first lookup, hits the IOTLB.",
1205+ "UMask": "0x8",
1206+ "Unit": "IIO"
1207+ },
1208+ {
1209+ "BriefDescription": ": IOTLB Hits to a 4K Page",
1210+ "EventCode": "0x40",
1211+ "EventName": "UNC_IIO_IOMMU0.4K_HITS",
1212+ "PerPkg": "1",
1213+ "PortMask": "0x0000",
1214+ "PublicDescription": ": IOTLB Hits to a 4K Page : Counts if a transaction to a 4K page, on its first lookup, hits the IOTLB.",
1215+ "UMask": "0x4",
1216+ "Unit": "IIO"
1217+ },
11881218 {
11891219 "BriefDescription": ": Context cache hits",
11901220 "EventCode": "0x40",
tools/perf/pmu-events/arch/x86/icelakex/icx-metrics.json+6−0
@@ -1846,6 +1846,12 @@ · 1845 unmodified lines
18461846 "MetricName": "uncore_frequency",
18471847 "ScaleUnit": "1GHz"
18481848 },
1849+ {
1850+ "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)",
1851+ "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
1852+ "MetricName": "upi_data_receive_bw",
1853+ "ScaleUnit": "1MB/s"
1854+ },
18491855 {
18501856 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
18511857 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
tools/perf/pmu-events/arch/x86/icelakex/other.json+1−1
@@ -19,7 +19,7 @@ · 18 unmodified lines
1919 "BriefDescription": "Core cycles where the core was running in a manner where Turbo may be clipped to the AVX512 turbo schedule.",
2020 "EventCode": "0x28",
2121 "EventName": "CORE_POWER.LVL2_TURBO_LICENSE",
22− "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server microarchtecture). This includes high current AVX 512-bit instructions.",
22+ "PublicDescription": "Core cycles where the core was running with power-delivery for license level 2 (introduced in Skylake Server microarchitecture). This includes high current AVX 512-bit instructions.",
2323 "SampleAfterValue": "200003",
2424 "UMask": "0x20"
2525 },
tools/perf/pmu-events/arch/x86/icelakex/pipeline.json+1−1
@@ -519,7 +519,7 @@ · 518 unmodified lines
519519 "BriefDescription": "Cycles when Reservation Station (RS) is empty for the thread",
520520 "EventCode": "0x5e",
521521 "EventName": "RS_EVENTS.EMPTY_CYCLES",
522− "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into stravation periods (e.g. branch mispredictions or i-cache misses)",
522+ "PublicDescription": "Counts cycles during which the reservation station (RS) is empty for this logical processor. This is usually caused when the front-end pipeline runs into starvation periods (e.g. branch mispredictions or i-cache misses)",
523523 "SampleAfterValue": "1000003",
524524 "UMask": "0x1"
525525 },
tools/perf/pmu-events/arch/x86/icelakex/uncore-interconnect.json+3−3
@@ -38,7 +38,7 @@ · 37 unmodified lines
3838 "EventCode": "0x10",
3939 "EventName": "UNC_I_COHERENT_OPS.CLFLUSH",
4040 "PerPkg": "1",
41− "PublicDescription": "Coherent Ops : CLFlush : Counts the number of coherency related operations servied by the IRP",
41+ "PublicDescription": "Coherent Ops : CLFlush : Counts the number of coherency related operations serviced by the IRP",
4242 "UMask": "0x80",
4343 "Unit": "IRP"
4444 },
@@ -65,7 +65,7 @@ · 20 unmodified lines
6565 "EventCode": "0x10",
6666 "EventName": "UNC_I_COHERENT_OPS.WBMTOI",
6767 "PerPkg": "1",
68− "PublicDescription": "Coherent Ops : WbMtoI : Counts the number of coherency related operations servied by the IRP",
68+ "PublicDescription": "Coherent Ops : WbMtoI : Counts the number of coherency related operations serviced by the IRP",
6969 "UMask": "0x40",
7070 "Unit": "IRP"
7171 },
@@ -454,7 +454,7 @@ · 382 unmodified lines
454454 "EventCode": "0x11",
455455 "EventName": "UNC_I_TRANSACTIONS.WRITES",
456456 "PerPkg": "1",
457− "PublicDescription": "Inbound Transaction Count : Writes : Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID. : Trackes only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.",
457+ "PublicDescription": "Inbound Transaction Count : Writes : Counts the number of Inbound transactions from the IRP to the Uncore. This can be filtered based on request type in addition to the source queue. Note the special filtering equation. We do OR-reduction on the request type. If the SOURCE bit is set, then we also do AND qualification based on the source portID. : Tracks only write requests. Each write request should have a prefetch, so there is no need to explicitly track these requests. For writes that are tickled and have to retry, the counter will be incremented for each retry.",
458458 "UMask": "0x2",
459459 "Unit": "IRP"
460460 },
tools/perf/pmu-events/arch/x86/mapfile.csv+3−3
@@ -7,7 +7,7 @@ GenuineIntel-6-56,v11,broadwellde,core · 6 unmodified lines
77 GenuineIntel-6-4F,v22,broadwellx,core
88 GenuineIntel-6-55-[56789ABCDEF],v1.20,cascadelakex,core
99 GenuineIntel-6-9[6C],v1.04,elkhartlake,core
10−GenuineIntel-6-CF,v1.01,emeraldrapids,core
10+GenuineIntel-6-CF,v1.02,emeraldrapids,core
1111 GenuineIntel-6-5[CF],v13,goldmont,core
1212 GenuineIntel-6-7A,v1.01,goldmontplus,core
1313 GenuineIntel-6-B6,v1.00,grandridge,core
@@ -15,7 +15,7 @@ GenuineIntel-6-A[DE],v1.01,graniterapids,core · 1 unmodified line
1515 GenuineIntel-6-(3C|45|46),v33,haswell,core
1616 GenuineIntel-6-3F,v28,haswellx,core
1717 GenuineIntel-6-7[DE],v1.19,icelake,core
18−GenuineIntel-6-6[AC],v1.21,icelakex,core
18+GenuineIntel-6-6[AC],v1.23,icelakex,core
1919 GenuineIntel-6-3A,v24,ivybridge,core
2020 GenuineIntel-6-3E,v24,ivytown,core
2121 GenuineIntel-6-2D,v24,jaketown,core
@@ -26,7 +26,7 @@ GenuineIntel-6-1[AEF],v4,nehalemep,core · 4 unmodified lines
2626 GenuineIntel-6-2E,v4,nehalemex,core
2727 GenuineIntel-6-A7,v1.01,rocketlake,core
2828 GenuineIntel-6-2A,v19,sandybridge,core
29−GenuineIntel-6-8F,v1.16,sapphirerapids,core
29+GenuineIntel-6-8F,v1.17,sapphirerapids,core
3030 GenuineIntel-6-AF,v1.00,sierraforest,core
3131 GenuineIntel-6-(37|4A|4C|4D|5A),v15,silvermont,core
3232 GenuineIntel-6-(4E|5E|8E|9E|A5|A6),v57,skylake,core
tools/perf/pmu-events/arch/x86/rocketlake/rkl-metrics.json+1−1
@@ -985,7 +985,7 @@ · 984 unmodified lines
985985 },
986986 {
987987 "BriefDescription": "Average number of parallel data read requests to external memory",
988− "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / cpu@UNC_ARB_DAT_OCCUPANCY.RD\\,cmask\\=1@",
988+ "MetricExpr": "UNC_ARB_DAT_OCCUPANCY.RD / UNC_ARB_DAT_OCCUPANCY.RD@cmask\\=1@",
989989 "MetricGroup": "Mem;MemoryBW;SoC",
990990 "MetricName": "tma_info_system_mem_parallel_reads",
991991 "PublicDescription": "Average number of parallel data read requests to external memory. Accounts for demand loads and L1/L2 prefetches"
tools/perf/pmu-events/arch/x86/sapphirerapids/floating-point.json+24−3
@@ -23,26 +23,47 @@ · 22 unmodified lines
2323 "UMask": "0x10"
2424 },
2525 {
26− "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0",
26+ "BriefDescription": "FP_ARITH_DISPATCHED.PORT_0 [This event is alias to FP_ARITH_DISPATCHED.V0]",
2727 "EventCode": "0xb3",
2828 "EventName": "FP_ARITH_DISPATCHED.PORT_0",
2929 "SampleAfterValue": "2000003",
3030 "UMask": "0x1"
3131 },
3232 {
33− "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1",
33+ "BriefDescription": "FP_ARITH_DISPATCHED.PORT_1 [This event is alias to FP_ARITH_DISPATCHED.V1]",
3434 "EventCode": "0xb3",
3535 "EventName": "FP_ARITH_DISPATCHED.PORT_1",
3636 "SampleAfterValue": "2000003",
3737 "UMask": "0x2"
3838 },
3939 {
40− "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5",
40+ "BriefDescription": "FP_ARITH_DISPATCHED.PORT_5 [This event is alias to FP_ARITH_DISPATCHED.V2]",
4141 "EventCode": "0xb3",
4242 "EventName": "FP_ARITH_DISPATCHED.PORT_5",
4343 "SampleAfterValue": "2000003",
4444 "UMask": "0x4"
4545 },
46+ {
47+ "BriefDescription": "FP_ARITH_DISPATCHED.V0 [This event is alias to FP_ARITH_DISPATCHED.PORT_0]",
48+ "EventCode": "0xb3",
49+ "EventName": "FP_ARITH_DISPATCHED.V0",
50+ "SampleAfterValue": "2000003",
51+ "UMask": "0x1"
52+ },
53+ {
54+ "BriefDescription": "FP_ARITH_DISPATCHED.V1 [This event is alias to FP_ARITH_DISPATCHED.PORT_1]",
55+ "EventCode": "0xb3",
56+ "EventName": "FP_ARITH_DISPATCHED.V1",
57+ "SampleAfterValue": "2000003",
58+ "UMask": "0x2"
59+ },
60+ {
61+ "BriefDescription": "FP_ARITH_DISPATCHED.V2 [This event is alias to FP_ARITH_DISPATCHED.PORT_5]",
62+ "EventCode": "0xb3",
63+ "EventName": "FP_ARITH_DISPATCHED.V2",
64+ "SampleAfterValue": "2000003",
65+ "UMask": "0x4"
66+ },
4667 {
4768 "BriefDescription": "Counts number of SSE/AVX computational 128-bit packed double precision floating-point instructions retired; some instructions will count twice as noted below. Each count represents 2 computation operations, one for each element. Applies to SSE* and AVX* packed double precision floating-point instructions: ADD SUB HADD HSUB SUBADD MUL DIV MIN MAX SQRT DPP FM(N)ADD/SUB. DPP and FM(N)ADD/SUB instructions count twice as they perform 2 calculations per element.",
4869 "EventCode": "0xc7",
tools/perf/pmu-events/arch/x86/sapphirerapids/pipeline.json+1−1
@@ -505,7 +505,7 @@ · 504 unmodified lines
505505 "UMask": "0x1"
506506 },
507507 {
508− "BriefDescription": "INT_MISC.UNKNOWN_BRANCH_CYCLES",
508+ "BriefDescription": "Bubble cycles of BAClear (Unknown Branch).",
509509 "EventCode": "0xad",
510510 "EventName": "INT_MISC.UNKNOWN_BRANCH_CYCLES",
511511 "MSRIndex": "0x3F7",
tools/perf/pmu-events/arch/x86/sapphirerapids/spr-metrics.json+6−0
@@ -1964,6 +1964,12 @@ · 1963 unmodified lines
19641964 "MetricName": "uncore_frequency",
19651965 "ScaleUnit": "1GHz"
19661966 },
1967+ {
1968+ "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)",
1969+ "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
1970+ "MetricName": "upi_data_receive_bw",
1971+ "ScaleUnit": "1MB/s"
1972+ },
19671973 {
19681974 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
19691975 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-interconnect.json+4−4
@@ -4825,11 +4825,11 @@ · 4824 unmodified lines
48254825 "Unit": "M3UPI"
48264826 },
48274827 {
4828− "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bouncable)",
4828+ "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (AD Bounceable)",
48294829 "EventCode": "0x47",
48304830 "EventName": "UNC_MDF_CRS_TxR_INSERTS.AD_BNC",
48314831 "PerPkg": "1",
4832− "PublicDescription": "AD Bouncable : Number of allocations into the CRS Egress",
4832+ "PublicDescription": "AD Bounceable : Number of allocations into the CRS Egress",
48334833 "UMask": "0x1",
48344834 "Unit": "MDF"
48354835 },
@@ -4861,11 +4861,11 @@ · 25 unmodified lines
48614861 "Unit": "MDF"
48624862 },
48634863 {
4864− "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bouncable)",
4864+ "BriefDescription": "Number of allocations into the CRS Egress used to queue up requests destined to the mesh (BL Bounceable)",
48654865 "EventCode": "0x47",
48664866 "EventName": "UNC_MDF_CRS_TxR_INSERTS.BL_BNC",
48674867 "PerPkg": "1",
4868− "PublicDescription": "BL Bouncable : Number of allocations into the CRS Egress",
4868+ "PublicDescription": "BL Bounceable : Number of allocations into the CRS Egress",
48694869 "UMask": "0x4",
48704870 "Unit": "MDF"
48714871 },
tools/perf/pmu-events/arch/x86/sapphirerapids/uncore-io.json+30−0
@@ -1249,6 +1249,36 @@ · 1248 unmodified lines
12491249 "UMask": "0x70ff010",
12501250 "Unit": "IIO"
12511251 },
1252+ {
1253+ "BriefDescription": ": IOTLB Hits to a 1G Page",
1254+ "EventCode": "0x40",
1255+ "EventName": "UNC_IIO_IOMMU0.1G_HITS",
1256+ "PerPkg": "1",
1257+ "PortMask": "0x0000",
1258+ "PublicDescription": ": IOTLB Hits to a 1G Page : Counts if a transaction to a 1G page, on its first lookup, hits the IOTLB.",
1259+ "UMask": "0x10",
1260+ "Unit": "IIO"
1261+ },
1262+ {
1263+ "BriefDescription": ": IOTLB Hits to a 2M Page",
1264+ "EventCode": "0x40",
1265+ "EventName": "UNC_IIO_IOMMU0.2M_HITS",
1266+ "PerPkg": "1",
1267+ "PortMask": "0x0000",
1268+ "PublicDescription": ": IOTLB Hits to a 2M Page : Counts if a transaction to a 2M page, on its first lookup, hits the IOTLB.",
1269+ "UMask": "0x8",
1270+ "Unit": "IIO"
1271+ },
1272+ {
1273+ "BriefDescription": ": IOTLB Hits to a 4K Page",
1274+ "EventCode": "0x40",
1275+ "EventName": "UNC_IIO_IOMMU0.4K_HITS",
1276+ "PerPkg": "1",
1277+ "PortMask": "0x0000",
1278+ "PublicDescription": ": IOTLB Hits to a 4K Page : Counts if a transaction to a 4K page, on its first lookup, hits the IOTLB.",
1279+ "UMask": "0x4",
1280+ "Unit": "IIO"
1281+ },
12521282 {
12531283 "BriefDescription": ": Context cache hits",
12541284 "EventCode": "0x40",
tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json+6−0
@@ -1806,6 +1806,12 @@ · 1805 unmodified lines
18061806 "MetricName": "uncore_frequency",
18071807 "ScaleUnit": "1GHz"
18081808 },
1809+ {
1810+ "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data receive bandwidth (MB/sec)",
1811+ "MetricExpr": "UNC_UPI_RxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
1812+ "MetricName": "upi_data_receive_bw",
1813+ "ScaleUnit": "1MB/s"
1814+ },
18091815 {
18101816 "BriefDescription": "Intel(R) Ultra Path Interconnect (UPI) data transmit bandwidth (MB/sec)",
18111817 "MetricExpr": "UNC_UPI_TxL_FLITS.ALL_DATA * 7.111111111111111 / 1e6 / duration_time",
tools/perf/pmu-events/jevents.py+3−1
@@ -83,7 +83,7 @@ def c_len(s: str) -> int: · 82 unmodified lines
8383 """Return the length of s a C string
8484
8585 This doesn't handle all escape characters properly. It first assumes
86− all \ are for escaping, it then adjusts as it will have over counted
86+ all \\ are for escaping, it then adjusts as it will have over counted
8787 \\. The code uses \000 rather than \0 as a terminator as an adjacent
8888 number would be folded into a string of \0 (ie. "\0" + "5" doesn't
8989 equal a terminator followed by the number 5 but the escape of
@@ -286,6 +286,7 @@ class JsonEvent: · 196 unmodified lines
286286 'imx8_ddr': 'imx8_ddr',
287287 'L3PMC': 'amd_l3',
288288 'DFPMC': 'amd_df',
289+ 'UMCPMC': 'amd_umc',
289290 'cpu_core': 'cpu_core',
290291 'cpu_atom': 'cpu_atom',
291292 'ali_drw': 'ali_drw',
@@ -354,6 +355,7 @@ class JsonEvent: · 62 unmodified lines
354355 ('SampleAfterValue', 'period='),
355356 ('UMask', 'umask='),
356357 ('NodeType', 'type='),
358+ ('RdWrMask', 'rdwrmask='),
357359 ]
358360 for key, value in event_fields:
359361 if key in jd and jd[key] != '0':
tools/perf/scripts/python/arm-cs-trace-disasm.py+16−14
@@ -45,8 +45,8 @@ parser = OptionParser(option_list=option_list) · 44 unmodified lines
4545 # Initialize global dicts and regular expression
4646 disasm_cache = dict()
4747 cpu_data = dict()
48−disasm_re = re.compile("^\s*([0-9a-fA-F]+):")
49−disasm_func_re = re.compile("^\s*([0-9a-fA-F]+)\s.*:")
48+disasm_re = re.compile(r"^\s*([0-9a-fA-F]+):")
49+disasm_func_re = re.compile(r"^\s*([0-9a-fA-F]+)\s.*:")
5050 cache_size = 64*1024
5151
5252 glb_source_file_name = None
@@ -188,6 +188,17 @@ def process_event(param_dict): · 135 unmodified lines
188188 dso_end = get_optional(param_dict, "dso_map_end")
189189 symbol = get_optional(param_dict, "symbol")
190190
191+ cpu = sample["cpu"]
192+ ip = sample["ip"]
193+ addr = sample["addr"]
194+
195+ # Initialize CPU data if it's empty, and directly return back
196+ # if this is the first tracing event for this CPU.
197+ if (cpu_data.get(str(cpu) + 'addr') == None):
198+ cpu_data[str(cpu) + 'addr'] = addr
199+ return
200+
201+
191202 if (options.verbose == True):
192203 print("Event type: %s" % name)
193204 print_sample(sample)
@@ -209,16 +220,6 @@ def process_event(param_dict): · 15 unmodified lines
209220 if (name[0:8] != "branches"):
210221 return
211222
212− cpu = sample["cpu"]
213− ip = sample["ip"]
214− addr = sample["addr"]
215−
216− # Initialize CPU data if it's empty, and directly return back
217− # if this is the first tracing event for this CPU.
218− if (cpu_data.get(str(cpu) + 'addr') == None):
219− cpu_data[str(cpu) + 'addr'] = addr
220− return
221−
222223 # The format for packet is:
223224 #
224225 # +------------+------------+------------+
@@ -258,8 +259,9 @@ def process_event(param_dict): · 33 unmodified lines
258259
259260 if (options.objdump_name != None):
260261 # It doesn't need to decrease virtual memory offset for disassembly
261− # for kernel dso, so in this case we set vm_start to zero.
262− if (dso == "[kernel.kallsyms]"):
262+ # for kernel dso and executable file dso, so in this case we set
263+ # vm_start to zero.
264+ if (dso == "[kernel.kallsyms]" or dso_start == 0x400000):
263265 dso_vm_start = 0
264266 else:
265267 dso_vm_start = int(dso_start)
tools/perf/scripts/python/compaction-times.py+1−1
@@ -260,7 +260,7 @@ def pr_help(): · 259 unmodified lines
260260
261261 comm_re = None
262262 pid_re = None
263−pid_regex = "^(\d*)-(\d*)$|^(\d*)$"
263+pid_regex = r"^(\d*)-(\d*)$|^(\d*)$"
264264
265265 opt_proc = popt.DISP_DFL
266266 opt_disp = topt.DISP_ALL
tools/perf/scripts/python/exported-sql-viewer.py+2−2
@@ -677,8 +677,8 @@ class CallGraphModelBase(TreeModel): · 676 unmodified lines
677677 # sqlite supports GLOB (text only) which uses * and ? and is case sensitive
678678 if not self.glb.dbref.is_sqlite3:
679679 # Escape % and _
680− s = value.replace("%", "\%")
681− s = s.replace("_", "\_")
680+ s = value.replace("%", "\\%")
681+ s = s.replace("_", "\\_")
682682 # Translate * and ? into SQL LIKE pattern characters % and _
683683 trans = string.maketrans("*?", "%_")
684684 match = " LIKE '" + str(s).translate(trans) + "'"
tools/perf/tests/Build+14−0
@@ -77,3 +77,17 @@ CFLAGS_python-use.o += -DPYTHONPATH="BUILD_STR($(OUTPUT)python)" -DPYTHON="BUI · 76 unmodified lines
7777 CFLAGS_dwarf-unwind.o += -fno-optimize-sibling-calls
7878
7979 perf-y += workloads/
80+
81+ifdef SHELLCHECK
82+ SHELL_TESTS := $(shell find tests/shell -executable -type f -name '*.sh')
83+ TEST_LOGS := $(SHELL_TESTS:tests/shell/%=shell/%.shellcheck_log)
84+else
85+ SHELL_TESTS :=
86+ TEST_LOGS :=
87+endif
88+
89+$(OUTPUT)%.shellcheck_log: %
90+ $(call rule_mkdir)
91+ $(Q)$(call echo-cmd,test)shellcheck -a -S warning "$<" > $@ || (cat $@ && rm $@ && false)
92+
93+perf-y += $(TEST_LOGS)
tools/perf/tests/attr.c+1−1
@@ -188,7 +188,7 @@ static int test__attr(struct test_suite *test __maybe_unused, int subtest __mayb · 187 unmodified lines
188188 if (perf_pmus__num_core_pmus() > 1) {
189189 /*
190190 * TODO: Attribute tests hard code the PMU type. If there are >1
191− * core PMU then each PMU will have a different type whic
191+ * core PMU then each PMU will have a different type which
192192 * requires additional support.
193193 */
194194 pr_debug("Skip test on hybrid systems");
tools/perf/tests/attr/base-record+1−1
@@ -6,7 +6,7 @@ flags=0|8 · 5 unmodified lines
66 cpu=*
77 type=0|1
88 size=136
9−config=0
9+config=0|1
1010 sample_period=*
1111 sample_type=263
1212 read_format=0|4|20
tools/perf/tests/attr/test-record-user-regs-no-sve-aarch64+1−1
@@ -6,4 +6,4 @@ args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 · 5 unmodified lines
66 ret = 129
77 test_ret = true
88 arch = aarch64
9−auxv = auxv["AT_HWCAP"] & 0x200000 == 0
9+auxv = auxv["AT_HWCAP"] & 0x400000 == 0
tools/perf/tests/attr/test-record-user-regs-sve-aarch64+1−1
@@ -6,7 +6,7 @@ args = --no-bpf-event --user-regs=vg kill >/dev/null 2>&1 · 5 unmodified lines
66 ret = 1
77 test_ret = true
88 arch = aarch64
9−auxv = auxv["AT_HWCAP"] & 0x200000 == 0x200000
9+auxv = auxv["AT_HWCAP"] & 0x400000 == 0x400000
1010 kernel_since = 6.1
1111
1212 [event:base-record]
tools/perf/tests/builtin-test.c+15−2
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <sys/wait.h>
1515 #include <sys/stat.h>
1616 #include "builtin.h"
17+#include "config.h"
1718 #include "hist.h"
1819 #include "intlist.h"
1920 #include "tests.h"
@@ -32,6 +33,7 @@ · 12 unmodified lines
3233
3334 static bool dont_fork;
3435 const char *dso_to_test;
36+const char *test_objdump_path = "objdump";
3537
3638 /*
3739 * List of architecture specific tests. Not a weak symbol as the array length is
@@ -60,8 +62,6 @@ static struct test_suite *generic_tests[] = { · 22 unmodified lines
6062 &suite__pmu,
6163 &suite__pmu_events,
6264 &suite__dso_data,
63− &suite__dso_data_cache,
64− &suite__dso_data_reopen,
6565 &suite__perf_evsel__roundtrip_name_test,
6666 #ifdef HAVE_LIBTRACEEVENT
6767 &suite__perf_evsel__tp_sched_test,
@@ -513,6 +513,15 @@ static int run_workload(const char *work, int argc, const char **argv) · 445 unmodified lines
513513 return -1;
514514 }
515515
516+static int perf_test__config(const char *var, const char *value,
517+ void *data __maybe_unused)
518+{
519+ if (!strcmp(var, "annotate.objdump"))
520+ test_objdump_path = value;
521+
522+ return 0;
523+}
524+
516525 int cmd_test(int argc, const char **argv)
517526 {
518527 const char *test_usage[] = {
@@ -529,6 +538,8 @@ int cmd_test(int argc, const char **argv) · 10 unmodified lines
529538 "Do not fork for testcase"),
530539 OPT_STRING('w', "workload", &workload, "work", "workload to run for testing"),
531540 OPT_STRING(0, "dso", &dso_to_test, "dso", "dso to test"),
541+ OPT_STRING(0, "objdump", &test_objdump_path, "path",
542+ "objdump binary to use for disassembly and annotations"),
532543 OPT_END()
533544 };
534545 const char * const test_subcommands[] = { "list", NULL };
@@ -538,6 +549,8 @@ int cmd_test(int argc, const char **argv) · 3 unmodified lines
538549 if (ret < 0)
539550 return ret;
540551
552+ perf_config(perf_test__config, NULL);
553+
541554 /* Unbuffered output */
542555 setvbuf(stdout, NULL, _IONBF, 0);
543556
tools/perf/tests/code-reading.c+25−55
@@ -185,7 +185,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, · 184 unmodified lines
185185 int ret;
186186
187187 fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
188− ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
188+ ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path, addr, addr + len,
189189 filename);
190190 if (ret <= 0 || (size_t)ret >= sizeof(cmd))
191191 return -1;
@@ -511,38 +511,6 @@ static void fs_something(void) · 319 unmodified lines
511511 }
512512 }
513513
514−#ifdef __s390x__
515−#include "header.h" // for get_cpuid()
516−#endif
517−
518−static const char *do_determine_event(bool excl_kernel)
519−{
520− const char *event = excl_kernel ? "cycles:u" : "cycles";
521−
522−#ifdef __s390x__
523− char cpuid[128], model[16], model_c[16], cpum_cf_v[16];
524− unsigned int family;
525− int ret, cpum_cf_a;
526−
527− if (get_cpuid(cpuid, sizeof(cpuid)))
528− goto out_clocks;
529− ret = sscanf(cpuid, "%*[^,],%u,%[^,],%[^,],%[^,],%x", &family, model_c,
530− model, cpum_cf_v, &cpum_cf_a);
531− if (ret != 5) /* Not available */
532− goto out_clocks;
533− if (excl_kernel && (cpum_cf_a & 4))
534− return event;
535− if (!excl_kernel && (cpum_cf_a & 2))
536− return event;
537−
538− /* Fall through: missing authorization */
539−out_clocks:
540− event = excl_kernel ? "cpu-clock:u" : "cpu-clock";
541−
542−#endif
543− return event;
544−}
545−
546514 static void do_something(void)
547515 {
548516 fs_something();
@@ -583,8 +551,10 @@ static int do_test_code_reading(bool try_kcore) · 34 unmodified lines
583551 int err = -1, ret;
584552 pid_t pid;
585553 struct map *map;
586− bool have_vmlinux, have_kcore, excl_kernel = false;
554+ bool have_vmlinux, have_kcore;
587555 struct dso *dso;
556+ const char *events[] = { "cycles", "cycles:u", "cpu-clock", "cpu-clock:u", NULL };
557+ int evidx = 0;
588558
589559 pid = getpid();
590560
@@ -618,7 +588,7 @@ static int do_test_code_reading(bool try_kcore) · 27 unmodified lines
618588
619589 /* No point getting kernel events if there is no kernel object */
620590 if (!have_vmlinux && !have_kcore)
621− excl_kernel = true;
591+ evidx++;
622592
623593 threads = thread_map__new_by_tid(pid);
624594 if (!threads) {
@@ -640,13 +610,13 @@ static int do_test_code_reading(bool try_kcore) · 15 unmodified lines
640610 goto out_put;
641611 }
642612
643− cpus = perf_cpu_map__new(NULL);
613+ cpus = perf_cpu_map__new_online_cpus();
644614 if (!cpus) {
645615 pr_debug("perf_cpu_map__new failed\n");
646616 goto out_put;
647617 }
648618
649− while (1) {
619+ while (events[evidx]) {
650620 const char *str;
651621
652622 evlist = evlist__new();
@@ -657,7 +627,7 @@ static int do_test_code_reading(bool try_kcore) · 4 unmodified lines
657627
658628 perf_evlist__set_maps(&evlist->core, cpus, threads);
659629
660− str = do_determine_event(excl_kernel);
630+ str = events[evidx];
661631 pr_debug("Parsing event '%s'\n", str);
662632 ret = parse_event(evlist, str);
663633 if (ret < 0) {
@@ -675,32 +645,32 @@ static int do_test_code_reading(bool try_kcore) · 11 unmodified lines
675645
676646 ret = evlist__open(evlist);
677647 if (ret < 0) {
678− if (!excl_kernel) {
679− excl_kernel = true;
680− /*
681− * Both cpus and threads are now owned by evlist
682− * and will be freed by following perf_evlist__set_maps
683− * call. Getting reference to keep them alive.
684− */
685− perf_cpu_map__get(cpus);
686− perf_thread_map__get(threads);
687− perf_evlist__set_maps(&evlist->core, NULL, NULL);
688− evlist__delete(evlist);
689− evlist = NULL;
690− continue;
691− }
648+ evidx++;
692649
693− if (verbose > 0) {
650+ if (events[evidx] == NULL && verbose > 0) {
694651 char errbuf[512];
695652 evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
696653 pr_debug("perf_evlist__open() failed!\n%s\n", errbuf);
697654 }
698655
699− goto out_put;
656+ /*
657+ * Both cpus and threads are now owned by evlist
658+ * and will be freed by following perf_evlist__set_maps
659+ * call. Getting reference to keep them alive.
660+ */
661+ perf_cpu_map__get(cpus);
662+ perf_thread_map__get(threads);
663+ perf_evlist__set_maps(&evlist->core, NULL, NULL);
664+ evlist__delete(evlist);
665+ evlist = NULL;
666+ continue;
700667 }
701668 break;
702669 }
703670
671+ if (events[evidx] == NULL)
672+ goto out_put;
673+
704674 ret = evlist__mmap(evlist, UINT_MAX);
705675 if (ret < 0) {
706676 pr_debug("evlist__mmap failed\n");
@@ -721,7 +691,7 @@ static int do_test_code_reading(bool try_kcore) · 14 unmodified lines
721691 err = TEST_CODE_READING_NO_KERNEL_OBJ;
722692 else if (!have_vmlinux && !try_kcore)
723693 err = TEST_CODE_READING_NO_VMLINUX;
724− else if (excl_kernel)
694+ else if (strstr(events[evidx], ":u"))
725695 err = TEST_CODE_READING_NO_ACCESS;
726696 else
727697 err = TEST_CODE_READING_OK;
tools/perf/tests/cpumap.c+1−1
@@ -213,7 +213,7 @@ static int test__cpu_map_intersect(struct test_suite *test __maybe_unused, · 212 unmodified lines
213213
214214 static int test__cpu_map_equal(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
215215 {
216− struct perf_cpu_map *any = perf_cpu_map__dummy_new();
216+ struct perf_cpu_map *any = perf_cpu_map__new_any_cpu();
217217 struct perf_cpu_map *one = perf_cpu_map__new("1");
218218 struct perf_cpu_map *two = perf_cpu_map__new("2");
219219 struct perf_cpu_map *empty = perf_cpu_map__intersect(one, two);
tools/perf/tests/dso-data.c+12−3
@@ -394,6 +394,15 @@ static int test__dso_data_reopen(struct test_suite *test __maybe_unused, int sub · 393 unmodified lines
394394 return 0;
395395 }
396396
397−DEFINE_SUITE("DSO data read", dso_data);
398−DEFINE_SUITE("DSO data cache", dso_data_cache);
399−DEFINE_SUITE("DSO data reopen", dso_data_reopen);
397+
398+static struct test_case tests__dso_data[] = {
399+ TEST_CASE("read", dso_data),
400+ TEST_CASE("cache", dso_data_cache),
401+ TEST_CASE("reopen", dso_data_reopen),
402+ { .name = NULL, }
403+};
404+
405+struct test_suite suite__dso_data = {
406+ .desc = "DSO data tests",
407+ .test_cases = tests__dso_data,
408+};
tools/perf/tests/keep-tracking.c+1−1
@@ -81,7 +81,7 @@ static int test__keep_tracking(struct test_suite *test __maybe_unused, int subte · 80 unmodified lines
8181 threads = thread_map__new(-1, getpid(), UINT_MAX);
8282 CHECK_NOT_NULL__(threads);
8383
84− cpus = perf_cpu_map__new(NULL);
84+ cpus = perf_cpu_map__new_online_cpus();
8585 CHECK_NOT_NULL__(cpus);
8686
8787 evlist = evlist__new();
tools/perf/tests/make+1−1
@@ -183,7 +183,7 @@ run += make_install_prefix_slash · 182 unmodified lines
183183 # run += make_install_pdf
184184 run += make_minimal
185185
186−old_libbpf := $(shell echo '\#include <bpf/libbpf.h>' | $(CC) -E -dM -x c -| egrep -q "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}")
186+old_libbpf := $(shell echo '\#include <bpf/libbpf.h>' | $(CC) -E -dM -x c -| grep -q -E "define[[:space:]]+LIBBPF_MAJOR_VERSION[[:space:]]+0{1}")
187187
188188 ifneq ($(old_libbpf),)
189189 run += make_libbpf_dynamic
tools/perf/tests/maps.c+38−23
@@ -14,44 +14,59 @@ struct map_def { · 13 unmodified lines
1414 u64 end;
1515 };
1616
17+struct check_maps_cb_args {
18+ struct map_def *merged;
19+ unsigned int i;
20+};
21+
22+static int check_maps_cb(struct map *map, void *data)
23+{
24+ struct check_maps_cb_args *args = data;
25+ struct map_def *merged = &args->merged[args->i];
26+
27+ if (map__start(map) != merged->start ||
28+ map__end(map) != merged->end ||
29+ strcmp(map__dso(map)->name, merged->name) ||
30+ refcount_read(map__refcnt(map)) != 1) {
31+ return 1;
32+ }
33+ args->i++;
34+ return 0;
35+}
36+
37+static int failed_cb(struct map *map, void *data __maybe_unused)
38+{
39+ pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: %d\n",
40+ map__start(map),
41+ map__end(map),
42+ map__dso(map)->name,
43+ refcount_read(map__refcnt(map)));
44+
45+ return 0;
46+}
47+
1748 static int check_maps(struct map_def *merged, unsigned int size, struct maps *maps)
1849 {
19− struct map_rb_node *rb_node;
20− unsigned int i = 0;
2150 bool failed = false;
2251
2352 if (maps__nr_maps(maps) != size) {
2453 pr_debug("Expected %d maps, got %d", size, maps__nr_maps(maps));
2554 failed = true;
2655 } else {
27− maps__for_each_entry(maps, rb_node) {
28− struct map *map = rb_node->map;
29−
30− if (map__start(map) != merged[i].start ||
31− map__end(map) != merged[i].end ||
32− strcmp(map__dso(map)->name, merged[i].name) ||
33− refcount_read(map__refcnt(map)) != 1) {
34− failed = true;
35− }
36− i++;
37− }
56+ struct check_maps_cb_args args = {
57+ .merged = merged,
58+ .i = 0,
59+ };
60+ failed = maps__for_each_map(maps, check_maps_cb, &args);
3861 }
3962 if (failed) {
4063 pr_debug("Expected:\n");
41− for (i = 0; i < size; i++) {
64+ for (unsigned int i = 0; i < size; i++) {
4265 pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: 1\n",
4366 merged[i].start, merged[i].end, merged[i].name);
4467 }
4568 pr_debug("Got:\n");
46− maps__for_each_entry(maps, rb_node) {
47− struct map *map = rb_node->map;
48−
49− pr_debug("\tstart: %" PRIu64 " end: %" PRIu64 " name: '%s' refcnt: %d\n",
50− map__start(map),
51− map__end(map),
52− map__dso(map)->name,
53− refcount_read(map__refcnt(map)));
54− }
69+ maps__for_each_map(maps, failed_cb, NULL);
5570 }
5671 return failed ? TEST_FAIL : TEST_OK;
5772 }
tools/perf/tests/mmap-basic.c+1−1
@@ -52,7 +52,7 @@ static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest · 51 unmodified lines
5252 return -1;
5353 }
5454
55− cpus = perf_cpu_map__new(NULL);
55+ cpus = perf_cpu_map__new_online_cpus();
5656 if (cpus == NULL) {
5757 pr_debug("perf_cpu_map__new\n");
5858 goto out_free_threads;
tools/perf/tests/openat-syscall-all-cpus.c+1−1
@@ -37,7 +37,7 @@ static int test__openat_syscall_event_on_all_cpus(struct test_suite *test __mayb · 36 unmodified lines
3737 return -1;
3838 }
3939
40− cpus = perf_cpu_map__new(NULL);
40+ cpus = perf_cpu_map__new_online_cpus();
4141 if (cpus == NULL) {
4242 pr_debug("perf_cpu_map__new\n");
4343 goto out_thread_map_delete;
tools/perf/tests/parse-events.c+187−73
@@ -162,6 +162,22 @@ static int test__checkevent_numeric(struct evlist *evlist) · 161 unmodified lines
162162 return TEST_OK;
163163 }
164164
165+
166+static int assert_hw(struct perf_evsel *evsel, enum perf_hw_id id, const char *name)
167+{
168+ struct perf_pmu *pmu;
169+
170+ if (evsel->attr.type == PERF_TYPE_HARDWARE) {
171+ TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, id));
172+ return 0;
173+ }
174+ pmu = perf_pmus__find_by_type(evsel->attr.type);
175+
176+ TEST_ASSERT_VAL("unexpected PMU type", pmu);
177+ TEST_ASSERT_VAL("PMU missing event", perf_pmu__have_event(pmu, name));
178+ return 0;
179+}
180+
165181 static int test__checkevent_symbolic_name(struct evlist *evlist)
166182 {
167183 struct perf_evsel *evsel;
@@ -169,10 +185,12 @@ static int test__checkevent_symbolic_name(struct evlist *evlist) · 1 unmodified line
169185 TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries);
170186
171187 perf_evlist__for_each_evsel(&evlist->core, evsel) {
172− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
173− TEST_ASSERT_VAL("wrong config",
174− test_perf_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
188+ int ret = assert_hw(evsel, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
189+
190+ if (ret)
191+ return ret;
175192 }
193+
176194 return TEST_OK;
177195 }
178196
@@ -183,8 +201,10 @@ static int test__checkevent_symbolic_name_config(struct evlist *evlist) · 4 unmodified lines
183201 TEST_ASSERT_VAL("wrong number of entries", 0 != evlist->core.nr_entries);
184202
185203 perf_evlist__for_each_evsel(&evlist->core, evsel) {
186− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
187− TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
204+ int ret = assert_hw(evsel, PERF_COUNT_HW_CPU_CYCLES, "cycles");
205+
206+ if (ret)
207+ return ret;
188208 /*
189209 * The period value gets configured within evlist__config,
190210 * while this test executes only parse events method.
@@ -861,10 +881,14 @@ static int test__group1(struct evlist *evlist) · 670 unmodified lines
861881 evlist__nr_groups(evlist) == num_core_entries());
862882
863883 for (int i = 0; i < num_core_entries(); i++) {
884+ int ret;
885+
864886 /* instructions:k */
865887 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
866− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
867− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
888+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
889+ if (ret)
890+ return ret;
891+
868892 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
869893 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
870894 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -878,8 +902,10 @@ static int test__group1(struct evlist *evlist) · 7 unmodified lines
878902
879903 /* cycles:upp */
880904 evsel = evsel__next(evsel);
881− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
882− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
905+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
906+ if (ret)
907+ return ret;
908+
883909 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
884910 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
885911 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -907,6 +933,8 @@ static int test__group2(struct evlist *evlist) · 21 unmodified lines
907933 TEST_ASSERT_VAL("wrong number of groups", 1 == evlist__nr_groups(evlist));
908934
909935 evlist__for_each_entry(evlist, evsel) {
936+ int ret;
937+
910938 if (evsel->core.attr.type == PERF_TYPE_SOFTWARE) {
911939 /* faults + :ku modifier */
912940 leader = evsel;
@@ -939,8 +967,10 @@ static int test__group2(struct evlist *evlist) · 26 unmodified lines
939967 continue;
940968 }
941969 /* cycles:k */
942− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
943− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
970+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
971+ if (ret)
972+ return ret;
973+
944974 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
945975 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
946976 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -957,6 +987,7 @@ static int test__group2(struct evlist *evlist) · 10 unmodified lines
957987 static int test__group3(struct evlist *evlist __maybe_unused)
958988 {
959989 struct evsel *evsel, *group1_leader = NULL, *group2_leader = NULL;
990+ int ret;
960991
961992 TEST_ASSERT_VAL("wrong number of entries",
962993 evlist->core.nr_entries == (3 * perf_pmus__num_core_pmus() + 2));
@@ -1045,8 +1076,10 @@ static int test__group3(struct evlist *evlist __maybe_unused) · 82 unmodified lines
10451076 continue;
10461077 }
10471078 /* instructions:u */
1048− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1049− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
1079+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1080+ if (ret)
1081+ return ret;
1082+
10501083 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
10511084 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
10521085 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1070,10 +1103,14 @@ static int test__group4(struct evlist *evlist __maybe_unused) · 17 unmodified lines
10701103 num_core_entries() == evlist__nr_groups(evlist));
10711104
10721105 for (int i = 0; i < num_core_entries(); i++) {
1106+ int ret;
1107+
10731108 /* cycles:u + p */
10741109 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1075− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1076− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1110+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1111+ if (ret)
1112+ return ret;
1113+
10771114 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
10781115 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
10791116 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1089,8 +1126,10 @@ static int test__group4(struct evlist *evlist __maybe_unused) · 9 unmodified lines
10891126
10901127 /* instructions:kp + p */
10911128 evsel = evsel__next(evsel);
1092− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1093− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
1129+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1130+ if (ret)
1131+ return ret;
1132+
10941133 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
10951134 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
10961135 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1108,6 +1147,7 @@ static int test__group4(struct evlist *evlist __maybe_unused) · 11 unmodified lines
11081147 static int test__group5(struct evlist *evlist __maybe_unused)
11091148 {
11101149 struct evsel *evsel = NULL, *leader;
1150+ int ret;
11111151
11121152 TEST_ASSERT_VAL("wrong number of entries",
11131153 evlist->core.nr_entries == (5 * num_core_entries()));
@@ -1117,8 +1157,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) · 3 unmodified lines
11171157 for (int i = 0; i < num_core_entries(); i++) {
11181158 /* cycles + G */
11191159 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1120− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1121− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1160+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1161+ if (ret)
1162+ return ret;
1163+
11221164 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
11231165 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
11241166 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1133,8 +1175,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) · 8 unmodified lines
11331175
11341176 /* instructions + G */
11351177 evsel = evsel__next(evsel);
1136− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1137− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
1178+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1179+ if (ret)
1180+ return ret;
1181+
11381182 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
11391183 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
11401184 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1148,8 +1192,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) · 7 unmodified lines
11481192 for (int i = 0; i < num_core_entries(); i++) {
11491193 /* cycles:G */
11501194 evsel = leader = evsel__next(evsel);
1151− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1152− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1195+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1196+ if (ret)
1197+ return ret;
1198+
11531199 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
11541200 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
11551201 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1164,8 +1210,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) · 8 unmodified lines
11641210
11651211 /* instructions:G */
11661212 evsel = evsel__next(evsel);
1167− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1168− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
1213+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1214+ if (ret)
1215+ return ret;
1216+
11691217 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
11701218 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
11711219 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1178,8 +1226,10 @@ static int test__group5(struct evlist *evlist __maybe_unused) · 6 unmodified lines
11781226 for (int i = 0; i < num_core_entries(); i++) {
11791227 /* cycles */
11801228 evsel = evsel__next(evsel);
1181− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1182− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1229+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1230+ if (ret)
1231+ return ret;
1232+
11831233 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
11841234 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
11851235 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1201,10 +1251,14 @@ static int test__group_gh1(struct evlist *evlist) · 15 unmodified lines
12011251 evlist__nr_groups(evlist) == num_core_entries());
12021252
12031253 for (int i = 0; i < num_core_entries(); i++) {
1254+ int ret;
1255+
12041256 /* cycles + :H group modifier */
12051257 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1206− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1207− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1258+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1259+ if (ret)
1260+ return ret;
1261+
12081262 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
12091263 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
12101264 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1218,8 +1272,10 @@ static int test__group_gh1(struct evlist *evlist) · 7 unmodified lines
12181272
12191273 /* cache-misses:G + :H group modifier */
12201274 evsel = evsel__next(evsel);
1221− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1222− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));
1275+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1276+ if (ret)
1277+ return ret;
1278+
12231279 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
12241280 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
12251281 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1242,10 +1298,14 @@ static int test__group_gh2(struct evlist *evlist) · 16 unmodified lines
12421298 evlist__nr_groups(evlist) == num_core_entries());
12431299
12441300 for (int i = 0; i < num_core_entries(); i++) {
1301+ int ret;
1302+
12451303 /* cycles + :G group modifier */
12461304 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1247− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1248− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1305+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1306+ if (ret)
1307+ return ret;
1308+
12491309 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
12501310 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
12511311 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1259,8 +1319,10 @@ static int test__group_gh2(struct evlist *evlist) · 7 unmodified lines
12591319
12601320 /* cache-misses:H + :G group modifier */
12611321 evsel = evsel__next(evsel);
1262− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1263− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));
1322+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1323+ if (ret)
1324+ return ret;
1325+
12641326 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
12651327 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
12661328 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1283,10 +1345,14 @@ static int test__group_gh3(struct evlist *evlist) · 16 unmodified lines
12831345 evlist__nr_groups(evlist) == num_core_entries());
12841346
12851347 for (int i = 0; i < num_core_entries(); i++) {
1348+ int ret;
1349+
12861350 /* cycles:G + :u group modifier */
12871351 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1288− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1289− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1352+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1353+ if (ret)
1354+ return ret;
1355+
12901356 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
12911357 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
12921358 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1300,8 +1366,10 @@ static int test__group_gh3(struct evlist *evlist) · 7 unmodified lines
13001366
13011367 /* cache-misses:H + :u group modifier */
13021368 evsel = evsel__next(evsel);
1303− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1304− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));
1369+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1370+ if (ret)
1371+ return ret;
1372+
13051373 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
13061374 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
13071375 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1324,10 +1392,14 @@ static int test__group_gh4(struct evlist *evlist) · 16 unmodified lines
13241392 evlist__nr_groups(evlist) == num_core_entries());
13251393
13261394 for (int i = 0; i < num_core_entries(); i++) {
1395+ int ret;
1396+
13271397 /* cycles:G + :uG group modifier */
13281398 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1329− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1330− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1399+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1400+ if (ret)
1401+ return ret;
1402+
13311403 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
13321404 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
13331405 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1341,8 +1413,10 @@ static int test__group_gh4(struct evlist *evlist) · 7 unmodified lines
13411413
13421414 /* cache-misses:H + :uG group modifier */
13431415 evsel = evsel__next(evsel);
1344− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1345− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));
1416+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1417+ if (ret)
1418+ return ret;
1419+
13461420 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
13471421 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
13481422 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1363,10 +1437,14 @@ static int test__leader_sample1(struct evlist *evlist) · 14 unmodified lines
13631437 evlist->core.nr_entries == (3 * num_core_entries()));
13641438
13651439 for (int i = 0; i < num_core_entries(); i++) {
1440+ int ret;
1441+
13661442 /* cycles - sampling group leader */
13671443 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1368− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1369− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1444+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1445+ if (ret)
1446+ return ret;
1447+
13701448 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
13711449 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
13721450 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1379,8 +1457,10 @@ static int test__leader_sample1(struct evlist *evlist) · 6 unmodified lines
13791457
13801458 /* cache-misses - not sampling */
13811459 evsel = evsel__next(evsel);
1382− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1383− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));
1460+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1461+ if (ret)
1462+ return ret;
1463+
13841464 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
13851465 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
13861466 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1392,8 +1472,10 @@ static int test__leader_sample1(struct evlist *evlist) · 5 unmodified lines
13921472
13931473 /* branch-misses - not sampling */
13941474 evsel = evsel__next(evsel);
1395− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1396− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES));
1475+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses");
1476+ if (ret)
1477+ return ret;
1478+
13971479 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
13981480 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel);
13991481 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->core.attr.exclude_hv);
@@ -1415,10 +1497,14 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) · 15 unmodified lines
14151497 evlist->core.nr_entries == (2 * num_core_entries()));
14161498
14171499 for (int i = 0; i < num_core_entries(); i++) {
1500+ int ret;
1501+
14181502 /* instructions - sampling group leader */
14191503 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1420− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1421− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS));
1504+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_INSTRUCTIONS, "instructions");
1505+ if (ret)
1506+ return ret;
1507+
14221508 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
14231509 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
14241510 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1431,8 +1517,10 @@ static int test__leader_sample2(struct evlist *evlist __maybe_unused) · 6 unmodified lines
14311517
14321518 /* branch-misses - not sampling */
14331519 evsel = evsel__next(evsel);
1434− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1435− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES));
1520+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses");
1521+ if (ret)
1522+ return ret;
1523+
14361524 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user);
14371525 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
14381526 TEST_ASSERT_VAL("wrong exclude_hv", evsel->core.attr.exclude_hv);
@@ -1472,10 +1560,14 @@ static int test__pinned_group(struct evlist *evlist) · 33 unmodified lines
14721560 evlist->core.nr_entries == (3 * num_core_entries()));
14731561
14741562 for (int i = 0; i < num_core_entries(); i++) {
1563+ int ret;
1564+
14751565 /* cycles - group leader */
14761566 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1477− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1478− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1567+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1568+ if (ret)
1569+ return ret;
1570+
14791571 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
14801572 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
14811573 /* TODO: The group modifier is not copied to the split group leader. */
@@ -1484,13 +1576,18 @@ static int test__pinned_group(struct evlist *evlist) · 2 unmodified lines
14841576
14851577 /* cache-misses - can not be pinned, but will go on with the leader */
14861578 evsel = evsel__next(evsel);
1487− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1488− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));
1579+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1580+ if (ret)
1581+ return ret;
1582+
14891583 TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned);
14901584
14911585 /* branch-misses - ditto */
14921586 evsel = evsel__next(evsel);
1493− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES));
1587+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses");
1588+ if (ret)
1589+ return ret;
1590+
14941591 TEST_ASSERT_VAL("wrong pinned", !evsel->core.attr.pinned);
14951592 }
14961593 return TEST_OK;
@@ -1517,10 +1614,14 @@ static int test__exclusive_group(struct evlist *evlist) · 20 unmodified lines
15171614 evlist->core.nr_entries == 3 * num_core_entries());
15181615
15191616 for (int i = 0; i < num_core_entries(); i++) {
1617+ int ret;
1618+
15201619 /* cycles - group leader */
15211620 evsel = leader = (i == 0 ? evlist__first(evlist) : evsel__next(evsel));
1522− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1523− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
1621+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1622+ if (ret)
1623+ return ret;
1624+
15241625 TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
15251626 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader));
15261627 /* TODO: The group modifier is not copied to the split group leader. */
@@ -1529,13 +1630,18 @@ static int test__exclusive_group(struct evlist *evlist) · 2 unmodified lines
15291630
15301631 /* cache-misses - can not be pinned, but will go on with the leader */
15311632 evsel = evsel__next(evsel);
1532− TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type);
1533− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CACHE_MISSES));
1633+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_CACHE_MISSES, "cache-misses");
1634+ if (ret)
1635+ return ret;
1636+
15341637 TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive);
15351638
15361639 /* branch-misses - ditto */
15371640 evsel = evsel__next(evsel);
1538− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_BRANCH_MISSES));
1641+ ret = assert_hw(&evsel->core, PERF_COUNT_HW_BRANCH_MISSES, "branch-misses");
1642+ if (ret)
1643+ return ret;
1644+
15391645 TEST_ASSERT_VAL("wrong exclusive", !evsel->core.attr.exclusive);
15401646 }
15411647 return TEST_OK;
@@ -1677,9 +1783,11 @@ static int test__checkevent_raw_pmu(struct evlist *evlist) · 135 unmodified lines
16771783 static int test__sym_event_slash(struct evlist *evlist)
16781784 {
16791785 struct evsel *evsel = evlist__first(evlist);
1786+ int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1787+
1788+ if (ret)
1789+ return ret;
16801790
1681− TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE);
1682− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
16831791 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel);
16841792 return TEST_OK;
16851793 }
@@ -1687,9 +1795,11 @@ static int test__sym_event_slash(struct evlist *evlist) · 1 unmodified line
16871795 static int test__sym_event_dc(struct evlist *evlist)
16881796 {
16891797 struct evsel *evsel = evlist__first(evlist);
1798+ int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1799+
1800+ if (ret)
1801+ return ret;
16901802
1691− TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE);
1692− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
16931803 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user);
16941804 return TEST_OK;
16951805 }
@@ -1697,9 +1807,11 @@ static int test__sym_event_dc(struct evlist *evlist) · 1 unmodified line
16971807 static int test__term_equal_term(struct evlist *evlist)
16981808 {
16991809 struct evsel *evsel = evlist__first(evlist);
1810+ int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1811+
1812+ if (ret)
1813+ return ret;
17001814
1701− TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE);
1702− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
17031815 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "name") == 0);
17041816 return TEST_OK;
17051817 }
@@ -1707,9 +1819,11 @@ static int test__term_equal_term(struct evlist *evlist) · 1 unmodified line
17071819 static int test__term_equal_legacy(struct evlist *evlist)
17081820 {
17091821 struct evsel *evsel = evlist__first(evlist);
1822+ int ret = assert_hw(&evsel->core, PERF_COUNT_HW_CPU_CYCLES, "cycles");
1823+
1824+ if (ret)
1825+ return ret;
17101826
1711− TEST_ASSERT_VAL("wrong type", evsel->core.attr.type == PERF_TYPE_HARDWARE);
1712− TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES));
17131827 TEST_ASSERT_VAL("wrong name setting", strcmp(evsel->name, "l1d") == 0);
17141828 return TEST_OK;
17151829 }
@@ -2549,7 +2663,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest · 833 unmodified lines
25492663 if (strchr(ent->d_name, '.'))
25502664 continue;
25512665
2552− /* exclude parametrized ones (name contains '?') */
2666+ /* exclude parameterized ones (name contains '?') */
25532667 n = snprintf(pmu_event, sizeof(pmu_event), "%s%s", path, ent->d_name);
25542668 if (n >= PATH_MAX) {
25552669 pr_err("pmu event name crossed PATH_MAX(%d) size\n", PATH_MAX);
@@ -2578,7 +2692,7 @@ static int test__pmu_events(struct test_suite *test __maybe_unused, int subtest · 22 unmodified lines
25782692 fclose(file);
25792693
25802694 if (is_event_parameterized == 1) {
2581− pr_debug("skipping parametrized PMU event: %s which contains ?\n", pmu_event);
2695+ pr_debug("skipping parameterized PMU event: %s which contains ?\n", pmu_event);
25822696 continue;
25832697 }
25842698
tools/perf/tests/perf-time-to-tsc.c+1−1
@@ -93,7 +93,7 @@ static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int su · 92 unmodified lines
9393 threads = thread_map__new(-1, getpid(), UINT_MAX);
9494 CHECK_NOT_NULL__(threads);
9595
96− cpus = perf_cpu_map__new(NULL);
96+ cpus = perf_cpu_map__new_online_cpus();
9797 CHECK_NOT_NULL__(cpus);
9898
9999 evlist = evlist__new();
tools/perf/tests/shell/coresight/memcpy_thread/memcpy_thread.c+0−1
@@ -42,7 +42,6 @@ static pthread_t new_thr(void *(*fn) (void *arg), void *arg) · 41 unmodified lines
4242 int main(int argc, char **argv)
4343 {
4444 unsigned long i, len, size, thr;
45− pthread_t threads[256];
4645 struct args args[256];
4746 long long v;
4847
tools/perf/tests/shell/coresight/thread_loop/thread_loop.c+0−1
@@ -57,7 +57,6 @@ static pthread_t new_thr(void *(*fn) (void *arg), void *arg) · 56 unmodified lines
5757 int main(int argc, char **argv)
5858 {
5959 unsigned int i, len, thr;
60− pthread_t threads[256];
6160 struct args args[256];
6261
6362 if (argc < 3) {
tools/perf/tests/shell/coresight/unroll_loop_thread/unroll_loop_thread.c+0−1
@@ -51,7 +51,6 @@ static pthread_t new_thr(void *(*fn) (void *arg), void *arg) · 50 unmodified lines
5151 int main(int argc, char **argv)
5252 {
5353 unsigned int i, thr;
54− pthread_t threads[256];
5554 struct args args[256];
5655
5756 if (argc < 2) {
tools/perf/tests/shell/diff.sh+108−0
@@ -0,0 +1,108 @@
1+#!/bin/sh
2+# perf diff tests
3+# SPDX-License-Identifier: GPL-2.0
4+
5+set -e
6+
7+err=0
8+perfdata1=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
9+perfdata2=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
10+perfdata3=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
11+testprog="perf test -w thloop"
12+
13+shelldir=$(dirname "$0")
14+# shellcheck source=lib/perf_has_symbol.sh
15+. "${shelldir}"/lib/perf_has_symbol.sh
16+
17+testsym="test_loop"
18+
19+skip_test_missing_symbol ${testsym}
20+
21+cleanup() {
22+ rm -rf "${perfdata1}"
23+ rm -rf "${perfdata1}".old
24+ rm -rf "${perfdata2}"
25+ rm -rf "${perfdata2}".old
26+ rm -rf "${perfdata3}"
27+ rm -rf "${perfdata3}".old
28+
29+ trap - EXIT TERM INT
30+}
31+
32+trap_cleanup() {
33+ cleanup
34+ exit 1
35+}
36+trap trap_cleanup EXIT TERM INT
37+
38+make_data() {
39+ file="$1"
40+ if ! perf record -o "${file}" ${testprog} 2> /dev/null
41+ then
42+ echo "Workload record [Failed record]"
43+ echo 1
44+ return
45+ fi
46+ if ! perf report -i "${file}" -q | grep -q "${testsym}"
47+ then
48+ echo "Workload record [Failed missing output]"
49+ echo 1
50+ return
51+ fi
52+ echo 0
53+}
54+
55+test_two_files() {
56+ echo "Basic two file diff test"
57+ err=$(make_data "${perfdata1}")
58+ if [ $err != 0 ]
59+ then
60+ return
61+ fi
62+ err=$(make_data "${perfdata2}")
63+ if [ $err != 0 ]
64+ then
65+ return
66+ fi
67+
68+ if ! perf diff "${perfdata1}" "${perfdata2}" | grep -q "${testsym}"
69+ then
70+ echo "Basic two file diff test [Failed diff]"
71+ err=1
72+ return
73+ fi
74+ echo "Basic two file diff test [Success]"
75+}
76+
77+test_three_files() {
78+ echo "Basic three file diff test"
79+ err=$(make_data "${perfdata1}")
80+ if [ $err != 0 ]
81+ then
82+ return
83+ fi
84+ err=$(make_data "${perfdata2}")
85+ if [ $err != 0 ]
86+ then
87+ return
88+ fi
89+ err=$(make_data "${perfdata3}")
90+ if [ $err != 0 ]
91+ then
92+ return
93+ fi
94+
95+ if ! perf diff "${perfdata1}" "${perfdata2}" "${perfdata3}" | grep -q "${testsym}"
96+ then
97+ echo "Basic three file diff test [Failed diff]"
98+ err=1
99+ return
100+ fi
101+ echo "Basic three file diff test [Success]"
102+}
103+
104+test_two_files
105+test_three_files
106+
107+cleanup
108+exit $err
tools/perf/tests/shell/lib/perf_has_symbol.sh+21−0
@@ -0,0 +1,21 @@
1+#!/bin/sh
2+# SPDX-License-Identifier: GPL-2.0
3+
4+perf_has_symbol()
5+{
6+ if perf test -vv "Symbols" 2>&1 | grep "[[:space:]]$1$"; then
7+ echo "perf does have symbol '$1'"
8+ return 0
9+ fi
10+ echo "perf does not have symbol '$1'"
11+ return 1
12+}
13+
14+skip_test_missing_symbol()
15+{
16+ if ! perf_has_symbol "$1" ; then
17+ echo "perf is missing symbols - skipping test"
18+ exit 2
19+ fi
20+ return 0
21+}
tools/perf/tests/shell/lib/setup_python.sh+16−0
@@ -0,0 +1,16 @@
1+#!/bin/sh
2+# SPDX-License-Identifier: GPL-2.0
3+
4+if [ "x$PYTHON" = "x" ]
5+then
6+ python3 --version >/dev/null 2>&1 && PYTHON=python3
7+fi
8+if [ "x$PYTHON" = "x" ]
9+then
10+ python --version >/dev/null 2>&1 && PYTHON=python
11+fi
12+if [ "x$PYTHON" = "x" ]
13+then
14+ echo Skipping test, python not detected please set environment variable PYTHON.
15+ exit 2
16+fi
tools/perf/tests/shell/list.sh+19−0
@@ -0,0 +1,19 @@
1+#!/bin/sh
2+# perf list tests
3+# SPDX-License-Identifier: GPL-2.0
4+
5+set -e
6+err=0
7+
8+shelldir=$(dirname "$0")
9+# shellcheck source=lib/setup_python.sh
10+. "${shelldir}"/lib/setup_python.sh
11+
12+test_list_json() {
13+ echo "Json output test"
14+ perf list -j | $PYTHON -m json.tool
15+ echo "Json output test [Success]"
16+}
17+
18+test_list_json
19+exit $err
tools/perf/tests/shell/pipe_test.sh+8−1
@@ -2,10 +2,17 @@ · 1 unmodified line
22 # perf pipe recording and injection test
33 # SPDX-License-Identifier: GPL-2.0
44
5+shelldir=$(dirname "$0")
6+# shellcheck source=lib/perf_has_symbol.sh
7+. "${shelldir}"/lib/perf_has_symbol.sh
8+
9+sym="noploop"
10+
11+skip_test_missing_symbol ${sym}
12+
513 data=$(mktemp /tmp/perf.data.XXXXXX)
614 prog="perf test -w noploop"
715 task="perf"
8−sym="noploop"
916
1017 if ! perf record -e task-clock:u -o - ${prog} | perf report -i - --task | grep ${task}; then
1118 echo "cannot find the test file in the perf report"
tools/perf/tests/shell/record+probe_libc_inet_pton.sh+4−1
@@ -45,7 +45,10 @@ trace_libc_inet_pton_backtrace() { · 44 unmodified lines
4545 ;;
4646 ppc64|ppc64le)
4747 eventattr='max-stack=4'
48− echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected
48+ # Add gaih_inet to expected backtrace only if it is part of libc.
49+ if nm $libc | grep -F -q gaih_inet.; then
50+ echo "gaih_inet.*\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected
51+ fi
4952 echo "getaddrinfo\+0x[[:xdigit:]]+[[:space:]]\($libc\)$" >> $expected
5053 echo ".*(\+0x[[:xdigit:]]+|\[unknown\])[[:space:]]\(.*/bin/ping.*\)$" >> $expected
5154 ;;
tools/perf/tests/shell/record.sh+37−1
@@ -8,10 +8,19 @@ shelldir=$(dirname "$0") · 7 unmodified lines
88 # shellcheck source=lib/waiting.sh
99 . "${shelldir}"/lib/waiting.sh
1010
11+# shellcheck source=lib/perf_has_symbol.sh
12+. "${shelldir}"/lib/perf_has_symbol.sh
13+
14+testsym="test_loop"
15+
16+skip_test_missing_symbol ${testsym}
17+
1118 err=0
1219 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
1320 testprog="perf test -w thloop"
14−testsym="test_loop"
21+cpu_pmu_dir="/sys/bus/event_source/devices/cpu*"
22+br_cntr_file="/caps/branch_counter_nr"
23+br_cntr_output="branch stack counters"
1524
1625 cleanup() {
1726 rm -rf "${perfdata}"
@@ -155,10 +164,37 @@ test_workload() { · 137 unmodified lines
155164 echo "Basic target workload test [Success]"
156165 }
157166
167+test_branch_counter() {
168+ echo "Basic branch counter test"
169+ # Check if the branch counter feature is supported
170+ for dir in $cpu_pmu_dir
171+ do
172+ if [ ! -e "$dir$br_cntr_file" ]
173+ then
174+ echo "branch counter feature not supported on all core PMUs ($dir) [Skipped]"
175+ return
176+ fi
177+ done
178+ if ! perf record -o "${perfdata}" -j any,counter ${testprog} 2> /dev/null
179+ then
180+ echo "Basic branch counter test [Failed record]"
181+ err=1
182+ return
183+ fi
184+ if ! perf report -i "${perfdata}" -D -q | grep -q "$br_cntr_output"
185+ then
186+ echo "Basic branch record test [Failed missing output]"
187+ err=1
188+ return
189+ fi
190+ echo "Basic branch counter test [Success]"
191+}
192+
158193 test_per_thread
159194 test_register_capture
160195 test_system_wide
161196 test_workload
197+test_branch_counter
162198
163199 cleanup
164200 exit $err
tools/perf/tests/shell/record_offcpu.sh+2−2
@@ -77,9 +77,9 @@ test_offcpu_child() { · 76 unmodified lines
7777 err=1
7878 return
7979 fi
80− # each process waits for read and write, so it should be more than 800 events
80+ # each process waits at least for poll, so it should be more than 400 events
8181 if ! perf report -i ${perfdata} -s comm -q -n -t ';' --percent-limit=90 | \
82− awk -F ";" '{ if (NF > 3 && int($3) < 800) exit 1; }'
82+ awk -F ";" '{ if (NF > 3 && int($3) < 400) exit 1; }'
8383 then
8484 echo "Child task off-cpu test [Failed invalid output]"
8585 err=1
tools/perf/tests/shell/script.sh+66−0
@@ -0,0 +1,66 @@
1+#!/bin/sh
2+# perf script tests
3+# SPDX-License-Identifier: GPL-2.0
4+
5+set -e
6+
7+temp_dir=$(mktemp -d /tmp/perf-test-script.XXXXXXXXXX)
8+
9+perfdatafile="${temp_dir}/perf.data"
10+db_test="${temp_dir}/db_test.py"
11+
12+err=0
13+
14+cleanup()
15+{
16+ trap - EXIT TERM INT
17+ sane=$(echo "${temp_dir}" | cut -b 1-21)
18+ if [ "${sane}" = "/tmp/perf-test-script" ] ; then
19+ echo "--- Cleaning up ---"
20+ rm -f "${temp_dir}/"*
21+ rmdir "${temp_dir}"
22+ fi
23+}
24+
25+trap_cleanup()
26+{
27+ cleanup
28+ exit 1
29+}
30+
31+trap trap_cleanup EXIT TERM INT
32+
33+
34+test_db()
35+{
36+ echo "DB test"
37+
38+ # Check if python script is supported
39+ libpython=$(perf version --build-options | grep python | grep -cv OFF)
40+ if [ "${libpython}" != "1" ] ; then
41+ echo "SKIP: python scripting is not supported"
42+ err=2
43+ return
44+ fi
45+
46+ cat << "_end_of_file_" > "${db_test}"
47+perf_db_export_mode = True
48+perf_db_export_calls = False
49+perf_db_export_callchains = True
50+
51+def sample_table(*args):
52+ print(f'sample_table({args})')
53+
54+def call_path_table(*args):
55+ print(f'call_path_table({args}')
56+_end_of_file_
57+ perf record -g -o "${perfdatafile}" true
58+ perf script -i "${perfdatafile}" -s "${db_test}"
59+ echo "DB test [Success]"
60+}
61+
62+test_db
63+
64+cleanup
65+
66+exit $err
tools/perf/tests/shell/stat+json_output.sh+3−13
@@ -8,20 +8,10 @@ set -e · 7 unmodified lines
88
99 skip_test=0
1010
11+shelldir=$(dirname "$0")
12+# shellcheck source=lib/setup_python.sh
13+. "${shelldir}"/lib/setup_python.sh
1114 pythonchecker=$(dirname $0)/lib/perf_json_output_lint.py
12−if [ "x$PYTHON" == "x" ]
13−then
14− if which python3 > /dev/null
15− then
16− PYTHON=python3
17− elif which python > /dev/null
18− then
19− PYTHON=python
20− else
21− echo Skipping test, python not detected please set environment variable PYTHON.
22− exit 2
23− fi
24−fi
2515
2616 stat_output=$(mktemp /tmp/__perf_test.stat_output.json.XXXXX)
2717
tools/perf/tests/shell/stat_all_pmu.sh+1−1
@@ -4,7 +4,7 @@ · 3 unmodified lines
44
55 set -e
66
7−# Test all PMU events; however exclude parametrized ones (name contains '?')
7+# Test all PMU events; however exclude parameterized ones (name contains '?')
88 for p in $(perf list --raw-dump pmu | sed 's/[[:graph:]]\+?[[:graph:]]\+[[:space:]]//g'); do
99 echo "Testing $p"
1010 result=$(perf stat -e "$p" true 2>&1)
tools/perf/tests/shell/stat_metrics_values.sh+4−10
@@ -1,16 +1,10 @@
11 #!/bin/bash
22 # perf metrics value validation
33 # SPDX-License-Identifier: GPL-2.0
4−if [ "x$PYTHON" == "x" ]
5−then
6− if which python3 > /dev/null
7− then
8− PYTHON=python3
9− else
10− echo Skipping test, python3 not detected please set environment variable PYTHON.
11− exit 2
12− fi
13−fi
4+
5+shelldir=$(dirname "$0")
6+# shellcheck source=lib/setup_python.sh
7+. "${shelldir}"/lib/setup_python.sh
148
159 grep -q GenuineIntel /proc/cpuinfo || { echo Skipping non-Intel; exit 2; }
1610
tools/perf/tests/shell/test_arm_callgraph_fp.sh+6−0
@@ -2,8 +2,14 @@ · 1 unmodified line
22 # Check Arm64 callgraphs are complete in fp mode
33 # SPDX-License-Identifier: GPL-2.0
44
5+shelldir=$(dirname "$0")
6+# shellcheck source=lib/perf_has_symbol.sh
7+. "${shelldir}"/lib/perf_has_symbol.sh
8+
59 lscpu | grep -q "aarch64" || exit 2
610
11+skip_test_missing_symbol leafloop
12+
713 PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
814 TEST_PROGRAM="perf test -w leafloop"
915
tools/perf/tests/shell/test_brstack.sh+6−0
@@ -4,6 +4,10 @@ · 3 unmodified lines
44 # SPDX-License-Identifier: GPL-2.0
55 # German Gomez <german.gomez@arm.com>, 2022
66
7+shelldir=$(dirname "$0")
8+# shellcheck source=lib/perf_has_symbol.sh
9+. "${shelldir}"/lib/perf_has_symbol.sh
10+
711 # skip the test if the hardware doesn't support branch stack sampling
812 # and if the architecture doesn't support filter types: any,save_type,u
913 if ! perf record -o- --no-buildid --branch-filter any,save_type,u -- true > /dev/null 2>&1 ; then
@@ -11,6 +15,8 @@ if ! perf record -o- --no-buildid --branch-filter any,save_type,u -- true > /dev · 1 unmodified line
1115 exit 2
1216 fi
1317
18+skip_test_missing_symbol brstack_bench
19+
1420 TMPDIR=$(mktemp -d /tmp/__perf_test.program.XXXXX)
1521 TESTPROG="perf test -w brstack"
1622
tools/perf/tests/shell/test_data_symbol.sh+14−2
@@ -4,6 +4,13 @@ · 3 unmodified lines
44 # SPDX-License-Identifier: GPL-2.0
55 # Leo Yan <leo.yan@linaro.org>, 2022
66
7+shelldir=$(dirname "$0")
8+# shellcheck source=lib/waiting.sh
9+. "${shelldir}"/lib/waiting.sh
10+
11+# shellcheck source=lib/perf_has_symbol.sh
12+. "${shelldir}"/lib/perf_has_symbol.sh
13+
714 skip_if_no_mem_event() {
815 perf mem record -e list 2>&1 | grep -E -q 'available' && return 0
916 return 2
@@ -11,8 +18,11 @@ skip_if_no_mem_event() { · 1 unmodified line
1118
1219 skip_if_no_mem_event || exit 2
1320
21+skip_test_missing_symbol buf1
22+
1423 TEST_PROGRAM="perf test -w datasym"
1524 PERF_DATA=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
25+ERR_FILE=$(mktemp /tmp/__perf_test.stderr.XXXXX)
1626
1727 check_result() {
1828 # The memory report format is as below:
@@ -50,13 +60,15 @@ echo "Recording workload..." · 31 unmodified lines
5060 # specific CPU and test in per-CPU mode.
5161 is_amd=$(grep -E -c 'vendor_id.*AuthenticAMD' /proc/cpuinfo)
5262 if (($is_amd >= 1)); then
53− perf mem record -o ${PERF_DATA} -C 0 -- taskset -c 0 $TEST_PROGRAM &
63+ perf mem record -vvv -o ${PERF_DATA} -C 0 -- taskset -c 0 $TEST_PROGRAM 2>"${ERR_FILE}" &
5464 else
55− perf mem record --all-user -o ${PERF_DATA} -- $TEST_PROGRAM &
65+ perf mem record -vvv --all-user -o ${PERF_DATA} -- $TEST_PROGRAM 2>"${ERR_FILE}" &
5666 fi
5767
5868 PERFPID=$!
5969
70+wait_for_perf_to_start ${PERFPID} "${ERR_FILE}"
71+
6072 sleep 1
6173
6274 kill $PERFPID
tools/perf/tests/shell/test_perf_data_converter_json.sh+3−10
@@ -6,16 +6,9 @@ set -e · 5 unmodified lines
66
77 err=0
88
9−if [ "$PYTHON" = "" ] ; then
10− if which python3 > /dev/null ; then
11− PYTHON=python3
12− elif which python > /dev/null ; then
13− PYTHON=python
14− else
15− echo Skipping test, python not detected please set environment variable PYTHON.
16− exit 2
17− fi
18−fi
9+shelldir=$(dirname "$0")
10+# shellcheck source=lib/setup_python.sh
11+. "${shelldir}"/lib/setup_python.sh
1912
2013 perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
2114 result=$(mktemp /tmp/__perf_test.output.json.XXXXX)
tools/perf/tests/sigtrap.c+84−22
@@ -57,36 +57,79 @@ static struct perf_event_attr make_event_attr(void) · 56 unmodified lines
5757 #ifdef HAVE_BPF_SKEL
5858 #include <bpf/btf.h>
5959
60−static bool attr_has_sigtrap(void)
60+static struct btf *btf;
61+
62+static bool btf__available(void)
6163 {
62− bool ret = false;
63− struct btf *btf;
64− const struct btf_type *t;
64+ if (btf == NULL)
65+ btf = btf__load_vmlinux_btf();
66+
67+ return btf != NULL;
68+}
69+
70+static void btf__exit(void)
71+{
72+ btf__free(btf);
73+ btf = NULL;
74+}
75+
76+static const struct btf_member *__btf_type__find_member_by_name(int type_id, const char *member_name)
77+{
78+ const struct btf_type *t = btf__type_by_id(btf, type_id);
6579 const struct btf_member *m;
66− const char *name;
67− int i, id;
80+ int i;
81+
82+ for (i = 0, m = btf_members(t); i < btf_vlen(t); i++, m++) {
83+ const char *current_member_name = btf__name_by_offset(btf, m->name_off);
84+ if (!strcmp(current_member_name, member_name))
85+ return m;
86+ }
6887
69− btf = btf__load_vmlinux_btf();
70− if (btf == NULL) {
88+ return NULL;
89+}
90+
91+static bool attr_has_sigtrap(void)
92+{
93+ int id;
94+
95+ if (!btf__available()) {
7196 /* should be an old kernel */
7297 return false;
7398 }
7499
75100 id = btf__find_by_name_kind(btf, "perf_event_attr", BTF_KIND_STRUCT);
76101 if (id < 0)
77− goto out;
102+ return false;
78103
79− t = btf__type_by_id(btf, id);
80− for (i = 0, m = btf_members(t); i < btf_vlen(t); i++, m++) {
81− name = btf__name_by_offset(btf, m->name_off);
82− if (!strcmp(name, "sigtrap")) {
83− ret = true;
84− break;
85− }
86− }
87−out:
88− btf__free(btf);
89− return ret;
104+ return __btf_type__find_member_by_name(id, "sigtrap") != NULL;
105+}
106+
107+static bool kernel_with_sleepable_spinlocks(void)
108+{
109+ const struct btf_member *member;
110+ const struct btf_type *type;
111+ const char *type_name;
112+ int id;
113+
114+ if (!btf__available())
115+ return false;
116+
117+ id = btf__find_by_name_kind(btf, "spinlock", BTF_KIND_STRUCT);
118+ if (id < 0)
119+ return false;
120+
121+ // Only RT has a "lock" member for "struct spinlock"
122+ member = __btf_type__find_member_by_name(id, "lock");
123+ if (member == NULL)
124+ return false;
125+
126+ // But check its type as well
127+ type = btf__type_by_id(btf, member->type);
128+ if (!type || !btf_is_struct(type))
129+ return false;
130+
131+ type_name = btf__name_by_offset(btf, type->name_off);
132+ return type_name && !strcmp(type_name, "rt_mutex_base");
90133 }
91134 #else /* !HAVE_BPF_SKEL */
92135 static bool attr_has_sigtrap(void)
@@ -109,6 +152,15 @@ static bool attr_has_sigtrap(void) · 16 unmodified lines
109152
110153 return ret;
111154 }
155+
156+static bool kernel_with_sleepable_spinlocks(void)
157+{
158+ return false;
159+}
160+
161+static void btf__exit(void)
162+{
163+}
112164 #endif /* HAVE_BPF_SKEL */
113165
114166 static void
@@ -147,7 +199,7 @@ static int run_test_threads(pthread_t *threads, pthread_barrier_t *barrier) · 32 unmodified lines
147199
148200 static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrier)
149201 {
150− int ret;
202+ int ret, expected_sigtraps;
151203
152204 ctx.iterate_on = 3000;
153205
@@ -156,7 +208,16 @@ static int run_stress_test(int fd, pthread_t *threads, pthread_barrier_t *barrie · 2 unmodified lines
156208 ret = run_test_threads(threads, barrier);
157209 TEST_ASSERT_EQUAL("disable failed", ioctl(fd, PERF_EVENT_IOC_DISABLE, 0), 0);
158210
159− TEST_ASSERT_EQUAL("unexpected sigtraps", ctx.signal_count, NUM_THREADS * ctx.iterate_on);
211+ expected_sigtraps = NUM_THREADS * ctx.iterate_on;
212+
213+ if (ctx.signal_count < expected_sigtraps && kernel_with_sleepable_spinlocks()) {
214+ pr_debug("Expected %d sigtraps, got %d, running on a kernel with sleepable spinlocks.\n",
215+ expected_sigtraps, ctx.signal_count);
216+ pr_debug("See https://lore.kernel.org/all/e368f2c848d77fbc8d259f44e2055fe469c219cf.camel@gmx.de/\n");
217+ return TEST_SKIP;
218+ } else
219+ TEST_ASSERT_EQUAL("unexpected sigtraps", ctx.signal_count, expected_sigtraps);
220+
160221 TEST_ASSERT_EQUAL("missing signals or incorrectly delivered", ctx.tids_want_signal, 0);
161222 TEST_ASSERT_VAL("unexpected si_addr", ctx.first_siginfo.si_addr == &ctx.iterate_on);
162223 #if 0 /* FIXME: enable when libc's signal.h has si_perf_{type,data} */
@@ -221,6 +282,7 @@ out_restore_sigaction: · 58 unmodified lines
221282 sigaction(SIGTRAP, &oldact, NULL);
222283 out:
223284 pthread_barrier_destroy(&barrier);
285+ btf__exit();
224286 return ret;
225287 }
226288
tools/perf/tests/sw-clock.c+1−1
@@ -62,7 +62,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) · 61 unmodified lines
6262 }
6363 evlist__add(evlist, evsel);
6464
65− cpus = perf_cpu_map__dummy_new();
65+ cpus = perf_cpu_map__new_any_cpu();
6666 threads = thread_map__new_by_tid(getpid());
6767 if (!cpus || !threads) {
6868 err = -ENOMEM;
tools/perf/tests/switch-tracking.c+1−1
@@ -351,7 +351,7 @@ static int test__switch_tracking(struct test_suite *test __maybe_unused, int sub · 350 unmodified lines
351351 goto out_err;
352352 }
353353
354− cpus = perf_cpu_map__new(NULL);
354+ cpus = perf_cpu_map__new_online_cpus();
355355 if (!cpus) {
356356 pr_debug("perf_cpu_map__new failed!\n");
357357 goto out_err;
tools/perf/tests/task-exit.c+1−1
@@ -70,7 +70,7 @@ static int test__task_exit(struct test_suite *test __maybe_unused, int subtest _ · 69 unmodified lines
7070 * evlist__prepare_workload we'll fill in the only thread
7171 * we're monitoring, the one forked there.
7272 */
73− cpus = perf_cpu_map__dummy_new();
73+ cpus = perf_cpu_map__new_any_cpu();
7474 threads = thread_map__new_by_tid(-1);
7575 if (!cpus || !threads) {
7676 err = -ENOMEM;
tools/perf/tests/tests.h+1−0
@@ -207,5 +207,6 @@ DECLARE_WORKLOAD(brstack); · 206 unmodified lines
207207 DECLARE_WORKLOAD(datasym);
208208
209209 extern const char *dso_to_test;
210+extern const char *test_objdump_path;
210211
211212 #endif /* TESTS_H */
tools/perf/tests/topology.c+1−1
@@ -215,7 +215,7 @@ static int test__session_topology(struct test_suite *test __maybe_unused, int su · 214 unmodified lines
215215 if (session_write_header(path))
216216 goto free_path;
217217
218− map = perf_cpu_map__new(NULL);
218+ map = perf_cpu_map__new_online_cpus();
219219 if (map == NULL) {
220220 pr_debug("failed to get system cpumap\n");
221221 goto free_path;
tools/perf/tests/vmlinux-kallsyms.c+98−83
@@ -112,18 +112,92 @@ static bool is_ignored_symbol(const char *name, char type) · 111 unmodified lines
112112 return false;
113113 }
114114
115+struct test__vmlinux_matches_kallsyms_cb_args {
116+ struct machine kallsyms;
117+ struct map *vmlinux_map;
118+ bool header_printed;
119+};
120+
121+static int test__vmlinux_matches_kallsyms_cb1(struct map *map, void *data)
122+{
123+ struct test__vmlinux_matches_kallsyms_cb_args *args = data;
124+ struct dso *dso = map__dso(map);
125+ /*
126+ * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
127+ * the kernel will have the path for the vmlinux file being used, so use
128+ * the short name, less descriptive but the same ("[kernel]" in both
129+ * cases.
130+ */
131+ struct map *pair = maps__find_by_name(args->kallsyms.kmaps,
132+ (dso->kernel ? dso->short_name : dso->name));
133+
134+ if (pair)
135+ map__set_priv(pair, 1);
136+ else {
137+ if (!args->header_printed) {
138+ pr_info("WARN: Maps only in vmlinux:\n");
139+ args->header_printed = true;
140+ }
141+ map__fprintf(map, stderr);
142+ }
143+ return 0;
144+}
145+
146+static int test__vmlinux_matches_kallsyms_cb2(struct map *map, void *data)
147+{
148+ struct test__vmlinux_matches_kallsyms_cb_args *args = data;
149+ struct map *pair;
150+ u64 mem_start = map__unmap_ip(args->vmlinux_map, map__start(map));
151+ u64 mem_end = map__unmap_ip(args->vmlinux_map, map__end(map));
152+
153+ pair = maps__find(args->kallsyms.kmaps, mem_start);
154+ if (pair == NULL || map__priv(pair))
155+ return 0;
156+
157+ if (map__start(pair) == mem_start) {
158+ struct dso *dso = map__dso(map);
159+
160+ if (!args->header_printed) {
161+ pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n");
162+ args->header_printed = true;
163+ }
164+
165+ pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
166+ map__start(map), map__end(map), map__pgoff(map), dso->name);
167+ if (mem_end != map__end(pair))
168+ pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64,
169+ map__start(pair), map__end(pair), map__pgoff(pair));
170+ pr_info(" %s\n", dso->name);
171+ map__set_priv(pair, 1);
172+ }
173+ return 0;
174+}
175+
176+static int test__vmlinux_matches_kallsyms_cb3(struct map *map, void *data)
177+{
178+ struct test__vmlinux_matches_kallsyms_cb_args *args = data;
179+
180+ if (!map__priv(map)) {
181+ if (!args->header_printed) {
182+ pr_info("WARN: Maps only in kallsyms:\n");
183+ args->header_printed = true;
184+ }
185+ map__fprintf(map, stderr);
186+ }
187+ return 0;
188+}
189+
115190 static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused,
116191 int subtest __maybe_unused)
117192 {
118193 int err = TEST_FAIL;
119194 struct rb_node *nd;
120195 struct symbol *sym;
121− struct map *kallsyms_map, *vmlinux_map;
122− struct map_rb_node *rb_node;
123− struct machine kallsyms, vmlinux;
196+ struct map *kallsyms_map;
197+ struct machine vmlinux;
124198 struct maps *maps;
125199 u64 mem_start, mem_end;
126− bool header_printed;
200+ struct test__vmlinux_matches_kallsyms_cb_args args;
127201
128202 /*
129203 * Step 1:
@@ -131,7 +205,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 1 unmodified line
131205 * Init the machines that will hold kernel, modules obtained from
132206 * both vmlinux + .ko files and from /proc/kallsyms split by modules.
133207 */
134− machine__init(&kallsyms, "", HOST_KERNEL_ID);
208+ machine__init(&args.kallsyms, "", HOST_KERNEL_ID);
135209 machine__init(&vmlinux, "", HOST_KERNEL_ID);
136210
137211 maps = machine__kernel_maps(&vmlinux);
@@ -143,7 +217,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 5 unmodified lines
143217 * load /proc/kallsyms. Also create the modules maps from /proc/modules
144218 * and find the .ko files that match them in /lib/modules/`uname -r`/.
145219 */
146− if (machine__create_kernel_maps(&kallsyms) < 0) {
220+ if (machine__create_kernel_maps(&args.kallsyms) < 0) {
147221 pr_debug("machine__create_kernel_maps failed");
148222 err = TEST_SKIP;
149223 goto out;
@@ -160,7 +234,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 10 unmodified lines
160234 * be compacted against the list of modules found in the "vmlinux"
161235 * code and with the one got from /proc/modules from the "kallsyms" code.
162236 */
163− if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms") <= 0) {
237+ if (machine__load_kallsyms(&args.kallsyms, "/proc/kallsyms") <= 0) {
164238 pr_debug("machine__load_kallsyms failed");
165239 err = TEST_SKIP;
166240 goto out;
@@ -174,7 +248,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 7 unmodified lines
174248 * to see if the running kernel was relocated by checking if it has the
175249 * same value in the vmlinux file we load.
176250 */
177− kallsyms_map = machine__kernel_map(&kallsyms);
251+ kallsyms_map = machine__kernel_map(&args.kallsyms);
178252
179253 /*
180254 * Step 5:
@@ -186,7 +260,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 5 unmodified lines
186260 goto out;
187261 }
188262
189− vmlinux_map = machine__kernel_map(&vmlinux);
263+ args.vmlinux_map = machine__kernel_map(&vmlinux);
190264
191265 /*
192266 * Step 6:
@@ -213,7 +287,7 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 20 unmodified lines
213287 * in the kallsyms dso. For the ones that are in both, check its names and
214288 * end addresses too.
215289 */
216− map__for_each_symbol(vmlinux_map, sym, nd) {
290+ map__for_each_symbol(args.vmlinux_map, sym, nd) {
217291 struct symbol *pair, *first_pair;
218292
219293 sym = rb_entry(nd, struct symbol, rb_node);
@@ -221,10 +295,10 @@ static int test__vmlinux_matches_kallsyms(struct test_suite *test __maybe_unused · 1 unmodified line
221295 if (sym->start == sym->end)
222296 continue;
223297
224− mem_start = map__unmap_ip(vmlinux_map, sym->start);
225− mem_end = map__unmap_ip(vmlinux_map, sym->end);
298+ mem_start = map__unmap_ip(args.vmlinux_map, sym->start);
299+ mem_end = map__unmap_ip(args.vmlinux_map, sym->end);
226300
227− first_pair = machine__find_kernel_symbol(&kallsyms, mem_start, NULL);
301+ first_pair = machine__find_kernel_symbol(&args.kallsyms, mem_start, NULL);
228302 pair = first_pair;
229303
230304 if (pair && UM(pair->start) == mem_start) {
@@ -253,7 +327,8 @@ next_pair: · 22 unmodified lines
253327 */
254328 continue;
255329 } else {
256− pair = machine__find_kernel_symbol_by_name(&kallsyms, sym->name, NULL);
330+ pair = machine__find_kernel_symbol_by_name(&args.kallsyms,
331+ sym->name, NULL);
257332 if (pair) {
258333 if (UM(pair->start) == mem_start)
259334 goto next_pair;
@@ -267,7 +342,7 @@ next_pair: · 7 unmodified lines
267342
268343 continue;
269344 }
270− } else if (mem_start == map__end(kallsyms.vmlinux_map)) {
345+ } else if (mem_start == map__end(args.kallsyms.vmlinux_map)) {
271346 /*
272347 * Ignore aliases to _etext, i.e. to the end of the kernel text area,
273348 * such as __indirect_thunk_end.
@@ -289,78 +364,18 @@ next_pair: · 15 unmodified lines
289364 if (verbose <= 0)
290365 goto out;
291366
292− header_printed = false;
293−
294− maps__for_each_entry(maps, rb_node) {
295− struct map *map = rb_node->map;
296− struct dso *dso = map__dso(map);
297− /*
298− * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
299− * the kernel will have the path for the vmlinux file being used,
300− * so use the short name, less descriptive but the same ("[kernel]" in
301− * both cases.
302− */
303− struct map *pair = maps__find_by_name(kallsyms.kmaps, (dso->kernel ?
304− dso->short_name :
305− dso->name));
306− if (pair) {
307− map__set_priv(pair, 1);
308− } else {
309− if (!header_printed) {
310− pr_info("WARN: Maps only in vmlinux:\n");
311− header_printed = true;
312− }
313− map__fprintf(map, stderr);
314− }
315− }
316−
317− header_printed = false;
318−
319− maps__for_each_entry(maps, rb_node) {
320− struct map *pair, *map = rb_node->map;
321−
322− mem_start = map__unmap_ip(vmlinux_map, map__start(map));
323− mem_end = map__unmap_ip(vmlinux_map, map__end(map));
367+ args.header_printed = false;
368+ maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb1, &args);
324369
325− pair = maps__find(kallsyms.kmaps, mem_start);
326− if (pair == NULL || map__priv(pair))
327− continue;
328−
329− if (map__start(pair) == mem_start) {
330− struct dso *dso = map__dso(map);
331−
332− if (!header_printed) {
333− pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n");
334− header_printed = true;
335− }
336−
337− pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
338− map__start(map), map__end(map), map__pgoff(map), dso->name);
339− if (mem_end != map__end(pair))
340− pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64,
341− map__start(pair), map__end(pair), map__pgoff(pair));
342− pr_info(" %s\n", dso->name);
343− map__set_priv(pair, 1);
344− }
345− }
346−
347− header_printed = false;
348−
349− maps = machine__kernel_maps(&kallsyms);
370+ args.header_printed = false;
371+ maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb2, &args);
350372
351− maps__for_each_entry(maps, rb_node) {
352− struct map *map = rb_node->map;
373+ args.header_printed = false;
374+ maps = machine__kernel_maps(&args.kallsyms);
375+ maps__for_each_map(maps, test__vmlinux_matches_kallsyms_cb3, &args);
353376
354− if (!map__priv(map)) {
355− if (!header_printed) {
356− pr_info("WARN: Maps only in kallsyms:\n");
357− header_printed = true;
358− }
359− map__fprintf(map, stderr);
360− }
361− }
362377 out:
363− machine__exit(&kallsyms);
378+ machine__exit(&args.kallsyms);
364379 machine__exit(&vmlinux);
365380 return err;
366381 }
tools/perf/tests/workloads/thloop.c+1−3
@@ -7,7 +7,6 @@ · 6 unmodified lines
77 #include "../tests.h"
88
99 static volatile sig_atomic_t done;
10−static volatile unsigned count;
1110
1211 /* We want to check this symbol in perf report */
1312 noinline void test_loop(void);
@@ -19,8 +18,7 @@ static void sighandler(int sig __maybe_unused) · 5 unmodified lines
1918
2019 noinline void test_loop(void)
2120 {
22− while (!done)
23− __atomic_fetch_add(&count, 1, __ATOMIC_RELAXED);
21+ while (!done);
2422 }
2523
2624 static void *thfunc(void *arg)
tools/perf/trace/beauty/arch_errno_names.sh+6−4
@@ -57,13 +57,13 @@ create_arch_errno_table_func() · 56 unmodified lines
5757 archlist="$1"
5858 default="$2"
5959
60− printf 'const char *arch_syscalls__strerrno(const char *arch, int err)\n'
60+ printf 'arch_syscalls__strerrno_t *arch_syscalls__strerrno_function(const char *arch)\n'
6161 printf '{\n'
6262 for arch in $archlist; do
6363 printf '\tif (!strcmp(arch, "%s"))\n' $(arch_string "$arch")
64− printf '\t\treturn errno_to_name__%s(err);\n' $(arch_string "$arch")
64+ printf '\t\treturn errno_to_name__%s;\n' $(arch_string "$arch")
6565 done
66− printf '\treturn errno_to_name__%s(err);\n' $(arch_string "$default")
66+ printf '\treturn errno_to_name__%s;\n' $(arch_string "$default")
6767 printf '}\n'
6868 }
6969
@@ -76,7 +76,9 @@ EoHEADER · 6 unmodified lines
7676
7777 # Create list of architectures that have a specific errno.h.
7878 archlist=""
79−for arch in $(find $toolsdir/arch -maxdepth 1 -mindepth 1 -type d -printf "%f\n" | sort -r); do
79+for f in $toolsdir/arch/*/include/uapi/asm/errno.h; do
80+ d=${f%/include/uapi/asm/errno.h}
81+ arch="${d##*/}"
8082 test -f $toolsdir/arch/$arch/include/uapi/asm/errno.h && archlist="$archlist $arch"
8183 done
8284
tools/perf/trace/beauty/beauty.h+0−2
@@ -251,6 +251,4 @@ size_t open__scnprintf_flags(unsigned long flags, char *bf, size_t size, bool sh · 250 unmodified lines
251251 void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
252252 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg));
253253
254−const char *arch_syscalls__strerrno(const char *arch, int err);
255−
256254 #endif /* _PERF_TRACE_BEAUTY_H */
tools/perf/trace/beauty/prctl_option.sh+2−2
@@ -4,9 +4,9 @@ · 3 unmodified lines
44 [ $# -eq 1 ] && header_dir=$1 || header_dir=tools/include/uapi/linux/
55
66 printf "static const char *prctl_options[] = {\n"
7−regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*\/.*)?$'
7+regex='^#define[[:space:]]{1}PR_(\w+)[[:space:]]*([[:xdigit:]]+)([[:space:]]*/.*)?$'
88 grep -E $regex ${header_dir}/prctl.h | grep -v PR_SET_PTRACER | \
9− sed -r "s/$regex/\2 \1/g" | \
9+ sed -E "s%$regex%\2 \1%g" | \
1010 sort -n | xargs printf "\t[%s] = \"%s\",\n"
1111 printf "};\n"
1212
tools/perf/trace/beauty/socket.sh+2−2
@@ -18,10 +18,10 @@ grep -E $ipproto_regex ${uapi_header_dir}/in.h | \ · 17 unmodified lines
1818 printf "};\n\n"
1919
2020 printf "static const char *socket_level[] = {\n"
21−socket_level_regex='^#define[[:space:]]+SOL_(\w+)[[:space:]]+([[:digit:]]+)([[:space:]]+\/.*)?'
21+socket_level_regex='^#define[[:space:]]+SOL_(\w+)[[:space:]]+([[:digit:]]+)([[:space:]]+/.*)?'
2222
2323 grep -E $socket_level_regex ${beauty_header_dir}/socket.h | \
24− sed -r "s/$socket_level_regex/\2 \1/g" | \
24+ sed -E "s%$socket_level_regex%\2 \1%g" | \
2525 sort -n | xargs printf "\t[%s] = \"%s\",\n"
2626 printf "};\n\n"
2727
tools/perf/ui/browsers/annotate.c+48−56
@@ -27,7 +27,6 @@ struct annotate_browser { · 26 unmodified lines
2727 struct rb_node *curr_hot;
2828 struct annotation_line *selection;
2929 struct arch *arch;
30− struct annotation_options *opts;
3130 bool searching_backwards;
3231 char search_bf[128];
3332 };
@@ -38,11 +37,10 @@ static inline struct annotation *browser__annotation(struct ui_browser *browser) · 4 unmodified lines
3837 return symbol__annotation(ms->sym);
3938 }
4039
41−static bool disasm_line__filter(struct ui_browser *browser, void *entry)
40+static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, void *entry)
4241 {
43− struct annotation *notes = browser__annotation(browser);
4442 struct annotation_line *al = list_entry(entry, struct annotation_line, node);
45− return annotation_line__filter(al, notes);
43+ return annotation_line__filter(al);
4644 }
4745
4846 static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
@@ -97,7 +95,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int · 48 unmodified lines
9795 struct annotation_write_ops ops = {
9896 .first_line = row == 0,
9997 .current_entry = is_current_entry,
100− .change_color = (!notes->options->hide_src_code &&
98+ .change_color = (!annotate_opts.hide_src_code &&
10199 (!is_current_entry ||
102100 (browser->use_navkeypressed &&
103101 !browser->navkeypressed))),
@@ -114,7 +112,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int · 10 unmodified lines
114112 if (!browser->navkeypressed)
115113 ops.width += 1;
116114
117− annotation_line__write(al, notes, &ops, ab->opts);
115+ annotation_line__write(al, notes, &ops);
118116
119117 if (ops.current_entry)
120118 ab->selection = al;
@@ -128,7 +126,7 @@ static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor) · 7 unmodified lines
128126
129127 while (pos && pos->al.offset == -1) {
130128 pos = list_prev_entry(pos, al.node);
131− if (!ab->opts->hide_src_code)
129+ if (!annotate_opts.hide_src_code)
132130 diff++;
133131 }
134132
@@ -188,14 +186,14 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) · 53 unmodified lines
188186 * name right after the '<' token and probably treating this like a
189187 * 'call' instruction.
190188 */
191− target = notes->offsets[cursor->ops.target.offset];
189+ target = notes->src->offsets[cursor->ops.target.offset];
192190 if (target == NULL) {
193191 ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
194192 cursor->ops.target.offset);
195193 return;
196194 }
197195
198− if (notes->options->hide_src_code) {
196+ if (annotate_opts.hide_src_code) {
199197 from = cursor->al.idx_asm;
200198 to = target->idx_asm;
201199 } else {
@@ -224,7 +222,7 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) · 22 unmodified lines
224222 int ret = ui_browser__list_head_refresh(browser);
225223 int pcnt_width = annotation__pcnt_width(notes);
226224
227− if (notes->options->jump_arrows)
225+ if (annotate_opts.jump_arrows)
228226 annotate_browser__draw_current_jump(browser);
229227
230228 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
@@ -258,7 +256,7 @@ static void disasm_rb_tree__insert(struct annotate_browser *browser, · 27 unmodified lines
258256 parent = *p;
259257 l = rb_entry(parent, struct annotation_line, rb_node);
260258
261− if (disasm__cmp(al, l, browser->opts->percent_type) < 0)
259+ if (disasm__cmp(al, l, annotate_opts.percent_type) < 0)
262260 p = &(*p)->rb_left;
263261 else
264262 p = &(*p)->rb_right;
@@ -270,7 +268,6 @@ static void disasm_rb_tree__insert(struct annotate_browser *browser, · 5 unmodified lines
270268 static void annotate_browser__set_top(struct annotate_browser *browser,
271269 struct annotation_line *pos, u32 idx)
272270 {
273− struct annotation *notes = browser__annotation(&browser->b);
274271 unsigned back;
275272
276273 ui_browser__refresh_dimensions(&browser->b);
@@ -280,7 +277,7 @@ static void annotate_browser__set_top(struct annotate_browser *browser, · 3 unmodified lines
280277 while (browser->b.top_idx != 0 && back != 0) {
281278 pos = list_entry(pos->node.prev, struct annotation_line, node);
282279
283− if (annotation_line__filter(pos, notes))
280+ if (annotation_line__filter(pos))
284281 continue;
285282
286283 --browser->b.top_idx;
@@ -294,11 +291,10 @@ static void annotate_browser__set_top(struct annotate_browser *browser, · 7 unmodified lines
294291 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
295292 struct rb_node *nd)
296293 {
297− struct annotation *notes = browser__annotation(&browser->b);
298294 struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
299295 u32 idx = pos->idx;
300296
301− if (notes->options->hide_src_code)
297+ if (annotate_opts.hide_src_code)
302298 idx = pos->idx_asm;
303299 annotate_browser__set_top(browser, pos, idx);
304300 browser->curr_hot = nd;
@@ -331,13 +327,13 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, · 26 unmodified lines
331327 double percent;
332328
333329 percent = annotation_data__percent(&pos->al.data[i],
334− browser->opts->percent_type);
330+ annotate_opts.percent_type);
335331
336332 if (max_percent < percent)
337333 max_percent = percent;
338334 }
339335
340− if (max_percent < 0.01 && pos->al.ipc == 0) {
336+ if (max_percent < 0.01 && (!pos->al.cycles || pos->al.cycles->ipc == 0)) {
341337 RB_CLEAR_NODE(&pos->al.rb_node);
342338 continue;
343339 }
@@ -380,12 +376,12 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) · 36 unmodified lines
380376 browser->b.seek(&browser->b, offset, SEEK_CUR);
381377 al = list_entry(browser->b.top, struct annotation_line, node);
382378
383− if (notes->options->hide_src_code) {
379+ if (annotate_opts.hide_src_code) {
384380 if (al->idx_asm < offset)
385381 offset = al->idx;
386382
387− browser->b.nr_entries = notes->nr_entries;
388− notes->options->hide_src_code = false;
383+ browser->b.nr_entries = notes->src->nr_entries;
384+ annotate_opts.hide_src_code = false;
389385 browser->b.seek(&browser->b, -offset, SEEK_CUR);
390386 browser->b.top_idx = al->idx - offset;
391387 browser->b.index = al->idx;
@@ -402,8 +398,8 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) · 10 unmodified lines
402398 if (al->idx_asm < offset)
403399 offset = al->idx_asm;
404400
405− browser->b.nr_entries = notes->nr_asm_entries;
406− notes->options->hide_src_code = true;
401+ browser->b.nr_entries = notes->src->nr_asm_entries;
402+ annotate_opts.hide_src_code = true;
407403 browser->b.seek(&browser->b, -offset, SEEK_CUR);
408404 browser->b.top_idx = al->idx_asm - offset;
409405 browser->b.index = al->idx_asm;
@@ -435,7 +431,7 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser) · 25 unmodified lines
435431 {
436432 struct annotation *notes = browser__annotation(browser);
437433 ui_browser__reset_index(browser);
438− browser->nr_entries = notes->nr_asm_entries;
434+ browser->nr_entries = notes->src->nr_asm_entries;
439435 }
440436
441437 static int sym_title(struct symbol *sym, struct map *map, char *title,
@@ -483,8 +479,8 @@ static bool annotate_browser__callq(struct annotate_browser *browser, · 41 unmodified lines
483479 target_ms.map = ms->map;
484480 target_ms.sym = dl->ops.target.sym;
485481 annotation__unlock(notes);
486− symbol__tui_annotate(&target_ms, evsel, hbt, browser->opts);
487− sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type);
482+ symbol__tui_annotate(&target_ms, evsel, hbt);
483+ sym_title(ms->sym, ms->map, title, sizeof(title), annotate_opts.percent_type);
488484 ui_browser__show_title(&browser->b, title);
489485 return true;
490486 }
@@ -500,7 +496,7 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows · 9 unmodified lines
500496 list_for_each_entry(pos, &notes->src->source, al.node) {
501497 if (pos->al.offset == offset)
502498 return pos;
503− if (!annotation_line__filter(&pos->al, notes))
499+ if (!annotation_line__filter(&pos->al))
504500 ++*idx;
505501 }
506502
@@ -544,7 +540,7 @@ struct annotation_line *annotate_browser__find_string(struct annotate_browser *b · 37 unmodified lines
544540
545541 *idx = browser->b.index;
546542 list_for_each_entry_continue(al, &notes->src->source, node) {
547− if (annotation_line__filter(al, notes))
543+ if (annotation_line__filter(al))
548544 continue;
549545
550546 ++*idx;
@@ -581,7 +577,7 @@ struct annotation_line *annotate_browser__find_string_reverse(struct annotate_br · 30 unmodified lines
581577
582578 *idx = browser->b.index;
583579 list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
584− if (annotation_line__filter(al, notes))
580+ if (annotation_line__filter(al))
585581 continue;
586582
587583 --*idx;
@@ -659,7 +655,6 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, · 71 unmodified lines
659655
660656 static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help)
661657 {
662− struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
663658 struct map_symbol *ms = browser->priv;
664659 struct symbol *sym = ms->sym;
665660 char symbol_dso[SYM_TITLE_MAX_SIZE];
@@ -667,7 +662,7 @@ static int annotate_browser__show(struct ui_browser *browser, char *title, const · 1 unmodified line
667662 if (ui_browser__show(browser, title, help) < 0)
668663 return -1;
669664
670− sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type);
665+ sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), annotate_opts.percent_type);
671666
672667 ui_browser__gotorc_title(browser, 0, 0);
673668 ui_browser__set_color(browser, HE_COLORSET_ROOT);
@@ -809,7 +804,7 @@ static int annotate_browser__run(struct annotate_browser *browser, · 135 unmodified lines
809804 annotate_browser__show(&browser->b, title, help);
810805 continue;
811806 case 'k':
812− notes->options->show_linenr = !notes->options->show_linenr;
807+ annotate_opts.show_linenr = !annotate_opts.show_linenr;
813808 continue;
814809 case 'l':
815810 annotate_browser__show_full_location (&browser->b);
@@ -822,18 +817,18 @@ static int annotate_browser__run(struct annotate_browser *browser, · 6 unmodified lines
822817 ui_helpline__puts(help);
823818 continue;
824819 case 'o':
825− notes->options->use_offset = !notes->options->use_offset;
820+ annotate_opts.use_offset = !annotate_opts.use_offset;
826821 annotation__update_column_widths(notes);
827822 continue;
828823 case 'O':
829− if (++notes->options->offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
830− notes->options->offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
824+ if (++annotate_opts.offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
825+ annotate_opts.offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
831826 continue;
832827 case 'j':
833− notes->options->jump_arrows = !notes->options->jump_arrows;
828+ annotate_opts.jump_arrows = !annotate_opts.jump_arrows;
834829 continue;
835830 case 'J':
836− notes->options->show_nr_jumps = !notes->options->show_nr_jumps;
831+ annotate_opts.show_nr_jumps = !annotate_opts.show_nr_jumps;
837832 annotation__update_column_widths(notes);
838833 continue;
839834 case '/':
@@ -860,7 +855,7 @@ show_help: · 20 unmodified lines
860855 browser->b.height,
861856 browser->b.index,
862857 browser->b.top_idx,
863− notes->nr_asm_entries);
858+ notes->src->nr_asm_entries);
864859 }
865860 continue;
866861 case K_ENTER:
@@ -884,7 +879,7 @@ show_sup_ins: · 17 unmodified lines
884879 continue;
885880 }
886881 case 'P':
887− map_symbol__annotation_dump(ms, evsel, browser->opts);
882+ map_symbol__annotation_dump(ms, evsel);
888883 continue;
889884 case 't':
890885 if (symbol_conf.show_total_period) {
@@ -897,15 +892,15 @@ show_sup_ins: · 6 unmodified lines
897892 annotation__update_column_widths(notes);
898893 continue;
899894 case 'c':
900− if (notes->options->show_minmax_cycle)
901− notes->options->show_minmax_cycle = false;
895+ if (annotate_opts.show_minmax_cycle)
896+ annotate_opts.show_minmax_cycle = false;
902897 else
903− notes->options->show_minmax_cycle = true;
898+ annotate_opts.show_minmax_cycle = true;
904899 annotation__update_column_widths(notes);
905900 continue;
906901 case 'p':
907902 case 'b':
908− switch_percent_type(browser->opts, key == 'b');
903+ switch_percent_type(&annotate_opts, key == 'b');
909904 hists__scnprintf_title(hists, title, sizeof(title));
910905 annotate_browser__show(&browser->b, title, help);
911906 continue;
@@ -932,26 +927,24 @@ out: · 20 unmodified lines
932927 }
933928
934929 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
935− struct hist_browser_timer *hbt,
936− struct annotation_options *opts)
930+ struct hist_browser_timer *hbt)
937931 {
938− return symbol__tui_annotate(ms, evsel, hbt, opts);
932+ return symbol__tui_annotate(ms, evsel, hbt);
939933 }
940934
941935 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
942− struct hist_browser_timer *hbt,
943− struct annotation_options *opts)
936+ struct hist_browser_timer *hbt)
944937 {
945938 /* reset abort key so that it can get Ctrl-C as a key */
946939 SLang_reset_tty();
947940 SLang_init_tty(0, 0, 0);
941+ SLtty_set_suspend_state(true);
948942
949− return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts);
943+ return map_symbol__tui_annotate(&he->ms, evsel, hbt);
950944 }
951945
952946 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
953− struct hist_browser_timer *hbt,
954− struct annotation_options *opts)
947+ struct hist_browser_timer *hbt)
955948 {
956949 struct symbol *sym = ms->sym;
957950 struct annotation *notes = symbol__annotation(sym);
@@ -965,7 +958,6 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, · 7 unmodified lines
965958 .priv = ms,
966959 .use_navkeypressed = true,
967960 },
968− .opts = opts,
969961 };
970962 struct dso *dso;
971963 int ret = -1, err;
@@ -979,7 +971,7 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, · 7 unmodified lines
979971 return -1;
980972
981973 if (not_annotated) {
982− err = symbol__annotate2(ms, evsel, opts, &browser.arch);
974+ err = symbol__annotate2(ms, evsel, &browser.arch);
983975 if (err) {
984976 char msg[BUFSIZ];
985977 dso->annotate_warned = true;
@@ -991,12 +983,12 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, · 5 unmodified lines
991983
992984 ui_helpline__push("Press ESC to exit");
993985
994− browser.b.width = notes->max_line_len;
995− browser.b.nr_entries = notes->nr_entries;
986+ browser.b.width = notes->src->max_line_len;
987+ browser.b.nr_entries = notes->src->nr_entries;
996988 browser.b.entries = &notes->src->source,
997989 browser.b.width += 18; /* Percentage */
998990
999− if (notes->options->hide_src_code)
991+ if (annotate_opts.hide_src_code)
1000992 ui_browser__init_asm_mode(&browser.b);
1001993
1002994 ret = annotate_browser__run(&browser, evsel, hbt);
@@ -1006,6 +998,6 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, · 3 unmodified lines
1006998
1007999 out_free_offsets:
10081000 if(not_annotated)
1009− zfree(&notes->offsets);
1001+ zfree(&notes->src->offsets);
10101002 return ret;
10111003 }
tools/perf/ui/browsers/hists.c+14−22
@@ -2250,8 +2250,7 @@ struct hist_browser *hist_browser__new(struct hists *hists) · 2249 unmodified lines
22502250 static struct hist_browser *
22512251 perf_evsel_browser__new(struct evsel *evsel,
22522252 struct hist_browser_timer *hbt,
2253− struct perf_env *env,
2254− struct annotation_options *annotation_opts)
2253+ struct perf_env *env)
22552254 {
22562255 struct hist_browser *browser = hist_browser__new(evsel__hists(evsel));
22572256
@@ -2259,7 +2258,6 @@ perf_evsel_browser__new(struct evsel *evsel, · 1 unmodified line
22592258 browser->hbt = hbt;
22602259 browser->env = env;
22612260 browser->title = hists_browser__scnprintf_title;
2262− browser->annotation_opts = annotation_opts;
22632261 }
22642262 return browser;
22652263 }
@@ -2432,8 +2430,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) · 166 unmodified lines
24322430 struct hist_entry *he;
24332431 int err;
24342432
2435− if (!browser->annotation_opts->objdump_path &&
2436− perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path))
2433+ if (!annotate_opts.objdump_path &&
2434+ perf_env__lookup_objdump(browser->env, &annotate_opts.objdump_path))
24372435 return 0;
24382436
24392437 notes = symbol__annotation(act->ms.sym);
@@ -2445,8 +2443,7 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) · 5 unmodified lines
24452443 else
24462444 evsel = hists_to_evsel(browser->hists);
24472445
2448− err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,
2449− browser->annotation_opts);
2446+ err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
24502447 he = hist_browser__selected_entry(browser);
24512448 /*
24522449 * offer option to annotate the other branch source or target
@@ -2943,11 +2940,10 @@ next: · 490 unmodified lines
29432940
29442941 static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *helpline,
29452942 bool left_exits, struct hist_browser_timer *hbt, float min_pcnt,
2946− struct perf_env *env, bool warn_lost_event,
2947− struct annotation_options *annotation_opts)
2943+ struct perf_env *env, bool warn_lost_event)
29482944 {
29492945 struct hists *hists = evsel__hists(evsel);
2950− struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts);
2946+ struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
29512947 struct branch_info *bi = NULL;
29522948 #define MAX_OPTIONS 16
29532949 char *options[MAX_OPTIONS];
@@ -3004,6 +3000,7 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h · 50 unmodified lines
30043000 /* reset abort key so that it can get Ctrl-C as a key */
30053001 SLang_reset_tty();
30063002 SLang_init_tty(0, 0, 0);
3003+ SLtty_set_suspend_state(true);
30073004
30083005 if (min_pcnt)
30093006 browser->min_pcnt = min_pcnt;
@@ -3398,7 +3395,6 @@ out: · 388 unmodified lines
33983395 struct evsel_menu {
33993396 struct ui_browser b;
34003397 struct evsel *selection;
3401− struct annotation_options *annotation_opts;
34023398 bool lost_events, lost_events_warned;
34033399 float min_pcnt;
34043400 struct perf_env *env;
@@ -3499,8 +3495,7 @@ browse_hists: · 94 unmodified lines
34993495 hbt->timer(hbt->arg);
35003496 key = evsel__hists_browse(pos, nr_events, help, true, hbt,
35013497 menu->min_pcnt, menu->env,
3502− warn_lost_event,
3503− menu->annotation_opts);
3498+ warn_lost_event);
35043499 ui_browser__show_title(&menu->b, title);
35053500 switch (key) {
35063501 case K_TAB:
@@ -3557,7 +3552,7 @@ static bool filter_group_entries(struct ui_browser *browser __maybe_unused, · 50 unmodified lines
35573552
35583553 static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, const char *help,
35593554 struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env,
3560− bool warn_lost_event, struct annotation_options *annotation_opts)
3555+ bool warn_lost_event)
35613556 {
35623557 struct evsel *pos;
35633558 struct evsel_menu menu = {
@@ -3572,7 +3567,6 @@ static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, con · 8 unmodified lines
35723567 },
35733568 .min_pcnt = min_pcnt,
35743569 .env = env,
3575− .annotation_opts = annotation_opts,
35763570 };
35773571
35783572 ui_helpline__push("Press ESC to exit");
@@ -3607,8 +3601,7 @@ static bool evlist__single_entry(struct evlist *evlist) · 28 unmodified lines
36073601 }
36083602
36093603 int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt,
3610− float min_pcnt, struct perf_env *env, bool warn_lost_event,
3611− struct annotation_options *annotation_opts)
3604+ float min_pcnt, struct perf_env *env, bool warn_lost_event)
36123605 {
36133606 int nr_entries = evlist->core.nr_entries;
36143607
@@ -3617,7 +3610,7 @@ single_entry: { · 2 unmodified lines
36173610 struct evsel *first = evlist__first(evlist);
36183611
36193612 return evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt,
3620− env, warn_lost_event, annotation_opts);
3613+ env, warn_lost_event);
36213614 }
36223615 }
36233616
@@ -3635,7 +3628,7 @@ single_entry: { · 11 unmodified lines
36353628 }
36363629
36373630 return __evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env,
3638− warn_lost_event, annotation_opts);
3631+ warn_lost_event);
36393632 }
36403633
36413634 static int block_hists_browser__title(struct hist_browser *browser, char *bf,
@@ -3654,8 +3647,7 @@ static int block_hists_browser__title(struct hist_browser *browser, char *bf, · 12 unmodified lines
36543647 }
36553648
36563649 int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
3657− float min_percent, struct perf_env *env,
3658− struct annotation_options *annotation_opts)
3650+ float min_percent, struct perf_env *env)
36593651 {
36603652 struct hists *hists = &bh->block_hists;
36613653 struct hist_browser *browser;
@@ -3672,11 +3664,11 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, · 10 unmodified lines
36723664 browser->title = block_hists_browser__title;
36733665 browser->min_pcnt = min_percent;
36743666 browser->env = env;
3675− browser->annotation_opts = annotation_opts;
36763667
36773668 /* reset abort key so that it can get Ctrl-C as a key */
36783669 SLang_reset_tty();
36793670 SLang_init_tty(0, 0, 0);
3671+ SLtty_set_suspend_state(true);
36803672
36813673 memset(&action, 0, sizeof(action));
36823674
tools/perf/ui/browsers/hists.h+0−2
@@ -4,7 +4,6 @@ · 3 unmodified lines
44
55 #include "ui/browser.h"
66
7−struct annotation_options;
87 struct evsel;
98
109 struct hist_browser {
@@ -15,7 +14,6 @@ struct hist_browser { · 4 unmodified lines
1514 struct hist_browser_timer *hbt;
1615 struct pstack *pstack;
1716 struct perf_env *env;
18− struct annotation_options *annotation_opts;
1917 struct evsel *block_evsel;
2018 int print_seq;
2119 bool show_dso;
tools/perf/ui/browsers/scripts.c+1−0
@@ -166,6 +166,7 @@ void run_script(char *cmd) · 165 unmodified lines
166166 printf("\033[c\033[H\033[J");
167167 fflush(stdout);
168168 SLang_init_tty(0, 0, 0);
169+ SLtty_set_suspend_state(true);
169170 SLsmg_refresh();
170171 }
171172
tools/perf/ui/gtk/annotate.c+2−4
@@ -162,7 +162,6 @@ static int perf_gtk__annotate_symbol(GtkWidget *window, struct map_symbol *ms, · 161 unmodified lines
162162 }
163163
164164 static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel,
165− struct annotation_options *options,
166165 struct hist_browser_timer *hbt)
167166 {
168167 struct dso *dso = map__dso(ms->map);
@@ -176,7 +175,7 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, · 7 unmodified lines
176175 if (dso->annotate_warned)
177176 return -1;
178177
179− err = symbol__annotate(ms, evsel, options, NULL);
178+ err = symbol__annotate(ms, evsel, NULL);
180179 if (err) {
181180 char msg[BUFSIZ];
182181 dso->annotate_warned = true;
@@ -244,10 +243,9 @@ static int symbol__gtk_annotate(struct map_symbol *ms, struct evsel *evsel, · 61 unmodified lines
244243
245244 int hist_entry__gtk_annotate(struct hist_entry *he,
246245 struct evsel *evsel,
247− struct annotation_options *options,
248246 struct hist_browser_timer *hbt)
249247 {
250− return symbol__gtk_annotate(&he->ms, evsel, options, hbt);
248+ return symbol__gtk_annotate(&he->ms, evsel, hbt);
251249 }
252250
253251 void perf_gtk__show_annotations(void)
tools/perf/ui/gtk/gtk.h+0−2
@@ -56,13 +56,11 @@ struct evsel; · 55 unmodified lines
5656 struct evlist;
5757 struct hist_entry;
5858 struct hist_browser_timer;
59−struct annotation_options;
6059
6160 int evlist__gtk_browse_hists(struct evlist *evlist, const char *help,
6261 struct hist_browser_timer *hbt, float min_pcnt);
6362 int hist_entry__gtk_annotate(struct hist_entry *he,
6463 struct evsel *evsel,
65− struct annotation_options *options,
6664 struct hist_browser_timer *hbt);
6765 void perf_gtk__show_annotations(void);
6866
tools/perf/ui/tui/setup.c+22−0
@@ -2,12 +2,14 @@ · 1 unmodified line
22 #include <signal.h>
33 #include <stdbool.h>
44 #include <stdlib.h>
5+#include <termios.h>
56 #include <unistd.h>
67 #include <linux/kernel.h>
78 #ifdef HAVE_BACKTRACE_SUPPORT
89 #include <execinfo.h>
910 #endif
1011
12+#include "../../util/color.h"
1113 #include "../../util/debug.h"
1214 #include "../browser.h"
1315 #include "../helpline.h"
@@ -121,6 +123,23 @@ static void ui__signal(int sig) · 107 unmodified lines
121123 exit(0);
122124 }
123125
126+static void ui__sigcont(int sig)
127+{
128+ static struct termios tty;
129+
130+ if (sig == SIGTSTP) {
131+ while (tcgetattr(SLang_TT_Read_FD, &tty) == -1 && errno == EINTR)
132+ ;
133+ while (write(SLang_TT_Read_FD, PERF_COLOR_RESET, sizeof(PERF_COLOR_RESET) - 1) == -1 && errno == EINTR)
134+ ;
135+ raise(SIGSTOP);
136+ } else {
137+ while (tcsetattr(SLang_TT_Read_FD, TCSADRAIN, &tty) == -1 && errno == EINTR)
138+ ;
139+ raise(SIGWINCH);
140+ }
141+}
142+
124143 int ui__init(void)
125144 {
126145 int err;
@@ -135,6 +154,7 @@ int ui__init(void) · 8 unmodified lines
135154 err = SLang_init_tty(-1, 0, 0);
136155 if (err < 0)
137156 goto out;
157+ SLtty_set_suspend_state(true);
138158
139159 err = SLkp_init();
140160 if (err < 0) {
@@ -149,6 +169,8 @@ int ui__init(void) · 8 unmodified lines
149169 signal(SIGINT, ui__signal);
150170 signal(SIGQUIT, ui__signal);
151171 signal(SIGTERM, ui__signal);
172+ signal(SIGTSTP, ui__sigcont);
173+ signal(SIGCONT, ui__sigcont);
152174
153175 perf_error__register(&perf_tui_eops);
154176
tools/perf/util/Build+2−0
@@ -195,6 +195,8 @@ endif · 194 unmodified lines
195195 perf-$(CONFIG_DWARF) += probe-finder.o
196196 perf-$(CONFIG_DWARF) += dwarf-aux.o
197197 perf-$(CONFIG_DWARF) += dwarf-regs.o
198+perf-$(CONFIG_DWARF) += debuginfo.o
199+perf-$(CONFIG_DWARF) += annotate-data.o
198200
199201 perf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
200202 perf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o
tools/perf/util/annotate-data.c+405−0
@@ -0,0 +1,405 @@
1+/* SPDX-License-Identifier: GPL-2.0 */
2+/*
3+ * Convert sample address to data type using DWARF debug info.
4+ *
5+ * Written by Namhyung Kim <namhyung@kernel.org>
6+ */
7+
8+#include <stdio.h>
9+#include <stdlib.h>
10+#include <inttypes.h>
11+
12+#include "annotate-data.h"
13+#include "debuginfo.h"
14+#include "debug.h"
15+#include "dso.h"
16+#include "evsel.h"
17+#include "evlist.h"
18+#include "map.h"
19+#include "map_symbol.h"
20+#include "strbuf.h"
21+#include "symbol.h"
22+#include "symbol_conf.h"
23+
24+/*
25+ * Compare type name and size to maintain them in a tree.
26+ * I'm not sure if DWARF would have information of a single type in many
27+ * different places (compilation units). If not, it could compare the
28+ * offset of the type entry in the .debug_info section.
29+ */
30+static int data_type_cmp(const void *_key, const struct rb_node *node)
31+{
32+ const struct annotated_data_type *key = _key;
33+ struct annotated_data_type *type;
34+
35+ type = rb_entry(node, struct annotated_data_type, node);
36+
37+ if (key->self.size != type->self.size)
38+ return key->self.size - type->self.size;
39+ return strcmp(key->self.type_name, type->self.type_name);
40+}
41+
42+static bool data_type_less(struct rb_node *node_a, const struct rb_node *node_b)
43+{
44+ struct annotated_data_type *a, *b;
45+
46+ a = rb_entry(node_a, struct annotated_data_type, node);
47+ b = rb_entry(node_b, struct annotated_data_type, node);
48+
49+ if (a->self.size != b->self.size)
50+ return a->self.size < b->self.size;
51+ return strcmp(a->self.type_name, b->self.type_name) < 0;
52+}
53+
54+/* Recursively add new members for struct/union */
55+static int __add_member_cb(Dwarf_Die *die, void *arg)
56+{
57+ struct annotated_member *parent = arg;
58+ struct annotated_member *member;
59+ Dwarf_Die member_type, die_mem;
60+ Dwarf_Word size, loc;
61+ Dwarf_Attribute attr;
62+ struct strbuf sb;
63+ int tag;
64+
65+ if (dwarf_tag(die) != DW_TAG_member)
66+ return DIE_FIND_CB_SIBLING;
67+
68+ member = zalloc(sizeof(*member));
69+ if (member == NULL)
70+ return DIE_FIND_CB_END;
71+
72+ strbuf_init(&sb, 32);
73+ die_get_typename(die, &sb);
74+
75+ die_get_real_type(die, &member_type);
76+ if (dwarf_aggregate_size(&member_type, &size) < 0)
77+ size = 0;
78+
79+ if (!dwarf_attr_integrate(die, DW_AT_data_member_location, &attr))
80+ loc = 0;
81+ else
82+ dwarf_formudata(&attr, &loc);
83+
84+ member->type_name = strbuf_detach(&sb, NULL);
85+ /* member->var_name can be NULL */
86+ if (dwarf_diename(die))
87+ member->var_name = strdup(dwarf_diename(die));
88+ member->size = size;
89+ member->offset = loc + parent->offset;
90+ INIT_LIST_HEAD(&member->children);
91+ list_add_tail(&member->node, &parent->children);
92+
93+ tag = dwarf_tag(&member_type);
94+ switch (tag) {
95+ case DW_TAG_structure_type:
96+ case DW_TAG_union_type:
97+ die_find_child(&member_type, __add_member_cb, member, &die_mem);
98+ break;
99+ default:
100+ break;
101+ }
102+ return DIE_FIND_CB_SIBLING;
103+}
104+
105+static void add_member_types(struct annotated_data_type *parent, Dwarf_Die *type)
106+{
107+ Dwarf_Die die_mem;
108+
109+ die_find_child(type, __add_member_cb, &parent->self, &die_mem);
110+}
111+
112+static void delete_members(struct annotated_member *member)
113+{
114+ struct annotated_member *child, *tmp;
115+
116+ list_for_each_entry_safe(child, tmp, &member->children, node) {
117+ list_del(&child->node);
118+ delete_members(child);
119+ free(child->type_name);
120+ free(child->var_name);
121+ free(child);
122+ }
123+}
124+
125+static struct annotated_data_type *dso__findnew_data_type(struct dso *dso,
126+ Dwarf_Die *type_die)
127+{
128+ struct annotated_data_type *result = NULL;
129+ struct annotated_data_type key;
130+ struct rb_node *node;
131+ struct strbuf sb;
132+ char *type_name;
133+ Dwarf_Word size;
134+
135+ strbuf_init(&sb, 32);
136+ if (die_get_typename_from_type(type_die, &sb) < 0)
137+ strbuf_add(&sb, "(unknown type)", 14);
138+ type_name = strbuf_detach(&sb, NULL);
139+ dwarf_aggregate_size(type_die, &size);
140+
141+ /* Check existing nodes in dso->data_types tree */
142+ key.self.type_name = type_name;
143+ key.self.size = size;
144+ node = rb_find(&key, &dso->data_types, data_type_cmp);
145+ if (node) {
146+ result = rb_entry(node, struct annotated_data_type, node);
147+ free(type_name);
148+ return result;
149+ }
150+
151+ /* If not, add a new one */
152+ result = zalloc(sizeof(*result));
153+ if (result == NULL) {
154+ free(type_name);
155+ return NULL;
156+ }
157+
158+ result->self.type_name = type_name;
159+ result->self.size = size;
160+ INIT_LIST_HEAD(&result->self.children);
161+
162+ if (symbol_conf.annotate_data_member)
163+ add_member_types(result, type_die);
164+
165+ rb_add(&result->node, &dso->data_types, data_type_less);
166+ return result;
167+}
168+
169+static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die)
170+{
171+ Dwarf_Off off, next_off;
172+ size_t header_size;
173+
174+ if (dwarf_addrdie(di->dbg, pc, cu_die) != NULL)
175+ return cu_die;
176+
177+ /*
178+ * There are some kernels don't have full aranges and contain only a few
179+ * aranges entries. Fallback to iterate all CU entries in .debug_info
180+ * in case it's missing.
181+ */
182+ off = 0;
183+ while (dwarf_nextcu(di->dbg, off, &next_off, &header_size,
184+ NULL, NULL, NULL) == 0) {
185+ if (dwarf_offdie(di->dbg, off + header_size, cu_die) &&
186+ dwarf_haspc(cu_die, pc))
187+ return true;
188+
189+ off = next_off;
190+ }
191+ return false;
192+}
193+
194+/* The type info will be saved in @type_die */
195+static int check_variable(Dwarf_Die *var_die, Dwarf_Die *type_die, int offset)
196+{
197+ Dwarf_Word size;
198+
199+ /* Get the type of the variable */
200+ if (die_get_real_type(var_die, type_die) == NULL) {
201+ pr_debug("variable has no type\n");
202+ ann_data_stat.no_typeinfo++;
203+ return -1;
204+ }
205+
206+ /*
207+ * It expects a pointer type for a memory access.
208+ * Convert to a real type it points to.
209+ */
210+ if (dwarf_tag(type_die) != DW_TAG_pointer_type ||
211+ die_get_real_type(type_die, type_die) == NULL) {
212+ pr_debug("no pointer or no type\n");
213+ ann_data_stat.no_typeinfo++;
214+ return -1;
215+ }
216+
217+ /* Get the size of the actual type */
218+ if (dwarf_aggregate_size(type_die, &size) < 0) {
219+ pr_debug("type size is unknown\n");
220+ ann_data_stat.invalid_size++;
221+ return -1;
222+ }
223+
224+ /* Minimal sanity check */
225+ if ((unsigned)offset >= size) {
226+ pr_debug("offset: %d is bigger than size: %" PRIu64 "\n", offset, size);
227+ ann_data_stat.bad_offset++;
228+ return -1;
229+ }
230+
231+ return 0;
232+}
233+
234+/* The result will be saved in @type_die */
235+static int find_data_type_die(struct debuginfo *di, u64 pc,
236+ int reg, int offset, Dwarf_Die *type_die)
237+{
238+ Dwarf_Die cu_die, var_die;
239+ Dwarf_Die *scopes = NULL;
240+ int ret = -1;
241+ int i, nr_scopes;
242+
243+ /* Get a compile_unit for this address */
244+ if (!find_cu_die(di, pc, &cu_die)) {
245+ pr_debug("cannot find CU for address %" PRIx64 "\n", pc);
246+ ann_data_stat.no_cuinfo++;
247+ return -1;
248+ }
249+
250+ /* Get a list of nested scopes - i.e. (inlined) functions and blocks. */
251+ nr_scopes = die_get_scopes(&cu_die, pc, &scopes);
252+
253+ /* Search from the inner-most scope to the outer */
254+ for (i = nr_scopes - 1; i >= 0; i--) {
255+ /* Look up variables/parameters in this scope */
256+ if (!die_find_variable_by_reg(&scopes[i], pc, reg, &var_die))
257+ continue;
258+
259+ /* Found a variable, see if it's correct */
260+ ret = check_variable(&var_die, type_die, offset);
261+ goto out;
262+ }
263+ if (ret < 0)
264+ ann_data_stat.no_var++;
265+
266+out:
267+ free(scopes);
268+ return ret;
269+}
270+
271+/**
272+ * find_data_type - Return a data type at the location
273+ * @ms: map and symbol at the location
274+ * @ip: instruction address of the memory access
275+ * @reg: register that holds the base address
276+ * @offset: offset from the base address
277+ *
278+ * This functions searches the debug information of the binary to get the data
279+ * type it accesses. The exact location is expressed by (ip, reg, offset).
280+ * It return %NULL if not found.
281+ */
282+struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
283+ int reg, int offset)
284+{
285+ struct annotated_data_type *result = NULL;
286+ struct dso *dso = map__dso(ms->map);
287+ struct debuginfo *di;
288+ Dwarf_Die type_die;
289+ u64 pc;
290+
291+ di = debuginfo__new(dso->long_name);
292+ if (di == NULL) {
293+ pr_debug("cannot get the debug info\n");
294+ return NULL;
295+ }
296+
297+ /*
298+ * IP is a relative instruction address from the start of the map, as
299+ * it can be randomized/relocated, it needs to translate to PC which is
300+ * a file address for DWARF processing.
301+ */
302+ pc = map__rip_2objdump(ms->map, ip);
303+ if (find_data_type_die(di, pc, reg, offset, &type_die) < 0)
304+ goto out;
305+
306+ result = dso__findnew_data_type(dso, &type_die);
307+
308+out:
309+ debuginfo__delete(di);
310+ return result;
311+}
312+
313+static int alloc_data_type_histograms(struct annotated_data_type *adt, int nr_entries)
314+{
315+ int i;
316+ size_t sz = sizeof(struct type_hist);
317+
318+ sz += sizeof(struct type_hist_entry) * adt->self.size;
319+
320+ /* Allocate a table of pointers for each event */
321+ adt->nr_histograms = nr_entries;
322+ adt->histograms = calloc(nr_entries, sizeof(*adt->histograms));
323+ if (adt->histograms == NULL)
324+ return -ENOMEM;
325+
326+ /*
327+ * Each histogram is allocated for the whole size of the type.
328+ * TODO: Probably we can move the histogram to members.
329+ */
330+ for (i = 0; i < nr_entries; i++) {
331+ adt->histograms[i] = zalloc(sz);
332+ if (adt->histograms[i] == NULL)
333+ goto err;
334+ }
335+ return 0;
336+
337+err:
338+ while (--i >= 0)
339+ free(adt->histograms[i]);
340+ free(adt->histograms);
341+ return -ENOMEM;
342+}
343+
344+static void delete_data_type_histograms(struct annotated_data_type *adt)
345+{
346+ for (int i = 0; i < adt->nr_histograms; i++)
347+ free(adt->histograms[i]);
348+ free(adt->histograms);
349+}
350+
351+void annotated_data_type__tree_delete(struct rb_root *root)
352+{
353+ struct annotated_data_type *pos;
354+
355+ while (!RB_EMPTY_ROOT(root)) {
356+ struct rb_node *node = rb_first(root);
357+
358+ rb_erase(node, root);
359+ pos = rb_entry(node, struct annotated_data_type, node);
360+ delete_members(&pos->self);
361+ delete_data_type_histograms(pos);
362+ free(pos->self.type_name);
363+ free(pos);
364+ }
365+}
366+
367+/**
368+ * annotated_data_type__update_samples - Update histogram
369+ * @adt: Data type to update
370+ * @evsel: Event to update
371+ * @offset: Offset in the type
372+ * @nr_samples: Number of samples at this offset
373+ * @period: Event count at this offset
374+ *
375+ * This function updates type histogram at @ofs for @evsel. Samples are
376+ * aggregated before calling this function so it can be called with more
377+ * than one samples at a certain offset.
378+ */
379+int annotated_data_type__update_samples(struct annotated_data_type *adt,
380+ struct evsel *evsel, int offset,
381+ int nr_samples, u64 period)
382+{
383+ struct type_hist *h;
384+
385+ if (adt == NULL)
386+ return 0;
387+
388+ if (adt->histograms == NULL) {
389+ int nr = evsel->evlist->core.nr_entries;
390+
391+ if (alloc_data_type_histograms(adt, nr) < 0)
392+ return -1;
393+ }
394+
395+ if (offset < 0 || offset >= adt->self.size)
396+ return -1;
397+
398+ h = adt->histograms[evsel->core.idx];
399+
400+ h->nr_samples += nr_samples;
401+ h->addr[offset].nr_samples += nr_samples;
402+ h->period += period;
403+ h->addr[offset].period += period;
404+ return 0;
405+}
tools/perf/util/annotate-data.h+143−0
@@ -0,0 +1,143 @@
1+/* SPDX-License-Identifier: GPL-2.0 */
2+#ifndef _PERF_ANNOTATE_DATA_H
3+#define _PERF_ANNOTATE_DATA_H
4+
5+#include <errno.h>
6+#include <linux/compiler.h>
7+#include <linux/rbtree.h>
8+#include <linux/types.h>
9+
10+struct evsel;
11+struct map_symbol;
12+
13+/**
14+ * struct annotated_member - Type of member field
15+ * @node: List entry in the parent list
16+ * @children: List head for child nodes
17+ * @type_name: Name of the member type
18+ * @var_name: Name of the member variable
19+ * @offset: Offset from the outer data type
20+ * @size: Size of the member field
21+ *
22+ * This represents a member type in a data type.
23+ */
24+struct annotated_member {
25+ struct list_head node;
26+ struct list_head children;
27+ char *type_name;
28+ char *var_name;
29+ int offset;
30+ int size;
31+};
32+
33+/**
34+ * struct type_hist_entry - Histogram entry per offset
35+ * @nr_samples: Number of samples
36+ * @period: Count of event
37+ */
38+struct type_hist_entry {
39+ int nr_samples;
40+ u64 period;
41+};
42+
43+/**
44+ * struct type_hist - Type histogram for each event
45+ * @nr_samples: Total number of samples in this data type
46+ * @period: Total count of the event in this data type
47+ * @offset: Array of histogram entry
48+ */
49+struct type_hist {
50+ u64 nr_samples;
51+ u64 period;
52+ struct type_hist_entry addr[];
53+};
54+
55+/**
56+ * struct annotated_data_type - Data type to profile
57+ * @node: RB-tree node for dso->type_tree
58+ * @self: Actual type information
59+ * @nr_histogram: Number of histogram entries
60+ * @histograms: An array of pointers to histograms
61+ *
62+ * This represents a data type accessed by samples in the profile data.
63+ */
64+struct annotated_data_type {
65+ struct rb_node node;
66+ struct annotated_member self;
67+ int nr_histograms;
68+ struct type_hist **histograms;
69+};
70+
71+extern struct annotated_data_type unknown_type;
72+
73+/**
74+ * struct annotated_data_stat - Debug statistics
75+ * @total: Total number of entry
76+ * @no_sym: No symbol or map found
77+ * @no_insn: Failed to get disasm line
78+ * @no_insn_ops: The instruction has no operands
79+ * @no_mem_ops: The instruction has no memory operands
80+ * @no_reg: Failed to extract a register from the operand
81+ * @no_dbginfo: The binary has no debug information
82+ * @no_cuinfo: Failed to find a compile_unit
83+ * @no_var: Failed to find a matching variable
84+ * @no_typeinfo: Failed to get a type info for the variable
85+ * @invalid_size: Failed to get a size info of the type
86+ * @bad_offset: The access offset is out of the type
87+ */
88+struct annotated_data_stat {
89+ int total;
90+ int no_sym;
91+ int no_insn;
92+ int no_insn_ops;
93+ int no_mem_ops;
94+ int no_reg;
95+ int no_dbginfo;
96+ int no_cuinfo;
97+ int no_var;
98+ int no_typeinfo;
99+ int invalid_size;
100+ int bad_offset;
101+};
102+extern struct annotated_data_stat ann_data_stat;
103+
104+#ifdef HAVE_DWARF_SUPPORT
105+
106+/* Returns data type at the location (ip, reg, offset) */
107+struct annotated_data_type *find_data_type(struct map_symbol *ms, u64 ip,
108+ int reg, int offset);
109+
110+/* Update type access histogram at the given offset */
111+int annotated_data_type__update_samples(struct annotated_data_type *adt,
112+ struct evsel *evsel, int offset,
113+ int nr_samples, u64 period);
114+
115+/* Release all data type information in the tree */
116+void annotated_data_type__tree_delete(struct rb_root *root);
117+
118+#else /* HAVE_DWARF_SUPPORT */
119+
120+static inline struct annotated_data_type *
121+find_data_type(struct map_symbol *ms __maybe_unused, u64 ip __maybe_unused,
122+ int reg __maybe_unused, int offset __maybe_unused)
123+{
124+ return NULL;
125+}
126+
127+static inline int
128+annotated_data_type__update_samples(struct annotated_data_type *adt __maybe_unused,
129+ struct evsel *evsel __maybe_unused,
130+ int offset __maybe_unused,
131+ int nr_samples __maybe_unused,
132+ u64 period __maybe_unused)
133+{
134+ return -1;
135+}
136+
137+static inline void annotated_data_type__tree_delete(struct rb_root *root __maybe_unused)
138+{
139+}
140+
141+#endif /* HAVE_DWARF_SUPPORT */
142+
143+#endif /* _PERF_ANNOTATE_DATA_H */
tools/perf/util/annotate.c+522−165
@@ -25,12 +25,14 @@ · 24 unmodified lines
2525 #include "units.h"
2626 #include "debug.h"
2727 #include "annotate.h"
28+#include "annotate-data.h"
2829 #include "evsel.h"
2930 #include "evlist.h"
3031 #include "bpf-event.h"
3132 #include "bpf-utils.h"
3233 #include "block-range.h"
3334 #include "string2.h"
35+#include "dwarf-regs.h"
3436 #include "util/event.h"
3537 #include "util/sharded_mutex.h"
3638 #include "arch/common.h"
@@ -57,6 +59,9 @@ · 20 unmodified lines
5759
5860 #include <linux/ctype.h>
5961
62+/* global annotation options */
63+struct annotation_options annotate_opts;
64+
6065 static regex_t file_lineno;
6166
6267 static struct ins_ops *ins__find(struct arch *arch, const char *name);
@@ -85,6 +90,8 @@ struct arch { · 22 unmodified lines
8590 struct {
8691 char comment_char;
8792 char skip_functions_char;
93+ char register_char;
94+ char memory_ref_char;
8895 } objdump;
8996 };
9097
@@ -96,6 +103,10 @@ static struct ins_ops nop_ops; · 5 unmodified lines
96103 static struct ins_ops lock_ops;
97104 static struct ins_ops ret_ops;
98105
106+/* Data type collection debug statistics */
107+struct annotated_data_stat ann_data_stat;
108+LIST_HEAD(ann_insn_stat);
109+
99110 static int arch__grow_instructions(struct arch *arch)
100111 {
101112 struct ins *new_instructions;
@@ -188,6 +199,8 @@ static struct arch architectures[] = { · 86 unmodified lines
188199 .insn_suffix = "bwlq",
189200 .objdump = {
190201 .comment_char = '#',
202+ .register_char = '%',
203+ .memory_ref_char = '(',
191204 },
192205 },
193206 {
@@ -340,10 +353,10 @@ bool ins__is_call(const struct ins *ins) · 146 unmodified lines
340353 */
341354 static inline const char *validate_comma(const char *c, struct ins_operands *ops)
342355 {
343− if (ops->raw_comment && c > ops->raw_comment)
356+ if (ops->jump.raw_comment && c > ops->jump.raw_comment)
344357 return NULL;
345358
346− if (ops->raw_func_start && c > ops->raw_func_start)
359+ if (ops->jump.raw_func_start && c > ops->jump.raw_func_start)
347360 return NULL;
348361
349362 return c;
@@ -359,8 +372,8 @@ static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_s · 9 unmodified lines
359372 const char *c = strchr(ops->raw, ',');
360373 u64 start, end;
361374
362− ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
363− ops->raw_func_start = strchr(ops->raw, '<');
375+ ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char);
376+ ops->jump.raw_func_start = strchr(ops->raw, '<');
364377
365378 c = validate_comma(c, ops);
366379
@@ -462,7 +475,16 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, · 95 unmodified lines
462475 ops->target.offset);
463476 }
464477
478+static void jump__delete(struct ins_operands *ops __maybe_unused)
479+{
480+ /*
481+ * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the
482+ * raw string, don't free them.
483+ */
484+}
485+
465486 static struct ins_ops jump_ops = {
487+ .free = jump__delete,
466488 .parse = jump__parse,
467489 .scnprintf = jump__scnprintf,
468490 };
@@ -557,6 +579,34 @@ static struct ins_ops lock_ops = { · 88 unmodified lines
557579 .scnprintf = lock__scnprintf,
558580 };
559581
582+/*
583+ * Check if the operand has more than one registers like x86 SIB addressing:
584+ * 0x1234(%rax, %rbx, 8)
585+ *
586+ * But it doesn't care segment selectors like %gs:0x5678(%rcx), so just check
587+ * the input string after 'memory_ref_char' if exists.
588+ */
589+static bool check_multi_regs(struct arch *arch, const char *op)
590+{
591+ int count = 0;
592+
593+ if (arch->objdump.register_char == 0)
594+ return false;
595+
596+ if (arch->objdump.memory_ref_char) {
597+ op = strchr(op, arch->objdump.memory_ref_char);
598+ if (op == NULL)
599+ return false;
600+ }
601+
602+ while ((op = strchr(op, arch->objdump.register_char)) != NULL) {
603+ count++;
604+ op++;
605+ }
606+
607+ return count > 1;
608+}
609+
560610 static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
561611 {
562612 char *s = strchr(ops->raw, ','), *target, *comment, prev;
@@ -584,6 +634,8 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_sy · 21 unmodified lines
584634 if (ops->source.raw == NULL)
585635 return -1;
586636
637+ ops->source.multi_regs = check_multi_regs(arch, ops->source.raw);
638+
587639 target = skip_spaces(++s);
588640 comment = strchr(s, arch->objdump.comment_char);
589641
@@ -604,6 +656,8 @@ static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_sy · 14 unmodified lines
604656 if (ops->target.raw == NULL)
605657 goto out_free_source;
606658
659+ ops->target.multi_regs = check_multi_regs(arch, ops->target.raw);
660+
607661 if (comment == NULL)
608662 return 0;
609663
@@ -795,6 +849,11 @@ static struct arch *arch__find(const char *name) · 185 unmodified lines
795849 return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
796850 }
797851
852+bool arch__is(struct arch *arch, const char *name)
853+{
854+ return !strcmp(arch->name, name);
855+}
856+
798857 static struct annotated_source *annotated_source__new(void)
799858 {
800859 struct annotated_source *src = zalloc(sizeof(*src));
@@ -810,7 +869,6 @@ static __maybe_unused void annotated_source__delete(struct annotated_source *src · 9 unmodified lines
810869 if (src == NULL)
811870 return;
812871 zfree(&src->histograms);
813− zfree(&src->cycles_hist);
814872 free(src);
815873 }
816874
@@ -845,18 +903,6 @@ static int annotated_source__alloc_histograms(struct annotated_source *src, · 28 unmodified lines
845903 return src->histograms ? 0 : -1;
846904 }
847905
848−/* The cycles histogram is lazily allocated. */
849−static int symbol__alloc_hist_cycles(struct symbol *sym)
850−{
851− struct annotation *notes = symbol__annotation(sym);
852− const size_t size = symbol__size(sym);
853−
854− notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist));
855− if (notes->src->cycles_hist == NULL)
856− return -1;
857− return 0;
858−}
859−
860906 void symbol__annotate_zero_histograms(struct symbol *sym)
861907 {
862908 struct annotation *notes = symbol__annotation(sym);
@@ -865,9 +911,10 @@ void symbol__annotate_zero_histograms(struct symbol *sym) · 2 unmodified lines
865911 if (notes->src != NULL) {
866912 memset(notes->src->histograms, 0,
867913 notes->src->nr_histograms * notes->src->sizeof_sym_hist);
868− if (notes->src->cycles_hist)
869− memset(notes->src->cycles_hist, 0,
870− symbol__size(sym) * sizeof(struct cyc_hist));
914+ }
915+ if (notes->branch && notes->branch->cycles_hist) {
916+ memset(notes->branch->cycles_hist, 0,
917+ symbol__size(sym) * sizeof(struct cyc_hist));
871918 }
872919 annotation__unlock(notes);
873920 }
@@ -958,23 +1005,33 @@ static int __symbol__inc_addr_samples(struct map_symbol *ms, · 84 unmodified lines
9581005 return 0;
9591006 }
9601007
1008+struct annotated_branch *annotation__get_branch(struct annotation *notes)
1009+{
1010+ if (notes == NULL)
1011+ return NULL;
1012+
1013+ if (notes->branch == NULL)
1014+ notes->branch = zalloc(sizeof(*notes->branch));
1015+
1016+ return notes->branch;
1017+}
1018+
9611019 static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
9621020 {
9631021 struct annotation *notes = symbol__annotation(sym);
1022+ struct annotated_branch *branch;
9641023
965− if (notes->src == NULL) {
966− notes->src = annotated_source__new();
967− if (notes->src == NULL)
968− return NULL;
969− goto alloc_cycles_hist;
970− }
1024+ branch = annotation__get_branch(notes);
1025+ if (branch == NULL)
1026+ return NULL;
1027+
1028+ if (branch->cycles_hist == NULL) {
1029+ const size_t size = symbol__size(sym);
9711030
972− if (!notes->src->cycles_hist) {
973−alloc_cycles_hist:
974− symbol__alloc_hist_cycles(sym);
1031+ branch->cycles_hist = calloc(size, sizeof(struct cyc_hist));
9751032 }
9761033
977− return notes->src->cycles_hist;
1034+ return branch->cycles_hist;
9781035 }
9791036
9801037 struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
@@ -1077,12 +1134,20 @@ static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 · 96 unmodified lines
10771134 u64 offset;
10781135
10791136 for (offset = start; offset <= end; offset++) {
1080− if (notes->offsets[offset])
1137+ if (notes->src->offsets[offset])
10811138 n_insn++;
10821139 }
10831140 return n_insn;
10841141 }
10851142
1143+static void annotated_branch__delete(struct annotated_branch *branch)
1144+{
1145+ if (branch) {
1146+ zfree(&branch->cycles_hist);
1147+ free(branch);
1148+ }
1149+}
1150+
10861151 static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch)
10871152 {
10881153 unsigned n_insn;
@@ -1091,6 +1156,7 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 · 2 unmodified lines
10911156
10921157 n_insn = annotation__count_insn(notes, start, end);
10931158 if (n_insn && ch->num && ch->cycles) {
1159+ struct annotated_branch *branch;
10941160 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
10951161
10961162 /* Hide data when there are too many overlaps. */
@@ -1098,54 +1164,76 @@ static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 · 1 unmodified line
10981164 return;
10991165
11001166 for (offset = start; offset <= end; offset++) {
1101− struct annotation_line *al = notes->offsets[offset];
1167+ struct annotation_line *al = notes->src->offsets[offset];
11021168
1103− if (al && al->ipc == 0.0) {
1104− al->ipc = ipc;
1169+ if (al && al->cycles && al->cycles->ipc == 0.0) {
1170+ al->cycles->ipc = ipc;
11051171 cover_insn++;
11061172 }
11071173 }
11081174
1109− if (cover_insn) {
1110− notes->hit_cycles += ch->cycles;
1111− notes->hit_insn += n_insn * ch->num;
1112− notes->cover_insn += cover_insn;
1175+ branch = annotation__get_branch(notes);
1176+ if (cover_insn && branch) {
1177+ branch->hit_cycles += ch->cycles;
1178+ branch->hit_insn += n_insn * ch->num;
1179+ branch->cover_insn += cover_insn;
11131180 }
11141181 }
11151182 }
11161183
1117−void annotation__compute_ipc(struct annotation *notes, size_t size)
1184+static int annotation__compute_ipc(struct annotation *notes, size_t size)
11181185 {
1186+ int err = 0;
11191187 s64 offset;
11201188
1121− if (!notes->src || !notes->src->cycles_hist)
1122− return;
1189+ if (!notes->branch || !notes->branch->cycles_hist)
1190+ return 0;
11231191
1124− notes->total_insn = annotation__count_insn(notes, 0, size - 1);
1125− notes->hit_cycles = 0;
1126− notes->hit_insn = 0;
1127− notes->cover_insn = 0;
1192+ notes->branch->total_insn = annotation__count_insn(notes, 0, size - 1);
1193+ notes->branch->hit_cycles = 0;
1194+ notes->branch->hit_insn = 0;
1195+ notes->branch->cover_insn = 0;
11281196
11291197 annotation__lock(notes);
11301198 for (offset = size - 1; offset >= 0; --offset) {
11311199 struct cyc_hist *ch;
11321200
1133− ch = &notes->src->cycles_hist[offset];
1201+ ch = &notes->branch->cycles_hist[offset];
11341202 if (ch && ch->cycles) {
11351203 struct annotation_line *al;
11361204
1205+ al = notes->src->offsets[offset];
1206+ if (al && al->cycles == NULL) {
1207+ al->cycles = zalloc(sizeof(*al->cycles));
1208+ if (al->cycles == NULL) {
1209+ err = ENOMEM;
1210+ break;
1211+ }
1212+ }
11371213 if (ch->have_start)
11381214 annotation__count_and_fill(notes, ch->start, offset, ch);
1139− al = notes->offsets[offset];
11401215 if (al && ch->num_aggr) {
1141− al->cycles = ch->cycles_aggr / ch->num_aggr;
1142− al->cycles_max = ch->cycles_max;
1143− al->cycles_min = ch->cycles_min;
1216+ al->cycles->avg = ch->cycles_aggr / ch->num_aggr;
1217+ al->cycles->max = ch->cycles_max;
1218+ al->cycles->min = ch->cycles_min;
1219+ }
1220+ }
1221+ }
1222+
1223+ if (err) {
1224+ while (++offset < (s64)size) {
1225+ struct cyc_hist *ch = &notes->branch->cycles_hist[offset];
1226+
1227+ if (ch && ch->cycles) {
1228+ struct annotation_line *al = notes->src->offsets[offset];
1229+ if (al)
1230+ zfree(&al->cycles);
11441231 }
1145− notes->have_cycles = true;
11461232 }
11471233 }
1234+
11481235 annotation__unlock(notes);
1236+ return 0;
11491237 }
11501238
11511239 int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
@@ -1225,6 +1313,7 @@ static void annotation_line__exit(struct annotation_line *al) · 73 unmodified lines
12251313 {
12261314 zfree_srcline(&al->path);
12271315 zfree(&al->line);
1316+ zfree(&al->cycles);
12281317 }
12291318
12301319 static size_t disasm_line_size(int nr)
@@ -1299,6 +1388,7 @@ int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool r · 68 unmodified lines
12991388 void annotation__exit(struct annotation *notes)
13001389 {
13011390 annotated_source__delete(notes->src);
1391+ annotated_branch__delete(notes->branch);
13021392 }
13031393
13041394 static struct sharded_mutex *sharded_mutex;
@@ -1817,7 +1907,6 @@ static int symbol__disassemble_bpf(struct symbol *sym, · 512 unmodified lines
18171907 struct annotate_args *args)
18181908 {
18191909 struct annotation *notes = symbol__annotation(sym);
1820− struct annotation_options *opts = args->options;
18211910 struct bpf_prog_linfo *prog_linfo = NULL;
18221911 struct bpf_prog_info_node *info_node;
18231912 int len = sym->end - sym->start;
@@ -1927,7 +2016,7 @@ static int symbol__disassemble_bpf(struct symbol *sym, · 103 unmodified lines
19272016 prev_buf_size = buf_size;
19282017 fflush(s);
19292018
1930− if (!opts->hide_src_code && srcline) {
2019+ if (!annotate_opts.hide_src_code && srcline) {
19312020 args->offset = -1;
19322021 args->line = strdup(srcline);
19332022 args->line_nr = 0;
@@ -2050,7 +2139,7 @@ static char *expand_tabs(char *line, char **storage, size_t *storage_len) · 116 unmodified lines
20502139
20512140 static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
20522141 {
2053− struct annotation_options *opts = args->options;
2142+ struct annotation_options *opts = &annotate_opts;
20542143 struct map *map = args->ms.map;
20552144 struct dso *dso = map__dso(map);
20562145 char *command;
@@ -2113,12 +2202,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) · 56 unmodified lines
21132202 err = asprintf(&command,
21142203 "%s %s%s --start-address=0x%016" PRIx64
21152204 " --stop-address=0x%016" PRIx64
2116− " -l -d %s %s %s %c%s%c %s%s -C \"$1\"",
2205+ " %s -d %s %s %s %c%s%c %s%s -C \"$1\"",
21172206 opts->objdump_path ?: "objdump",
21182207 opts->disassembler_style ? "-M " : "",
21192208 opts->disassembler_style ?: "",
21202209 map__rip_2objdump(map, sym->start),
21212210 map__rip_2objdump(map, sym->end),
2211+ opts->show_linenr ? "-l" : "",
21222212 opts->show_asm_raw ? "" : "--no-show-raw-insn",
21232213 opts->annotate_src ? "-S" : "",
21242214 opts->prefix ? "--prefix " : "",
@@ -2299,15 +2389,8 @@ void symbol__calc_percent(struct symbol *sym, struct evsel *evsel) · 174 unmodified lines
22992389 annotation__calc_percent(notes, evsel, symbol__size(sym));
23002390 }
23012391
2302−int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
2303− struct annotation_options *options, struct arch **parch)
2392+static int evsel__get_arch(struct evsel *evsel, struct arch **parch)
23042393 {
2305− struct symbol *sym = ms->sym;
2306− struct annotation *notes = symbol__annotation(sym);
2307− struct annotate_args args = {
2308− .evsel = evsel,
2309− .options = options,
2310− };
23112394 struct perf_env *env = evsel__env(evsel);
23122395 const char *arch_name = perf_env__arch(env);
23132396 struct arch *arch;
@@ -2316,25 +2399,45 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, · 2 unmodified lines
23162399 if (!arch_name)
23172400 return errno;
23182401
2319− args.arch = arch = arch__find(arch_name);
2402+ *parch = arch = arch__find(arch_name);
23202403 if (arch == NULL) {
23212404 pr_err("%s: unsupported arch %s\n", __func__, arch_name);
23222405 return ENOTSUP;
23232406 }
23242407
2325− if (parch)
2326− *parch = arch;
2327−
23282408 if (arch->init) {
23292409 err = arch->init(arch, env ? env->cpuid : NULL);
23302410 if (err) {
2331− pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
2411+ pr_err("%s: failed to initialize %s arch priv area\n",
2412+ __func__, arch->name);
23322413 return err;
23332414 }
23342415 }
2416+ return 0;
2417+}
23352418
2419+int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
2420+ struct arch **parch)
2421+{
2422+ struct symbol *sym = ms->sym;
2423+ struct annotation *notes = symbol__annotation(sym);
2424+ struct annotate_args args = {
2425+ .evsel = evsel,
2426+ .options = &annotate_opts,
2427+ };
2428+ struct arch *arch = NULL;
2429+ int err;
2430+
2431+ err = evsel__get_arch(evsel, &arch);
2432+ if (err < 0)
2433+ return err;
2434+
2435+ if (parch)
2436+ *parch = arch;
2437+
2438+ args.arch = arch;
23362439 args.ms = *ms;
2337− if (notes->options && notes->options->full_addr)
2440+ if (annotate_opts.full_addr)
23382441 notes->start = map__objdump_2mem(ms->map, ms->sym->start);
23392442 else
23402443 notes->start = map__rip_2objdump(ms->map, ms->sym->start);
@@ -2342,12 +2445,12 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel, · 1 unmodified line
23422445 return symbol__disassemble(sym, &args);
23432446 }
23442447
2345−static void insert_source_line(struct rb_root *root, struct annotation_line *al,
2346− struct annotation_options *opts)
2448+static void insert_source_line(struct rb_root *root, struct annotation_line *al)
23472449 {
23482450 struct annotation_line *iter;
23492451 struct rb_node **p = &root->rb_node;
23502452 struct rb_node *parent = NULL;
2453+ unsigned int percent_type = annotate_opts.percent_type;
23512454 int i, ret;
23522455
23532456 while (*p != NULL) {
@@ -2358,7 +2461,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, · 4 unmodified lines
23582461 if (ret == 0) {
23592462 for (i = 0; i < al->data_nr; i++) {
23602463 iter->data[i].percent_sum += annotation_data__percent(&al->data[i],
2361− opts->percent_type);
2464+ percent_type);
23622465 }
23632466 return;
23642467 }
@@ -2371,7 +2474,7 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al, · 6 unmodified lines
23712474
23722475 for (i = 0; i < al->data_nr; i++) {
23732476 al->data[i].percent_sum = annotation_data__percent(&al->data[i],
2374− opts->percent_type);
2477+ percent_type);
23752478 }
23762479
23772480 rb_link_node(&al->rb_node, parent, p);
@@ -2493,8 +2596,7 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) · 115 unmodified lines
24932596 return 0;
24942597 }
24952598
2496−int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,
2497− struct annotation_options *opts)
2599+int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel)
24982600 {
24992601 struct map *map = ms->map;
25002602 struct symbol *sym = ms->sym;
@@ -2505,6 +2607,7 @@ int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel, · 4 unmodified lines
25052607 struct annotation *notes = symbol__annotation(sym);
25062608 struct sym_hist *h = annotation__histogram(notes, evsel->core.idx);
25072609 struct annotation_line *pos, *queue = NULL;
2610+ struct annotation_options *opts = &annotate_opts;
25082611 u64 start = map__rip_2objdump(map, sym->start);
25092612 int printed = 2, queue_len = 0, addr_fmt_width;
25102613 int more = 0;
@@ -2633,8 +2736,7 @@ static void FILE__write_graph(void *fp, int graph) · 122 unmodified lines
26332736 fputs(s, fp);
26342737 }
26352738
2636−static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp,
2637− struct annotation_options *opts)
2739+static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp)
26382740 {
26392741 struct annotation *notes = symbol__annotation(sym);
26402742 struct annotation_write_ops wops = {
@@ -2649,9 +2751,9 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, · 8 unmodified lines
26492751 struct annotation_line *al;
26502752
26512753 list_for_each_entry(al, &notes->src->source, node) {
2652− if (annotation_line__filter(al, notes))
2754+ if (annotation_line__filter(al))
26532755 continue;
2654− annotation_line__write(al, notes, &wops, opts);
2756+ annotation_line__write(al, notes, &wops);
26552757 fputc('\n', fp);
26562758 wops.first_line = false;
26572759 }
@@ -2659,8 +2761,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, · 1 unmodified line
26592761 return 0;
26602762 }
26612763
2662−int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,
2663− struct annotation_options *opts)
2764+int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel)
26642765 {
26652766 const char *ev_name = evsel__name(evsel);
26662767 char buf[1024];
@@ -2682,7 +2783,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, · 15 unmodified lines
26822783
26832784 fprintf(fp, "%s() %s\nEvent: %s\n\n",
26842785 ms->sym->name, map__dso(ms->map)->long_name, ev_name);
2685− symbol__annotate_fprintf2(ms->sym, fp, opts);
2786+ symbol__annotate_fprintf2(ms->sym, fp);
26862787
26872788 fclose(fp);
26882789 err = 0;
@@ -2769,7 +2870,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) · 80 unmodified lines
27692870 return;
27702871
27712872 for (offset = 0; offset < size; ++offset) {
2772− struct annotation_line *al = notes->offsets[offset];
2873+ struct annotation_line *al = notes->src->offsets[offset];
27732874 struct disasm_line *dl;
27742875
27752876 dl = disasm_line(al);
@@ -2777,7 +2878,7 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) · 1 unmodified line
27772878 if (!disasm_line__is_valid_local_jump(dl, sym))
27782879 continue;
27792880
2780− al = notes->offsets[dl->ops.target.offset];
2881+ al = notes->src->offsets[dl->ops.target.offset];
27812882
27822883 /*
27832884 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
@@ -2794,19 +2895,20 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) · 10 unmodified lines
27942895 void annotation__set_offsets(struct annotation *notes, s64 size)
27952896 {
27962897 struct annotation_line *al;
2898+ struct annotated_source *src = notes->src;
27972899
2798− notes->max_line_len = 0;
2799− notes->nr_entries = 0;
2800− notes->nr_asm_entries = 0;
2900+ src->max_line_len = 0;
2901+ src->nr_entries = 0;
2902+ src->nr_asm_entries = 0;
28012903
2802− list_for_each_entry(al, &notes->src->source, node) {
2904+ list_for_each_entry(al, &src->source, node) {
28032905 size_t line_len = strlen(al->line);
28042906
2805− if (notes->max_line_len < line_len)
2806− notes->max_line_len = line_len;
2807− al->idx = notes->nr_entries++;
2907+ if (src->max_line_len < line_len)
2908+ src->max_line_len = line_len;
2909+ al->idx = src->nr_entries++;
28082910 if (al->offset != -1) {
2809− al->idx_asm = notes->nr_asm_entries++;
2911+ al->idx_asm = src->nr_asm_entries++;
28102912 /*
28112913 * FIXME: short term bandaid to cope with assembly
28122914 * routines that comes with labels in the same column
@@ -2815,7 +2917,7 @@ void annotation__set_offsets(struct annotation *notes, s64 size) · 2 unmodified lines
28152917 * E.g. copy_user_generic_unrolled
28162918 */
28172919 if (al->offset < size)
2818− notes->offsets[al->offset] = al;
2920+ notes->src->offsets[al->offset] = al;
28192921 } else
28202922 al->idx_asm = -1;
28212923 }
@@ -2858,24 +2960,24 @@ void annotation__init_column_widths(struct annotation *notes, struct symbol *sym · 36 unmodified lines
28582960
28592961 void annotation__update_column_widths(struct annotation *notes)
28602962 {
2861− if (notes->options->use_offset)
2963+ if (annotate_opts.use_offset)
28622964 notes->widths.target = notes->widths.min_addr;
2863− else if (notes->options->full_addr)
2965+ else if (annotate_opts.full_addr)
28642966 notes->widths.target = BITS_PER_LONG / 4;
28652967 else
28662968 notes->widths.target = notes->widths.max_addr;
28672969
28682970 notes->widths.addr = notes->widths.target;
28692971
2870− if (notes->options->show_nr_jumps)
2972+ if (annotate_opts.show_nr_jumps)
28712973 notes->widths.addr += notes->widths.jumps + 1;
28722974 }
28732975
28742976 void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *ms)
28752977 {
2876− notes->options->full_addr = !notes->options->full_addr;
2978+ annotate_opts.full_addr = !annotate_opts.full_addr;
28772979
2878− if (notes->options->full_addr)
2980+ if (annotate_opts.full_addr)
28792981 notes->start = map__objdump_2mem(ms->map, ms->sym->start);
28802982 else
28812983 notes->start = map__rip_2objdump(ms->map, ms->sym->start);
@@ -2884,8 +2986,7 @@ void annotation__toggle_full_addr(struct annotation *notes, struct map_symbol *m · 2 unmodified lines
28842986 }
28852987
28862988 static void annotation__calc_lines(struct annotation *notes, struct map *map,
2887− struct rb_root *root,
2888− struct annotation_options *opts)
2989+ struct rb_root *root)
28892990 {
28902991 struct annotation_line *al;
28912992 struct rb_root tmp_root = RB_ROOT;
@@ -2898,7 +2999,7 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, · 6 unmodified lines
28982999 double percent;
28993000
29003001 percent = annotation_data__percent(&al->data[i],
2901− opts->percent_type);
3002+ annotate_opts.percent_type);
29023003
29033004 if (percent > percent_max)
29043005 percent_max = percent;
@@ -2909,22 +3010,20 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, · 4 unmodified lines
29093010
29103011 al->path = get_srcline(map__dso(map), notes->start + al->offset, NULL,
29113012 false, true, notes->start + al->offset);
2912− insert_source_line(&tmp_root, al, opts);
3013+ insert_source_line(&tmp_root, al);
29133014 }
29143015
29153016 resort_source_line(root, &tmp_root);
29163017 }
29173018
2918−static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root,
2919− struct annotation_options *opts)
3019+static void symbol__calc_lines(struct map_symbol *ms, struct rb_root *root)
29203020 {
29213021 struct annotation *notes = symbol__annotation(ms->sym);
29223022
2923− annotation__calc_lines(notes, ms->map, root, opts);
3023+ annotation__calc_lines(notes, ms->map, root);
29243024 }
29253025
2926−int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel,
2927− struct annotation_options *opts)
3026+int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel)
29283027 {
29293028 struct dso *dso = map__dso(ms->map);
29303029 struct symbol *sym = ms->sym;
@@ -2933,7 +3032,7 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, · 2 unmodified lines
29333032 char buf[1024];
29343033 int err;
29353034
2936− err = symbol__annotate2(ms, evsel, opts, NULL);
3035+ err = symbol__annotate2(ms, evsel, NULL);
29373036 if (err) {
29383037 char msg[BUFSIZ];
29393038
@@ -2943,31 +3042,31 @@ int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, · 3 unmodified lines
29433042 return -1;
29443043 }
29453044
2946− if (opts->print_lines) {
2947− srcline_full_filename = opts->full_path;
2948− symbol__calc_lines(ms, &source_line, opts);
3045+ if (annotate_opts.print_lines) {
3046+ srcline_full_filename = annotate_opts.full_path;
3047+ symbol__calc_lines(ms, &source_line);
29493048 print_summary(&source_line, dso->long_name);
29503049 }
29513050
29523051 hists__scnprintf_title(hists, buf, sizeof(buf));
29533052 fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
2954− buf, percent_type_str(opts->percent_type), sym->name, dso->long_name);
2955− symbol__annotate_fprintf2(sym, stdout, opts);
3053+ buf, percent_type_str(annotate_opts.percent_type), sym->name,
3054+ dso->long_name);
3055+ symbol__annotate_fprintf2(sym, stdout);
29563056
29573057 annotated_source__purge(symbol__annotation(sym)->src);
29583058
29593059 return 0;
29603060 }
29613061
2962−int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel,
2963− struct annotation_options *opts)
3062+int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel)
29643063 {
29653064 struct dso *dso = map__dso(ms->map);
29663065 struct symbol *sym = ms->sym;
29673066 struct rb_root source_line = RB_ROOT;
29683067 int err;
29693068
2970− err = symbol__annotate(ms, evsel, opts, NULL);
3069+ err = symbol__annotate(ms, evsel, NULL);
29713070 if (err) {
29723071 char msg[BUFSIZ];
29733072
@@ -2979,13 +3078,13 @@ int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, · 5 unmodified lines
29793078
29803079 symbol__calc_percent(sym, evsel);
29813080
2982− if (opts->print_lines) {
2983− srcline_full_filename = opts->full_path;
2984− symbol__calc_lines(ms, &source_line, opts);
3081+ if (annotate_opts.print_lines) {
3082+ srcline_full_filename = annotate_opts.full_path;
3083+ symbol__calc_lines(ms, &source_line);
29853084 print_summary(&source_line, dso->long_name);
29863085 }
29873086
2988− symbol__annotate_printf(ms, evsel, opts);
3087+ symbol__annotate_printf(ms, evsel);
29893088
29903089 annotated_source__purge(symbol__annotation(sym)->src);
29913090
@@ -3046,19 +3145,20 @@ call_like: · 54 unmodified lines
30463145 obj__printf(obj, " ");
30473146 }
30483147
3049− disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset, notes->widths.max_ins_name);
3148+ disasm_line__scnprintf(dl, bf, size, !annotate_opts.use_offset, notes->widths.max_ins_name);
30503149 }
30513150
30523151 static void ipc_coverage_string(char *bf, int size, struct annotation *notes)
30533152 {
30543153 double ipc = 0.0, coverage = 0.0;
3154+ struct annotated_branch *branch = annotation__get_branch(notes);
30553155
3056− if (notes->hit_cycles)
3057− ipc = notes->hit_insn / ((double)notes->hit_cycles);
3156+ if (branch && branch->hit_cycles)
3157+ ipc = branch->hit_insn / ((double)branch->hit_cycles);
30583158
3059− if (notes->total_insn) {
3060− coverage = notes->cover_insn * 100.0 /
3061− ((double)notes->total_insn);
3159+ if (branch && branch->total_insn) {
3160+ coverage = branch->cover_insn * 100.0 /
3161+ ((double)branch->total_insn);
30623162 }
30633163
30643164 scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)",
@@ -3083,8 +3183,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 18 unmodified lines
30833183 int printed;
30843184
30853185 if (first_line && (al->offset == -1 || percent_max == 0.0)) {
3086− if (notes->have_cycles) {
3087− if (al->ipc == 0.0 && al->cycles == 0)
3186+ if (notes->branch && al->cycles) {
3187+ if (al->cycles->ipc == 0.0 && al->cycles->avg == 0)
30883188 show_title = true;
30893189 } else
30903190 show_title = true;
@@ -3120,18 +3220,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 29 unmodified lines
31203220 }
31213221 }
31223222
3123− if (notes->have_cycles) {
3124− if (al->ipc)
3125− obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
3223+ if (notes->branch) {
3224+ if (al->cycles && al->cycles->ipc)
3225+ obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->cycles->ipc);
31263226 else if (!show_title)
31273227 obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " ");
31283228 else
31293229 obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
31303230
3131− if (!notes->options->show_minmax_cycle) {
3132− if (al->cycles)
3231+ if (!annotate_opts.show_minmax_cycle) {
3232+ if (al->cycles && al->cycles->avg)
31333233 obj__printf(obj, "%*" PRIu64 " ",
3134− ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
3234+ ANNOTATION__CYCLES_WIDTH - 1, al->cycles->avg);
31353235 else if (!show_title)
31363236 obj__printf(obj, "%*s",
31373237 ANNOTATION__CYCLES_WIDTH, " ");
@@ -3145,8 +3245,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 7 unmodified lines
31453245
31463246 scnprintf(str, sizeof(str),
31473247 "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")",
3148− al->cycles, al->cycles_min,
3149− al->cycles_max);
3248+ al->cycles->avg, al->cycles->min,
3249+ al->cycles->max);
31503250
31513251 obj__printf(obj, "%*s ",
31523252 ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
@@ -3172,7 +3272,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 19 unmodified lines
31723272 if (!*al->line)
31733273 obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " ");
31743274 else if (al->offset == -1) {
3175− if (al->line_nr && notes->options->show_linenr)
3275+ if (al->line_nr && annotate_opts.show_linenr)
31763276 printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr);
31773277 else
31783278 printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->widths.addr, " ");
@@ -3182,15 +3282,15 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati · 3 unmodified lines
31823282 u64 addr = al->offset;
31833283 int color = -1;
31843284
3185− if (!notes->options->use_offset)
3285+ if (!annotate_opts.use_offset)
31863286 addr += notes->start;
31873287
3188− if (!notes->options->use_offset) {
3288+ if (!annotate_opts.use_offset) {
31893289 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
31903290 } else {
31913291 if (al->jump_sources &&
3192− notes->options->offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) {
3193− if (notes->options->show_nr_jumps) {
3292+ annotate_opts.offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) {
3293+ if (annotate_opts.show_nr_jumps) {
31943294 int prev;
31953295 printed = scnprintf(bf, sizeof(bf), "%*d ",
31963296 notes->widths.jumps,
@@ -3204,9 +3304,9 @@ print_addr: · 7 unmodified lines
32043304 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
32053305 notes->widths.target, addr);
32063306 } else if (ins__is_call(&disasm_line(al)->ins) &&
3207− notes->options->offset_level >= ANNOTATION__OFFSET_CALL) {
3307+ annotate_opts.offset_level >= ANNOTATION__OFFSET_CALL) {
32083308 goto print_addr;
3209− } else if (notes->options->offset_level == ANNOTATION__MAX_OFFSET_LEVEL) {
3309+ } else if (annotate_opts.offset_level == ANNOTATION__MAX_OFFSET_LEVEL) {
32103310 goto print_addr;
32113311 } else {
32123312 printed = scnprintf(bf, sizeof(bf), "%-*s ",
@@ -3228,43 +3328,44 @@ print_addr: · 15 unmodified lines
32283328 }
32293329
32303330 void annotation_line__write(struct annotation_line *al, struct annotation *notes,
3231− struct annotation_write_ops *wops,
3232− struct annotation_options *opts)
3331+ struct annotation_write_ops *wops)
32333332 {
32343333 __annotation_line__write(al, notes, wops->first_line, wops->current_entry,
32353334 wops->change_color, wops->width, wops->obj,
3236− opts->percent_type,
3335+ annotate_opts.percent_type,
32373336 wops->set_color, wops->set_percent_color,
32383337 wops->set_jumps_percent_color, wops->printf,
32393338 wops->write_graph);
32403339 }
32413340
32423341 int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel,
3243− struct annotation_options *options, struct arch **parch)
3342+ struct arch **parch)
32443343 {
32453344 struct symbol *sym = ms->sym;
32463345 struct annotation *notes = symbol__annotation(sym);
32473346 size_t size = symbol__size(sym);
32483347 int nr_pcnt = 1, err;
32493348
3250− notes->offsets = zalloc(size * sizeof(struct annotation_line *));
3251− if (notes->offsets == NULL)
3349+ notes->src->offsets = zalloc(size * sizeof(struct annotation_line *));
3350+ if (notes->src->offsets == NULL)
32523351 return ENOMEM;
32533352
32543353 if (evsel__is_group_event(evsel))
32553354 nr_pcnt = evsel->core.nr_members;
32563355
3257− err = symbol__annotate(ms, evsel, options, parch);
3356+ err = symbol__annotate(ms, evsel, parch);
32583357 if (err)
32593358 goto out_free_offsets;
32603359
3261− notes->options = options;
3262−
32633360 symbol__calc_percent(sym, evsel);
32643361
32653362 annotation__set_offsets(notes, size);
32663363 annotation__mark_jump_targets(notes, sym);
3267− annotation__compute_ipc(notes, size);
3364+
3365+ err = annotation__compute_ipc(notes, size);
3366+ if (err)
3367+ goto out_free_offsets;
3368+
32683369 annotation__init_column_widths(notes, sym);
32693370 notes->nr_events = nr_pcnt;
32703371
@@ -3274,7 +3375,7 @@ int symbol__annotate2(struct map_symbol *ms, struct evsel *evsel, · 3 unmodified lines
32743375 return 0;
32753376
32763377 out_free_offsets:
3277− zfree(&notes->offsets);
3378+ zfree(&notes->src->offsets);
32783379 return err;
32793380 }
32803381
@@ -3337,8 +3438,10 @@ static int annotation__config(const char *var, const char *value, void *data) · 56 unmodified lines
33373438 return 0;
33383439 }
33393440
3340−void annotation_options__init(struct annotation_options *opt)
3441+void annotation_options__init(void)
33413442 {
3443+ struct annotation_options *opt = &annotate_opts;
3444+
33423445 memset(opt, 0, sizeof(*opt));
33433446
33443447 /* Default values. */
@@ -3349,16 +3452,15 @@ void annotation_options__init(struct annotation_options *opt) · 4 unmodified lines
33493452 opt->percent_type = PERCENT_PERIOD_LOCAL;
33503453 }
33513454
3352−
3353−void annotation_options__exit(struct annotation_options *opt)
3455+void annotation_options__exit(void)
33543456 {
3355− zfree(&opt->disassembler_style);
3356− zfree(&opt->objdump_path);
3457+ zfree(&annotate_opts.disassembler_style);
3458+ zfree(&annotate_opts.objdump_path);
33573459 }
33583460
3359−void annotation_config__init(struct annotation_options *opt)
3461+void annotation_config__init(void)
33603462 {
3361− perf_config(annotation__config, opt);
3463+ perf_config(annotation__config, &annotate_opts);
33623464 }
33633465
33643466 static unsigned int parse_percent_type(char *str1, char *str2)
@@ -3382,10 +3484,9 @@ static unsigned int parse_percent_type(char *str1, char *str2) · 17 unmodified lines
33823484 return type;
33833485 }
33843486
3385−int annotate_parse_percent_type(const struct option *opt, const char *_str,
3487+int annotate_parse_percent_type(const struct option *opt __maybe_unused, const char *_str,
33863488 int unset __maybe_unused)
33873489 {
3388− struct annotation_options *opts = opt->value;
33893490 unsigned int type;
33903491 char *str1, *str2;
33913492 int err = -1;
@@ -3404,7 +3505,7 @@ int annotate_parse_percent_type(const struct option *opt, const char *_str, · 12 unmodified lines
34043505 if (type == (unsigned int) -1)
34053506 type = parse_percent_type(str2, str1);
34063507 if (type != (unsigned int) -1) {
3407− opts->percent_type = type;
3508+ annotate_opts.percent_type = type;
34083509 err = 0;
34093510 }
34103511
@@ -3413,11 +3514,267 @@ out: · 2 unmodified lines
34133514 return err;
34143515 }
34153516
3416−int annotate_check_args(struct annotation_options *args)
3517+int annotate_check_args(void)
34173518 {
3519+ struct annotation_options *args = &annotate_opts;
3520+
34183521 if (args->prefix_strip && !args->prefix) {
34193522 pr_err("--prefix-strip requires --prefix\n");
34203523 return -1;
34213524 }
34223525 return 0;
34233526 }
3527+
3528+/*
3529+ * Get register number and access offset from the given instruction.
3530+ * It assumes AT&T x86 asm format like OFFSET(REG). Maybe it needs
3531+ * to revisit the format when it handles different architecture.
3532+ * Fills @reg and @offset when return 0.
3533+ */
3534+static int extract_reg_offset(struct arch *arch, const char *str,
3535+ struct annotated_op_loc *op_loc)
3536+{
3537+ char *p;
3538+ char *regname;
3539+
3540+ if (arch->objdump.register_char == 0)
3541+ return -1;
3542+
3543+ /*
3544+ * It should start from offset, but it's possible to skip 0
3545+ * in the asm. So 0(%rax) should be same as (%rax).
3546+ *
3547+ * However, it also start with a segment select register like
3548+ * %gs:0x18(%rbx). In that case it should skip the part.
3549+ */
3550+ if (*str == arch->objdump.register_char) {
3551+ while (*str && !isdigit(*str) &&
3552+ *str != arch->objdump.memory_ref_char)
3553+ str++;
3554+ }
3555+
3556+ op_loc->offset = strtol(str, &p, 0);
3557+
3558+ p = strchr(p, arch->objdump.register_char);
3559+ if (p == NULL)
3560+ return -1;
3561+
3562+ regname = strdup(p);
3563+ if (regname == NULL)
3564+ return -1;
3565+
3566+ op_loc->reg = get_dwarf_regnum(regname, 0);
3567+ free(regname);
3568+ return 0;
3569+}
3570+
3571+/**
3572+ * annotate_get_insn_location - Get location of instruction
3573+ * @arch: the architecture info
3574+ * @dl: the target instruction
3575+ * @loc: a buffer to save the data
3576+ *
3577+ * Get detailed location info (register and offset) in the instruction.
3578+ * It needs both source and target operand and whether it accesses a
3579+ * memory location. The offset field is meaningful only when the
3580+ * corresponding mem flag is set.
3581+ *
3582+ * Some examples on x86:
3583+ *
3584+ * mov (%rax), %rcx # src_reg = rax, src_mem = 1, src_offset = 0
3585+ * # dst_reg = rcx, dst_mem = 0
3586+ *
3587+ * mov 0x18, %r8 # src_reg = -1, dst_reg = r8
3588+ */
3589+int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
3590+ struct annotated_insn_loc *loc)
3591+{
3592+ struct ins_operands *ops;
3593+ struct annotated_op_loc *op_loc;
3594+ int i;
3595+
3596+ if (!strcmp(dl->ins.name, "lock"))
3597+ ops = dl->ops.locked.ops;
3598+ else
3599+ ops = &dl->ops;
3600+
3601+ if (ops == NULL)
3602+ return -1;
3603+
3604+ memset(loc, 0, sizeof(*loc));
3605+
3606+ for_each_insn_op_loc(loc, i, op_loc) {
3607+ const char *insn_str = ops->source.raw;
3608+
3609+ if (i == INSN_OP_TARGET)
3610+ insn_str = ops->target.raw;
3611+
3612+ /* Invalidate the register by default */
3613+ op_loc->reg = -1;
3614+
3615+ if (insn_str == NULL)
3616+ continue;
3617+
3618+ if (strchr(insn_str, arch->objdump.memory_ref_char)) {
3619+ op_loc->mem_ref = true;
3620+ extract_reg_offset(arch, insn_str, op_loc);
3621+ } else {
3622+ char *s = strdup(insn_str);
3623+
3624+ if (s) {
3625+ op_loc->reg = get_dwarf_regnum(s, 0);
3626+ free(s);
3627+ }
3628+ }
3629+ }
3630+
3631+ return 0;
3632+}
3633+
3634+static void symbol__ensure_annotate(struct map_symbol *ms, struct evsel *evsel)
3635+{
3636+ struct disasm_line *dl, *tmp_dl;
3637+ struct annotation *notes;
3638+
3639+ notes = symbol__annotation(ms->sym);
3640+ if (!list_empty(&notes->src->source))
3641+ return;
3642+
3643+ if (symbol__annotate(ms, evsel, NULL) < 0)
3644+ return;
3645+
3646+ /* remove non-insn disasm lines for simplicity */
3647+ list_for_each_entry_safe(dl, tmp_dl, &notes->src->source, al.node) {
3648+ if (dl->al.offset == -1) {
3649+ list_del(&dl->al.node);
3650+ free(dl);
3651+ }
3652+ }
3653+}
3654+
3655+static struct disasm_line *find_disasm_line(struct symbol *sym, u64 ip)
3656+{
3657+ struct disasm_line *dl;
3658+ struct annotation *notes;
3659+
3660+ notes = symbol__annotation(sym);
3661+
3662+ list_for_each_entry(dl, &notes->src->source, al.node) {
3663+ if (sym->start + dl->al.offset == ip)
3664+ return dl;
3665+ }
3666+ return NULL;
3667+}
3668+
3669+static struct annotated_item_stat *annotate_data_stat(struct list_head *head,
3670+ const char *name)
3671+{
3672+ struct annotated_item_stat *istat;
3673+
3674+ list_for_each_entry(istat, head, list) {
3675+ if (!strcmp(istat->name, name))
3676+ return istat;
3677+ }
3678+
3679+ istat = zalloc(sizeof(*istat));
3680+ if (istat == NULL)
3681+ return NULL;
3682+
3683+ istat->name = strdup(name);
3684+ if (istat->name == NULL) {
3685+ free(istat);
3686+ return NULL;
3687+ }
3688+
3689+ list_add_tail(&istat->list, head);
3690+ return istat;
3691+}
3692+
3693+/**
3694+ * hist_entry__get_data_type - find data type for given hist entry
3695+ * @he: hist entry
3696+ *
3697+ * This function first annotates the instruction at @he->ip and extracts
3698+ * register and offset info from it. Then it searches the DWARF debug
3699+ * info to get a variable and type information using the address, register,
3700+ * and offset.
3701+ */
3702+struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he)
3703+{
3704+ struct map_symbol *ms = &he->ms;
3705+ struct evsel *evsel = hists_to_evsel(he->hists);
3706+ struct arch *arch;
3707+ struct disasm_line *dl;
3708+ struct annotated_insn_loc loc;
3709+ struct annotated_op_loc *op_loc;
3710+ struct annotated_data_type *mem_type;
3711+ struct annotated_item_stat *istat;
3712+ u64 ip = he->ip;
3713+ int i;
3714+
3715+ ann_data_stat.total++;
3716+
3717+ if (ms->map == NULL || ms->sym == NULL) {
3718+ ann_data_stat.no_sym++;
3719+ return NULL;
3720+ }
3721+
3722+ if (!symbol_conf.init_annotation) {
3723+ ann_data_stat.no_sym++;
3724+ return NULL;
3725+ }
3726+
3727+ if (evsel__get_arch(evsel, &arch) < 0) {
3728+ ann_data_stat.no_insn++;
3729+ return NULL;
3730+ }
3731+
3732+ /* Make sure it runs objdump to get disasm of the function */
3733+ symbol__ensure_annotate(ms, evsel);
3734+
3735+ /*
3736+ * Get a disasm to extract the location from the insn.
3737+ * This is too slow...
3738+ */
3739+ dl = find_disasm_line(ms->sym, ip);
3740+ if (dl == NULL) {
3741+ ann_data_stat.no_insn++;
3742+ return NULL;
3743+ }
3744+
3745+ istat = annotate_data_stat(&ann_insn_stat, dl->ins.name);
3746+ if (istat == NULL) {
3747+ ann_data_stat.no_insn++;
3748+ return NULL;
3749+ }
3750+
3751+ if (annotate_get_insn_location(arch, dl, &loc) < 0) {
3752+ ann_data_stat.no_insn_ops++;
3753+ istat->bad++;
3754+ return NULL;
3755+ }
3756+
3757+ for_each_insn_op_loc(&loc, i, op_loc) {
3758+ if (!op_loc->mem_ref)
3759+ continue;
3760+
3761+ mem_type = find_data_type(ms, ip, op_loc->reg, op_loc->offset);
3762+ if (mem_type)
3763+ istat->good++;
3764+ else
3765+ istat->bad++;
3766+
3767+ if (symbol_conf.annotate_data_sample) {
3768+ annotated_data_type__update_samples(mem_type, evsel,
3769+ op_loc->offset,
3770+ he->stat.nr_events,
3771+ he->stat.period);
3772+ }
3773+ he->mem_type_off = op_loc->offset;
3774+ return mem_type;
3775+ }
3776+
3777+ ann_data_stat.no_mem_ops++;
3778+ istat->bad++;
3779+ return NULL;
3780+}
tools/perf/util/annotate.h+100−44
@@ -23,6 +23,7 @@ struct option; · 22 unmodified lines
2323 struct perf_sample;
2424 struct evsel;
2525 struct symbol;
26+struct annotated_data_type;
2627
2728 struct ins {
2829 const char *name;
@@ -31,8 +32,6 @@ struct ins { · 2 unmodified lines
3132
3233 struct ins_operands {
3334 char *raw;
34− char *raw_comment;
35− char *raw_func_start;
3635 struct {
3736 char *raw;
3837 char *name;
@@ -41,22 +40,30 @@ struct ins_operands { · 2 unmodified lines
4140 s64 offset;
4241 bool offset_avail;
4342 bool outside;
43+ bool multi_regs;
4444 } target;
4545 union {
4646 struct {
4747 char *raw;
4848 char *name;
4949 u64 addr;
50+ bool multi_regs;
5051 } source;
5152 struct {
5253 struct ins ins;
5354 struct ins_operands *ops;
5455 } locked;
56+ struct {
57+ char *raw_comment;
58+ char *raw_func_start;
59+ } jump;
5560 };
5661 };
5762
5863 struct arch;
5964
65+bool arch__is(struct arch *arch, const char *name);
66+
6067 struct ins_ops {
6168 void (*free)(struct ins_operands *ops);
6269 int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms);
@@ -101,6 +108,8 @@ struct annotation_options { · 38 unmodified lines
101108 unsigned int percent_type;
102109 };
103110
111+extern struct annotation_options annotate_opts;
112+
104113 enum {
105114 ANNOTATION__OFFSET_JUMP_TARGETS = 1,
106115 ANNOTATION__OFFSET_CALL,
@@ -130,6 +139,13 @@ struct annotation_data { · 23 unmodified lines
130139 struct sym_hist_entry he;
131140 };
132141
142+struct cycles_info {
143+ float ipc;
144+ u64 avg;
145+ u64 max;
146+ u64 min;
147+};
148+
133149 struct annotation_line {
134150 struct list_head node;
135151 struct rb_node rb_node;
@@ -137,12 +153,9 @@ struct annotation_line { · 1 unmodified line
137153 char *line;
138154 int line_nr;
139155 char *fileloc;
140− int jump_sources;
141− float ipc;
142− u64 cycles;
143− u64 cycles_max;
144− u64 cycles_min;
145156 char *path;
157+ struct cycles_info *cycles;
158+ int jump_sources;
146159 u32 idx;
147160 int idx_asm;
148161 int data_nr;
@@ -214,8 +227,7 @@ struct annotation_write_ops { · 65 unmodified lines
214227 };
215228
216229 void annotation_line__write(struct annotation_line *al, struct annotation *notes,
217− struct annotation_write_ops *ops,
218− struct annotation_options *opts);
230+ struct annotation_write_ops *ops);
219231
220232 int __annotation__scnprintf_samples_period(struct annotation *notes,
221233 char *bf, size_t size,
@@ -264,27 +276,29 @@ struct cyc_hist { · 42 unmodified lines
264276 * returns.
265277 */
266278 struct annotated_source {
267− struct list_head source;
268− int nr_histograms;
269− size_t sizeof_sym_hist;
270− struct cyc_hist *cycles_hist;
271− struct sym_hist *histograms;
279+ struct list_head source;
280+ size_t sizeof_sym_hist;
281+ struct sym_hist *histograms;
282+ struct annotation_line **offsets;
283+ int nr_histograms;
284+ int nr_entries;
285+ int nr_asm_entries;
286+ u16 max_line_len;
272287 };
273288
274−struct LOCKABLE annotation {
275− u64 max_coverage;
276− u64 start;
289+struct annotated_branch {
277290 u64 hit_cycles;
278291 u64 hit_insn;
279292 unsigned int total_insn;
280293 unsigned int cover_insn;
281− struct annotation_options *options;
282− struct annotation_line **offsets;
294+ struct cyc_hist *cycles_hist;
295+ u64 max_coverage;
296+};
297+
298+struct LOCKABLE annotation {
299+ u64 start;
283300 int nr_events;
284301 int max_jump_sources;
285− int nr_entries;
286− int nr_asm_entries;
287− u16 max_line_len;
288302 struct {
289303 u8 addr;
290304 u8 jumps;
@@ -293,8 +307,8 @@ struct LOCKABLE annotation { · 2 unmodified lines
293307 u8 max_addr;
294308 u8 max_ins_name;
295309 } widths;
296− bool have_cycles;
297310 struct annotated_source *src;
311+ struct annotated_branch *branch;
298312 };
299313
300314 static inline void annotation__init(struct annotation *notes __maybe_unused)
@@ -308,10 +322,10 @@ bool annotation__trylock(struct annotation *notes) EXCLUSIVE_TRYLOCK_FUNCTION(tr · 7 unmodified lines
308322
309323 static inline int annotation__cycles_width(struct annotation *notes)
310324 {
311− if (notes->have_cycles && notes->options->show_minmax_cycle)
325+ if (notes->branch && annotate_opts.show_minmax_cycle)
312326 return ANNOTATION__IPC_WIDTH + ANNOTATION__MINMAX_CYCLES_WIDTH;
313327
314− return notes->have_cycles ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
328+ return notes->branch ? ANNOTATION__IPC_WIDTH + ANNOTATION__CYCLES_WIDTH : 0;
315329 }
316330
317331 static inline int annotation__pcnt_width(struct annotation *notes)
@@ -319,13 +333,12 @@ static inline int annotation__pcnt_width(struct annotation *notes) · 1 unmodified line
319333 return (symbol_conf.show_total_period ? 12 : 7) * notes->nr_events;
320334 }
321335
322−static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
336+static inline bool annotation_line__filter(struct annotation_line *al)
323337 {
324− return notes->options->hide_src_code && al->offset == -1;
338+ return annotate_opts.hide_src_code && al->offset == -1;
325339 }
326340
327341 void annotation__set_offsets(struct annotation *notes, s64 size);
328−void annotation__compute_ipc(struct annotation *notes, size_t size);
329342 void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym);
330343 void annotation__update_column_widths(struct annotation *notes);
331344 void annotation__init_column_widths(struct annotation *notes, struct symbol *sym);
@@ -349,6 +362,8 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) · 17 unmodified lines
349362 int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
350363 struct evsel *evsel);
351364
365+struct annotated_branch *annotation__get_branch(struct annotation *notes);
366+
352367 int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
353368 struct addr_map_symbol *start,
354369 unsigned cycles);
@@ -361,11 +376,9 @@ void symbol__annotate_zero_histograms(struct symbol *sym); · 6 unmodified lines
361376
362377 int symbol__annotate(struct map_symbol *ms,
363378 struct evsel *evsel,
364− struct annotation_options *options,
365379 struct arch **parch);
366380 int symbol__annotate2(struct map_symbol *ms,
367381 struct evsel *evsel,
368− struct annotation_options *options,
369382 struct arch **parch);
370383
371384 enum symbol_disassemble_errno {
@@ -392,43 +405,86 @@ enum symbol_disassemble_errno { · 20 unmodified lines
392405
393406 int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen);
394407
395−int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel,
396− struct annotation_options *options);
408+int symbol__annotate_printf(struct map_symbol *ms, struct evsel *evsel);
397409 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
398410 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
399411 void annotated_source__purge(struct annotated_source *as);
400412
401−int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel,
402− struct annotation_options *opts);
413+int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel);
403414
404415 bool ui__has_annotation(void);
405416
406−int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts);
417+int symbol__tty_annotate(struct map_symbol *ms, struct evsel *evsel);
407418
408−int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts);
419+int symbol__tty_annotate2(struct map_symbol *ms, struct evsel *evsel);
409420
410421 #ifdef HAVE_SLANG_SUPPORT
411422 int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
412− struct hist_browser_timer *hbt,
413− struct annotation_options *opts);
423+ struct hist_browser_timer *hbt);
414424 #else
415425 static inline int symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
416426 struct evsel *evsel __maybe_unused,
417− struct hist_browser_timer *hbt __maybe_unused,
418− struct annotation_options *opts __maybe_unused)
427+ struct hist_browser_timer *hbt __maybe_unused)
419428 {
420429 return 0;
421430 }
422431 #endif
423432
424−void annotation_options__init(struct annotation_options *opt);
425−void annotation_options__exit(struct annotation_options *opt);
433+void annotation_options__init(void);
434+void annotation_options__exit(void);
426435
427−void annotation_config__init(struct annotation_options *opt);
436+void annotation_config__init(void);
428437
429438 int annotate_parse_percent_type(const struct option *opt, const char *_str,
430439 int unset);
431440
432−int annotate_check_args(struct annotation_options *args);
441+int annotate_check_args(void);
442+
443+/**
444+ * struct annotated_op_loc - Location info of instruction operand
445+ * @reg: Register in the operand
446+ * @offset: Memory access offset in the operand
447+ * @mem_ref: Whether the operand accesses memory
448+ */
449+struct annotated_op_loc {
450+ int reg;
451+ int offset;
452+ bool mem_ref;
453+};
454+
455+enum annotated_insn_ops {
456+ INSN_OP_SOURCE = 0,
457+ INSN_OP_TARGET = 1,
458+
459+ INSN_OP_MAX,
460+};
461+
462+/**
463+ * struct annotated_insn_loc - Location info of instruction
464+ * @ops: Array of location info for source and target operands
465+ */
466+struct annotated_insn_loc {
467+ struct annotated_op_loc ops[INSN_OP_MAX];
468+};
469+
470+#define for_each_insn_op_loc(insn_loc, i, op_loc) \
471+ for (i = INSN_OP_SOURCE, op_loc = &(insn_loc)->ops[i]; \
472+ i < INSN_OP_MAX; \
473+ i++, op_loc++)
474+
475+/* Get detailed location info in the instruction */
476+int annotate_get_insn_location(struct arch *arch, struct disasm_line *dl,
477+ struct annotated_insn_loc *loc);
478+
479+/* Returns a data type from the sample instruction (if any) */
480+struct annotated_data_type *hist_entry__get_data_type(struct hist_entry *he);
481+
482+struct annotated_item_stat {
483+ struct list_head list;
484+ char *name;
485+ int good;
486+ int bad;
487+};
488+extern struct list_head ann_insn_stat;
433489
434490 #endif /* __PERF_ANNOTATE_H */
tools/perf/util/auxtrace.c+5−2
@@ -174,7 +174,7 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, · 173 unmodified lines
174174 struct evlist *evlist,
175175 struct evsel *evsel, int idx)
176176 {
177− bool per_cpu = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
177+ bool per_cpu = !perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus);
178178
179179 mp->mmap_needed = evsel->needs_auxtrace_mmap;
180180
@@ -648,7 +648,7 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, · 467 unmodified lines
648648
649649 static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx)
650650 {
651− bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.user_requested_cpus);
651+ bool per_cpu_mmaps = !perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus);
652652
653653 if (per_cpu_mmaps) {
654654 struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx);
@@ -1638,6 +1638,9 @@ int itrace_do_parse_synth_opts(struct itrace_synth_opts *synth_opts, · 983 unmodified lines
16381638 case 'Z':
16391639 synth_opts->timeless_decoding = true;
16401640 break;
1641+ case 'T':
1642+ synth_opts->use_timestamp = true;
1643+ break;
16411644 case ' ':
16421645 case ',':
16431646 break;
tools/perf/util/auxtrace.h+3−0
@@ -99,6 +99,7 @@ enum itrace_period_type { · 98 unmodified lines
9999 * @remote_access: whether to synthesize remote access events
100100 * @mem: whether to synthesize memory events
101101 * @timeless_decoding: prefer "timeless" decoding i.e. ignore timestamps
102+ * @use_timestamp: use the timestamp trace as kernel time
102103 * @vm_time_correlation: perform VM Time Correlation
103104 * @vm_tm_corr_dry_run: VM Time Correlation dry-run
104105 * @vm_tm_corr_args: VM Time Correlation implementation-specific arguments
@@ -146,6 +147,7 @@ struct itrace_synth_opts { · 41 unmodified lines
146147 bool remote_access;
147148 bool mem;
148149 bool timeless_decoding;
150+ bool use_timestamp;
149151 bool vm_time_correlation;
150152 bool vm_tm_corr_dry_run;
151153 char *vm_tm_corr_args;
@@ -678,6 +680,7 @@ bool auxtrace__evsel_is_auxtrace(struct perf_session *session, · 526 unmodified lines
678680 " q: quicker (less detailed) decoding\n" \
679681 " A: approximate IPC\n" \
680682 " Z: prefer to ignore timestamps (so-called \"timeless\" decoding)\n" \
683+" T: use the timestamp trace as kernel time\n" \
681684 " PERIOD[ns|us|ms|i|t]: specify period to sample stream\n" \
682685 " concatenate multiple options. Default is iybxwpe or cewp\n"
683686
tools/perf/util/block-info.c+4−6
@@ -129,9 +129,9 @@ int block_info__process_sym(struct hist_entry *he, struct block_hist *bh, · 128 unmodified lines
129129 al.sym = he->ms.sym;
130130
131131 notes = symbol__annotation(he->ms.sym);
132− if (!notes || !notes->src || !notes->src->cycles_hist)
132+ if (!notes || !notes->branch || !notes->branch->cycles_hist)
133133 return 0;
134− ch = notes->src->cycles_hist;
134+ ch = notes->branch->cycles_hist;
135135 for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {
136136 if (ch[i].num_aggr) {
137137 struct block_info *bi;
@@ -464,8 +464,7 @@ void block_info__free_report(struct block_report *reps, int nr_reps) · 326 unmodified lines
464464 }
465465
466466 int report__browse_block_hists(struct block_hist *bh, float min_percent,
467− struct evsel *evsel, struct perf_env *env,
468− struct annotation_options *annotation_opts)
467+ struct evsel *evsel, struct perf_env *env)
469468 {
470469 int ret;
471470
@@ -477,8 +476,7 @@ int report__browse_block_hists(struct block_hist *bh, float min_percent, · 5 unmodified lines
477476 return 0;
478477 case 1:
479478 symbol_conf.report_individual_block = true;
480− ret = block_hists_tui_browse(bh, evsel, min_percent,
481− env, annotation_opts);
479+ ret = block_hists_tui_browse(bh, evsel, min_percent, env);
482480 return ret;
483481 default:
484482 return -1;
tools/perf/util/block-info.h+1−2
@@ -78,8 +78,7 @@ struct block_report *block_info__create_report(struct evlist *evlist, · 77 unmodified lines
7878 void block_info__free_report(struct block_report *reps, int nr_reps);
7979
8080 int report__browse_block_hists(struct block_hist *bh, float min_percent,
81− struct evsel *evsel, struct perf_env *env,
82− struct annotation_options *annotation_opts);
81+ struct evsel *evsel, struct perf_env *env);
8382
8483 float block_info__total_cycles_percent(struct hist_entry *he);
8584
tools/perf/util/block-range.c+6−1
@@ -311,6 +311,7 @@ done: · 310 unmodified lines
311311 double block_range__coverage(struct block_range *br)
312312 {
313313 struct symbol *sym;
314+ struct annotated_branch *branch;
314315
315316 if (!br) {
316317 if (block_ranges.blocks)
@@ -323,5 +324,9 @@ double block_range__coverage(struct block_range *br) · 6 unmodified lines
323324 if (!sym)
324325 return -1;
325326
326− return (double)br->coverage / symbol__annotation(sym)->max_coverage;
327+ branch = symbol__annotation(sym)->branch;
328+ if (!branch)
329+ return -1;
330+
331+ return (double)br->coverage / branch->max_coverage;
327332 }
tools/perf/util/bpf-event.c+7−4
@@ -386,6 +386,9 @@ int perf_event__synthesize_bpf_events(struct perf_session *session, · 385 unmodified lines
386386 int err;
387387 int fd;
388388
389+ if (opts->no_bpf_event)
390+ return 0;
391+
389392 event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size);
390393 if (!event)
391394 return -1;
@@ -542,9 +545,9 @@ int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env) · 150 unmodified lines
542545 return evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env);
543546 }
544547
545−void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
546− struct perf_env *env,
547− FILE *fp)
548+void __bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
549+ struct perf_env *env,
550+ FILE *fp)
548551 {
549552 __u32 *prog_lens = (__u32 *)(uintptr_t)(info->jited_func_lens);
550553 __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms);
@@ -560,7 +563,7 @@ void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info, · 9 unmodified lines
560563 if (info->btf_id) {
561564 struct btf_node *node;
562565
563− node = perf_env__find_btf(env, info->btf_id);
566+ node = __perf_env__find_btf(env, info->btf_id);
564567 if (node)
565568 btf = btf__new((__u8 *)(node->data),
566569 node->data_size);
tools/perf/util/bpf-event.h+6−6
@@ -33,9 +33,9 @@ struct btf_node { · 32 unmodified lines
3333 int machine__process_bpf(struct machine *machine, union perf_event *event,
3434 struct perf_sample *sample);
3535 int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env);
36−void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
37− struct perf_env *env,
38− FILE *fp);
36+void __bpf_event__print_bpf_prog_info(struct bpf_prog_info *info,
37+ struct perf_env *env,
38+ FILE *fp);
3939 #else
4040 static inline int machine__process_bpf(struct machine *machine __maybe_unused,
4141 union perf_event *event __maybe_unused,
@@ -50,9 +50,9 @@ static inline int evlist__add_bpf_sb_event(struct evlist *evlist __maybe_unused, · 8 unmodified lines
5050 return 0;
5151 }
5252
53−static inline void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info __maybe_unused,
54− struct perf_env *env __maybe_unused,
55− FILE *fp __maybe_unused)
53+static inline void __bpf_event__print_bpf_prog_info(struct bpf_prog_info *info __maybe_unused,
54+ struct perf_env *env __maybe_unused,
55+ FILE *fp __maybe_unused)
5656 {
5757
5858 }
tools/perf/util/bpf_counter.c+1−1
@@ -455,7 +455,7 @@ static int bperf__load(struct evsel *evsel, struct target *target) · 454 unmodified lines
455455 return -1;
456456
457457 if (!all_cpu_map) {
458− all_cpu_map = perf_cpu_map__new(NULL);
458+ all_cpu_map = perf_cpu_map__new_online_cpus();
459459 if (!all_cpu_map)
460460 return -1;
461461 }
tools/perf/util/bpf_lock_contention.c+1−1
@@ -318,7 +318,7 @@ int lock_contention_read(struct lock_contention *con) · 317 unmodified lines
318318 }
319319
320320 /* make sure it loads the kernel map */
321− map__load(maps__first(machine->kmaps)->map);
321+ maps__load_first(machine->kmaps);
322322
323323 prev_key = NULL;
324324 while (!bpf_map_get_next_key(fd, prev_key, &key)) {
tools/perf/util/compress.h+5−2
@@ -3,6 +3,8 @@ · 2 unmodified lines
33 #define PERF_COMPRESS_H
44
55 #include <stdbool.h>
6+#include <stddef.h>
7+#include <sys/types.h>
68 #ifdef HAVE_ZSTD_SUPPORT
79 #include <zstd.h>
810 #endif
@@ -21,6 +23,7 @@ struct zstd_data { · 12 unmodified lines
2123 #ifdef HAVE_ZSTD_SUPPORT
2224 ZSTD_CStream *cstream;
2325 ZSTD_DStream *dstream;
26+ int comp_level;
2427 #endif
2528 };
2629
@@ -29,7 +32,7 @@ struct zstd_data { · 2 unmodified lines
2932 int zstd_init(struct zstd_data *data, int level);
3033 int zstd_fini(struct zstd_data *data);
3134
32−size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,
35+ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,
3336 void *src, size_t src_size, size_t max_record_size,
3437 size_t process_header(void *record, size_t increment));
3538
@@ -48,7 +51,7 @@ static inline int zstd_fini(struct zstd_data *data __maybe_unused) · 12 unmodified lines
4851 }
4952
5053 static inline
51−size_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused,
54+ssize_t zstd_compress_stream_to_records(struct zstd_data *data __maybe_unused,
5255 void *dst __maybe_unused, size_t dst_size __maybe_unused,
5356 void *src __maybe_unused, size_t src_size __maybe_unused,
5457 size_t max_record_size __maybe_unused,
tools/perf/util/cpumap.c+1−1
@@ -672,7 +672,7 @@ struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */ · 671 unmodified lines
672672 static struct perf_cpu_map *online;
673673
674674 if (!online)
675− online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */
675+ online = perf_cpu_map__new_online_cpus(); /* from /sys/devices/system/cpu/online */
676676
677677 return online;
678678 }
tools/perf/util/cputopo.c+1−1
@@ -267,7 +267,7 @@ struct cpu_topology *cpu_topology__new(void) · 266 unmodified lines
267267 ncpus = cpu__max_present_cpu().cpu;
268268
269269 /* build online CPU map */
270− map = perf_cpu_map__new(NULL);
270+ map = perf_cpu_map__new_online_cpus();
271271 if (map == NULL) {
272272 pr_debug("failed to get system cpumap\n");
273273 return NULL;
tools/perf/util/cs-etm.c+18−3
@@ -3346,12 +3346,27 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event, · 3345 unmodified lines
33463346 etm->metadata = metadata;
33473347 etm->auxtrace_type = auxtrace_info->type;
33483348
3349− /* Use virtual timestamps if all ETMs report ts_source = 1 */
3350− etm->has_virtual_ts = cs_etm__has_virtual_ts(metadata, num_cpu);
3349+ if (etm->synth_opts.use_timestamp)
3350+ /*
3351+ * Prior to Armv8.4, Arm CPUs don't support FEAT_TRF feature,
3352+ * therefore the decoder cannot know if the timestamp trace is
3353+ * same with the kernel time.
3354+ *
3355+ * If a user has knowledge for the working platform and can
3356+ * specify itrace option 'T' to tell decoder to forcely use the
3357+ * traced timestamp as the kernel time.
3358+ */
3359+ etm->has_virtual_ts = true;
3360+ else
3361+ /* Use virtual timestamps if all ETMs report ts_source = 1 */
3362+ etm->has_virtual_ts = cs_etm__has_virtual_ts(metadata, num_cpu);
33513363
33523364 if (!etm->has_virtual_ts)
33533365 ui__warning("Virtual timestamps are not enabled, or not supported by the traced system.\n"
3354− "The time field of the samples will not be set accurately.\n\n");
3366+ "The time field of the samples will not be set accurately.\n"
3367+ "For Arm CPUs prior to Armv8.4 or without support FEAT_TRF,\n"
3368+ "you can specify the itrace option 'T' for timestamp decoding\n"
3369+ "if the Coresight timestamp on the platform is same with the kernel time.\n\n");
33553370
33563371 etm->auxtrace.process_event = cs_etm__process_event;
33573372 etm->auxtrace.process_auxtrace_event = cs_etm__process_auxtrace_event;
tools/perf/util/db-export.c+2−2
@@ -253,8 +253,8 @@ static struct call_path *call_path_from_sample(struct db_export *dbe, · 252 unmodified lines
253253 */
254254 addr_location__init(&al);
255255 al.sym = node->ms.sym;
256− al.map = node->ms.map;
257− al.maps = thread__maps(thread);
256+ al.map = map__get(node->ms.map);
257+ al.maps = maps__get(thread__maps(thread));
258258 al.addr = node->ip;
259259
260260 if (al.map && !al.sym)
tools/perf/util/debug.c+15−7
@@ -38,12 +38,21 @@ bool dump_trace = false, quiet = false; · 37 unmodified lines
3838 int debug_ordered_events;
3939 static int redirect_to_stderr;
4040 int debug_data_convert;
41−static FILE *debug_file;
41+static FILE *_debug_file;
4242 bool debug_display_time;
4343
44+FILE *debug_file(void)
45+{
46+ if (!_debug_file) {
47+ pr_warning_once("debug_file not set");
48+ debug_set_file(stderr);
49+ }
50+ return _debug_file;
51+}
52+
4453 void debug_set_file(FILE *file)
4554 {
46− debug_file = file;
55+ _debug_file = file;
4756 }
4857
4958 void debug_set_display_time(bool set)
@@ -78,8 +87,8 @@ int veprintf(int level, int var, const char *fmt, va_list args) · 28 unmodified lines
7887 if (use_browser >= 1 && !redirect_to_stderr) {
7988 ui_helpline__vshow(fmt, args);
8089 } else {
81− ret = fprintf_time(debug_file);
82− ret += vfprintf(debug_file, fmt, args);
90+ ret = fprintf_time(debug_file());
91+ ret += vfprintf(debug_file(), fmt, args);
8392 }
8493 }
8594
@@ -107,9 +116,8 @@ static int veprintf_time(u64 t, const char *fmt, va_list args) · 21 unmodified lines
107116 nsecs -= secs * NSEC_PER_SEC;
108117 usecs = nsecs / NSEC_PER_USEC;
109118
110− ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
111− secs, usecs);
112− ret += vfprintf(stderr, fmt, args);
119+ ret = fprintf(debug_file(), "[%13" PRIu64 ".%06" PRIu64 "] ", secs, usecs);
120+ ret += vfprintf(debug_file(), fmt, args);
113121 return ret;
114122 }
115123
tools/perf/util/debug.h+1−0
@@ -77,6 +77,7 @@ int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __printf(4, 5) · 76 unmodified lines
7777 int veprintf(int level, int var, const char *fmt, va_list args);
7878
7979 int perf_debug_option(const char *str);
80+FILE *debug_file(void);
8081 void debug_set_file(FILE *file);
8182 void debug_set_display_time(bool set);
8283 void perf_debug_setup(void);
tools/perf/util/debuginfo.c+205−0
@@ -0,0 +1,205 @@
1+// SPDX-License-Identifier: GPL-2.0-or-later
2+/*
3+ * DWARF debug information handling code. Copied from probe-finder.c.
4+ *
5+ * Written by Masami Hiramatsu <mhiramat@redhat.com>
6+ */
7+
8+#include <errno.h>
9+#include <fcntl.h>
10+#include <stdio.h>
11+#include <stdlib.h>
12+#include <string.h>
13+#include <unistd.h>
14+#include <linux/zalloc.h>
15+
16+#include "build-id.h"
17+#include "dso.h"
18+#include "debug.h"
19+#include "debuginfo.h"
20+#include "symbol.h"
21+
22+#ifdef HAVE_DEBUGINFOD_SUPPORT
23+#include <elfutils/debuginfod.h>
24+#endif
25+
26+/* Dwarf FL wrappers */
27+static char *debuginfo_path; /* Currently dummy */
28+
29+static const Dwfl_Callbacks offline_callbacks = {
30+ .find_debuginfo = dwfl_standard_find_debuginfo,
31+ .debuginfo_path = &debuginfo_path,
32+
33+ .section_address = dwfl_offline_section_address,
34+
35+ /* We use this table for core files too. */
36+ .find_elf = dwfl_build_id_find_elf,
37+};
38+
39+/* Get a Dwarf from offline image */
40+static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
41+ const char *path)
42+{
43+ GElf_Addr dummy;
44+ int fd;
45+
46+ fd = open(path, O_RDONLY);
47+ if (fd < 0)
48+ return fd;
49+
50+ dbg->dwfl = dwfl_begin(&offline_callbacks);
51+ if (!dbg->dwfl)
52+ goto error;
53+
54+ dwfl_report_begin(dbg->dwfl);
55+ dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
56+ if (!dbg->mod)
57+ goto error;
58+
59+ dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
60+ if (!dbg->dbg)
61+ goto error;
62+
63+ dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy);
64+
65+ dwfl_report_end(dbg->dwfl, NULL, NULL);
66+
67+ return 0;
68+error:
69+ if (dbg->dwfl)
70+ dwfl_end(dbg->dwfl);
71+ else
72+ close(fd);
73+ memset(dbg, 0, sizeof(*dbg));
74+
75+ return -ENOENT;
76+}
77+
78+static struct debuginfo *__debuginfo__new(const char *path)
79+{
80+ struct debuginfo *dbg = zalloc(sizeof(*dbg));
81+ if (!dbg)
82+ return NULL;
83+
84+ if (debuginfo__init_offline_dwarf(dbg, path) < 0)
85+ zfree(&dbg);
86+ if (dbg)
87+ pr_debug("Open Debuginfo file: %s\n", path);
88+ return dbg;
89+}
90+
91+enum dso_binary_type distro_dwarf_types[] = {
92+ DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
93+ DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
94+ DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
95+ DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
96+ DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,
97+ DSO_BINARY_TYPE__NOT_FOUND,
98+};
99+
100+struct debuginfo *debuginfo__new(const char *path)
101+{
102+ enum dso_binary_type *type;
103+ char buf[PATH_MAX], nil = '\0';
104+ struct dso *dso;
105+ struct debuginfo *dinfo = NULL;
106+ struct build_id bid;
107+
108+ /* Try to open distro debuginfo files */
109+ dso = dso__new(path);
110+ if (!dso)
111+ goto out;
112+
113+ /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */
114+ if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0)
115+ dso__set_build_id(dso, &bid);
116+
117+ for (type = distro_dwarf_types;
118+ !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
119+ type++) {
120+ if (dso__read_binary_type_filename(dso, *type, &nil,
121+ buf, PATH_MAX) < 0)
122+ continue;
123+ dinfo = __debuginfo__new(buf);
124+ }
125+ dso__put(dso);
126+
127+out:
128+ /* if failed to open all distro debuginfo, open given binary */
129+ return dinfo ? : __debuginfo__new(path);
130+}
131+
132+void debuginfo__delete(struct debuginfo *dbg)
133+{
134+ if (dbg) {
135+ if (dbg->dwfl)
136+ dwfl_end(dbg->dwfl);
137+ free(dbg);
138+ }
139+}
140+
141+/* For the kernel module, we need a special code to get a DIE */
142+int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
143+ bool adjust_offset)
144+{
145+ int n, i;
146+ Elf32_Word shndx;
147+ Elf_Scn *scn;
148+ Elf *elf;
149+ GElf_Shdr mem, *shdr;
150+ const char *p;
151+
152+ elf = dwfl_module_getelf(dbg->mod, &dbg->bias);
153+ if (!elf)
154+ return -EINVAL;
155+
156+ /* Get the number of relocations */
157+ n = dwfl_module_relocations(dbg->mod);
158+ if (n < 0)
159+ return -ENOENT;
160+ /* Search the relocation related .text section */
161+ for (i = 0; i < n; i++) {
162+ p = dwfl_module_relocation_info(dbg->mod, i, &shndx);
163+ if (strcmp(p, ".text") == 0) {
164+ /* OK, get the section header */
165+ scn = elf_getscn(elf, shndx);
166+ if (!scn)
167+ return -ENOENT;
168+ shdr = gelf_getshdr(scn, &mem);
169+ if (!shdr)
170+ return -ENOENT;
171+ *offs = shdr->sh_addr;
172+ if (adjust_offset)
173+ *offs -= shdr->sh_offset;
174+ }
175+ }
176+ return 0;
177+}
178+
179+#ifdef HAVE_DEBUGINFOD_SUPPORT
180+int get_source_from_debuginfod(const char *raw_path,
181+ const char *sbuild_id, char **new_path)
182+{
183+ debuginfod_client *c = debuginfod_begin();
184+ const char *p = raw_path;
185+ int fd;
186+
187+ if (!c)
188+ return -ENOMEM;
189+
190+ fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,
191+ 0, p, new_path);
192+ pr_debug("Search %s from debuginfod -> %d\n", p, fd);
193+ if (fd >= 0)
194+ close(fd);
195+ debuginfod_end(c);
196+ if (fd < 0) {
197+ pr_debug("Failed to find %s in debuginfod (%s)\n",
198+ raw_path, sbuild_id);
199+ return -ENOENT;
200+ }
201+ pr_debug("Got a source %s\n", *new_path);
202+
203+ return 0;
204+}
205+#endif /* HAVE_DEBUGINFOD_SUPPORT */
tools/perf/util/debuginfo.h+64−0
@@ -0,0 +1,64 @@
1+/* SPDX-License-Identifier: GPL-2.0-or-later */
2+#ifndef _PERF_DEBUGINFO_H
3+#define _PERF_DEBUGINFO_H
4+
5+#include <errno.h>
6+#include <linux/compiler.h>
7+
8+#ifdef HAVE_DWARF_SUPPORT
9+
10+#include "dwarf-aux.h"
11+
12+/* debug information structure */
13+struct debuginfo {
14+ Dwarf *dbg;
15+ Dwfl_Module *mod;
16+ Dwfl *dwfl;
17+ Dwarf_Addr bias;
18+ const unsigned char *build_id;
19+};
20+
21+/* This also tries to open distro debuginfo */
22+struct debuginfo *debuginfo__new(const char *path);
23+void debuginfo__delete(struct debuginfo *dbg);
24+
25+int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
26+ bool adjust_offset);
27+
28+#else /* HAVE_DWARF_SUPPORT */
29+
30+/* dummy debug information structure */
31+struct debuginfo {
32+};
33+
34+static inline struct debuginfo *debuginfo__new(const char *path __maybe_unused)
35+{
36+ return NULL;
37+}
38+
39+static inline void debuginfo__delete(struct debuginfo *dbg __maybe_unused)
40+{
41+}
42+
43+static inline int debuginfo__get_text_offset(struct debuginfo *dbg __maybe_unused,
44+ Dwarf_Addr *offs __maybe_unused,
45+ bool adjust_offset __maybe_unused)
46+{
47+ return -EINVAL;
48+}
49+
50+#endif /* HAVE_DWARF_SUPPORT */
51+
52+#ifdef HAVE_DEBUGINFOD_SUPPORT
53+int get_source_from_debuginfod(const char *raw_path, const char *sbuild_id,
54+ char **new_path);
55+#else /* HAVE_DEBUGINFOD_SUPPORT */
56+static inline int get_source_from_debuginfod(const char *raw_path __maybe_unused,
57+ const char *sbuild_id __maybe_unused,
58+ char **new_path __maybe_unused)
59+{
60+ return -ENOTSUP;
61+}
62+#endif /* HAVE_DEBUGINFOD_SUPPORT */
63+
64+#endif /* _PERF_DEBUGINFO_H */
tools/perf/util/dso.c+4−0
@@ -31,6 +31,7 @@ · 30 unmodified lines
3131 #include "debug.h"
3232 #include "string2.h"
3333 #include "vdso.h"
34+#include "annotate-data.h"
3435
3536 static const char * const debuglink_paths[] = {
3637 "%.0s%s",
@@ -1327,6 +1328,7 @@ struct dso *dso__new_id(const char *name, struct dso_id *id) · 1290 unmodified lines
13271328 dso->data.cache = RB_ROOT;
13281329 dso->inlined_nodes = RB_ROOT_CACHED;
13291330 dso->srclines = RB_ROOT_CACHED;
1331+ dso->data_types = RB_ROOT;
13301332 dso->data.fd = -1;
13311333 dso->data.status = DSO_DATA_STATUS_UNKNOWN;
13321334 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
@@ -1370,6 +1372,8 @@ void dso__delete(struct dso *dso) · 37 unmodified lines
13701372 symbols__delete(&dso->symbols);
13711373 dso->symbol_names_len = 0;
13721374 zfree(&dso->symbol_names);
1375+ annotated_data_type__tree_delete(&dso->data_types);
1376+
13731377 if (dso->short_name_allocated) {
13741378 zfree((char **)&dso->short_name);
13751379 dso->short_name_allocated = false;
tools/perf/util/dso.h+2−0
@@ -154,6 +154,8 @@ struct dso { · 153 unmodified lines
154154 size_t symbol_names_len;
155155 struct rb_root_cached inlined_nodes;
156156 struct rb_root_cached srclines;
157+ struct rb_root data_types;
158+
157159 struct {
158160 u64 addr;
159161 struct symbol *symbol;
tools/perf/util/dwarf-aux.c+232−17
@@ -1051,32 +1051,28 @@ Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, · 1050 unmodified lines
10511051 }
10521052
10531053 /**
1054− * die_get_typename - Get the name of given variable DIE
1055− * @vr_die: a variable DIE
1054+ * die_get_typename_from_type - Get the name of given type DIE
1055+ * @type_die: a type DIE
10561056 * @buf: a strbuf for result type name
10571057 *
1058− * Get the name of @vr_die and stores it to @buf. Return 0 if succeeded.
1058+ * Get the name of @type_die and stores it to @buf. Return 0 if succeeded.
10591059 * and Return -ENOENT if failed to find type name.
10601060 * Note that the result will stores typedef name if possible, and stores
10611061 * "*(function_type)" if the type is a function pointer.
10621062 */
1063−int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)
1063+int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf)
10641064 {
1065− Dwarf_Die type;
10661065 int tag, ret;
10671066 const char *tmp = "";
10681067
1069− if (__die_get_real_type(vr_die, &type) == NULL)
1070− return -ENOENT;
1071−
1072− tag = dwarf_tag(&type);
1068+ tag = dwarf_tag(type_die);
10731069 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
10741070 tmp = "*";
10751071 else if (tag == DW_TAG_subroutine_type) {
10761072 /* Function pointer */
10771073 return strbuf_add(buf, "(function_type)", 15);
10781074 } else {
1079− const char *name = dwarf_diename(&type);
1075+ const char *name = dwarf_diename(type_die);
10801076
10811077 if (tag == DW_TAG_union_type)
10821078 tmp = "union ";
@@ -1089,8 +1085,35 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) · 6 unmodified lines
10891085 /* Write a base name */
10901086 return strbuf_addf(buf, "%s%s", tmp, name ?: "");
10911087 }
1092− ret = die_get_typename(&type, buf);
1093− return ret ? ret : strbuf_addstr(buf, tmp);
1088+ ret = die_get_typename(type_die, buf);
1089+ if (ret < 0) {
1090+ /* void pointer has no type attribute */
1091+ if (tag == DW_TAG_pointer_type && ret == -ENOENT)
1092+ return strbuf_addf(buf, "void*");
1093+
1094+ return ret;
1095+ }
1096+ return strbuf_addstr(buf, tmp);
1097+}
1098+
1099+/**
1100+ * die_get_typename - Get the name of given variable DIE
1101+ * @vr_die: a variable DIE
1102+ * @buf: a strbuf for result type name
1103+ *
1104+ * Get the name of @vr_die and stores it to @buf. Return 0 if succeeded.
1105+ * and Return -ENOENT if failed to find type name.
1106+ * Note that the result will stores typedef name if possible, and stores
1107+ * "*(function_type)" if the type is a function pointer.
1108+ */
1109+int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf)
1110+{
1111+ Dwarf_Die type;
1112+
1113+ if (__die_get_real_type(vr_die, &type) == NULL)
1114+ return -ENOENT;
1115+
1116+ return die_get_typename_from_type(&type, buf);
10941117 }
10951118
10961119 /**
@@ -1238,12 +1261,151 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) · 141 unmodified lines
12381261 out:
12391262 return ret;
12401263 }
1241−#else
1242−int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
1243− Dwarf_Die *vr_die __maybe_unused,
1244− struct strbuf *buf __maybe_unused)
1264+
1265+/* Interval parameters for __die_find_var_reg_cb() */
1266+struct find_var_data {
1267+ /* Target instruction address */
1268+ Dwarf_Addr pc;
1269+ /* Target memory address (for global data) */
1270+ Dwarf_Addr addr;
1271+ /* Target register */
1272+ unsigned reg;
1273+ /* Access offset, set for global data */
1274+ int offset;
1275+};
1276+
1277+/* Max number of registers DW_OP_regN supports */
1278+#define DWARF_OP_DIRECT_REGS 32
1279+
1280+/* Only checks direct child DIEs in the given scope. */
1281+static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg)
1282+{
1283+ struct find_var_data *data = arg;
1284+ int tag = dwarf_tag(die_mem);
1285+ ptrdiff_t off = 0;
1286+ Dwarf_Attribute attr;
1287+ Dwarf_Addr base, start, end;
1288+ Dwarf_Op *ops;
1289+ size_t nops;
1290+
1291+ if (tag != DW_TAG_variable && tag != DW_TAG_formal_parameter)
1292+ return DIE_FIND_CB_SIBLING;
1293+
1294+ if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL)
1295+ return DIE_FIND_CB_SIBLING;
1296+
1297+ while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) {
1298+ /* Assuming the location list is sorted by address */
1299+ if (end < data->pc)
1300+ continue;
1301+ if (start > data->pc)
1302+ break;
1303+
1304+ /* Only match with a simple case */
1305+ if (data->reg < DWARF_OP_DIRECT_REGS) {
1306+ if (ops->atom == (DW_OP_reg0 + data->reg) && nops == 1)
1307+ return DIE_FIND_CB_END;
1308+ } else {
1309+ if (ops->atom == DW_OP_regx && ops->number == data->reg &&
1310+ nops == 1)
1311+ return DIE_FIND_CB_END;
1312+ }
1313+ }
1314+ return DIE_FIND_CB_SIBLING;
1315+}
1316+
1317+/**
1318+ * die_find_variable_by_reg - Find a variable saved in a register
1319+ * @sc_die: a scope DIE
1320+ * @pc: the program address to find
1321+ * @reg: the register number to find
1322+ * @die_mem: a buffer to save the resulting DIE
1323+ *
1324+ * Find the variable DIE accessed by the given register.
1325+ */
1326+Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg,
1327+ Dwarf_Die *die_mem)
1328+{
1329+ struct find_var_data data = {
1330+ .pc = pc,
1331+ .reg = reg,
1332+ };
1333+ return die_find_child(sc_die, __die_find_var_reg_cb, &data, die_mem);
1334+}
1335+
1336+/* Only checks direct child DIEs in the given scope */
1337+static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg)
1338+{
1339+ struct find_var_data *data = arg;
1340+ int tag = dwarf_tag(die_mem);
1341+ ptrdiff_t off = 0;
1342+ Dwarf_Attribute attr;
1343+ Dwarf_Addr base, start, end;
1344+ Dwarf_Word size;
1345+ Dwarf_Die type_die;
1346+ Dwarf_Op *ops;
1347+ size_t nops;
1348+
1349+ if (tag != DW_TAG_variable)
1350+ return DIE_FIND_CB_SIBLING;
1351+
1352+ if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL)
1353+ return DIE_FIND_CB_SIBLING;
1354+
1355+ while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) {
1356+ if (ops->atom != DW_OP_addr)
1357+ continue;
1358+
1359+ if (data->addr < ops->number)
1360+ continue;
1361+
1362+ if (data->addr == ops->number) {
1363+ /* Update offset relative to the start of the variable */
1364+ data->offset = 0;
1365+ return DIE_FIND_CB_END;
1366+ }
1367+
1368+ if (die_get_real_type(die_mem, &type_die) == NULL)
1369+ continue;
1370+
1371+ if (dwarf_aggregate_size(&type_die, &size) < 0)
1372+ continue;
1373+
1374+ if (data->addr >= ops->number + size)
1375+ continue;
1376+
1377+ /* Update offset relative to the start of the variable */
1378+ data->offset = data->addr - ops->number;
1379+ return DIE_FIND_CB_END;
1380+ }
1381+ return DIE_FIND_CB_SIBLING;
1382+}
1383+
1384+/**
1385+ * die_find_variable_by_addr - Find variable located at given address
1386+ * @sc_die: a scope DIE
1387+ * @pc: the program address to find
1388+ * @addr: the data address to find
1389+ * @die_mem: a buffer to save the resulting DIE
1390+ * @offset: the offset in the resulting type
1391+ *
1392+ * Find the variable DIE located at the given address (in PC-relative mode).
1393+ * This is usually for global variables.
1394+ */
1395+Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc,
1396+ Dwarf_Addr addr, Dwarf_Die *die_mem,
1397+ int *offset)
12451398 {
1246− return -ENOTSUP;
1399+ struct find_var_data data = {
1400+ .pc = pc,
1401+ .addr = addr,
1402+ };
1403+ Dwarf_Die *result;
1404+
1405+ result = die_find_child(sc_die, __die_find_var_addr_cb, &data, die_mem);
1406+ if (result)
1407+ *offset = data.offset;
1408+ return result;
12471409 }
12481410 #endif
12491411
@@ -1425,3 +1587,56 @@ void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die, · 175 unmodified lines
14251587
14261588 *entrypc = postprologue_addr;
14271589 }
1590+
1591+/* Internal parameters for __die_find_scope_cb() */
1592+struct find_scope_data {
1593+ /* Target instruction address */
1594+ Dwarf_Addr pc;
1595+ /* Number of scopes found [output] */
1596+ int nr;
1597+ /* Array of scopes found, 0 for the outermost one. [output] */
1598+ Dwarf_Die *scopes;
1599+};
1600+
1601+static int __die_find_scope_cb(Dwarf_Die *die_mem, void *arg)
1602+{
1603+ struct find_scope_data *data = arg;
1604+
1605+ if (dwarf_haspc(die_mem, data->pc)) {
1606+ Dwarf_Die *tmp;
1607+
1608+ tmp = realloc(data->scopes, (data->nr + 1) * sizeof(*tmp));
1609+ if (tmp == NULL)
1610+ return DIE_FIND_CB_END;
1611+
1612+ memcpy(tmp + data->nr, die_mem, sizeof(*die_mem));
1613+ data->scopes = tmp;
1614+ data->nr++;
1615+ return DIE_FIND_CB_CHILD;
1616+ }
1617+ return DIE_FIND_CB_SIBLING;
1618+}
1619+
1620+/**
1621+ * die_get_scopes - Return a list of scopes including the address
1622+ * @cu_die: a compile unit DIE
1623+ * @pc: the address to find
1624+ * @scopes: the array of DIEs for scopes (result)
1625+ *
1626+ * This function does the same as the dwarf_getscopes() but doesn't follow
1627+ * the origins of inlined functions. It returns the number of scopes saved
1628+ * in the @scopes argument. The outer scope will be saved first (index 0) and
1629+ * the last one is the innermost scope at the @pc.
1630+ */
1631+int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes)
1632+{
1633+ struct find_scope_data data = {
1634+ .pc = pc,
1635+ };
1636+ Dwarf_Die die_mem;
1637+
1638+ die_find_child(cu_die, __die_find_scope_cb, &data, &die_mem);
1639+
1640+ *scopes = data.scopes;
1641+ return data.nr;
1642+}
tools/perf/util/dwarf-aux.h+49−2
@@ -116,12 +116,14 @@ Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, · 115 unmodified lines
116116 Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
117117 Dwarf_Die *die_mem);
118118
119+/* Get the name of given type DIE */
120+int die_get_typename_from_type(Dwarf_Die *type_die, struct strbuf *buf);
121+
119122 /* Get the name of given variable DIE */
120123 int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);
121124
122125 /* Get the name and type of given variable DIE, stored as "type\tname" */
123126 int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);
124−int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
125127
126128 /* Check if target program is compiled with optimization */
127129 bool die_is_optimized_target(Dwarf_Die *cu_die);
@@ -130,4 +132,49 @@ bool die_is_optimized_target(Dwarf_Die *cu_die); · 2 unmodified lines
130132 void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
131133 Dwarf_Addr *entrypc);
132134
133−#endif
135+/* Get the list of including scopes */
136+int die_get_scopes(Dwarf_Die *cu_die, Dwarf_Addr pc, Dwarf_Die **scopes);
137+
138+#ifdef HAVE_DWARF_GETLOCATIONS_SUPPORT
139+
140+/* Get byte offset range of given variable DIE */
141+int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
142+
143+/* Find a variable saved in the 'reg' at given address */
144+Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg,
145+ Dwarf_Die *die_mem);
146+
147+/* Find a (global) variable located in the 'addr' */
148+Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die, Dwarf_Addr pc,
149+ Dwarf_Addr addr, Dwarf_Die *die_mem,
150+ int *offset);
151+
152+#else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */
153+
154+static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
155+ Dwarf_Die *vr_die __maybe_unused,
156+ struct strbuf *buf __maybe_unused)
157+{
158+ return -ENOTSUP;
159+}
160+
161+static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unused,
162+ Dwarf_Addr pc __maybe_unused,
163+ int reg __maybe_unused,
164+ Dwarf_Die *die_mem __maybe_unused)
165+{
166+ return NULL;
167+}
168+
169+static inline Dwarf_Die *die_find_variable_by_addr(Dwarf_Die *sc_die __maybe_unused,
170+ Dwarf_Addr pc __maybe_unused,
171+ Dwarf_Addr addr __maybe_unused,
172+ Dwarf_Die *die_mem __maybe_unused,
173+ int *offset __maybe_unused)
174+{
175+ return NULL;
176+}
177+
178+#endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */
179+
180+#endif /* _DWARF_AUX_H */
tools/perf/util/dwarf-regs.c+34−0
@@ -5,9 +5,12 @@ · 4 unmodified lines
55 * Written by: Masami Hiramatsu <mhiramat@kernel.org>
66 */
77
8+#include <stdlib.h>
9+#include <string.h>
810 #include <debug.h>
911 #include <dwarf-regs.h>
1012 #include <elf.h>
13+#include <errno.h>
1114 #include <linux/kernel.h>
1215
1316 #ifndef EM_AARCH64
@@ -68,3 +71,34 @@ const char *get_dwarf_regstr(unsigned int n, unsigned int machine) · 54 unmodified lines
6871 }
6972 return NULL;
7073 }
74+
75+__weak int get_arch_regnum(const char *name __maybe_unused)
76+{
77+ return -ENOTSUP;
78+}
79+
80+/* Return DWARF register number from architecture register name */
81+int get_dwarf_regnum(const char *name, unsigned int machine)
82+{
83+ char *regname = strdup(name);
84+ int reg = -1;
85+ char *p;
86+
87+ if (regname == NULL)
88+ return -EINVAL;
89+
90+ /* For convenience, remove trailing characters */
91+ p = strpbrk(regname, " ,)");
92+ if (p)
93+ *p = '\0';
94+
95+ switch (machine) {
96+ case EM_NONE: /* Generic arch - use host arch */
97+ reg = get_arch_regnum(regname);
98+ break;
99+ default:
100+ pr_err("ELF MACHINE %x is not supported.\n", machine);
101+ }
102+ free(regname);
103+ return reg;
104+}
tools/perf/util/env.c+64−18
@@ -3,6 +3,7 @@ · 2 unmodified lines
33 #include "debug.h"
44 #include "env.h"
55 #include "util/header.h"
6+#include "linux/compiler.h"
67 #include <linux/ctype.h>
78 #include <linux/zalloc.h>
89 #include "cgroup.h"
@@ -12,6 +13,7 @@ · 3 unmodified lines
1213 #include <string.h>
1314 #include "pmus.h"
1415 #include "strbuf.h"
16+#include "trace/beauty/beauty.h"
1517
1618 struct perf_env perf_env;
1719
@@ -22,13 +24,19 @@ struct perf_env perf_env; · 4 unmodified lines
2224
2325 void perf_env__insert_bpf_prog_info(struct perf_env *env,
2426 struct bpf_prog_info_node *info_node)
27+{
28+ down_write(&env->bpf_progs.lock);
29+ __perf_env__insert_bpf_prog_info(env, info_node);
30+ up_write(&env->bpf_progs.lock);
31+}
32+
33+void __perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node)
2534 {
2635 __u32 prog_id = info_node->info_linear->info.id;
2736 struct bpf_prog_info_node *node;
2837 struct rb_node *parent = NULL;
2938 struct rb_node **p;
3039
31− down_write(&env->bpf_progs.lock);
3240 p = &env->bpf_progs.infos.rb_node;
3341
3442 while (*p != NULL) {
@@ -40,15 +48,13 @@ void perf_env__insert_bpf_prog_info(struct perf_env *env, · 5 unmodified lines
4048 p = &(*p)->rb_right;
4149 } else {
4250 pr_debug("duplicated bpf prog info %u\n", prog_id);
43− goto out;
51+ return;
4452 }
4553 }
4654
4755 rb_link_node(&info_node->rb_node, parent, p);
4856 rb_insert_color(&info_node->rb_node, &env->bpf_progs.infos);
4957 env->bpf_progs.infos_cnt++;
50−out:
51− up_write(&env->bpf_progs.lock);
5258 }
5359
5460 struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
@@ -77,14 +83,22 @@ out: · 22 unmodified lines
7783 }
7884
7985 bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
86+{
87+ bool ret;
88+
89+ down_write(&env->bpf_progs.lock);
90+ ret = __perf_env__insert_btf(env, btf_node);
91+ up_write(&env->bpf_progs.lock);
92+ return ret;
93+}
94+
95+bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node)
8096 {
8197 struct rb_node *parent = NULL;
8298 __u32 btf_id = btf_node->id;
8399 struct btf_node *node;
84100 struct rb_node **p;
85− bool ret = true;
86101
87− down_write(&env->bpf_progs.lock);
88102 p = &env->bpf_progs.btfs.rb_node;
89103
90104 while (*p != NULL) {
@@ -96,25 +110,31 @@ bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node) · 5 unmodified lines
96110 p = &(*p)->rb_right;
97111 } else {
98112 pr_debug("duplicated btf %u\n", btf_id);
99− ret = false;
100− goto out;
113+ return false;
101114 }
102115 }
103116
104117 rb_link_node(&btf_node->rb_node, parent, p);
105118 rb_insert_color(&btf_node->rb_node, &env->bpf_progs.btfs);
106119 env->bpf_progs.btfs_cnt++;
107−out:
108− up_write(&env->bpf_progs.lock);
109− return ret;
120+ return true;
110121 }
111122
112123 struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id)
124+{
125+ struct btf_node *res;
126+
127+ down_read(&env->bpf_progs.lock);
128+ res = __perf_env__find_btf(env, btf_id);
129+ up_read(&env->bpf_progs.lock);
130+ return res;
131+}
132+
133+struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id)
113134 {
114135 struct btf_node *node = NULL;
115136 struct rb_node *n;
116137
117− down_read(&env->bpf_progs.lock);
118138 n = env->bpf_progs.btfs.rb_node;
119139
120140 while (n) {
@@ -124,13 +144,9 @@ struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id) · 3 unmodified lines
124144 else if (btf_id > node->id)
125145 n = n->rb_right;
126146 else
127− goto out;
147+ return node;
128148 }
129− node = NULL;
130−
131−out:
132− up_read(&env->bpf_progs.lock);
133− return node;
149+ return NULL;
134150 }
135151
136152 /* purge data in bpf_progs.infos tree */
@@ -453,6 +469,18 @@ const char *perf_env__arch(struct perf_env *env) · 316 unmodified lines
453469 return normalize_arch(arch_name);
454470 }
455471
472+const char *perf_env__arch_strerrno(struct perf_env *env __maybe_unused, int err __maybe_unused)
473+{
474+#if defined(HAVE_SYSCALL_TABLE_SUPPORT) && defined(HAVE_LIBTRACEEVENT)
475+ if (env->arch_strerrno == NULL)
476+ env->arch_strerrno = arch_syscalls__strerrno_function(perf_env__arch(env));
477+
478+ return env->arch_strerrno ? env->arch_strerrno(err) : "no arch specific strerrno function";
479+#else
480+ return "!(HAVE_SYSCALL_TABLE_SUPPORT && HAVE_LIBTRACEEVENT)";
481+#endif
482+}
483+
456484 const char *perf_env__cpuid(struct perf_env *env)
457485 {
458486 int status;
@@ -531,6 +559,24 @@ int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu) · 72 unmodified lines
531559 return cpu.cpu >= 0 && cpu.cpu < env->nr_numa_map ? env->numa_map[cpu.cpu] : -1;
532560 }
533561
562+bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name)
563+{
564+ char *pmu_mapping = env->pmu_mappings, *colon;
565+
566+ for (int i = 0; i < env->nr_pmu_mappings; ++i) {
567+ if (strtoul(pmu_mapping, &colon, 0) == ULONG_MAX || *colon != ':')
568+ goto out_error;
569+
570+ pmu_mapping = colon + 1;
571+ if (strcmp(pmu_mapping, pmu_name) == 0)
572+ return true;
573+
574+ pmu_mapping += strlen(pmu_mapping) + 1;
575+ }
576+out_error:
577+ return false;
578+}
579+
534580 char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
535581 const char *cap)
536582 {
tools/perf/util/env.h+17−0
@@ -46,10 +46,17 @@ struct hybrid_node { · 45 unmodified lines
4646 struct pmu_caps {
4747 int nr_caps;
4848 unsigned int max_branches;
49+ unsigned int br_cntr_nr;
50+ unsigned int br_cntr_width;
51+
4952 char **caps;
5053 char *pmu_name;
5154 };
5255
56+typedef const char *(arch_syscalls__strerrno_t)(int err);
57+
58+arch_syscalls__strerrno_t *arch_syscalls__strerrno_function(const char *arch);
59+
5360 struct perf_env {
5461 char *hostname;
5562 char *os_release;
@@ -62,6 +69,8 @@ struct perf_env { · 6 unmodified lines
6269 unsigned long long total_mem;
6370 unsigned int msr_pmu_type;
6471 unsigned int max_branches;
72+ unsigned int br_cntr_nr;
73+ unsigned int br_cntr_width;
6574 int kernel_is_64_bit;
6675
6776 int nr_cmdline;
@@ -130,6 +139,7 @@ struct perf_env { · 62 unmodified lines
130139 */
131140 bool enabled;
132141 } clock;
142+ arch_syscalls__strerrno_t *arch_strerrno;
133143 };
134144
135145 enum perf_compress_type {
@@ -159,19 +169,26 @@ int perf_env__read_cpu_topology_map(struct perf_env *env); · 23 unmodified lines
159169 void cpu_cache_level__free(struct cpu_cache_level *cache);
160170
161171 const char *perf_env__arch(struct perf_env *env);
172+const char *perf_env__arch_strerrno(struct perf_env *env, int err);
162173 const char *perf_env__cpuid(struct perf_env *env);
163174 const char *perf_env__raw_arch(struct perf_env *env);
164175 int perf_env__nr_cpus_avail(struct perf_env *env);
165176
166177 void perf_env__init(struct perf_env *env);
178+void __perf_env__insert_bpf_prog_info(struct perf_env *env,
179+ struct bpf_prog_info_node *info_node);
167180 void perf_env__insert_bpf_prog_info(struct perf_env *env,
168181 struct bpf_prog_info_node *info_node);
169182 struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *env,
170183 __u32 prog_id);
171184 bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
185+bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node);
172186 struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id);
187+struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id);
173188
174189 int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu);
175190 char *perf_env__find_pmu_cap(struct perf_env *env, const char *pmu_name,
176191 const char *cap);
192+
193+bool perf_env__has_pmu_mapping(struct perf_env *env, const char *pmu_name);
177194 #endif /* __PERF_ENV_H */
tools/perf/util/event.c+2−2
@@ -617,13 +617,13 @@ struct map *thread__find_map(struct thread *thread, u8 cpumode, u64 addr, · 616 unmodified lines
617617 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
618618 al->level = 'k';
619619 maps = machine__kernel_maps(machine);
620− load_map = true;
620+ load_map = !symbol_conf.lazy_load_kernel_maps;
621621 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
622622 al->level = '.';
623623 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
624624 al->level = 'g';
625625 maps = machine__kernel_maps(machine);
626− load_map = true;
626+ load_map = !symbol_conf.lazy_load_kernel_maps;
627627 } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) {
628628 al->level = 'u';
629629 } else {
tools/perf/util/evlist.c+32−2
@@ -1056,7 +1056,7 @@ int evlist__create_maps(struct evlist *evlist, struct target *target) · 1055 unmodified lines
10561056 return -1;
10571057
10581058 if (target__uses_dummy_map(target))
1059− cpus = perf_cpu_map__dummy_new();
1059+ cpus = perf_cpu_map__new_any_cpu();
10601060 else
10611061 cpus = perf_cpu_map__new(target->cpu_list);
10621062
@@ -1352,7 +1352,7 @@ static int evlist__create_syswide_maps(struct evlist *evlist) · 289 unmodified lines
13521352 * error, and we may not want to do that fallback to a
13531353 * default cpu identity map :-\
13541354 */
1355− cpus = perf_cpu_map__new(NULL);
1355+ cpus = perf_cpu_map__new_online_cpus();
13561356 if (!cpus)
13571357 goto out;
13581358
@@ -2518,3 +2518,33 @@ void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_lis · 1159 unmodified lines
25182518 }
25192519 perf_cpu_map__put(user_requested_cpus);
25202520 }
2521+
2522+void evlist__uniquify_name(struct evlist *evlist)
2523+{
2524+ char *new_name, empty_attributes[2] = ":", *attributes;
2525+ struct evsel *pos;
2526+
2527+ if (perf_pmus__num_core_pmus() == 1)
2528+ return;
2529+
2530+ evlist__for_each_entry(evlist, pos) {
2531+ if (!evsel__is_hybrid(pos))
2532+ continue;
2533+
2534+ if (strchr(pos->name, '/'))
2535+ continue;
2536+
2537+ attributes = strchr(pos->name, ':');
2538+ if (attributes)
2539+ *attributes = '\0';
2540+ else
2541+ attributes = empty_attributes;
2542+
2543+ if (asprintf(&new_name, "%s/%s/%s", pos->pmu_name, pos->name, attributes + 1)) {
2544+ free(pos->name);
2545+ pos->name = new_name;
2546+ } else {
2547+ *attributes = ':';
2548+ }
2549+ }
2550+}
tools/perf/util/evlist.h+1−0
@@ -442,5 +442,6 @@ struct evsel *evlist__find_evsel(struct evlist *evlist, int idx); · 441 unmodified lines
442442 int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf);
443443 void evlist__check_mem_load_aux(struct evlist *evlist);
444444 void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list);
445+void evlist__uniquify_name(struct evlist *evlist);
445446
446447 #endif /* __PERF_EVLIST_H */
tools/perf/util/evsel.c+45−10
@@ -1801,7 +1801,7 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, · 1800 unmodified lines
18011801
18021802 if (cpus == NULL) {
18031803 if (empty_cpu_map == NULL) {
1804− empty_cpu_map = perf_cpu_map__dummy_new();
1804+ empty_cpu_map = perf_cpu_map__new_any_cpu();
18051805 if (empty_cpu_map == NULL)
18061806 return -ENOMEM;
18071807 }
@@ -1832,6 +1832,8 @@ static int __evsel__prepare_open(struct evsel *evsel, struct perf_cpu_map *cpus, · 24 unmodified lines
18321832
18331833 static void evsel__disable_missing_features(struct evsel *evsel)
18341834 {
1835+ if (perf_missing_features.branch_counters)
1836+ evsel->core.attr.branch_sample_type &= ~PERF_SAMPLE_BRANCH_COUNTERS;
18351837 if (perf_missing_features.read_lost)
18361838 evsel->core.attr.read_format &= ~PERF_FORMAT_LOST;
18371839 if (perf_missing_features.weight_struct) {
@@ -1885,7 +1887,12 @@ bool evsel__detect_missing_features(struct evsel *evsel) · 47 unmodified lines
18851887 * Must probe features in the order they were added to the
18861888 * perf_event_attr interface.
18871889 */
1888− if (!perf_missing_features.read_lost &&
1890+ if (!perf_missing_features.branch_counters &&
1891+ (evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS)) {
1892+ perf_missing_features.branch_counters = true;
1893+ pr_debug2("switching off branch counters support\n");
1894+ return true;
1895+ } else if (!perf_missing_features.read_lost &&
18891896 (evsel->core.attr.read_format & PERF_FORMAT_LOST)) {
18901897 perf_missing_features.read_lost = true;
18911898 pr_debug2("switching off PERF_FORMAT_LOST support\n");
@@ -2318,6 +2325,22 @@ u64 evsel__bitfield_swap_branch_flags(u64 value) · 426 unmodified lines
23182325 return new_val;
23192326 }
23202327
2328+static inline bool evsel__has_branch_counters(const struct evsel *evsel)
2329+{
2330+ struct evsel *cur, *leader = evsel__leader(evsel);
2331+
2332+ /* The branch counters feature only supports group */
2333+ if (!leader || !evsel->evlist)
2334+ return false;
2335+
2336+ evlist__for_each_entry(evsel->evlist, cur) {
2337+ if ((leader == evsel__leader(cur)) &&
2338+ (cur->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS))
2339+ return true;
2340+ }
2341+ return false;
2342+}
2343+
23212344 int evsel__parse_sample(struct evsel *evsel, union perf_event *event,
23222345 struct perf_sample *data)
23232346 {
@@ -2551,6 +2574,16 @@ int evsel__parse_sample(struct evsel *evsel, union perf_event *event, · 227 unmodified lines
25512574
25522575 OVERFLOW_CHECK(array, sz, max_size);
25532576 array = (void *)array + sz;
2577+
2578+ if (evsel__has_branch_counters(evsel)) {
2579+ OVERFLOW_CHECK_u64(array);
2580+
2581+ data->branch_stack_cntr = (u64 *)array;
2582+ sz = data->branch_stack->nr * sizeof(u64);
2583+
2584+ OVERFLOW_CHECK(array, sz, max_size);
2585+ array = (void *)array + sz;
2586+ }
25542587 }
25552588
25562589 if (type & PERF_SAMPLE_REGS_USER) {
@@ -2820,7 +2853,8 @@ u64 evsel__intval_common(struct evsel *evsel, struct perf_sample *sample, const · 263 unmodified lines
28202853
28212854 #endif
28222855
2823−bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize)
2856+bool evsel__fallback(struct evsel *evsel, struct target *target, int err,
2857+ char *msg, size_t msgsize)
28242858 {
28252859 int paranoid;
28262860
@@ -2828,18 +2862,19 @@ bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize) · 1 unmodified line
28282862 evsel->core.attr.type == PERF_TYPE_HARDWARE &&
28292863 evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES) {
28302864 /*
2831− * If it's cycles then fall back to hrtimer based
2832− * cpu-clock-tick sw counter, which is always available even if
2833− * no PMU support.
2865+ * If it's cycles then fall back to hrtimer based cpu-clock sw
2866+ * counter, which is always available even if no PMU support.
28342867 *
28352868 * PPC returns ENXIO until 2.6.37 (behavior changed with commit
28362869 * b0a873e).
28372870 */
2838− scnprintf(msg, msgsize, "%s",
2839−"The cycles event is not supported, trying to fall back to cpu-clock-ticks");
2840−
28412871 evsel->core.attr.type = PERF_TYPE_SOFTWARE;
2842− evsel->core.attr.config = PERF_COUNT_SW_CPU_CLOCK;
2872+ evsel->core.attr.config = target__has_cpu(target)
2873+ ? PERF_COUNT_SW_CPU_CLOCK
2874+ : PERF_COUNT_SW_TASK_CLOCK;
2875+ scnprintf(msg, msgsize,
2876+ "The cycles event is not supported, trying to fall back to %s",
2877+ target__has_cpu(target) ? "cpu-clock" : "task-clock");
28432878
28442879 zfree(&evsel->name);
28452880 return true;
tools/perf/util/evsel.h+3−1
@@ -191,6 +191,7 @@ struct perf_missing_features { · 190 unmodified lines
191191 bool code_page_size;
192192 bool weight_struct;
193193 bool read_lost;
194+ bool branch_counters;
194195 };
195196
196197 extern struct perf_missing_features perf_missing_features;
@@ -459,7 +460,8 @@ static inline bool evsel__is_clock(const struct evsel *evsel) · 262 unmodified lines
459460 evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK);
460461 }
461462
462−bool evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize);
463+bool evsel__fallback(struct evsel *evsel, struct target *target, int err,
464+ char *msg, size_t msgsize);
463465 int evsel__open_strerror(struct evsel *evsel, struct target *target,
464466 int err, char *msg, size_t size);
465467
tools/perf/util/genelf.c+3−3
@@ -293,9 +293,9 @@ jit_write_elf(int fd, uint64_t load_addr, const char *sym, · 292 unmodified lines
293293 */
294294 phdr = elf_newphdr(e, 1);
295295 phdr[0].p_type = PT_LOAD;
296− phdr[0].p_offset = 0;
297− phdr[0].p_vaddr = 0;
298− phdr[0].p_paddr = 0;
296+ phdr[0].p_offset = GEN_ELF_TEXT_OFFSET;
297+ phdr[0].p_vaddr = GEN_ELF_TEXT_OFFSET;
298+ phdr[0].p_paddr = GEN_ELF_TEXT_OFFSET;
299299 phdr[0].p_filesz = csize;
300300 phdr[0].p_memsz = csize;
301301 phdr[0].p_flags = PF_X | PF_R;
tools/perf/util/header.c+33−10
@@ -1444,7 +1444,9 @@ static int build_mem_topology(struct memory_node **nodesp, u64 *cntp) · 1443 unmodified lines
14441444 nodes = new_nodes;
14451445 size += 4;
14461446 }
1447− ret = memory_node__read(&nodes[cnt++], idx);
1447+ ret = memory_node__read(&nodes[cnt], idx);
1448+ if (!ret)
1449+ cnt += 1;
14481450 }
14491451 out:
14501452 closedir(dir);
@@ -1847,8 +1849,8 @@ static void print_bpf_prog_info(struct feat_fd *ff, FILE *fp) · 396 unmodified lines
18471849 node = rb_entry(next, struct bpf_prog_info_node, rb_node);
18481850 next = rb_next(&node->rb_node);
18491851
1850− bpf_event__print_bpf_prog_info(&node->info_linear->info,
1851− env, fp);
1852+ __bpf_event__print_bpf_prog_info(&node->info_linear->info,
1853+ env, fp);
18521854 }
18531855
18541856 up_read(&env->bpf_progs.lock);
@@ -2145,6 +2147,14 @@ static void print_pmu_caps(struct feat_fd *ff, FILE *fp) · 290 unmodified lines
21452147 __print_pmu_caps(fp, pmu_caps->nr_caps, pmu_caps->caps,
21462148 pmu_caps->pmu_name);
21472149 }
2150+
2151+ if (strcmp(perf_env__arch(&ff->ph->env), "x86") == 0 &&
2152+ perf_env__has_pmu_mapping(&ff->ph->env, "ibs_op")) {
2153+ char *max_precise = perf_env__find_pmu_cap(&ff->ph->env, "cpu", "max_precise");
2154+
2155+ if (max_precise != NULL && atoi(max_precise) == 0)
2156+ fprintf(fp, "# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the 'perf list' man page for further details.\n");
2157+ }
21482158 }
21492159
21502160 static void print_pmu_mappings(struct feat_fd *ff, FILE *fp)
@@ -3178,7 +3188,7 @@ static int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused) · 1027 unmodified lines
31783188 /* after reading from file, translate offset to address */
31793189 bpil_offs_to_addr(info_linear);
31803190 info_node->info_linear = info_linear;
3181− perf_env__insert_bpf_prog_info(env, info_node);
3191+ __perf_env__insert_bpf_prog_info(env, info_node);
31823192 }
31833193
31843194 up_write(&env->bpf_progs.lock);
@@ -3225,7 +3235,7 @@ static int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused) · 40 unmodified lines
32253235 if (__do_read(ff, node->data, data_size))
32263236 goto out;
32273237
3228− perf_env__insert_btf(env, node);
3238+ __perf_env__insert_btf(env, node);
32293239 node = NULL;
32303240 }
32313241
@@ -3259,7 +3269,9 @@ static int process_compressed(struct feat_fd *ff, · 27 unmodified lines
32593269 }
32603270
32613271 static int __process_pmu_caps(struct feat_fd *ff, int *nr_caps,
3262− char ***caps, unsigned int *max_branches)
3272+ char ***caps, unsigned int *max_branches,
3273+ unsigned int *br_cntr_nr,
3274+ unsigned int *br_cntr_width)
32633275 {
32643276 char *name, *value, *ptr;
32653277 u32 nr_pmu_caps, i;
@@ -3294,6 +3306,12 @@ static int __process_pmu_caps(struct feat_fd *ff, int *nr_caps, · 28 unmodified lines
32943306 if (!strcmp(name, "branches"))
32953307 *max_branches = atoi(value);
32963308
3309+ if (!strcmp(name, "branch_counter_nr"))
3310+ *br_cntr_nr = atoi(value);
3311+
3312+ if (!strcmp(name, "branch_counter_width"))
3313+ *br_cntr_width = atoi(value);
3314+
32973315 free(value);
32983316 free(name);
32993317 }
@@ -3318,7 +3336,9 @@ static int process_cpu_pmu_caps(struct feat_fd *ff, · 18 unmodified lines
33183336 {
33193337 int ret = __process_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps,
33203338 &ff->ph->env.cpu_pmu_caps,
3321− &ff->ph->env.max_branches);
3339+ &ff->ph->env.max_branches,
3340+ &ff->ph->env.br_cntr_nr,
3341+ &ff->ph->env.br_cntr_width);
33223342
33233343 if (!ret && !ff->ph->env.cpu_pmu_caps)
33243344 pr_debug("cpu pmu capabilities not available\n");
@@ -3347,7 +3367,9 @@ static int process_pmu_caps(struct feat_fd *ff, void *data __maybe_unused) · 22 unmodified lines
33473367 for (i = 0; i < nr_pmu; i++) {
33483368 ret = __process_pmu_caps(ff, &pmu_caps[i].nr_caps,
33493369 &pmu_caps[i].caps,
3350− &pmu_caps[i].max_branches);
3370+ &pmu_caps[i].max_branches,
3371+ &pmu_caps[i].br_cntr_nr,
3372+ &pmu_caps[i].br_cntr_width);
33513373 if (ret)
33523374 goto err;
33533375
@@ -4369,9 +4391,10 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) · 1015 unmodified lines
43694391 ret += fprintf(fp, "... ");
43704392
43714393 map = cpu_map__new_data(&ev->cpus.cpus);
4372− if (map)
4394+ if (map) {
43734395 ret += cpu_map__fprintf(map, fp);
4374− else
4396+ perf_cpu_map__put(map);
4397+ } else
43754398 ret += fprintf(fp, "failed to get cpus\n");
43764399 break;
43774400 default:
tools/perf/util/hisi-ptt.c+1−0
@@ -123,6 +123,7 @@ static int hisi_ptt_process_auxtrace_event(struct perf_session *session, · 122 unmodified lines
123123 if (dump_trace)
124124 hisi_ptt_dump_event(ptt, data, size);
125125
126+ free(data);
126127 return 0;
127128 }
128129
tools/perf/util/hist.h+11−17
@@ -82,6 +82,9 @@ enum hist_column { · 81 unmodified lines
8282 HISTC_ADDR_TO,
8383 HISTC_ADDR,
8484 HISTC_SIMD,
85+ HISTC_TYPE,
86+ HISTC_TYPE_OFFSET,
87+ HISTC_SYMBOL_OFFSET,
8588 HISTC_NR_COLS, /* Last entry */
8689 };
8790
@@ -457,7 +460,6 @@ struct hist_browser_timer { · 369 unmodified lines
457460 int refresh;
458461 };
459462
460−struct annotation_options;
461463 struct res_sample;
462464
463465 enum rstype {
@@ -473,16 +475,13 @@ struct block_hist; · 9 unmodified lines
473475 void attr_to_script(char *buf, struct perf_event_attr *attr);
474476
475477 int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
476− struct hist_browser_timer *hbt,
477− struct annotation_options *annotation_opts);
478+ struct hist_browser_timer *hbt);
478479
479480 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
480− struct hist_browser_timer *hbt,
481− struct annotation_options *annotation_opts);
481+ struct hist_browser_timer *hbt);
482482
483483 int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt,
484− float min_pcnt, struct perf_env *env, bool warn_lost_event,
485− struct annotation_options *annotation_options);
484+ float min_pcnt, struct perf_env *env, bool warn_lost_event);
486485
487486 int script_browse(const char *script_opt, struct evsel *evsel);
488487
@@ -492,8 +491,7 @@ int res_sample_browse(struct res_sample *res_samples, int num_res, · 3 unmodified lines
492491 void res_sample_init(void);
493492
494493 int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
495− float min_percent, struct perf_env *env,
496− struct annotation_options *annotation_opts);
494+ float min_percent, struct perf_env *env);
497495 #else
498496 static inline
499497 int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused,
@@ -501,23 +499,20 @@ int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused, · 1 unmodified line
501499 struct hist_browser_timer *hbt __maybe_unused,
502500 float min_pcnt __maybe_unused,
503501 struct perf_env *env __maybe_unused,
504− bool warn_lost_event __maybe_unused,
505− struct annotation_options *annotation_options __maybe_unused)
502+ bool warn_lost_event __maybe_unused)
506503 {
507504 return 0;
508505 }
509506 static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused,
510507 struct evsel *evsel __maybe_unused,
511− struct hist_browser_timer *hbt __maybe_unused,
512− struct annotation_options *annotation_options __maybe_unused)
508+ struct hist_browser_timer *hbt __maybe_unused)
513509 {
514510 return 0;
515511 }
516512
517513 static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused,
518514 struct evsel *evsel __maybe_unused,
519− struct hist_browser_timer *hbt __maybe_unused,
520− struct annotation_options *annotation_opts __maybe_unused)
515+ struct hist_browser_timer *hbt __maybe_unused)
521516 {
522517 return 0;
523518 }
@@ -541,8 +536,7 @@ static inline void res_sample_init(void) {} · 17 unmodified lines
541536 static inline int block_hists_tui_browse(struct block_hist *bh __maybe_unused,
542537 struct evsel *evsel __maybe_unused,
543538 float min_percent __maybe_unused,
544− struct perf_env *env __maybe_unused,
545− struct annotation_options *annotation_opts __maybe_unused)
539+ struct perf_env *env __maybe_unused)
546540 {
547541 return 0;
548542 }
tools/perf/util/include/dwarf-regs.h+19−0
@@ -2,6 +2,9 @@ · 1 unmodified line
22 #ifndef _PERF_DWARF_REGS_H_
33 #define _PERF_DWARF_REGS_H_
44
5+#define DWARF_REG_PC 0xd3af9c /* random number */
6+#define DWARF_REG_FB 0xd3affb /* random number */
7+
58 #ifdef HAVE_DWARF_SUPPORT
69 const char *get_arch_regstr(unsigned int n);
710 /*
@@ -10,6 +13,22 @@ const char *get_arch_regstr(unsigned int n); · 2 unmodified lines
1013 * machine: ELF machine signature (EM_*)
1114 */
1215 const char *get_dwarf_regstr(unsigned int n, unsigned int machine);
16+
17+int get_arch_regnum(const char *name);
18+/*
19+ * get_dwarf_regnum - Returns DWARF regnum from register name
20+ * name: architecture register name
21+ * machine: ELF machine signature (EM_*)
22+ */
23+int get_dwarf_regnum(const char *name, unsigned int machine);
24+
25+#else /* HAVE_DWARF_SUPPORT */
26+
27+static inline int get_dwarf_regnum(const char *name __maybe_unused,
28+ unsigned int machine __maybe_unused)
29+{
30+ return -1;
31+}
1332 #endif
1433
1534 #ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
tools/perf/util/machine.c+41−34
@@ -453,7 +453,7 @@ static struct thread *findnew_guest_code(struct machine *machine, · 452 unmodified lines
453453 * Guest code can be found in hypervisor process at the same address
454454 * so copy host maps.
455455 */
456− err = maps__clone(thread, thread__maps(host_thread));
456+ err = maps__copy_from(thread__maps(thread), thread__maps(host_thread));
457457 thread__put(host_thread);
458458 if (err)
459459 goto out_err;
@@ -1285,33 +1285,46 @@ static u64 find_entry_trampoline(struct dso *dso) · 825 unmodified lines
12851285 #define X86_64_CPU_ENTRY_AREA_SIZE 0x2c000
12861286 #define X86_64_ENTRY_TRAMPOLINE 0x6000
12871287
1288+struct machine__map_x86_64_entry_trampolines_args {
1289+ struct maps *kmaps;
1290+ bool found;
1291+};
1292+
1293+static int machine__map_x86_64_entry_trampolines_cb(struct map *map, void *data)
1294+{
1295+ struct machine__map_x86_64_entry_trampolines_args *args = data;
1296+ struct map *dest_map;
1297+ struct kmap *kmap = __map__kmap(map);
1298+
1299+ if (!kmap || !is_entry_trampoline(kmap->name))
1300+ return 0;
1301+
1302+ dest_map = maps__find(args->kmaps, map__pgoff(map));
1303+ if (dest_map != map)
1304+ map__set_pgoff(map, map__map_ip(dest_map, map__pgoff(map)));
1305+
1306+ args->found = true;
1307+ return 0;
1308+}
1309+
12881310 /* Map x86_64 PTI entry trampolines */
12891311 int machine__map_x86_64_entry_trampolines(struct machine *machine,
12901312 struct dso *kernel)
12911313 {
1292− struct maps *kmaps = machine__kernel_maps(machine);
1314+ struct machine__map_x86_64_entry_trampolines_args args = {
1315+ .kmaps = machine__kernel_maps(machine),
1316+ .found = false,
1317+ };
12931318 int nr_cpus_avail, cpu;
1294− bool found = false;
1295− struct map_rb_node *rb_node;
12961319 u64 pgoff;
12971320
12981321 /*
12991322 * In the vmlinux case, pgoff is a virtual address which must now be
13001323 * mapped to a vmlinux offset.
13011324 */
1302− maps__for_each_entry(kmaps, rb_node) {
1303− struct map *dest_map, *map = rb_node->map;
1304− struct kmap *kmap = __map__kmap(map);
1305−
1306− if (!kmap || !is_entry_trampoline(kmap->name))
1307− continue;
1325+ maps__for_each_map(args.kmaps, machine__map_x86_64_entry_trampolines_cb, &args);
13081326
1309− dest_map = maps__find(kmaps, map__pgoff(map));
1310− if (dest_map != map)
1311− map__set_pgoff(map, map__map_ip(dest_map, map__pgoff(map)));
1312− found = true;
1313− }
1314− if (found || machine->trampolines_mapped)
1327+ if (args.found || machine->trampolines_mapped)
13151328 return 0;
13161329
13171330 pgoff = find_entry_trampoline(kernel);
@@ -1359,8 +1372,7 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) · 41 unmodified lines
13591372 if (machine->vmlinux_map == NULL)
13601373 return -ENOMEM;
13611374
1362− map__set_map_ip(machine->vmlinux_map, identity__map_ip);
1363− map__set_unmap_ip(machine->vmlinux_map, identity__map_ip);
1375+ map__set_mapping_type(machine->vmlinux_map, MAPPING_TYPE__IDENTITY);
13641376 return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map);
13651377 }
13661378
@@ -1750,12 +1762,11 @@ int machine__create_kernel_maps(struct machine *machine) · 383 unmodified lines
17501762
17511763 if (end == ~0ULL) {
17521764 /* update end address of the kernel map using adjacent module address */
1753− struct map_rb_node *rb_node = maps__find_node(machine__kernel_maps(machine),
1754− machine__kernel_map(machine));
1755− struct map_rb_node *next = map_rb_node__next(rb_node);
1765+ struct map *next = maps__find_next_entry(machine__kernel_maps(machine),
1766+ machine__kernel_map(machine));
17561767
17571768 if (next)
1758− machine__set_kernel_mmap(machine, start, map__start(next->map));
1769+ machine__set_kernel_mmap(machine, start, map__start(next));
17591770 }
17601771
17611772 out_put:
@@ -2157,9 +2168,13 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event · 395 unmodified lines
21572168 if (dump_trace)
21582169 perf_event__fprintf_task(event, stdout);
21592170
2160− if (thread != NULL)
2161− thread__put(thread);
2162−
2171+ if (thread != NULL) {
2172+ if (symbol_conf.keep_exited_threads)
2173+ thread__set_exited(thread, /*exited=*/true);
2174+ else
2175+ machine__remove_thread(machine, thread);
2176+ }
2177+ thread__put(thread);
21632178 return 0;
21642179 }
21652180
@@ -3395,16 +3410,8 @@ int machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv · 1229 unmodified lines
33953410 int machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv)
33963411 {
33973412 struct maps *maps = machine__kernel_maps(machine);
3398− struct map_rb_node *pos;
3399− int err = 0;
34003413
3401− maps__for_each_entry(maps, pos) {
3402− err = fn(pos->map, priv);
3403− if (err != 0) {
3404− break;
3405− }
3406− }
3407− return err;
3414+ return maps__for_each_map(maps, fn, priv);
34083415 }
34093416
34103417 bool machine__is_lock_function(struct machine *machine, u64 addr)
tools/perf/util/map.c+2−18
@@ -109,8 +109,7 @@ void map__init(struct map *map, u64 start, u64 end, u64 pgoff, struct dso *dso) · 108 unmodified lines
109109 map__set_pgoff(map, pgoff);
110110 map__set_reloc(map, 0);
111111 map__set_dso(map, dso__get(dso));
112− map__set_map_ip(map, map__dso_map_ip);
113− map__set_unmap_ip(map, map__dso_unmap_ip);
112+ map__set_mapping_type(map, MAPPING_TYPE__DSO);
114113 map__set_erange_warned(map, false);
115114 refcount_set(map__refcnt(map), 1);
116115 }
@@ -172,7 +171,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len, · 55 unmodified lines
172171 map__init(result, start, start + len, pgoff, dso);
173172
174173 if (anon || no_dso) {
175− map->map_ip = map->unmap_ip = identity__map_ip;
174+ map->mapping_type = MAPPING_TYPE__IDENTITY;
176175
177176 /*
178177 * Set memory without DSO as loaded. All map__find_*
@@ -630,18 +629,3 @@ struct maps *map__kmaps(struct map *map) · 451 unmodified lines
630629 }
631630 return kmap->kmaps;
632631 }
633−
634−u64 map__dso_map_ip(const struct map *map, u64 ip)
635−{
636− return ip - map__start(map) + map__pgoff(map);
637−}
638−
639−u64 map__dso_unmap_ip(const struct map *map, u64 ip)
640−{
641− return ip + map__start(map) - map__pgoff(map);
642−}
643−
644−u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip)
645−{
646− return ip;
647−}
tools/perf/util/map.h+43−40
@@ -16,23 +16,25 @@ struct dso; · 15 unmodified lines
1616 struct maps;
1717 struct machine;
1818
19+enum mapping_type {
20+ /* map__map_ip/map__unmap_ip are given as offsets in the DSO. */
21+ MAPPING_TYPE__DSO,
22+ /* map__map_ip/map__unmap_ip are just the given ip value. */
23+ MAPPING_TYPE__IDENTITY,
24+};
25+
1926 DECLARE_RC_STRUCT(map) {
2027 u64 start;
2128 u64 end;
22− bool erange_warned:1;
23− bool priv:1;
24− u32 prot;
2529 u64 pgoff;
2630 u64 reloc;
27−
28− /* ip -> dso rip */
29− u64 (*map_ip)(const struct map *, u64);
30− /* dso rip -> ip */
31− u64 (*unmap_ip)(const struct map *, u64);
32−
3331 struct dso *dso;
3432 refcount_t refcnt;
33+ u32 prot;
3534 u32 flags;
35+ enum mapping_type mapping_type:8;
36+ bool erange_warned;
37+ bool priv;
3638 };
3739
3840 struct kmap;
@@ -41,38 +43,11 @@ struct kmap *__map__kmap(struct map *map); · 2 unmodified lines
4143 struct kmap *map__kmap(struct map *map);
4244 struct maps *map__kmaps(struct map *map);
4345
44−/* ip -> dso rip */
45−u64 map__dso_map_ip(const struct map *map, u64 ip);
46−/* dso rip -> ip */
47−u64 map__dso_unmap_ip(const struct map *map, u64 ip);
48−/* Returns ip */
49−u64 identity__map_ip(const struct map *map __maybe_unused, u64 ip);
50−
5146 static inline struct dso *map__dso(const struct map *map)
5247 {
5348 return RC_CHK_ACCESS(map)->dso;
5449 }
5550
56−static inline u64 map__map_ip(const struct map *map, u64 ip)
57−{
58− return RC_CHK_ACCESS(map)->map_ip(map, ip);
59−}
60−
61−static inline u64 map__unmap_ip(const struct map *map, u64 ip)
62−{
63− return RC_CHK_ACCESS(map)->unmap_ip(map, ip);
64−}
65−
66−static inline void *map__map_ip_ptr(struct map *map)
67−{
68− return RC_CHK_ACCESS(map)->map_ip;
69−}
70−
71−static inline void* map__unmap_ip_ptr(struct map *map)
72−{
73− return RC_CHK_ACCESS(map)->unmap_ip;
74−}
75−
7651 static inline u64 map__start(const struct map *map)
7752 {
7853 return RC_CHK_ACCESS(map)->start;
@@ -123,6 +98,34 @@ static inline size_t map__size(const struct map *map) · 44 unmodified lines
12398 return map__end(map) - map__start(map);
12499 }
125100
101+/* ip -> dso rip */
102+static inline u64 map__dso_map_ip(const struct map *map, u64 ip)
103+{
104+ return ip - map__start(map) + map__pgoff(map);
105+}
106+
107+/* dso rip -> ip */
108+static inline u64 map__dso_unmap_ip(const struct map *map, u64 rip)
109+{
110+ return rip + map__start(map) - map__pgoff(map);
111+}
112+
113+static inline u64 map__map_ip(const struct map *map, u64 ip_or_rip)
114+{
115+ if ((RC_CHK_ACCESS(map)->mapping_type) == MAPPING_TYPE__DSO)
116+ return map__dso_map_ip(map, ip_or_rip);
117+ else
118+ return ip_or_rip;
119+}
120+
121+static inline u64 map__unmap_ip(const struct map *map, u64 ip_or_rip)
122+{
123+ if ((RC_CHK_ACCESS(map)->mapping_type) == MAPPING_TYPE__DSO)
124+ return map__dso_unmap_ip(map, ip_or_rip);
125+ else
126+ return ip_or_rip;
127+}
128+
126129 /* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
127130 u64 map__rip_2objdump(struct map *map, u64 rip);
128131
@@ -294,13 +297,13 @@ static inline void map__set_dso(struct map *map, struct dso *dso) · 165 unmodified lines
294297 RC_CHK_ACCESS(map)->dso = dso;
295298 }
296299
297−static inline void map__set_map_ip(struct map *map, u64 (*map_ip)(const struct map *map, u64 ip))
300+static inline void map__set_mapping_type(struct map *map, enum mapping_type type)
298301 {
299− RC_CHK_ACCESS(map)->map_ip = map_ip;
302+ RC_CHK_ACCESS(map)->mapping_type = type;
300303 }
301304
302−static inline void map__set_unmap_ip(struct map *map, u64 (*unmap_ip)(const struct map *map, u64 rip))
305+static inline enum mapping_type map__mapping_type(struct map *map)
303306 {
304− RC_CHK_ACCESS(map)->unmap_ip = unmap_ip;
307+ return RC_CHK_ACCESS(map)->mapping_type;
305308 }
306309 #endif /* __PERF_MAP_H */
tools/perf/util/maps.c+445−83
@@ -10,6 +10,68 @@ · 9 unmodified lines
1010 #include "ui/ui.h"
1111 #include "unwind.h"
1212
13+struct map_rb_node {
14+ struct rb_node rb_node;
15+ struct map *map;
16+};
17+
18+#define maps__for_each_entry(maps, map) \
19+ for (map = maps__first(maps); map; map = map_rb_node__next(map))
20+
21+#define maps__for_each_entry_safe(maps, map, next) \
22+ for (map = maps__first(maps), next = map_rb_node__next(map); map; \
23+ map = next, next = map_rb_node__next(map))
24+
25+static struct rb_root *maps__entries(struct maps *maps)
26+{
27+ return &RC_CHK_ACCESS(maps)->entries;
28+}
29+
30+static struct rw_semaphore *maps__lock(struct maps *maps)
31+{
32+ return &RC_CHK_ACCESS(maps)->lock;
33+}
34+
35+static struct map **maps__maps_by_name(struct maps *maps)
36+{
37+ return RC_CHK_ACCESS(maps)->maps_by_name;
38+}
39+
40+static struct map_rb_node *maps__first(struct maps *maps)
41+{
42+ struct rb_node *first = rb_first(maps__entries(maps));
43+
44+ if (first)
45+ return rb_entry(first, struct map_rb_node, rb_node);
46+ return NULL;
47+}
48+
49+static struct map_rb_node *map_rb_node__next(struct map_rb_node *node)
50+{
51+ struct rb_node *next;
52+
53+ if (!node)
54+ return NULL;
55+
56+ next = rb_next(&node->rb_node);
57+
58+ if (!next)
59+ return NULL;
60+
61+ return rb_entry(next, struct map_rb_node, rb_node);
62+}
63+
64+static struct map_rb_node *maps__find_node(struct maps *maps, struct map *map)
65+{
66+ struct map_rb_node *rb_node;
67+
68+ maps__for_each_entry(maps, rb_node) {
69+ if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map))
70+ return rb_node;
71+ }
72+ return NULL;
73+}
74+
1375 static void maps__init(struct maps *maps, struct machine *machine)
1476 {
1577 refcount_set(maps__refcnt(maps), 1);
@@ -196,6 +258,41 @@ void maps__put(struct maps *maps) · 180 unmodified lines
196258 RC_CHK_PUT(maps);
197259 }
198260
261+int maps__for_each_map(struct maps *maps, int (*cb)(struct map *map, void *data), void *data)
262+{
263+ struct map_rb_node *pos;
264+ int ret = 0;
265+
266+ down_read(maps__lock(maps));
267+ maps__for_each_entry(maps, pos) {
268+ ret = cb(pos->map, data);
269+ if (ret)
270+ break;
271+ }
272+ up_read(maps__lock(maps));
273+ return ret;
274+}
275+
276+void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data), void *data)
277+{
278+ struct map_rb_node *pos, *next;
279+ unsigned int start_nr_maps;
280+
281+ down_write(maps__lock(maps));
282+
283+ start_nr_maps = maps__nr_maps(maps);
284+ maps__for_each_entry_safe(maps, pos, next) {
285+ if (cb(pos->map, data)) {
286+ __maps__remove(maps, pos);
287+ --RC_CHK_ACCESS(maps)->nr_maps;
288+ }
289+ }
290+ if (maps__maps_by_name(maps) && start_nr_maps != maps__nr_maps(maps))
291+ __maps__free_maps_by_name(maps);
292+
293+ up_write(maps__lock(maps));
294+}
295+
199296 struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)
200297 {
201298 struct map *map = maps__find(maps, addr);
@@ -210,31 +307,40 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) · 8 unmodified lines
210307 return NULL;
211308 }
212309
213−struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp)
214−{
310+struct maps__find_symbol_by_name_args {
311+ struct map **mapp;
312+ const char *name;
215313 struct symbol *sym;
216− struct map_rb_node *pos;
314+};
217315
218− down_read(maps__lock(maps));
316+static int maps__find_symbol_by_name_cb(struct map *map, void *data)
317+{
318+ struct maps__find_symbol_by_name_args *args = data;
219319
220− maps__for_each_entry(maps, pos) {
221− sym = map__find_symbol_by_name(pos->map, name);
320+ args->sym = map__find_symbol_by_name(map, args->name);
321+ if (!args->sym)
322+ return 0;
222323
223− if (sym == NULL)
224− continue;
225− if (!map__contains_symbol(pos->map, sym)) {
226− sym = NULL;
227− continue;
228− }
229− if (mapp != NULL)
230− *mapp = pos->map;
231− goto out;
324+ if (!map__contains_symbol(map, args->sym)) {
325+ args->sym = NULL;
326+ return 0;
232327 }
233328
234− sym = NULL;
235−out:
236− up_read(maps__lock(maps));
237− return sym;
329+ if (args->mapp != NULL)
330+ *args->mapp = map__get(map);
331+ return 1;
332+}
333+
334+struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp)
335+{
336+ struct maps__find_symbol_by_name_args args = {
337+ .mapp = mapp,
338+ .name = name,
339+ .sym = NULL,
340+ };
341+
342+ maps__for_each_map(maps, maps__find_symbol_by_name_cb, &args);
343+ return args.sym;
238344 }
239345
240346 int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams)
@@ -253,41 +359,46 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) · 12 unmodified lines
253359 return ams->ms.sym ? 0 : -1;
254360 }
255361
256−size_t maps__fprintf(struct maps *maps, FILE *fp)
257−{
258− size_t printed = 0;
259− struct map_rb_node *pos;
362+struct maps__fprintf_args {
363+ FILE *fp;
364+ size_t printed;
365+};
260366
261− down_read(maps__lock(maps));
367+static int maps__fprintf_cb(struct map *map, void *data)
368+{
369+ struct maps__fprintf_args *args = data;
262370
263− maps__for_each_entry(maps, pos) {
264− printed += fprintf(fp, "Map:");
265− printed += map__fprintf(pos->map, fp);
266− if (verbose > 2) {
267− printed += dso__fprintf(map__dso(pos->map), fp);
268− printed += fprintf(fp, "--\n");
269− }
371+ args->printed += fprintf(args->fp, "Map:");
372+ args->printed += map__fprintf(map, args->fp);
373+ if (verbose > 2) {
374+ args->printed += dso__fprintf(map__dso(map), args->fp);
375+ args->printed += fprintf(args->fp, "--\n");
270376 }
377+ return 0;
378+}
271379
272− up_read(maps__lock(maps));
380+size_t maps__fprintf(struct maps *maps, FILE *fp)
381+{
382+ struct maps__fprintf_args args = {
383+ .fp = fp,
384+ .printed = 0,
385+ };
386+
387+ maps__for_each_map(maps, maps__fprintf_cb, &args);
273388
274− return printed;
389+ return args.printed;
275390 }
276391
277−int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
392+/*
393+ * Find first map where end > map->start.
394+ * Same as find_vma() in kernel.
395+ */
396+static struct rb_node *first_ending_after(struct maps *maps, const struct map *map)
278397 {
279398 struct rb_root *root;
280399 struct rb_node *next, *first;
281− int err = 0;
282−
283− down_write(maps__lock(maps));
284400
285401 root = maps__entries(maps);
286−
287− /*
288− * Find first map where end > map->start.
289− * Same as find_vma() in kernel.
290− */
291402 next = root->rb_node;
292403 first = NULL;
293404 while (next) {
@@ -301,8 +412,23 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 7 unmodified lines
301412 } else
302413 next = next->rb_right;
303414 }
415+ return first;
416+}
304417
305− next = first;
418+/*
419+ * Adds new to maps, if new overlaps existing entries then the existing maps are
420+ * adjusted or removed so that new fits without overlapping any entries.
421+ */
422+int maps__fixup_overlap_and_insert(struct maps *maps, struct map *new)
423+{
424+
425+ struct rb_node *next;
426+ int err = 0;
427+ FILE *fp = debug_file();
428+
429+ down_write(maps__lock(maps));
430+
431+ next = first_ending_after(maps, new);
306432 while (next && !err) {
307433 struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node);
308434 next = rb_next(&pos->rb_node);
@@ -311,27 +437,27 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 2 unmodified lines
311437 * Stop if current map starts after map->end.
312438 * Maps are ordered by start: next will not overlap for sure.
313439 */
314− if (map__start(pos->map) >= map__end(map))
440+ if (map__start(pos->map) >= map__end(new))
315441 break;
316442
317443 if (verbose >= 2) {
318444
319445 if (use_browser) {
320446 pr_debug("overlapping maps in %s (disable tui for more info)\n",
321− map__dso(map)->name);
447+ map__dso(new)->name);
322448 } else {
323− fputs("overlapping maps:\n", fp);
324− map__fprintf(map, fp);
449+ pr_debug("overlapping maps:\n");
450+ map__fprintf(new, fp);
325451 map__fprintf(pos->map, fp);
326452 }
327453 }
328454
329− rb_erase_init(&pos->rb_node, root);
455+ rb_erase_init(&pos->rb_node, maps__entries(maps));
330456 /*
331457 * Now check if we need to create new maps for areas not
332458 * overlapped by the new map:
333459 */
334− if (map__start(map) > map__start(pos->map)) {
460+ if (map__start(new) > map__start(pos->map)) {
335461 struct map *before = map__clone(pos->map);
336462
337463 if (before == NULL) {
@@ -339,7 +465,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 1 unmodified line
339465 goto put_map;
340466 }
341467
342− map__set_end(before, map__start(map));
468+ map__set_end(before, map__start(new));
343469 err = __maps__insert(maps, before);
344470 if (err) {
345471 map__put(before);
@@ -351,7 +477,7 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 5 unmodified lines
351477 map__put(before);
352478 }
353479
354− if (map__end(map) < map__end(pos->map)) {
480+ if (map__end(new) < map__end(pos->map)) {
355481 struct map *after = map__clone(pos->map);
356482
357483 if (after == NULL) {
@@ -359,10 +485,10 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) · 1 unmodified line
359485 goto put_map;
360486 }
361487
362− map__set_start(after, map__end(map));
363− map__add_pgoff(after, map__end(map) - map__start(pos->map));
364− assert(map__map_ip(pos->map, map__end(map)) ==
365− map__map_ip(after, map__end(map)));
488+ map__set_start(after, map__end(new));
489+ map__add_pgoff(after, map__end(new) - map__start(pos->map));
490+ assert(map__map_ip(pos->map, map__end(new)) ==
491+ map__map_ip(after, map__end(new)));
366492 err = __maps__insert(maps, after);
367493 if (err) {
368494 map__put(after);
@@ -376,16 +502,14 @@ put_map: · 7 unmodified lines
376502 map__put(pos->map);
377503 free(pos);
378504 }
505+ /* Add the map. */
506+ err = __maps__insert(maps, new);
379507 up_write(maps__lock(maps));
380508 return err;
381509 }
382510
383−/*
384− * XXX This should not really _copy_ te maps, but refcount them.
385− */
386−int maps__clone(struct thread *thread, struct maps *parent)
511+int maps__copy_from(struct maps *maps, struct maps *parent)
387512 {
388− struct maps *maps = thread__maps(thread);
389513 int err;
390514 struct map_rb_node *rb_node;
391515
@@ -416,17 +540,6 @@ out_unlock: · 24 unmodified lines
416540 return err;
417541 }
418542
419−struct map_rb_node *maps__find_node(struct maps *maps, struct map *map)
420−{
421− struct map_rb_node *rb_node;
422−
423− maps__for_each_entry(maps, rb_node) {
424− if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map))
425− return rb_node;
426− }
427− return NULL;
428−}
429−
430543 struct map *maps__find(struct maps *maps, u64 ip)
431544 {
432545 struct rb_node *p;
@@ -452,26 +565,275 @@ out: · 19 unmodified lines
452565 return m ? m->map : NULL;
453566 }
454567
455−struct map_rb_node *maps__first(struct maps *maps)
568+static int map__strcmp(const void *a, const void *b)
456569 {
457− struct rb_node *first = rb_first(maps__entries(maps));
570+ const struct map *map_a = *(const struct map **)a;
571+ const struct map *map_b = *(const struct map **)b;
572+ const struct dso *dso_a = map__dso(map_a);
573+ const struct dso *dso_b = map__dso(map_b);
574+ int ret = strcmp(dso_a->short_name, dso_b->short_name);
458575
459− if (first)
460− return rb_entry(first, struct map_rb_node, rb_node);
461− return NULL;
576+ if (ret == 0 && map_a != map_b) {
577+ /*
578+ * Ensure distinct but name equal maps have an order in part to
579+ * aid reference counting.
580+ */
581+ ret = (int)map__start(map_a) - (int)map__start(map_b);
582+ if (ret == 0)
583+ ret = (int)((intptr_t)map_a - (intptr_t)map_b);
584+ }
585+
586+ return ret;
462587 }
463588
464−struct map_rb_node *map_rb_node__next(struct map_rb_node *node)
589+static int map__strcmp_name(const void *name, const void *b)
465590 {
466− struct rb_node *next;
591+ const struct dso *dso = map__dso(*(const struct map **)b);
467592
468− if (!node)
469− return NULL;
593+ return strcmp(name, dso->short_name);
594+}
470595
471− next = rb_next(&node->rb_node);
596+void __maps__sort_by_name(struct maps *maps)
597+{
598+ qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp);
599+}
472600
473− if (!next)
601+static int map__groups__sort_by_name_from_rbtree(struct maps *maps)
602+{
603+ struct map_rb_node *rb_node;
604+ struct map **maps_by_name = realloc(maps__maps_by_name(maps),
605+ maps__nr_maps(maps) * sizeof(struct map *));
606+ int i = 0;
607+
608+ if (maps_by_name == NULL)
609+ return -1;
610+
611+ up_read(maps__lock(maps));
612+ down_write(maps__lock(maps));
613+
614+ RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name;
615+ RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps);
616+
617+ maps__for_each_entry(maps, rb_node)
618+ maps_by_name[i++] = map__get(rb_node->map);
619+
620+ __maps__sort_by_name(maps);
621+
622+ up_write(maps__lock(maps));
623+ down_read(maps__lock(maps));
624+
625+ return 0;
626+}
627+
628+static struct map *__maps__find_by_name(struct maps *maps, const char *name)
629+{
630+ struct map **mapp;
631+
632+ if (maps__maps_by_name(maps) == NULL &&
633+ map__groups__sort_by_name_from_rbtree(maps))
474634 return NULL;
475635
476− return rb_entry(next, struct map_rb_node, rb_node);
636+ mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps),
637+ sizeof(*mapp), map__strcmp_name);
638+ if (mapp)
639+ return *mapp;
640+ return NULL;
641+}
642+
643+struct map *maps__find_by_name(struct maps *maps, const char *name)
644+{
645+ struct map_rb_node *rb_node;
646+ struct map *map;
647+
648+ down_read(maps__lock(maps));
649+
650+
651+ if (RC_CHK_ACCESS(maps)->last_search_by_name) {
652+ const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name);
653+
654+ if (strcmp(dso->short_name, name) == 0) {
655+ map = RC_CHK_ACCESS(maps)->last_search_by_name;
656+ goto out_unlock;
657+ }
658+ }
659+ /*
660+ * If we have maps->maps_by_name, then the name isn't in the rbtree,
661+ * as maps->maps_by_name mirrors the rbtree when lookups by name are
662+ * made.
663+ */
664+ map = __maps__find_by_name(maps, name);
665+ if (map || maps__maps_by_name(maps) != NULL)
666+ goto out_unlock;
667+
668+ /* Fallback to traversing the rbtree... */
669+ maps__for_each_entry(maps, rb_node) {
670+ struct dso *dso;
671+
672+ map = rb_node->map;
673+ dso = map__dso(map);
674+ if (strcmp(dso->short_name, name) == 0) {
675+ RC_CHK_ACCESS(maps)->last_search_by_name = map;
676+ goto out_unlock;
677+ }
678+ }
679+ map = NULL;
680+
681+out_unlock:
682+ up_read(maps__lock(maps));
683+ return map;
684+}
685+
686+struct map *maps__find_next_entry(struct maps *maps, struct map *map)
687+{
688+ struct map_rb_node *rb_node = maps__find_node(maps, map);
689+ struct map_rb_node *next = map_rb_node__next(rb_node);
690+
691+ if (next)
692+ return next->map;
693+
694+ return NULL;
695+}
696+
697+void maps__fixup_end(struct maps *maps)
698+{
699+ struct map_rb_node *prev = NULL, *curr;
700+
701+ down_write(maps__lock(maps));
702+
703+ maps__for_each_entry(maps, curr) {
704+ if (prev && (!map__end(prev->map) || map__end(prev->map) > map__start(curr->map)))
705+ map__set_end(prev->map, map__start(curr->map));
706+
707+ prev = curr;
708+ }
709+
710+ /*
711+ * We still haven't the actual symbols, so guess the
712+ * last map final address.
713+ */
714+ if (curr && !map__end(curr->map))
715+ map__set_end(curr->map, ~0ULL);
716+
717+ up_write(maps__lock(maps));
718+}
719+
720+/*
721+ * Merges map into maps by splitting the new map within the existing map
722+ * regions.
723+ */
724+int maps__merge_in(struct maps *kmaps, struct map *new_map)
725+{
726+ struct map_rb_node *rb_node;
727+ struct rb_node *first;
728+ bool overlaps;
729+ LIST_HEAD(merged);
730+ int err = 0;
731+
732+ down_read(maps__lock(kmaps));
733+ first = first_ending_after(kmaps, new_map);
734+ rb_node = first ? rb_entry(first, struct map_rb_node, rb_node) : NULL;
735+ overlaps = rb_node && map__start(rb_node->map) < map__end(new_map);
736+ up_read(maps__lock(kmaps));
737+
738+ if (!overlaps)
739+ return maps__insert(kmaps, new_map);
740+
741+ maps__for_each_entry(kmaps, rb_node) {
742+ struct map *old_map = rb_node->map;
743+
744+ /* no overload with this one */
745+ if (map__end(new_map) < map__start(old_map) ||
746+ map__start(new_map) >= map__end(old_map))
747+ continue;
748+
749+ if (map__start(new_map) < map__start(old_map)) {
750+ /*
751+ * |new......
752+ * |old....
753+ */
754+ if (map__end(new_map) < map__end(old_map)) {
755+ /*
756+ * |new......| -> |new..|
757+ * |old....| -> |old....|
758+ */
759+ map__set_end(new_map, map__start(old_map));
760+ } else {
761+ /*
762+ * |new.............| -> |new..| |new..|
763+ * |old....| -> |old....|
764+ */
765+ struct map_list_node *m = map_list_node__new();
766+
767+ if (!m) {
768+ err = -ENOMEM;
769+ goto out;
770+ }
771+
772+ m->map = map__clone(new_map);
773+ if (!m->map) {
774+ free(m);
775+ err = -ENOMEM;
776+ goto out;
777+ }
778+
779+ map__set_end(m->map, map__start(old_map));
780+ list_add_tail(&m->node, &merged);
781+ map__add_pgoff(new_map, map__end(old_map) - map__start(new_map));
782+ map__set_start(new_map, map__end(old_map));
783+ }
784+ } else {
785+ /*
786+ * |new......
787+ * |old....
788+ */
789+ if (map__end(new_map) < map__end(old_map)) {
790+ /*
791+ * |new..| -> x
792+ * |old.........| -> |old.........|
793+ */
794+ map__put(new_map);
795+ new_map = NULL;
796+ break;
797+ } else {
798+ /*
799+ * |new......| -> |new...|
800+ * |old....| -> |old....|
801+ */
802+ map__add_pgoff(new_map, map__end(old_map) - map__start(new_map));
803+ map__set_start(new_map, map__end(old_map));
804+ }
805+ }
806+ }
807+
808+out:
809+ while (!list_empty(&merged)) {
810+ struct map_list_node *old_node;
811+
812+ old_node = list_entry(merged.next, struct map_list_node, node);
813+ list_del_init(&old_node->node);
814+ if (!err)
815+ err = maps__insert(kmaps, old_node->map);
816+ map__put(old_node->map);
817+ free(old_node);
818+ }
819+
820+ if (new_map) {
821+ if (!err)
822+ err = maps__insert(kmaps, new_map);
823+ map__put(new_map);
824+ }
825+ return err;
826+}
827+
828+void maps__load_first(struct maps *maps)
829+{
830+ struct map_rb_node *first;
831+
832+ down_read(maps__lock(maps));
833+
834+ first = maps__first(maps);
835+ if (first)
836+ map__load(first->map);
837+
838+ up_read(maps__lock(maps));
477839 }
tools/perf/util/maps.h+19−29
@@ -14,24 +14,18 @@ struct ref_reloc_sym; · 13 unmodified lines
1414 struct machine;
1515 struct map;
1616 struct maps;
17−struct thread;
1817
19−struct map_rb_node {
20− struct rb_node rb_node;
18+struct map_list_node {
19+ struct list_head node;
2120 struct map *map;
2221 };
2322
24−struct map_rb_node *maps__first(struct maps *maps);
25−struct map_rb_node *map_rb_node__next(struct map_rb_node *node);
26−struct map_rb_node *maps__find_node(struct maps *maps, struct map *map);
27−struct map *maps__find(struct maps *maps, u64 addr);
28−
29−#define maps__for_each_entry(maps, map) \
30− for (map = maps__first(maps); map; map = map_rb_node__next(map))
23+static inline struct map_list_node *map_list_node__new(void)
24+{
25+ return malloc(sizeof(struct map_list_node));
26+}
3127
32−#define maps__for_each_entry_safe(maps, map, next) \
33− for (map = maps__first(maps), next = map_rb_node__next(map); map; \
34− map = next, next = map_rb_node__next(map))
28+struct map *maps__find(struct maps *maps, u64 addr);
3529
3630 DECLARE_RC_STRUCT(maps) {
3731 struct rb_root entries;
@@ -58,7 +52,7 @@ struct kmap { · 20 unmodified lines
5852
5953 struct maps *maps__new(struct machine *machine);
6054 bool maps__empty(struct maps *maps);
61−int maps__clone(struct thread *thread, struct maps *parent);
55+int maps__copy_from(struct maps *maps, struct maps *parent);
6256
6357 struct maps *maps__get(struct maps *maps);
6458 void maps__put(struct maps *maps);
@@ -71,26 +65,16 @@ static inline void __maps__zput(struct maps **map) · 6 unmodified lines
7165
7266 #define maps__zput(map) __maps__zput(&map)
7367
74−static inline struct rb_root *maps__entries(struct maps *maps)
75−{
76− return &RC_CHK_ACCESS(maps)->entries;
77−}
68+/* Iterate over map calling cb for each entry. */
69+int maps__for_each_map(struct maps *maps, int (*cb)(struct map *map, void *data), void *data);
70+/* Iterate over map removing an entry if cb returns true. */
71+void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data), void *data);
7872
7973 static inline struct machine *maps__machine(struct maps *maps)
8074 {
8175 return RC_CHK_ACCESS(maps)->machine;
8276 }
8377
84−static inline struct rw_semaphore *maps__lock(struct maps *maps)
85−{
86− return &RC_CHK_ACCESS(maps)->lock;
87−}
88−
89−static inline struct map **maps__maps_by_name(struct maps *maps)
90−{
91− return RC_CHK_ACCESS(maps)->maps_by_name;
92−}
93−
9478 static inline unsigned int maps__nr_maps(const struct maps *maps)
9579 {
9680 return RC_CHK_ACCESS(maps)->nr_maps;
@@ -125,12 +109,18 @@ struct addr_map_symbol; · 28 unmodified lines
125109
126110 int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams);
127111
128−int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp);
112+int maps__fixup_overlap_and_insert(struct maps *maps, struct map *new);
129113
130114 struct map *maps__find_by_name(struct maps *maps, const char *name);
131115
116+struct map *maps__find_next_entry(struct maps *maps, struct map *map);
117+
132118 int maps__merge_in(struct maps *kmaps, struct map *new_map);
133119
134120 void __maps__sort_by_name(struct maps *maps);
135121
122+void maps__fixup_end(struct maps *maps);
123+
124+void maps__load_first(struct maps *maps);
125+
136126 #endif // __PERF_MAPS_H
tools/perf/util/mem-events.c+14−11
@@ -100,11 +100,14 @@ int perf_mem_events__parse(const char *str) · 99 unmodified lines
100100 return -1;
101101 }
102102
103−static bool perf_mem_event__supported(const char *mnt, char *sysfs_name)
103+static bool perf_mem_event__supported(const char *mnt, struct perf_pmu *pmu,
104+ struct perf_mem_event *e)
104105 {
106+ char sysfs_name[100];
105107 char path[PATH_MAX];
106108 struct stat st;
107109
110+ scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name);
108111 scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name);
109112 return !stat(path, &st);
110113 }
@@ -120,7 +123,6 @@ int perf_mem_events__init(void) · 9 unmodified lines
120123
121124 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
122125 struct perf_mem_event *e = perf_mem_events__ptr(j);
123− char sysfs_name[100];
124126 struct perf_pmu *pmu = NULL;
125127
126128 /*
@@ -136,12 +138,12 @@ int perf_mem_events__init(void) · 9 unmodified lines
136138 * of core PMU.
137139 */
138140 while ((pmu = perf_pmus__scan(pmu)) != NULL) {
139− scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name);
140− e->supported |= perf_mem_event__supported(mnt, sysfs_name);
141+ e->supported |= perf_mem_event__supported(mnt, pmu, e);
142+ if (e->supported) {
143+ found = true;
144+ break;
145+ }
141146 }
142−
143− if (e->supported)
144− found = true;
145147 }
146148
147149 return found ? 0 : -ENOENT;
@@ -167,13 +169,10 @@ static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e, · 19 unmodified lines
167169 int idx)
168170 {
169171 const char *mnt = sysfs__mount();
170− char sysfs_name[100];
171172 struct perf_pmu *pmu = NULL;
172173
173174 while ((pmu = perf_pmus__scan(pmu)) != NULL) {
174− scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name,
175− pmu->name);
176− if (!perf_mem_event__supported(mnt, sysfs_name)) {
175+ if (!perf_mem_event__supported(mnt, pmu, e)) {
177176 pr_err("failed: event '%s' not supported\n",
178177 perf_mem_events__name(idx, pmu->name));
179178 }
@@ -183,6 +182,7 @@ static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e, · 3 unmodified lines
183182 int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
184183 char **rec_tmp, int *tmp_nr)
185184 {
185+ const char *mnt = sysfs__mount();
186186 int i = *argv_nr, k = 0;
187187 struct perf_mem_event *e;
188188
@@ -211,6 +211,9 @@ int perf_mem_events__record_args(const char **rec_argv, int *argv_nr, · 22 unmodified lines
211211 while ((pmu = perf_pmus__scan(pmu)) != NULL) {
212212 const char *s = perf_mem_events__name(j, pmu->name);
213213
214+ if (!perf_mem_event__supported(mnt, pmu, e))
215+ continue;
216+
214217 rec_argv[i++] = "-e";
215218 if (s) {
216219 char *copy = strdup(s);
tools/perf/util/mmap.c+2−3
@@ -295,15 +295,14 @@ int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, struct perf_cpu · 294 unmodified lines
295295
296296 map->core.flush = mp->flush;
297297
298− map->comp_level = mp->comp_level;
299298 #ifndef PYTHON_PERF
300− if (zstd_init(&map->zstd_data, map->comp_level)) {
299+ if (zstd_init(&map->zstd_data, mp->comp_level)) {
301300 pr_debug2("failed to init mmap compressor, error %d\n", errno);
302301 return -1;
303302 }
304303 #endif
305304
306− if (map->comp_level && !perf_mmap__aio_enabled(map)) {
305+ if (mp->comp_level && !perf_mmap__aio_enabled(map)) {
307306 map->data = mmap(NULL, mmap__mmap_len(map), PROT_READ|PROT_WRITE,
308307 MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
309308 if (map->data == MAP_FAILED) {
tools/perf/util/mmap.h+0−1
@@ -39,7 +39,6 @@ struct mmap { · 38 unmodified lines
3939 #endif
4040 struct mmap_cpu_mask affinity_mask;
4141 void *data;
42− int comp_level;
4342 struct perf_data_file *file;
4443 struct zstd_data zstd_data;
4544 };
tools/perf/util/parse-branch-options.c+1−0
@@ -36,6 +36,7 @@ static const struct branch_mode branch_modes[] = { · 35 unmodified lines
3636 BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK),
3737 BRANCH_OPT("hw_index", PERF_SAMPLE_BRANCH_HW_INDEX),
3838 BRANCH_OPT("priv", PERF_SAMPLE_BRANCH_PRIV_SAVE),
39+ BRANCH_OPT("counter", PERF_SAMPLE_BRANCH_COUNTERS),
3940 BRANCH_END
4041 };
4142
tools/perf/util/parse-events.c+38−14
@@ -976,7 +976,7 @@ static int config_term_pmu(struct perf_event_attr *attr, · 975 unmodified lines
976976 struct parse_events_error *err)
977977 {
978978 if (term->type_term == PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE) {
979− const struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
979+ struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
980980
981981 if (!pmu) {
982982 char *err_str;
@@ -986,15 +986,23 @@ static int config_term_pmu(struct perf_event_attr *attr, · 3 unmodified lines
986986 err_str, /*help=*/NULL);
987987 return -EINVAL;
988988 }
989− if (perf_pmu__supports_legacy_cache(pmu)) {
989+ /*
990+ * Rewrite the PMU event to a legacy cache one unless the PMU
991+ * doesn't support legacy cache events or the event is present
992+ * within the PMU.
993+ */
994+ if (perf_pmu__supports_legacy_cache(pmu) &&
995+ !perf_pmu__have_event(pmu, term->config)) {
990996 attr->type = PERF_TYPE_HW_CACHE;
991997 return parse_events__decode_legacy_cache(term->config, pmu->type,
992998 &attr->config);
993− } else
999+ } else {
9941000 term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
1001+ term->no_value = true;
1002+ }
9951003 }
9961004 if (term->type_term == PARSE_EVENTS__TERM_TYPE_HARDWARE) {
997− const struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
1005+ struct perf_pmu *pmu = perf_pmus__find_by_type(attr->type);
9981006
9991007 if (!pmu) {
10001008 char *err_str;
@@ -1004,10 +1012,19 @@ static int config_term_pmu(struct perf_event_attr *attr, · 3 unmodified lines
10041012 err_str, /*help=*/NULL);
10051013 return -EINVAL;
10061014 }
1007− attr->type = PERF_TYPE_HARDWARE;
1008− attr->config = term->val.num;
1009− if (perf_pmus__supports_extended_type())
1010− attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
1015+ /*
1016+ * If the PMU has a sysfs or json event prefer it over
1017+ * legacy. ARM requires this.
1018+ */
1019+ if (perf_pmu__have_event(pmu, term->config)) {
1020+ term->type_term = PARSE_EVENTS__TERM_TYPE_USER;
1021+ term->no_value = true;
1022+ } else {
1023+ attr->type = PERF_TYPE_HARDWARE;
1024+ attr->config = term->val.num;
1025+ if (perf_pmus__supports_extended_type())
1026+ attr->config |= (__u64)pmu->type << PERF_PMU_TYPE_SHIFT;
1027+ }
10111028 return 0;
10121029 }
10131030 if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER ||
@@ -1381,6 +1398,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, · 367 unmodified lines
13811398 YYLTYPE *loc = loc_;
13821399 LIST_HEAD(config_terms);
13831400 struct parse_events_terms parsed_terms;
1401+ bool alias_rewrote_terms = false;
13841402
13851403 pmu = parse_state->fake_pmu ?: perf_pmus__find(name);
13861404
@@ -1433,7 +1451,15 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, · 46 unmodified lines
14331451 return evsel ? 0 : -ENOMEM;
14341452 }
14351453
1436− if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, &parsed_terms, &info, err)) {
1454+ /* Configure attr/terms with a known PMU, this will set hardcoded terms. */
1455+ if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) {
1456+ parse_events_terms__exit(&parsed_terms);
1457+ return -EINVAL;
1458+ }
1459+
1460+ /* Look for event names in the terms and rewrite into format based terms. */
1461+ if (!parse_state->fake_pmu && perf_pmu__check_alias(pmu, &parsed_terms,
1462+ &info, &alias_rewrote_terms, err)) {
14371463 parse_events_terms__exit(&parsed_terms);
14381464 return -EINVAL;
14391465 }
@@ -1447,11 +1473,9 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, · 7 unmodified lines
14471473 strbuf_release(&sb);
14481474 }
14491475
1450− /*
1451− * Configure hardcoded terms first, no need to check
1452− * return value when called with fail == 0 ;)
1453− */
1454− if (config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) {
1476+ /* Configure attr/terms again if an alias was expanded. */
1477+ if (alias_rewrote_terms &&
1478+ config_attr(&attr, &parsed_terms, parse_state->error, config_term_pmu)) {
14551479 parse_events_terms__exit(&parsed_terms);
14561480 return -EINVAL;
14571481 }
tools/perf/util/perf_api_probe.c+2−2
@@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn) · 63 unmodified lines
6464 struct perf_cpu cpu;
6565 int ret, i = 0;
6666
67− cpus = perf_cpu_map__new(NULL);
67+ cpus = perf_cpu_map__new_online_cpus();
6868 if (!cpus)
6969 return false;
7070 cpu = perf_cpu_map__cpu(cpus, 0);
@@ -140,7 +140,7 @@ bool perf_can_record_cpu_wide(void) · 69 unmodified lines
140140 struct perf_cpu cpu;
141141 int fd;
142142
143− cpus = perf_cpu_map__new(NULL);
143+ cpus = perf_cpu_map__new_online_cpus();
144144 if (!cpus)
145145 return false;
146146
tools/perf/util/perf_event_attr_fprintf.c+1−0
@@ -55,6 +55,7 @@ static void __p_branch_sample_type(char *buf, size_t size, u64 value) · 54 unmodified lines
5555 bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP),
5656 bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES),
5757 bit_name(TYPE_SAVE), bit_name(HW_INDEX), bit_name(PRIV_SAVE),
58+ bit_name(COUNTERS),
5859 { .name = NULL, }
5960 };
6061 #undef bit_name
tools/perf/util/pmu.c+6−2
@@ -1494,12 +1494,14 @@ static int check_info_data(struct perf_pmu *pmu, · 1493 unmodified lines
14941494 * defined for the alias
14951495 */
14961496 int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,
1497− struct perf_pmu_info *info, struct parse_events_error *err)
1497+ struct perf_pmu_info *info, bool *rewrote_terms,
1498+ struct parse_events_error *err)
14981499 {
14991500 struct parse_events_term *term, *h;
15001501 struct perf_pmu_alias *alias;
15011502 int ret;
15021503
1504+ *rewrote_terms = false;
15031505 info->per_pkg = false;
15041506
15051507 /*
@@ -1521,7 +1523,7 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_ · 15 unmodified lines
15211523 NULL);
15221524 return ret;
15231525 }
1524−
1526+ *rewrote_terms = true;
15251527 ret = check_info_data(pmu, alias, info, err, term->err_term);
15261528 if (ret)
15271529 return ret;
@@ -1615,6 +1617,8 @@ bool perf_pmu__auto_merge_stats(const struct perf_pmu *pmu) · 87 unmodified lines
16151617
16161618 bool perf_pmu__have_event(struct perf_pmu *pmu, const char *name)
16171619 {
1620+ if (!name)
1621+ return false;
16181622 if (perf_pmu__find_alias(pmu, name, /*load=*/ true) != NULL)
16191623 return true;
16201624 if (pmu->cpu_aliases_added || !pmu->events_table)
tools/perf/util/pmu.h+2−1
@@ -201,7 +201,8 @@ int perf_pmu__config_terms(const struct perf_pmu *pmu, · 200 unmodified lines
201201 __u64 perf_pmu__format_bits(struct perf_pmu *pmu, const char *name);
202202 int perf_pmu__format_type(struct perf_pmu *pmu, const char *name);
203203 int perf_pmu__check_alias(struct perf_pmu *pmu, struct parse_events_terms *head_terms,
204− struct perf_pmu_info *info, struct parse_events_error *err);
204+ struct perf_pmu_info *info, bool *rewrote_terms,
205+ struct parse_events_error *err);
205206 int perf_pmu__find_event(struct perf_pmu *pmu, const char *event, void *state, pmu_event_callback cb);
206207
207208 int perf_pmu__format_parse(struct perf_pmu *pmu, int dirfd, bool eager_load);
tools/perf/util/probe-event.c+26−14
@@ -149,10 +149,32 @@ static int kernel_get_symbol_address_by_name(const char *name, u64 *addr, · 148 unmodified lines
149149 return 0;
150150 }
151151
152+struct kernel_get_module_map_cb_args {
153+ const char *module;
154+ struct map *result;
155+};
156+
157+static int kernel_get_module_map_cb(struct map *map, void *data)
158+{
159+ struct kernel_get_module_map_cb_args *args = data;
160+ struct dso *dso = map__dso(map);
161+ const char *short_name = dso->short_name; /* short_name is "[module]" */
162+ u16 short_name_len = dso->short_name_len;
163+
164+ if (strncmp(short_name + 1, args->module, short_name_len - 2) == 0 &&
165+ args->module[short_name_len - 2] == '\0') {
166+ args->result = map__get(map);
167+ return 1;
168+ }
169+ return 0;
170+}
171+
152172 static struct map *kernel_get_module_map(const char *module)
153173 {
154− struct maps *maps = machine__kernel_maps(host_machine);
155− struct map_rb_node *pos;
174+ struct kernel_get_module_map_cb_args args = {
175+ .module = module,
176+ .result = NULL,
177+ };
156178
157179 /* A file path -- this is an offline module */
158180 if (module && strchr(module, '/'))
@@ -164,19 +186,9 @@ static struct map *kernel_get_module_map(const char *module) · 5 unmodified lines
164186 return map__get(map);
165187 }
166188
167− maps__for_each_entry(maps, pos) {
168− /* short_name is "[module]" */
169− struct dso *dso = map__dso(pos->map);
170− const char *short_name = dso->short_name;
171− u16 short_name_len = dso->short_name_len;
189+ maps__for_each_map(machine__kernel_maps(host_machine), kernel_get_module_map_cb, &args);
172190
173− if (strncmp(short_name + 1, module,
174− short_name_len - 2) == 0 &&
175− module[short_name_len - 2] == '\0') {
176− return map__get(pos->map);
177− }
178− }
179− return NULL;
191+ return args.result;
180192 }
181193
182194 struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)
tools/perf/util/probe-finder.c+5−196
@@ -23,6 +23,7 @@ · 22 unmodified lines
2323 #include "event.h"
2424 #include "dso.h"
2525 #include "debug.h"
26+#include "debuginfo.h"
2627 #include "intlist.h"
2728 #include "strbuf.h"
2829 #include "strlist.h"
@@ -31,128 +32,9 @@ · 2 unmodified lines
3132 #include "probe-file.h"
3233 #include "string2.h"
3334
34−#ifdef HAVE_DEBUGINFOD_SUPPORT
35−#include <elfutils/debuginfod.h>
36−#endif
37−
3835 /* Kprobe tracer basic type is up to u64 */
3936 #define MAX_BASIC_TYPE_BITS 64
4037
41−/* Dwarf FL wrappers */
42−static char *debuginfo_path; /* Currently dummy */
43−
44−static const Dwfl_Callbacks offline_callbacks = {
45− .find_debuginfo = dwfl_standard_find_debuginfo,
46− .debuginfo_path = &debuginfo_path,
47−
48− .section_address = dwfl_offline_section_address,
49−
50− /* We use this table for core files too. */
51− .find_elf = dwfl_build_id_find_elf,
52−};
53−
54−/* Get a Dwarf from offline image */
55−static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
56− const char *path)
57−{
58− GElf_Addr dummy;
59− int fd;
60−
61− fd = open(path, O_RDONLY);
62− if (fd < 0)
63− return fd;
64−
65− dbg->dwfl = dwfl_begin(&offline_callbacks);
66− if (!dbg->dwfl)
67− goto error;
68−
69− dwfl_report_begin(dbg->dwfl);
70− dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd);
71− if (!dbg->mod)
72− goto error;
73−
74− dbg->dbg = dwfl_module_getdwarf(dbg->mod, &dbg->bias);
75− if (!dbg->dbg)
76− goto error;
77−
78− dwfl_module_build_id(dbg->mod, &dbg->build_id, &dummy);
79−
80− dwfl_report_end(dbg->dwfl, NULL, NULL);
81−
82− return 0;
83−error:
84− if (dbg->dwfl)
85− dwfl_end(dbg->dwfl);
86− else
87− close(fd);
88− memset(dbg, 0, sizeof(*dbg));
89−
90− return -ENOENT;
91−}
92−
93−static struct debuginfo *__debuginfo__new(const char *path)
94−{
95− struct debuginfo *dbg = zalloc(sizeof(*dbg));
96− if (!dbg)
97− return NULL;
98−
99− if (debuginfo__init_offline_dwarf(dbg, path) < 0)
100− zfree(&dbg);
101− if (dbg)
102− pr_debug("Open Debuginfo file: %s\n", path);
103− return dbg;
104−}
105−
106−enum dso_binary_type distro_dwarf_types[] = {
107− DSO_BINARY_TYPE__FEDORA_DEBUGINFO,
108− DSO_BINARY_TYPE__UBUNTU_DEBUGINFO,
109− DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
110− DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
111− DSO_BINARY_TYPE__MIXEDUP_UBUNTU_DEBUGINFO,
112− DSO_BINARY_TYPE__NOT_FOUND,
113−};
114−
115−struct debuginfo *debuginfo__new(const char *path)
116−{
117− enum dso_binary_type *type;
118− char buf[PATH_MAX], nil = '\0';
119− struct dso *dso;
120− struct debuginfo *dinfo = NULL;
121− struct build_id bid;
122−
123− /* Try to open distro debuginfo files */
124− dso = dso__new(path);
125− if (!dso)
126− goto out;
127−
128− /* Set the build id for DSO_BINARY_TYPE__BUILDID_DEBUGINFO */
129− if (is_regular_file(path) && filename__read_build_id(path, &bid) > 0)
130− dso__set_build_id(dso, &bid);
131−
132− for (type = distro_dwarf_types;
133− !dinfo && *type != DSO_BINARY_TYPE__NOT_FOUND;
134− type++) {
135− if (dso__read_binary_type_filename(dso, *type, &nil,
136− buf, PATH_MAX) < 0)
137− continue;
138− dinfo = __debuginfo__new(buf);
139− }
140− dso__put(dso);
141−
142−out:
143− /* if failed to open all distro debuginfo, open given binary */
144− return dinfo ? : __debuginfo__new(path);
145−}
146−
147−void debuginfo__delete(struct debuginfo *dbg)
148−{
149− if (dbg) {
150− if (dbg->dwfl)
151− dwfl_end(dbg->dwfl);
152− free(dbg);
153− }
154−}
155−
15638 /*
15739 * Probe finder related functions
15840 */
@@ -722,7 +604,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) · 563 unmodified lines
722604 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
723605 if (ret <= 0 || nops == 0) {
724606 pf->fb_ops = NULL;
725−#if _ELFUTILS_PREREQ(0, 142)
607+#ifdef HAVE_DWARF_CFI_SUPPORT
726608 } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
727609 (pf->cfi_eh != NULL || pf->cfi_dbg != NULL)) {
728610 if ((dwarf_cfi_addrframe(pf->cfi_eh, pf->addr, &frame) != 0 &&
@@ -733,7 +615,7 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) · 4 unmodified lines
733615 free(frame);
734616 return -ENOENT;
735617 }
736−#endif
618+#endif /* HAVE_DWARF_CFI_SUPPORT */
737619 }
738620
739621 /* Call finder's callback handler */
@@ -1258,7 +1140,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg, · 518 unmodified lines
12581140
12591141 pf->machine = ehdr.e_machine;
12601142
1261−#if _ELFUTILS_PREREQ(0, 142)
1143+#ifdef HAVE_DWARF_CFI_SUPPORT
12621144 do {
12631145 GElf_Shdr shdr;
12641146
@@ -1268,7 +1150,7 @@ static int debuginfo__find_probes(struct debuginfo *dbg, · 3 unmodified lines
12681150
12691151 pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
12701152 } while (0);
1271−#endif
1153+#endif /* HAVE_DWARF_CFI_SUPPORT */
12721154
12731155 ret = debuginfo__find_probe_location(dbg, pf);
12741156 return ret;
@@ -1677,44 +1559,6 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, · 402 unmodified lines
16771559 return (ret < 0) ? ret : af.nvls;
16781560 }
16791561
1680−/* For the kernel module, we need a special code to get a DIE */
1681−int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
1682− bool adjust_offset)
1683−{
1684− int n, i;
1685− Elf32_Word shndx;
1686− Elf_Scn *scn;
1687− Elf *elf;
1688− GElf_Shdr mem, *shdr;
1689− const char *p;
1690−
1691− elf = dwfl_module_getelf(dbg->mod, &dbg->bias);
1692− if (!elf)
1693− return -EINVAL;
1694−
1695− /* Get the number of relocations */
1696− n = dwfl_module_relocations(dbg->mod);
1697− if (n < 0)
1698− return -ENOENT;
1699− /* Search the relocation related .text section */
1700− for (i = 0; i < n; i++) {
1701− p = dwfl_module_relocation_info(dbg->mod, i, &shndx);
1702− if (strcmp(p, ".text") == 0) {
1703− /* OK, get the section header */
1704− scn = elf_getscn(elf, shndx);
1705− if (!scn)
1706− return -ENOENT;
1707− shdr = gelf_getshdr(scn, &mem);
1708− if (!shdr)
1709− return -ENOENT;
1710− *offs = shdr->sh_addr;
1711− if (adjust_offset)
1712− *offs -= shdr->sh_offset;
1713− }
1714− }
1715− return 0;
1716−}
1717−
17181562 /* Reverse search */
17191563 int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
17201564 struct perf_probe_point *ppt)
@@ -2009,41 +1853,6 @@ found: · 288 unmodified lines
20091853 return (ret < 0) ? ret : lf.found;
20101854 }
20111855
2012−#ifdef HAVE_DEBUGINFOD_SUPPORT
2013−/* debuginfod doesn't require the comp_dir but buildid is required */
2014−static int get_source_from_debuginfod(const char *raw_path,
2015− const char *sbuild_id, char **new_path)
2016−{
2017− debuginfod_client *c = debuginfod_begin();
2018− const char *p = raw_path;
2019− int fd;
2020−
2021− if (!c)
2022− return -ENOMEM;
2023−
2024− fd = debuginfod_find_source(c, (const unsigned char *)sbuild_id,
2025− 0, p, new_path);
2026− pr_debug("Search %s from debuginfod -> %d\n", p, fd);
2027− if (fd >= 0)
2028− close(fd);
2029− debuginfod_end(c);
2030− if (fd < 0) {
2031− pr_debug("Failed to find %s in debuginfod (%s)\n",
2032− raw_path, sbuild_id);
2033− return -ENOENT;
2034− }
2035− pr_debug("Got a source %s\n", *new_path);
2036−
2037− return 0;
2038−}
2039−#else
2040−static inline int get_source_from_debuginfod(const char *raw_path __maybe_unused,
2041− const char *sbuild_id __maybe_unused,
2042− char **new_path __maybe_unused)
2043−{
2044− return -ENOTSUP;
2045−}
2046−#endif
20471856 /*
20481857 * Find a src file from a DWARF tag path. Prepend optional source path prefix
20491858 * and chop off leading directories that do not exist. Result is passed back as
tools/perf/util/probe-finder.h+1−18
@@ -24,21 +24,7 @@ static inline int is_c_varname(const char *name) · 23 unmodified lines
2424 #ifdef HAVE_DWARF_SUPPORT
2525
2626 #include "dwarf-aux.h"
27−
28−/* TODO: export debuginfo data structure even if no dwarf support */
29−
30−/* debug information structure */
31−struct debuginfo {
32− Dwarf *dbg;
33− Dwfl_Module *mod;
34− Dwfl *dwfl;
35− Dwarf_Addr bias;
36− const unsigned char *build_id;
37−};
38−
39−/* This also tries to open distro debuginfo */
40−struct debuginfo *debuginfo__new(const char *path);
41−void debuginfo__delete(struct debuginfo *dbg);
27+#include "debuginfo.h"
4228
4329 /* Find probe_trace_events specified by perf_probe_event from debuginfo */
4430 int debuginfo__find_trace_events(struct debuginfo *dbg,
@@ -49,9 +35,6 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, · 4 unmodified lines
4935 int debuginfo__find_probe_point(struct debuginfo *dbg, u64 addr,
5036 struct perf_probe_point *ppt);
5137
52−int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
53− bool adjust_offset);
54−
5538 /* Find a line range */
5639 int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr);
5740
tools/perf/util/record.c+2−2
@@ -237,8 +237,8 @@ bool evlist__can_select_event(struct evlist *evlist, const char *str) · 236 unmodified lines
237237
238238 evsel = evlist__last(temp_evlist);
239239
240− if (!evlist || perf_cpu_map__empty(evlist->core.user_requested_cpus)) {
241− struct perf_cpu_map *cpus = perf_cpu_map__new(NULL);
240+ if (!evlist || perf_cpu_map__has_any_cpu_or_is_empty(evlist->core.user_requested_cpus)) {
241+ struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus();
242242
243243 if (cpus)
244244 cpu = perf_cpu_map__cpu(cpus, 0);
tools/perf/util/s390-cpumcf-kernel.h+2−0
@@ -12,6 +12,8 @@ · 11 unmodified lines
1212 #define S390_CPUMCF_DIAG_DEF 0xfeef /* Counter diagnostic entry ID */
1313 #define PERF_EVENT_CPUM_CF_DIAG 0xBC000 /* Event: Counter sets */
1414 #define PERF_EVENT_CPUM_SF_DIAG 0xBD000 /* Event: Combined-sampling */
15+#define PERF_EVENT_PAI_CRYPTO_ALL 0x1000 /* Event: CRYPTO_ALL */
16+#define PERF_EVENT_PAI_NNPA_ALL 0x1800 /* Event: NNPA_ALL */
1517
1618 struct cf_ctrset_entry { /* CPU-M CF counter set entry (8 byte) */
1719 unsigned int def:16; /* 0-15 Data Entry Format */
tools/perf/util/s390-sample-raw.c+104−10
@@ -51,8 +51,6 @@ static bool s390_cpumcfdg_testctr(struct perf_sample *sample) · 50 unmodified lines
5151 struct cf_trailer_entry *te;
5252 struct cf_ctrset_entry *cep, ce;
5353
54− if (!len)
55− return false;
5654 while (offset < len) {
5755 cep = (struct cf_ctrset_entry *)(buf + offset);
5856 ce.def = be16_to_cpu(cep->def);
@@ -125,6 +123,9 @@ static int get_counterset_start(int setnr) · 66 unmodified lines
125123 return 128;
126124 case CPUMF_CTR_SET_MT_DIAG: /* Diagnostic counter set */
127125 return 448;
126+ case PERF_EVENT_PAI_NNPA_ALL: /* PAI NNPA counter set */
127+ case PERF_EVENT_PAI_CRYPTO_ALL: /* PAI CRYPTO counter set */
128+ return setnr;
128129 default:
129130 return -1;
130131 }
@@ -212,27 +213,120 @@ static void s390_cpumcfdg_dump(struct perf_pmu *pmu, struct perf_sample *sample) · 81 unmodified lines
212213 }
213214 }
214215
216+#pragma GCC diagnostic push
217+#pragma GCC diagnostic ignored "-Wpacked"
218+#pragma GCC diagnostic ignored "-Wattributes"
219+/*
220+ * Check for consistency of PAI_CRYPTO/PAI_NNPA raw data.
221+ */
222+struct pai_data { /* Event number and value */
223+ u16 event_nr;
224+ u64 event_val;
225+} __packed;
226+
227+#pragma GCC diagnostic pop
228+
229+/*
230+ * Test for valid raw data. At least one PAI event should be in the raw
231+ * data section.
232+ */
233+static bool s390_pai_all_test(struct perf_sample *sample)
234+{
235+ size_t len = sample->raw_size;
236+
237+ if (len < 0xa)
238+ return false;
239+ return true;
240+}
241+
242+static void s390_pai_all_dump(struct evsel *evsel, struct perf_sample *sample)
243+{
244+ size_t len = sample->raw_size, offset = 0;
245+ unsigned char *p = sample->raw_data;
246+ const char *color = PERF_COLOR_BLUE;
247+ struct pai_data pai_data;
248+ char *ev_name;
249+
250+ while (offset < len) {
251+ memcpy(&pai_data.event_nr, p, sizeof(pai_data.event_nr));
252+ pai_data.event_nr = be16_to_cpu(pai_data.event_nr);
253+ p += sizeof(pai_data.event_nr);
254+ offset += sizeof(pai_data.event_nr);
255+
256+ memcpy(&pai_data.event_val, p, sizeof(pai_data.event_val));
257+ pai_data.event_val = be64_to_cpu(pai_data.event_val);
258+ p += sizeof(pai_data.event_val);
259+ offset += sizeof(pai_data.event_val);
260+
261+ ev_name = get_counter_name(evsel->core.attr.config,
262+ pai_data.event_nr, evsel->pmu);
263+ color_fprintf(stdout, color, "\tCounter:%03d %s Value:%#018lx\n",
264+ pai_data.event_nr, ev_name ?: "<unknown>",
265+ pai_data.event_val);
266+ free(ev_name);
267+
268+ if (offset + 0xa > len)
269+ break;
270+ }
271+ color_fprintf(stdout, color, "\n");
272+}
273+
215274 /* S390 specific trace event function. Check for PERF_RECORD_SAMPLE events
216− * and if the event was triggered by a counter set diagnostic event display
217− * its raw data.
275+ * and if the event was triggered by a
276+ * - counter set diagnostic event
277+ * - processor activity assist (PAI) crypto counter event
278+ * - processor activity assist (PAI) neural network processor assist (NNPA)
279+ * counter event
280+ * display its raw data.
218281 * The function is only invoked when the dump flag -D is set.
282+ *
283+ * Function evlist__s390_sample_raw() is defined as call back after it has
284+ * been verified that the perf.data file was created on s390 platform.
219285 */
220−void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample)
286+void evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event,
287+ struct perf_sample *sample)
221288 {
289+ const char *pai_name;
222290 struct evsel *evsel;
223291
224292 if (event->header.type != PERF_RECORD_SAMPLE)
225293 return;
226294
227295 evsel = evlist__event2evsel(evlist, event);
228− if (evsel == NULL ||
229− evsel->core.attr.config != PERF_EVENT_CPUM_CF_DIAG)
296+ if (!evsel)
297+ return;
298+
299+ /* Check for raw data in sample */
300+ if (!sample->raw_size || !sample->raw_data)
230301 return;
231302
232303 /* Display raw data on screen */
233− if (!s390_cpumcfdg_testctr(sample)) {
234− pr_err("Invalid counter set data encountered\n");
304+ if (evsel->core.attr.config == PERF_EVENT_CPUM_CF_DIAG) {
305+ if (!evsel->pmu)
306+ evsel->pmu = perf_pmus__find("cpum_cf");
307+ if (!s390_cpumcfdg_testctr(sample))
308+ pr_err("Invalid counter set data encountered\n");
309+ else
310+ s390_cpumcfdg_dump(evsel->pmu, sample);
311+ return;
312+ }
313+
314+ switch (evsel->core.attr.config) {
315+ case PERF_EVENT_PAI_NNPA_ALL:
316+ pai_name = "NNPA_ALL";
317+ break;
318+ case PERF_EVENT_PAI_CRYPTO_ALL:
319+ pai_name = "CRYPTO_ALL";
320+ break;
321+ default:
235322 return;
236323 }
237− s390_cpumcfdg_dump(evsel->pmu, sample);
324+
325+ if (!s390_pai_all_test(sample)) {
326+ pr_err("Invalid %s raw data encountered\n", pai_name);
327+ } else {
328+ if (!evsel->pmu)
329+ evsel->pmu = perf_pmus__find_by_type(evsel->core.attr.type);
330+ s390_pai_all_dump(evsel, sample);
331+ }
238332 }
tools/perf/util/sample.h+1−0
@@ -113,6 +113,7 @@ struct perf_sample { · 112 unmodified lines
113113 void *raw_data;
114114 struct ip_callchain *callchain;
115115 struct branch_stack *branch_stack;
116+ u64 *branch_stack_cntr;
116117 struct regs_dump user_regs;
117118 struct regs_dump intr_regs;
118119 struct stack_dump user_stack;
tools/perf/util/scripting-engines/trace-event-perl.c+3−0
@@ -490,6 +490,9 @@ static int perl_start_script(const char *script, int argc, const char **argv, · 489 unmodified lines
490490 scripting_context->session = session;
491491
492492 command_line = malloc((argc + 2) * sizeof(const char *));
493+ if (!command_line)
494+ return -ENOMEM;
495+
493496 command_line[0] = "";
494497 command_line[1] = script;
495498 for (i = 2; i < argc + 2; i++)
tools/perf/util/scripting-engines/trace-event-python.c+15−2
@@ -353,6 +353,8 @@ static PyObject *get_field_numeric_entry(struct tep_event *event, · 352 unmodified lines
353353
354354 if (is_array) {
355355 list = PyList_New(field->arraylen);
356+ if (!list)
357+ Py_FatalError("couldn't create Python list");
356358 item_size = field->size / field->arraylen;
357359 n_items = field->arraylen;
358360 } else {
@@ -754,7 +756,7 @@ static void regs_map(struct regs_dump *regs, uint64_t mask, const char *arch, ch · 395 unmodified lines
754756 }
755757 }
756758
757−static void set_regs_in_dict(PyObject *dict,
759+static int set_regs_in_dict(PyObject *dict,
758760 struct perf_sample *sample,
759761 struct evsel *evsel)
760762 {
@@ -770,6 +772,8 @@ static void set_regs_in_dict(PyObject *dict, · 9 unmodified lines
770772 */
771773 int size = __sw_hweight64(attr->sample_regs_intr) * 28;
772774 char *bf = malloc(size);
775+ if (!bf)
776+ return -1;
773777
774778 regs_map(&sample->intr_regs, attr->sample_regs_intr, arch, bf, size);
775779
@@ -781,6 +785,8 @@ static void set_regs_in_dict(PyObject *dict, · 5 unmodified lines
781785 pydict_set_item_string_decref(dict, "uregs",
782786 _PyUnicode_FromString(bf));
783787 free(bf);
788+
789+ return 0;
784790 }
785791
786792 static void set_sym_in_dict(PyObject *dict, struct addr_location *al,
@@ -920,7 +926,8 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, · 133 unmodified lines
920926 PyLong_FromUnsignedLongLong(sample->cyc_cnt));
921927 }
922928
923− set_regs_in_dict(dict, sample, evsel);
929+ if (set_regs_in_dict(dict, sample, evsel))
930+ Py_FatalError("Failed to setting regs in dict");
924931
925932 return dict;
926933 }
@@ -1918,12 +1925,18 @@ static int python_start_script(const char *script, int argc, const char **argv, · 991 unmodified lines
19181925 scripting_context->session = session;
19191926 #if PY_MAJOR_VERSION < 3
19201927 command_line = malloc((argc + 1) * sizeof(const char *));
1928+ if (!command_line)
1929+ return -1;
1930+
19211931 command_line[0] = script;
19221932 for (i = 1; i < argc + 1; i++)
19231933 command_line[i] = argv[i - 1];
19241934 PyImport_AppendInittab(name, initperf_trace_context);
19251935 #else
19261936 command_line = malloc((argc + 1) * sizeof(wchar_t *));
1937+ if (!command_line)
1938+ return -1;
1939+
19271940 command_line[0] = Py_DecodeLocale(script, NULL);
19281941 for (i = 1; i < argc + 1; i++)
19291942 command_line[i] = Py_DecodeLocale(argv[i - 1], NULL);
tools/perf/util/session.c+18−2
@@ -115,6 +115,11 @@ static int perf_session__open(struct perf_session *session, int repipe_fd) · 114 unmodified lines
115115 return -1;
116116 }
117117
118+ if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) {
119+ /* Auxiliary events may reference exited threads, hold onto dead ones. */
120+ symbol_conf.keep_exited_threads = true;
121+ }
122+
118123 if (perf_data__is_pipe(data))
119124 return 0;
120125
@@ -1150,9 +1155,13 @@ static void callchain__printf(struct evsel *evsel, · 1029 unmodified lines
11501155 i, callchain->ips[i]);
11511156 }
11521157
1153−static void branch_stack__printf(struct perf_sample *sample, bool callstack)
1158+static void branch_stack__printf(struct perf_sample *sample,
1159+ struct evsel *evsel)
11541160 {
11551161 struct branch_entry *entries = perf_sample__branch_entries(sample);
1162+ bool callstack = evsel__has_branch_callstack(evsel);
1163+ u64 *branch_stack_cntr = sample->branch_stack_cntr;
1164+ struct perf_env *env = evsel__env(evsel);
11561165 uint64_t i;
11571166
11581167 if (!callstack) {
@@ -1194,6 +1203,13 @@ static void branch_stack__printf(struct perf_sample *sample, bool callstack) · 35 unmodified lines
11941203 }
11951204 }
11961205 }
1206+
1207+ if (branch_stack_cntr) {
1208+ printf("... branch stack counters: nr:%" PRIu64 " (counter width: %u max counter nr:%u)\n",
1209+ sample->branch_stack->nr, env->br_cntr_width, env->br_cntr_nr);
1210+ for (i = 0; i < sample->branch_stack->nr; i++)
1211+ printf("..... %2"PRIu64": %016" PRIx64 "\n", i, branch_stack_cntr[i]);
1212+ }
11971213 }
11981214
11991215 static void regs_dump__printf(u64 mask, u64 *regs, const char *arch)
@@ -1355,7 +1371,7 @@ static void dump_sample(struct evsel *evsel, union perf_event *event, · 155 unmodified lines
13551371 callchain__printf(evsel, sample);
13561372
13571373 if (evsel__has_br_stack(evsel))
1358− branch_stack__printf(sample, evsel__has_branch_callstack(evsel));
1374+ branch_stack__printf(sample, evsel);
13591375
13601376 if (sample_type & PERF_SAMPLE_REGS_USER)
13611377 regs_user__printf(sample, arch);
tools/perf/util/sort.c+207−9
@@ -24,6 +24,7 @@ · 23 unmodified lines
2424 #include "strbuf.h"
2525 #include "mem-events.h"
2626 #include "annotate.h"
27+#include "annotate-data.h"
2728 #include "event.h"
2829 #include "time-utils.h"
2930 #include "cgroup.h"
@@ -418,6 +419,52 @@ struct sort_entry sort_sym = { · 388 unmodified lines
418419 .se_width_idx = HISTC_SYMBOL,
419420 };
420421
422+/* --sort symoff */
423+
424+static int64_t
425+sort__symoff_cmp(struct hist_entry *left, struct hist_entry *right)
426+{
427+ int64_t ret;
428+
429+ ret = sort__sym_cmp(left, right);
430+ if (ret)
431+ return ret;
432+
433+ return left->ip - right->ip;
434+}
435+
436+static int64_t
437+sort__symoff_sort(struct hist_entry *left, struct hist_entry *right)
438+{
439+ int64_t ret;
440+
441+ ret = sort__sym_sort(left, right);
442+ if (ret)
443+ return ret;
444+
445+ return left->ip - right->ip;
446+}
447+
448+static int
449+hist_entry__symoff_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width)
450+{
451+ struct symbol *sym = he->ms.sym;
452+
453+ if (sym == NULL)
454+ return repsep_snprintf(bf, size, "[%c] %-#.*llx", he->level, width - 4, he->ip);
455+
456+ return repsep_snprintf(bf, size, "[%c] %s+0x%llx", he->level, sym->name, he->ip - sym->start);
457+}
458+
459+struct sort_entry sort_sym_offset = {
460+ .se_header = "Symbol Offset",
461+ .se_cmp = sort__symoff_cmp,
462+ .se_sort = sort__symoff_sort,
463+ .se_snprintf = hist_entry__symoff_snprintf,
464+ .se_filter = hist_entry__sym_filter,
465+ .se_width_idx = HISTC_SYMBOL_OFFSET,
466+};
467+
421468 /* --sort srcline */
422469
423470 char *hist_entry__srcline(struct hist_entry *he)
@@ -583,21 +630,21 @@ static int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf, · 159 unmodified lines
583630 {
584631
585632 struct symbol *sym = he->ms.sym;
586− struct annotation *notes;
633+ struct annotated_branch *branch;
587634 double ipc = 0.0, coverage = 0.0;
588635 char tmp[64];
589636
590637 if (!sym)
591638 return repsep_snprintf(bf, size, "%-*s", width, "-");
592639
593− notes = symbol__annotation(sym);
640+ branch = symbol__annotation(sym)->branch;
594641
595− if (notes->hit_cycles)
596− ipc = notes->hit_insn / ((double)notes->hit_cycles);
642+ if (branch && branch->hit_cycles)
643+ ipc = branch->hit_insn / ((double)branch->hit_cycles);
597644
598− if (notes->total_insn) {
599− coverage = notes->cover_insn * 100.0 /
600− ((double)notes->total_insn);
645+ if (branch && branch->total_insn) {
646+ coverage = branch->cover_insn * 100.0 /
647+ ((double)branch->total_insn);
601648 }
602649
603650 snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage);
@@ -2094,7 +2141,7 @@ struct sort_entry sort_dso_size = { · 1490 unmodified lines
20942141 .se_width_idx = HISTC_DSO_SIZE,
20952142 };
20962143
2097−/* --sort dso_size */
2144+/* --sort addr */
20982145
20992146 static int64_t
21002147 sort__addr_cmp(struct hist_entry *left, struct hist_entry *right)
@@ -2131,6 +2178,152 @@ struct sort_entry sort_addr = { · 30 unmodified lines
21312178 .se_width_idx = HISTC_ADDR,
21322179 };
21332180
2181+/* --sort type */
2182+
2183+struct annotated_data_type unknown_type = {
2184+ .self = {
2185+ .type_name = (char *)"(unknown)",
2186+ .children = LIST_HEAD_INIT(unknown_type.self.children),
2187+ },
2188+};
2189+
2190+static int64_t
2191+sort__type_cmp(struct hist_entry *left, struct hist_entry *right)
2192+{
2193+ return sort__addr_cmp(left, right);
2194+}
2195+
2196+static void sort__type_init(struct hist_entry *he)
2197+{
2198+ if (he->mem_type)
2199+ return;
2200+
2201+ he->mem_type = hist_entry__get_data_type(he);
2202+ if (he->mem_type == NULL) {
2203+ he->mem_type = &unknown_type;
2204+ he->mem_type_off = 0;
2205+ }
2206+}
2207+
2208+static int64_t
2209+sort__type_collapse(struct hist_entry *left, struct hist_entry *right)
2210+{
2211+ struct annotated_data_type *left_type = left->mem_type;
2212+ struct annotated_data_type *right_type = right->mem_type;
2213+
2214+ if (!left_type) {
2215+ sort__type_init(left);
2216+ left_type = left->mem_type;
2217+ }
2218+
2219+ if (!right_type) {
2220+ sort__type_init(right);
2221+ right_type = right->mem_type;
2222+ }
2223+
2224+ return strcmp(left_type->self.type_name, right_type->self.type_name);
2225+}
2226+
2227+static int64_t
2228+sort__type_sort(struct hist_entry *left, struct hist_entry *right)
2229+{
2230+ return sort__type_collapse(left, right);
2231+}
2232+
2233+static int hist_entry__type_snprintf(struct hist_entry *he, char *bf,
2234+ size_t size, unsigned int width)
2235+{
2236+ return repsep_snprintf(bf, size, "%-*s", width, he->mem_type->self.type_name);
2237+}
2238+
2239+struct sort_entry sort_type = {
2240+ .se_header = "Data Type",
2241+ .se_cmp = sort__type_cmp,
2242+ .se_collapse = sort__type_collapse,
2243+ .se_sort = sort__type_sort,
2244+ .se_init = sort__type_init,
2245+ .se_snprintf = hist_entry__type_snprintf,
2246+ .se_width_idx = HISTC_TYPE,
2247+};
2248+
2249+/* --sort typeoff */
2250+
2251+static int64_t
2252+sort__typeoff_sort(struct hist_entry *left, struct hist_entry *right)
2253+{
2254+ struct annotated_data_type *left_type = left->mem_type;
2255+ struct annotated_data_type *right_type = right->mem_type;
2256+ int64_t ret;
2257+
2258+ if (!left_type) {
2259+ sort__type_init(left);
2260+ left_type = left->mem_type;
2261+ }
2262+
2263+ if (!right_type) {
2264+ sort__type_init(right);
2265+ right_type = right->mem_type;
2266+ }
2267+
2268+ ret = strcmp(left_type->self.type_name, right_type->self.type_name);
2269+ if (ret)
2270+ return ret;
2271+ return left->mem_type_off - right->mem_type_off;
2272+}
2273+
2274+static void fill_member_name(char *buf, size_t sz, struct annotated_member *m,
2275+ int offset, bool first)
2276+{
2277+ struct annotated_member *child;
2278+
2279+ if (list_empty(&m->children))
2280+ return;
2281+
2282+ list_for_each_entry(child, &m->children, node) {
2283+ if (child->offset <= offset && offset < child->offset + child->size) {
2284+ int len = 0;
2285+
2286+ /* It can have anonymous struct/union members */
2287+ if (child->var_name) {
2288+ len = scnprintf(buf, sz, "%s%s",
2289+ first ? "" : ".", child->var_name);
2290+ first = false;
2291+ }
2292+
2293+ fill_member_name(buf + len, sz - len, child, offset, first);
2294+ return;
2295+ }
2296+ }
2297+}
2298+
2299+static int hist_entry__typeoff_snprintf(struct hist_entry *he, char *bf,
2300+ size_t size, unsigned int width __maybe_unused)
2301+{
2302+ struct annotated_data_type *he_type = he->mem_type;
2303+ char buf[4096];
2304+
2305+ buf[0] = '\0';
2306+ if (list_empty(&he_type->self.children))
2307+ snprintf(buf, sizeof(buf), "no field");
2308+ else
2309+ fill_member_name(buf, sizeof(buf), &he_type->self,
2310+ he->mem_type_off, true);
2311+ buf[4095] = '\0';
2312+
2313+ return repsep_snprintf(bf, size, "%s %+d (%s)", he_type->self.type_name,
2314+ he->mem_type_off, buf);
2315+}
2316+
2317+struct sort_entry sort_type_offset = {
2318+ .se_header = "Data Type Offset",
2319+ .se_cmp = sort__type_cmp,
2320+ .se_collapse = sort__typeoff_sort,
2321+ .se_sort = sort__typeoff_sort,
2322+ .se_init = sort__type_init,
2323+ .se_snprintf = hist_entry__typeoff_snprintf,
2324+ .se_width_idx = HISTC_TYPE_OFFSET,
2325+};
2326+
21342327
21352328 struct sort_dimension {
21362329 const char *name;
@@ -2185,7 +2378,10 @@ static struct sort_dimension common_sort_dimensions[] = { · 48 unmodified lines
21852378 DIM(SORT_ADDR, "addr", sort_addr),
21862379 DIM(SORT_LOCAL_RETIRE_LAT, "local_retire_lat", sort_local_p_stage_cyc),
21872380 DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc),
2188− DIM(SORT_SIMD, "simd", sort_simd)
2381+ DIM(SORT_SIMD, "simd", sort_simd),
2382+ DIM(SORT_ANNOTATE_DATA_TYPE, "type", sort_type),
2383+ DIM(SORT_ANNOTATE_DATA_TYPE_OFFSET, "typeoff", sort_type_offset),
2384+ DIM(SORT_SYM_OFFSET, "symoff", sort_sym_offset),
21892385 };
21902386
21912387 #undef DIM
@@ -3205,6 +3401,8 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok, · 1013 unmodified lines
32053401 list->thread = 1;
32063402 } else if (sd->entry == &sort_comm) {
32073403 list->comm = 1;
3404+ } else if (sd->entry == &sort_type_offset) {
3405+ symbol_conf.annotate_data_member = true;
32083406 }
32093407
32103408 return __sort_dimension__add(sd, list, level);
tools/perf/util/sort.h+7−0
@@ -15,6 +15,7 @@ · 14 unmodified lines
1515
1616 struct option;
1717 struct thread;
18+struct annotated_data_type;
1819
1920 extern regex_t parent_regex;
2021 extern const char *sort_order;
@@ -34,6 +35,7 @@ extern struct sort_entry sort_dso_to; · 13 unmodified lines
3435 extern struct sort_entry sort_sym_from;
3536 extern struct sort_entry sort_sym_to;
3637 extern struct sort_entry sort_srcline;
38+extern struct sort_entry sort_type;
3739 extern const char default_mem_sort_order[];
3840 extern bool chk_double_cl;
3941
@@ -111,6 +113,7 @@ struct hist_entry { · 71 unmodified lines
111113 u64 p_stage_cyc;
112114 u8 cpumode;
113115 u8 depth;
116+ int mem_type_off;
114117 struct simd_flags simd_flags;
115118
116119 /* We are added by hists__add_dummy_entry. */
@@ -154,6 +157,7 @@ struct hist_entry { · 37 unmodified lines
154157 struct perf_hpp_list *hpp_list;
155158 struct hist_entry *parent_he;
156159 struct hist_entry_ops *ops;
160+ struct annotated_data_type *mem_type;
157161 union {
158162 /* this is for hierarchical entry structure */
159163 struct {
@@ -243,6 +247,9 @@ enum sort_type { · 83 unmodified lines
243247 SORT_LOCAL_RETIRE_LAT,
244248 SORT_GLOBAL_RETIRE_LAT,
245249 SORT_SIMD,
250+ SORT_ANNOTATE_DATA_TYPE,
251+ SORT_ANNOTATE_DATA_TYPE_OFFSET,
252+ SORT_SYM_OFFSET,
246253
247254 /* branch stack specific sort keys */
248255 __SORT_BRANCH_STACK,
tools/perf/util/stat-display.c+1−1
@@ -898,7 +898,7 @@ static bool hybrid_uniquify(struct evsel *evsel, struct perf_stat_config *config · 897 unmodified lines
898898
899899 static void uniquify_counter(struct perf_stat_config *config, struct evsel *counter)
900900 {
901− if (config->no_merge || hybrid_uniquify(counter, config))
901+ if (config->aggr_mode == AGGR_NONE || hybrid_uniquify(counter, config))
902902 uniquify_event_name(counter);
903903 }
904904
tools/perf/util/stat-shadow.c+1−1
@@ -264,7 +264,7 @@ static void print_ll_miss(struct perf_stat_config *config, · 263 unmodified lines
264264 static const double color_ratios[3] = {20.0, 10.0, 5.0};
265265
266266 print_ratio(config, evsel, aggr_idx, misses, out, STAT_LL_CACHE, color_ratios,
267− "of all L1-icache accesses");
267+ "of all LL-cache accesses");
268268 }
269269
270270 static void print_dtlb_miss(struct perf_stat_config *config,
tools/perf/util/stat.c+2−2
@@ -315,7 +315,7 @@ static int check_per_pkg(struct evsel *counter, struct perf_counts_values *vals, · 314 unmodified lines
315315 if (!counter->per_pkg)
316316 return 0;
317317
318− if (perf_cpu_map__empty(cpus))
318+ if (perf_cpu_map__has_any_cpu_or_is_empty(cpus))
319319 return 0;
320320
321321 if (!mask) {
@@ -592,7 +592,7 @@ void perf_stat_merge_counters(struct perf_stat_config *config, struct evlist *ev · 270 unmodified lines
592592 {
593593 struct evsel *evsel;
594594
595− if (config->no_merge)
595+ if (config->aggr_mode == AGGR_NONE)
596596 return;
597597
598598 evlist__for_each_entry(evlist, evsel)
tools/perf/util/stat.h+0−1
@@ -76,7 +76,6 @@ struct perf_stat_config { · 75 unmodified lines
7676 bool null_run;
7777 bool ru_display;
7878 bool big_num;
79− bool no_merge;
8079 bool hybrid_merge;
8180 bool walltime_run_table;
8281 bool all_kernel;
tools/perf/util/symbol-elf.c+2−4
@@ -1392,8 +1392,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, · 1391 unmodified lines
13921392 map__set_start(map, shdr->sh_addr + ref_reloc(kmap));
13931393 map__set_end(map, map__start(map) + shdr->sh_size);
13941394 map__set_pgoff(map, shdr->sh_offset);
1395− map__set_map_ip(map, map__dso_map_ip);
1396− map__set_unmap_ip(map, map__dso_unmap_ip);
1395+ map__set_mapping_type(map, MAPPING_TYPE__DSO);
13971396 /* Ensure maps are correctly ordered */
13981397 if (kmaps) {
13991398 int err;
@@ -1455,8 +1454,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, · 55 unmodified lines
14551454 map__set_end(curr_map, map__start(curr_map) + shdr->sh_size);
14561455 map__set_pgoff(curr_map, shdr->sh_offset);
14571456 } else {
1458− map__set_map_ip(curr_map, identity__map_ip);
1459− map__set_unmap_ip(curr_map, identity__map_ip);
1457+ map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY);
14601458 }
14611459 curr_dso->symtab_type = dso->symtab_type;
14621460 if (maps__insert(kmaps, curr_map))
tools/perf/util/symbol-minimal.c+6−4
@@ -159,9 +159,10 @@ int filename__read_build_id(const char *filename, struct build_id *bid) · 158 unmodified lines
159159 goto out_free;
160160
161161 ret = read_build_id(buf, buf_size, bid, need_swap);
162− if (ret == 0)
162+ if (ret == 0) {
163163 ret = bid->size;
164− break;
164+ break;
165+ }
165166 }
166167 } else {
167168 Elf64_Ehdr ehdr;
@@ -210,9 +211,10 @@ int filename__read_build_id(const char *filename, struct build_id *bid) · 42 unmodified lines
210211 goto out_free;
211212
212213 ret = read_build_id(buf, buf_size, bid, need_swap);
213− if (ret == 0)
214+ if (ret == 0) {
214215 ret = bid->size;
215− break;
216+ break;
217+ }
216218 }
217219 }
218220 out_free:
tools/perf/util/symbol.c+29−277
@@ -48,11 +48,6 @@ static bool symbol__is_idle(const char *name); · 47 unmodified lines
4848 int vmlinux_path__nr_entries;
4949 char **vmlinux_path;
5050
51−struct map_list_node {
52− struct list_head node;
53− struct map *map;
54−};
55−
5651 struct symbol_conf symbol_conf = {
5752 .nanosecs = false,
5853 .use_modules = true,
@@ -90,11 +85,6 @@ static enum dso_binary_type binary_type_symtab[] = { · 31 unmodified lines
9085
9186 #define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
9287
93−static struct map_list_node *map_list_node__new(void)
94−{
95− return malloc(sizeof(struct map_list_node));
96−}
97−
9888 static bool symbol_type__filter(char symbol_type)
9989 {
10090 symbol_type = toupper(symbol_type);
@@ -270,29 +260,6 @@ void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms) · 169 unmodified lines
270260 curr->end = roundup(curr->start, 4096) + 4096;
271261 }
272262
273−void maps__fixup_end(struct maps *maps)
274−{
275− struct map_rb_node *prev = NULL, *curr;
276−
277− down_write(maps__lock(maps));
278−
279− maps__for_each_entry(maps, curr) {
280− if (prev != NULL && !map__end(prev->map))
281− map__set_end(prev->map, map__start(curr->map));
282−
283− prev = curr;
284− }
285−
286− /*
287− * We still haven't the actual symbols, so guess the
288− * last map final address.
289− */
290− if (curr && !map__end(curr->map))
291− map__set_end(curr->map, ~0ULL);
292−
293− up_write(maps__lock(maps));
294−}
295−
296263 struct symbol *symbol__new(u64 start, u64 len, u8 binding, u8 type, const char *name)
297264 {
298265 size_t namelen = strlen(name) + 1;
@@ -956,8 +923,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, · 657 unmodified lines
956923 return -1;
957924 }
958925
959− map__set_map_ip(curr_map, identity__map_ip);
960− map__set_unmap_ip(curr_map, identity__map_ip);
926+ map__set_mapping_type(curr_map, MAPPING_TYPE__IDENTITY);
961927 if (maps__insert(kmaps, curr_map)) {
962928 dso__put(ndso);
963929 return -1;
@@ -1148,33 +1114,35 @@ out_delete_from: · 184 unmodified lines
11481114 return ret;
11491115 }
11501116
1117+static int do_validate_kcore_modules_cb(struct map *old_map, void *data)
1118+{
1119+ struct rb_root *modules = data;
1120+ struct module_info *mi;
1121+ struct dso *dso;
1122+
1123+ if (!__map__is_kmodule(old_map))
1124+ return 0;
1125+
1126+ dso = map__dso(old_map);
1127+ /* Module must be in memory at the same address */
1128+ mi = find_module(dso->short_name, modules);
1129+ if (!mi || mi->start != map__start(old_map))
1130+ return -EINVAL;
1131+
1132+ return 0;
1133+}
1134+
11511135 static int do_validate_kcore_modules(const char *filename, struct maps *kmaps)
11521136 {
11531137 struct rb_root modules = RB_ROOT;
1154− struct map_rb_node *old_node;
11551138 int err;
11561139
11571140 err = read_proc_modules(filename, &modules);
11581141 if (err)
11591142 return err;
11601143
1161− maps__for_each_entry(kmaps, old_node) {
1162− struct map *old_map = old_node->map;
1163− struct module_info *mi;
1164− struct dso *dso;
1144+ err = maps__for_each_map(kmaps, do_validate_kcore_modules_cb, &modules);
11651145
1166− if (!__map__is_kmodule(old_map)) {
1167− continue;
1168− }
1169− dso = map__dso(old_map);
1170− /* Module must be in memory at the same address */
1171− mi = find_module(dso->short_name, &modules);
1172− if (!mi || mi->start != map__start(old_map)) {
1173− err = -EINVAL;
1174− goto out;
1175− }
1176− }
1177−out:
11781146 delete_modules(&modules);
11791147 return err;
11801148 }
@@ -1271,101 +1239,15 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data) · 90 unmodified lines
12711239 return 0;
12721240 }
12731241
1274−/*
1275− * Merges map into maps by splitting the new map within the existing map
1276− * regions.
1277− */
1278−int maps__merge_in(struct maps *kmaps, struct map *new_map)
1242+static bool remove_old_maps(struct map *map, void *data)
12791243 {
1280− struct map_rb_node *rb_node;
1281− LIST_HEAD(merged);
1282− int err = 0;
1283−
1284− maps__for_each_entry(kmaps, rb_node) {
1285− struct map *old_map = rb_node->map;
1286−
1287− /* no overload with this one */
1288− if (map__end(new_map) < map__start(old_map) ||
1289− map__start(new_map) >= map__end(old_map))
1290− continue;
1291−
1292− if (map__start(new_map) < map__start(old_map)) {
1293− /*
1294− * |new......
1295− * |old....
1296− */
1297− if (map__end(new_map) < map__end(old_map)) {
1298− /*
1299− * |new......| -> |new..|
1300− * |old....| -> |old....|
1301− */
1302− map__set_end(new_map, map__start(old_map));
1303− } else {
1304− /*
1305− * |new.............| -> |new..| |new..|
1306− * |old....| -> |old....|
1307− */
1308− struct map_list_node *m = map_list_node__new();
1309−
1310− if (!m) {
1311− err = -ENOMEM;
1312− goto out;
1313− }
1314−
1315− m->map = map__clone(new_map);
1316− if (!m->map) {
1317− free(m);
1318− err = -ENOMEM;
1319− goto out;
1320− }
1321−
1322− map__set_end(m->map, map__start(old_map));
1323− list_add_tail(&m->node, &merged);
1324− map__add_pgoff(new_map, map__end(old_map) - map__start(new_map));
1325− map__set_start(new_map, map__end(old_map));
1326− }
1327− } else {
1328− /*
1329− * |new......
1330− * |old....
1331− */
1332− if (map__end(new_map) < map__end(old_map)) {
1333− /*
1334− * |new..| -> x
1335− * |old.........| -> |old.........|
1336− */
1337− map__put(new_map);
1338− new_map = NULL;
1339− break;
1340− } else {
1341− /*
1342− * |new......| -> |new...|
1343− * |old....| -> |old....|
1344− */
1345− map__add_pgoff(new_map, map__end(old_map) - map__start(new_map));
1346− map__set_start(new_map, map__end(old_map));
1347− }
1348− }
1349− }
1350−
1351−out:
1352− while (!list_empty(&merged)) {
1353− struct map_list_node *old_node;
1354−
1355− old_node = list_entry(merged.next, struct map_list_node, node);
1356− list_del_init(&old_node->node);
1357− if (!err)
1358− err = maps__insert(kmaps, old_node->map);
1359− map__put(old_node->map);
1360− free(old_node);
1361− }
1244+ const struct map *map_to_save = data;
13621245
1363− if (new_map) {
1364− if (!err)
1365− err = maps__insert(kmaps, new_map);
1366− map__put(new_map);
1367− }
1368− return err;
1246+ /*
1247+ * We need to preserve eBPF maps even if they are covered by kcore,
1248+ * because we need to access eBPF dso for source data.
1249+ */
1250+ return !RC_CHK_EQUAL(map, map_to_save) && !__map__is_bpf_prog(map);
13691251 }
13701252
13711253 static int dso__load_kcore(struct dso *dso, struct map *map,
@@ -1374,7 +1256,6 @@ static int dso__load_kcore(struct dso *dso, struct map *map, · 2 unmodified lines
13741256 struct maps *kmaps = map__kmaps(map);
13751257 struct kcore_mapfn_data md;
13761258 struct map *replacement_map = NULL;
1377− struct map_rb_node *old_node, *next;
13781259 struct machine *machine;
13791260 bool is_64_bit;
13801261 int err, fd;
@@ -1421,17 +1302,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, · 40 unmodified lines
14211302 }
14221303
14231304 /* Remove old maps */
1424− maps__for_each_entry_safe(kmaps, old_node, next) {
1425− struct map *old_map = old_node->map;
1426−
1427− /*
1428− * We need to preserve eBPF maps even if they are
1429− * covered by kcore, because we need to access
1430− * eBPF dso for source data.
1431− */
1432− if (old_map != map && !__map__is_bpf_prog(old_map))
1433− maps__remove(kmaps, old_map);
1434− }
1305+ maps__remove_maps(kmaps, remove_old_maps, map);
14351306 machine->trampolines_mapped = false;
14361307
14371308 /* Find the kernel map using the '_stext' symbol */
@@ -1475,8 +1346,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map, · 37 unmodified lines
14751346 map__set_start(map, map__start(new_map));
14761347 map__set_end(map, map__end(new_map));
14771348 map__set_pgoff(map, map__pgoff(new_map));
1478− map__set_map_ip(map, map__map_ip_ptr(new_map));
1479− map__set_unmap_ip(map, map__unmap_ip_ptr(new_map));
1349+ map__set_mapping_type(map, map__mapping_type(new_map));
14801350 /* Ensure maps are correctly ordered */
14811351 map_ref = map__get(map);
14821352 maps__remove(kmaps, map_ref);
@@ -2067,124 +1937,6 @@ out: · 584 unmodified lines
20671937 return ret;
20681938 }
20691939
2070−static int map__strcmp(const void *a, const void *b)
2071−{
2072− const struct map *map_a = *(const struct map **)a;
2073− const struct map *map_b = *(const struct map **)b;
2074− const struct dso *dso_a = map__dso(map_a);
2075− const struct dso *dso_b = map__dso(map_b);
2076− int ret = strcmp(dso_a->short_name, dso_b->short_name);
2077−
2078− if (ret == 0 && map_a != map_b) {
2079− /*
2080− * Ensure distinct but name equal maps have an order in part to
2081− * aid reference counting.
2082− */
2083− ret = (int)map__start(map_a) - (int)map__start(map_b);
2084− if (ret == 0)
2085− ret = (int)((intptr_t)map_a - (intptr_t)map_b);
2086− }
2087−
2088− return ret;
2089−}
2090−
2091−static int map__strcmp_name(const void *name, const void *b)
2092−{
2093− const struct dso *dso = map__dso(*(const struct map **)b);
2094−
2095− return strcmp(name, dso->short_name);
2096−}
2097−
2098−void __maps__sort_by_name(struct maps *maps)
2099−{
2100− qsort(maps__maps_by_name(maps), maps__nr_maps(maps), sizeof(struct map *), map__strcmp);
2101−}
2102−
2103−static int map__groups__sort_by_name_from_rbtree(struct maps *maps)
2104−{
2105− struct map_rb_node *rb_node;
2106− struct map **maps_by_name = realloc(maps__maps_by_name(maps),
2107− maps__nr_maps(maps) * sizeof(struct map *));
2108− int i = 0;
2109−
2110− if (maps_by_name == NULL)
2111− return -1;
2112−
2113− up_read(maps__lock(maps));
2114− down_write(maps__lock(maps));
2115−
2116− RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name;
2117− RC_CHK_ACCESS(maps)->nr_maps_allocated = maps__nr_maps(maps);
2118−
2119− maps__for_each_entry(maps, rb_node)
2120− maps_by_name[i++] = map__get(rb_node->map);
2121−
2122− __maps__sort_by_name(maps);
2123−
2124− up_write(maps__lock(maps));
2125− down_read(maps__lock(maps));
2126−
2127− return 0;
2128−}
2129−
2130−static struct map *__maps__find_by_name(struct maps *maps, const char *name)
2131−{
2132− struct map **mapp;
2133−
2134− if (maps__maps_by_name(maps) == NULL &&
2135− map__groups__sort_by_name_from_rbtree(maps))
2136− return NULL;
2137−
2138− mapp = bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps),
2139− sizeof(*mapp), map__strcmp_name);
2140− if (mapp)
2141− return *mapp;
2142− return NULL;
2143−}
2144−
2145−struct map *maps__find_by_name(struct maps *maps, const char *name)
2146−{
2147− struct map_rb_node *rb_node;
2148− struct map *map;
2149−
2150− down_read(maps__lock(maps));
2151−
2152−
2153− if (RC_CHK_ACCESS(maps)->last_search_by_name) {
2154− const struct dso *dso = map__dso(RC_CHK_ACCESS(maps)->last_search_by_name);
2155−
2156− if (strcmp(dso->short_name, name) == 0) {
2157− map = RC_CHK_ACCESS(maps)->last_search_by_name;
2158− goto out_unlock;
2159− }
2160− }
2161− /*
2162− * If we have maps->maps_by_name, then the name isn't in the rbtree,
2163− * as maps->maps_by_name mirrors the rbtree when lookups by name are
2164− * made.
2165− */
2166− map = __maps__find_by_name(maps, name);
2167− if (map || maps__maps_by_name(maps) != NULL)
2168− goto out_unlock;
2169−
2170− /* Fallback to traversing the rbtree... */
2171− maps__for_each_entry(maps, rb_node) {
2172− struct dso *dso;
2173−
2174− map = rb_node->map;
2175− dso = map__dso(map);
2176− if (strcmp(dso->short_name, name) == 0) {
2177− RC_CHK_ACCESS(maps)->last_search_by_name = map;
2178− goto out_unlock;
2179− }
2180− }
2181− map = NULL;
2182−
2183−out_unlock:
2184− up_read(maps__lock(maps));
2185− return map;
2186−}
2187−
21881940 int dso__load_vmlinux(struct dso *dso, struct map *map,
21891941 const char *vmlinux, bool vmlinux_allocated)
21901942 {
tools/perf/util/symbol.h+0−1
@@ -189,7 +189,6 @@ void __symbols__insert(struct rb_root_cached *symbols, struct symbol *sym, · 188 unmodified lines
189189 void symbols__insert(struct rb_root_cached *symbols, struct symbol *sym);
190190 void symbols__fixup_duplicate(struct rb_root_cached *symbols);
191191 void symbols__fixup_end(struct rb_root_cached *symbols, bool is_kallsyms);
192−void maps__fixup_end(struct maps *maps);
193192
194193 typedef int (*mapfn_t)(u64 start, u64 len, u64 pgoff, void *data);
195194 int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
tools/perf/util/symbol_conf.h+5−1
@@ -42,7 +42,11 @@ struct symbol_conf { · 41 unmodified lines
4242 inline_name,
4343 disable_add2line_warn,
4444 buildid_mmap2,
45− guest_code;
45+ guest_code,
46+ lazy_load_kernel_maps,
47+ keep_exited_threads,
48+ annotate_data_member,
49+ annotate_data_sample;
4650 const char *vmlinux_name,
4751 *kallsyms_name,
4852 *source_prefix,
tools/perf/util/synthetic-events.c+67−51
@@ -665,18 +665,74 @@ int perf_event__synthesize_cgroups(struct perf_tool *tool __maybe_unused, · 664 unmodified lines
665665 }
666666 #endif
667667
668+struct perf_event__synthesize_modules_maps_cb_args {
669+ struct perf_tool *tool;
670+ perf_event__handler_t process;
671+ struct machine *machine;
672+ union perf_event *event;
673+};
674+
675+static int perf_event__synthesize_modules_maps_cb(struct map *map, void *data)
676+{
677+ struct perf_event__synthesize_modules_maps_cb_args *args = data;
678+ union perf_event *event = args->event;
679+ struct dso *dso;
680+ size_t size;
681+
682+ if (!__map__is_kmodule(map))
683+ return 0;
684+
685+ dso = map__dso(map);
686+ if (symbol_conf.buildid_mmap2) {
687+ size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64));
688+ event->mmap2.header.type = PERF_RECORD_MMAP2;
689+ event->mmap2.header.size = (sizeof(event->mmap2) -
690+ (sizeof(event->mmap2.filename) - size));
691+ memset(event->mmap2.filename + size, 0, args->machine->id_hdr_size);
692+ event->mmap2.header.size += args->machine->id_hdr_size;
693+ event->mmap2.start = map__start(map);
694+ event->mmap2.len = map__size(map);
695+ event->mmap2.pid = args->machine->pid;
696+
697+ memcpy(event->mmap2.filename, dso->long_name, dso->long_name_len + 1);
698+
699+ perf_record_mmap2__read_build_id(&event->mmap2, args->machine, false);
700+ } else {
701+ size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64));
702+ event->mmap.header.type = PERF_RECORD_MMAP;
703+ event->mmap.header.size = (sizeof(event->mmap) -
704+ (sizeof(event->mmap.filename) - size));
705+ memset(event->mmap.filename + size, 0, args->machine->id_hdr_size);
706+ event->mmap.header.size += args->machine->id_hdr_size;
707+ event->mmap.start = map__start(map);
708+ event->mmap.len = map__size(map);
709+ event->mmap.pid = args->machine->pid;
710+
711+ memcpy(event->mmap.filename, dso->long_name, dso->long_name_len + 1);
712+ }
713+
714+ if (perf_tool__process_synth_event(args->tool, event, args->machine, args->process) != 0)
715+ return -1;
716+
717+ return 0;
718+}
719+
668720 int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process,
669721 struct machine *machine)
670722 {
671− int rc = 0;
672− struct map_rb_node *pos;
723+ int rc;
673724 struct maps *maps = machine__kernel_maps(machine);
674− union perf_event *event;
675− size_t size = symbol_conf.buildid_mmap2 ?
676− sizeof(event->mmap2) : sizeof(event->mmap);
725+ struct perf_event__synthesize_modules_maps_cb_args args = {
726+ .tool = tool,
727+ .process = process,
728+ .machine = machine,
729+ };
730+ size_t size = symbol_conf.buildid_mmap2
731+ ? sizeof(args.event->mmap2)
732+ : sizeof(args.event->mmap);
677733
678− event = zalloc(size + machine->id_hdr_size);
679− if (event == NULL) {
734+ args.event = zalloc(size + machine->id_hdr_size);
735+ if (args.event == NULL) {
680736 pr_debug("Not enough memory synthesizing mmap event "
681737 "for kernel modules\n");
682738 return -1;
@@ -687,53 +743,13 @@ int perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t · 4 unmodified lines
687743 * __perf_event_mmap
688744 */
689745 if (machine__is_host(machine))
690− event->header.misc = PERF_RECORD_MISC_KERNEL;
746+ args.event->header.misc = PERF_RECORD_MISC_KERNEL;
691747 else
692− event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
693−
694− maps__for_each_entry(maps, pos) {
695− struct map *map = pos->map;
696− struct dso *dso;
748+ args.event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
697749
698− if (!__map__is_kmodule(map))
699− continue;
750+ rc = maps__for_each_map(maps, perf_event__synthesize_modules_maps_cb, &args);
700751
701− dso = map__dso(map);
702− if (symbol_conf.buildid_mmap2) {
703− size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64));
704− event->mmap2.header.type = PERF_RECORD_MMAP2;
705− event->mmap2.header.size = (sizeof(event->mmap2) -
706− (sizeof(event->mmap2.filename) - size));
707− memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
708− event->mmap2.header.size += machine->id_hdr_size;
709− event->mmap2.start = map__start(map);
710− event->mmap2.len = map__size(map);
711− event->mmap2.pid = machine->pid;
712−
713− memcpy(event->mmap2.filename, dso->long_name, dso->long_name_len + 1);
714−
715− perf_record_mmap2__read_build_id(&event->mmap2, machine, false);
716− } else {
717− size = PERF_ALIGN(dso->long_name_len + 1, sizeof(u64));
718− event->mmap.header.type = PERF_RECORD_MMAP;
719− event->mmap.header.size = (sizeof(event->mmap) -
720− (sizeof(event->mmap.filename) - size));
721− memset(event->mmap.filename + size, 0, machine->id_hdr_size);
722− event->mmap.header.size += machine->id_hdr_size;
723− event->mmap.start = map__start(map);
724− event->mmap.len = map__size(map);
725− event->mmap.pid = machine->pid;
726−
727− memcpy(event->mmap.filename, dso->long_name, dso->long_name_len + 1);
728− }
729−
730− if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
731− rc = -1;
732− break;
733− }
734− }
735−
736− free(event);
752+ free(args.event);
737753 return rc;
738754 }
739755
tools/perf/util/thread.c+20−22
@@ -345,38 +345,36 @@ int thread__insert_map(struct thread *thread, struct map *map) · 344 unmodified lines
345345 if (ret)
346346 return ret;
347347
348− maps__fixup_overlappings(thread__maps(thread), map, stderr);
349− return maps__insert(thread__maps(thread), map);
348+ return maps__fixup_overlap_and_insert(thread__maps(thread), map);
350349 }
351350
352−static int __thread__prepare_access(struct thread *thread)
351+struct thread__prepare_access_maps_cb_args {
352+ int err;
353+ struct maps *maps;
354+};
355+
356+static int thread__prepare_access_maps_cb(struct map *map, void *data)
353357 {
354358 bool initialized = false;
355− int err = 0;
356− struct maps *maps = thread__maps(thread);
357− struct map_rb_node *rb_node;
358−
359− down_read(maps__lock(maps));
360−
361− maps__for_each_entry(maps, rb_node) {
362− err = unwind__prepare_access(thread__maps(thread), rb_node->map, &initialized);
363− if (err || initialized)
364− break;
365− }
359+ struct thread__prepare_access_maps_cb_args *args = data;
366360
367− up_read(maps__lock(maps));
361+ args->err = unwind__prepare_access(args->maps, map, &initialized);
368362
369− return err;
363+ return (args->err || initialized) ? 1 : 0;
370364 }
371365
372366 static int thread__prepare_access(struct thread *thread)
373367 {
374− int err = 0;
368+ struct thread__prepare_access_maps_cb_args args = {
369+ .err = 0,
370+ };
375371
376− if (dwarf_callchain_users)
377− err = __thread__prepare_access(thread);
372+ if (dwarf_callchain_users) {
373+ args.maps = thread__maps(thread);
374+ maps__for_each_map(thread__maps(thread), thread__prepare_access_maps_cb, &args);
375+ }
378376
379− return err;
377+ return args.err;
380378 }
381379
382380 static int thread__clone_maps(struct thread *thread, struct thread *parent, bool do_maps_clone)
@@ -385,14 +383,14 @@ static int thread__clone_maps(struct thread *thread, struct thread *parent, bool · 2 unmodified lines
385383 if (thread__pid(thread) == thread__pid(parent))
386384 return thread__prepare_access(thread);
387385
388− if (thread__maps(thread) == thread__maps(parent)) {
386+ if (RC_CHK_EQUAL(thread__maps(thread), thread__maps(parent))) {
389387 pr_debug("broken map groups on thread %d/%d parent %d/%d\n",
390388 thread__pid(thread), thread__tid(thread),
391389 thread__pid(parent), thread__tid(parent));
392390 return 0;
393391 }
394392 /* But this one is new process, copy maps. */
395− return do_maps_clone ? maps__clone(thread, thread__maps(parent)) : 0;
393+ return do_maps_clone ? maps__copy_from(thread__maps(thread), thread__maps(parent)) : 0;
396394 }
397395
398396 int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp, bool do_maps_clone)
tools/perf/util/thread.h+14−0
@@ -36,13 +36,22 @@ struct thread_rb_node { · 35 unmodified lines
3636 };
3737
3838 DECLARE_RC_STRUCT(thread) {
39+ /** @maps: mmaps associated with this thread. */
3940 struct maps *maps;
4041 pid_t pid_; /* Not all tools update this */
42+ /** @tid: thread ID number unique to a machine. */
4143 pid_t tid;
44+ /** @ppid: parent process of the process this thread belongs to. */
4245 pid_t ppid;
4346 int cpu;
4447 int guest_cpu; /* For QEMU thread */
4548 refcount_t refcnt;
49+ /**
50+ * @exited: Has the thread had an exit event. Such threads are usually
51+ * removed from the machine's threads but some events/tools require
52+ * access to dead threads.
53+ */
54+ bool exited;
4655 bool comm_set;
4756 int comm_len;
4857 struct list_head namespaces_list;
@@ -189,6 +198,11 @@ static inline refcount_t *thread__refcnt(struct thread *thread) · 140 unmodified lines
189198 return &RC_CHK_ACCESS(thread)->refcnt;
190199 }
191200
201+static inline void thread__set_exited(struct thread *thread, bool exited)
202+{
203+ RC_CHK_ACCESS(thread)->exited = exited;
204+}
205+
192206 static inline bool thread__comm_set(const struct thread *thread)
193207 {
194208 return RC_CHK_ACCESS(thread)->comm_set;
tools/perf/util/top.c+4−5
@@ -28,6 +28,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) · 27 unmodified lines
2828 struct record_opts *opts = &top->record_opts;
2929 struct target *target = &opts->target;
3030 size_t ret = 0;
31+ int nr_cpus;
3132
3233 if (top->samples) {
3334 samples_per_sec = top->samples / top->delay_secs;
@@ -93,19 +94,17 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) · 59 unmodified lines
9394 else
9495 ret += SNPRINTF(bf + ret, size - ret, " (all");
9596
97+ nr_cpus = perf_cpu_map__nr(top->evlist->core.user_requested_cpus);
9698 if (target->cpu_list)
9799 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
98− perf_cpu_map__nr(top->evlist->core.user_requested_cpus) > 1
99− ? "s" : "",
100+ nr_cpus > 1 ? "s" : "",
100101 target->cpu_list);
101102 else {
102103 if (target->tid)
103104 ret += SNPRINTF(bf + ret, size - ret, ")");
104105 else
105106 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
106− perf_cpu_map__nr(top->evlist->core.user_requested_cpus),
107− perf_cpu_map__nr(top->evlist->core.user_requested_cpus) > 1
108− ? "s" : "");
107+ nr_cpus, nr_cpus > 1 ? "s" : "");
109108 }
110109
111110 perf_top__reset_sample_counters(top);
tools/perf/util/top.h+0−1
@@ -21,7 +21,6 @@ struct perf_top { · 20 unmodified lines
2121 struct perf_tool tool;
2222 struct evlist *evlist, *sb_evlist;
2323 struct record_opts record_opts;
24− struct annotation_options annotation_opts;
2524 struct evswitch evswitch;
2625 /*
2726 * Symbols will be added here in perf_event__process_sample and will
tools/perf/util/unwind-libdw.c+17−4
@@ -46,6 +46,7 @@ static int __report_module(struct addr_location *al, u64 ip, · 45 unmodified lines
4646 {
4747 Dwfl_Module *mod;
4848 struct dso *dso = NULL;
49+ Dwarf_Addr base;
4950 /*
5051 * Some callers will use al->sym, so we can't just use the
5152 * cheaper thread__find_map() here.
@@ -58,13 +59,25 @@ static int __report_module(struct addr_location *al, u64 ip, · 6 unmodified lines
5859 if (!dso)
5960 return 0;
6061
62+ /*
63+ * The generated JIT DSO files only map the code segment without
64+ * ELF headers. Since JIT codes used to be packed in a memory
65+ * segment, calculating the base address using pgoff falls into
66+ * a different code in another DSO. So just use the map->start
67+ * directly to pick the correct one.
68+ */
69+ if (!strncmp(dso->long_name, "/tmp/jitted-", 12))
70+ base = map__start(al->map);
71+ else
72+ base = map__start(al->map) - map__pgoff(al->map);
73+
6174 mod = dwfl_addrmodule(ui->dwfl, ip);
6275 if (mod) {
6376 Dwarf_Addr s;
6477
6578 dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
66− if (s != map__start(al->map) - map__pgoff(al->map))
67− mod = 0;
79+ if (s != base)
80+ mod = NULL;
6881 }
6982
7083 if (!mod) {
@@ -72,14 +85,14 @@ static int __report_module(struct addr_location *al, u64 ip, · 1 unmodified line
7285
7386 __symbol__join_symfs(filename, sizeof(filename), dso->long_name);
7487 mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
75− map__start(al->map) - map__pgoff(al->map), false);
88+ base, false);
7689 }
7790 if (!mod) {
7891 char filename[PATH_MAX];
7992
8093 if (dso__build_id_filename(dso, filename, sizeof(filename), false))
8194 mod = dwfl_report_elf(ui->dwfl, dso->short_name, filename, -1,
82− map__start(al->map) - map__pgoff(al->map), false);
95+ base, false);
8396 }
8497
8598 if (mod) {
tools/perf/util/unwind-libunwind-local.c+24−10
@@ -302,12 +302,31 @@ static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, · 301 unmodified lines
302302 return 0;
303303 }
304304
305+struct read_unwind_spec_eh_frame_maps_cb_args {
306+ struct dso *dso;
307+ u64 base_addr;
308+};
309+
310+static int read_unwind_spec_eh_frame_maps_cb(struct map *map, void *data)
311+{
312+
313+ struct read_unwind_spec_eh_frame_maps_cb_args *args = data;
314+
315+ if (map__dso(map) == args->dso && map__start(map) - map__pgoff(map) < args->base_addr)
316+ args->base_addr = map__start(map) - map__pgoff(map);
317+
318+ return 0;
319+}
320+
321+
305322 static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui,
306323 u64 *table_data, u64 *segbase,
307324 u64 *fde_count)
308325 {
309− struct map_rb_node *map_node;
310− u64 base_addr = UINT64_MAX;
326+ struct read_unwind_spec_eh_frame_maps_cb_args args = {
327+ .dso = dso,
328+ .base_addr = UINT64_MAX,
329+ };
311330 int ret, fd;
312331
313332 if (dso->data.eh_frame_hdr_offset == 0) {
@@ -325,16 +344,11 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *ui, · 11 unmodified lines
325344 return -EINVAL;
326345 }
327346
328− maps__for_each_entry(thread__maps(ui->thread), map_node) {
329− struct map *map = map_node->map;
330− u64 start = map__start(map);
347+ maps__for_each_map(thread__maps(ui->thread), read_unwind_spec_eh_frame_maps_cb, &args);
331348
332− if (map__dso(map) == dso && start < base_addr)
333− base_addr = start;
334− }
335− base_addr -= dso->data.elf_base_addr;
349+ args.base_addr -= dso->data.elf_base_addr;
336350 /* Address of .eh_frame_hdr */
337− *segbase = base_addr + dso->data.eh_frame_hdr_addr;
351+ *segbase = args.base_addr + dso->data.eh_frame_hdr_addr;
338352 ret = unwind_spec_ehframe(dso, ui->machine, dso->data.eh_frame_hdr_offset,
339353 table_data, fde_count);
340354 if (ret)
tools/perf/util/vdso.c+23−12
@@ -140,23 +140,34 @@ static struct dso *__machine__addnew_vdso(struct machine *machine, const char *s · 139 unmodified lines
140140 return dso;
141141 }
142142
143+struct machine__thread_dso_type_maps_cb_args {
144+ struct machine *machine;
145+ enum dso_type dso_type;
146+};
147+
148+static int machine__thread_dso_type_maps_cb(struct map *map, void *data)
149+{
150+ struct machine__thread_dso_type_maps_cb_args *args = data;
151+ struct dso *dso = map__dso(map);
152+
153+ if (!dso || dso->long_name[0] != '/')
154+ return 0;
155+
156+ args->dso_type = dso__type(dso, args->machine);
157+ return (args->dso_type != DSO__TYPE_UNKNOWN) ? 1 : 0;
158+}
159+
143160 static enum dso_type machine__thread_dso_type(struct machine *machine,
144161 struct thread *thread)
145162 {
146− enum dso_type dso_type = DSO__TYPE_UNKNOWN;
147− struct map_rb_node *rb_node;
148−
149− maps__for_each_entry(thread__maps(thread), rb_node) {
150− struct dso *dso = map__dso(rb_node->map);
163+ struct machine__thread_dso_type_maps_cb_args args = {
164+ .machine = machine,
165+ .dso_type = DSO__TYPE_UNKNOWN,
166+ };
151167
152− if (!dso || dso->long_name[0] != '/')
153− continue;
154− dso_type = dso__type(dso, machine);
155− if (dso_type != DSO__TYPE_UNKNOWN)
156− break;
157− }
168+ maps__for_each_map(thread__maps(thread), machine__thread_dso_type_maps_cb, &args);
158169
159− return dso_type;
170+ return args.dso_type;
160171 }
161172
162173 #if BITS_PER_LONG == 64
tools/perf/util/zstd.c+33−30
@@ -7,35 +7,9 @@ · 6 unmodified lines
77
88 int zstd_init(struct zstd_data *data, int level)
99 {
10− size_t ret;
11−
12− data->dstream = ZSTD_createDStream();
13− if (data->dstream == NULL) {
14− pr_err("Couldn't create decompression stream.\n");
15− return -1;
16− }
17−
18− ret = ZSTD_initDStream(data->dstream);
19− if (ZSTD_isError(ret)) {
20− pr_err("Failed to initialize decompression stream: %s\n", ZSTD_getErrorName(ret));
21− return -1;
22− }
23−
24− if (!level)
25− return 0;
26−
27− data->cstream = ZSTD_createCStream();
28− if (data->cstream == NULL) {
29− pr_err("Couldn't create compression stream.\n");
30− return -1;
31− }
32−
33− ret = ZSTD_initCStream(data->cstream, level);
34− if (ZSTD_isError(ret)) {
35− pr_err("Failed to initialize compression stream: %s\n", ZSTD_getErrorName(ret));
36− return -1;
37− }
38−
10+ data->comp_level = level;
11+ data->dstream = NULL;
12+ data->cstream = NULL;
3913 return 0;
4014 }
4115
@@ -54,7 +28,7 @@ int zstd_fini(struct zstd_data *data) · 12 unmodified lines
5428 return 0;
5529 }
5630
57−size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,
31+ssize_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t dst_size,
5832 void *src, size_t src_size, size_t max_record_size,
5933 size_t process_header(void *record, size_t increment))
6034 {
@@ -63,6 +37,21 @@ size_t zstd_compress_stream_to_records(struct zstd_data *data, void *dst, size_t · 2 unmodified lines
6337 ZSTD_outBuffer output;
6438 void *record;
6539
40+ if (!data->cstream) {
41+ data->cstream = ZSTD_createCStream();
42+ if (data->cstream == NULL) {
43+ pr_err("Couldn't create compression stream.\n");
44+ return -1;
45+ }
46+
47+ ret = ZSTD_initCStream(data->cstream, data->comp_level);
48+ if (ZSTD_isError(ret)) {
49+ pr_err("Failed to initialize compression stream: %s\n",
50+ ZSTD_getErrorName(ret));
51+ return -1;
52+ }
53+ }
54+
6655 while (input.pos < input.size) {
6756 record = dst;
6857 size = process_header(record, 0);
@@ -96,6 +85,20 @@ size_t zstd_decompress_stream(struct zstd_data *data, void *src, size_t src_size · 27 unmodified lines
9685 ZSTD_inBuffer input = { src, src_size, 0 };
9786 ZSTD_outBuffer output = { dst, dst_size, 0 };
9887
88+ if (!data->dstream) {
89+ data->dstream = ZSTD_createDStream();
90+ if (data->dstream == NULL) {
91+ pr_err("Couldn't create decompression stream.\n");
92+ return 0;
93+ }
94+
95+ ret = ZSTD_initDStream(data->dstream);
96+ if (ZSTD_isError(ret)) {
97+ pr_err("Failed to initialize decompression stream: %s\n",
98+ ZSTD_getErrorName(ret));
99+ return 0;
100+ }
101+ }
99102 while (input.pos < input.size) {
100103 ret = ZSTD_decompressStream(data->dstream, &output, &input);
101104 if (ZSTD_isError(ret)) {